雑記

ものを書く練習。学びをまとめる場。

Chromiumを手探る 2

前回に引き続き、chromiumにシークレットタブを導入することを目標に奮闘していきます。
記載忘れていましたが使用しているOSは macOS High Sierra です。

いざ実装

はじめに

今日のこの記事を読んで真似してみようとしてくださる方がもしいらっしゃるならば、必ず一度は最後まで目を通してからにしてください。

NewIncognitoTab() の追加

まずは Window について
NewWindow(Browser* browser_);
NewIncognitoWindow(Browser* browser)
があるので、Tab についても同様に
NewTab(Browser* browser_);
NewIncognitoTab(Browser* browser)
を追加して Window の構造を真似してみます。

/src/chrome/browser/ui/browser_commands.cc

void NewTab(Browser* browser){
  NewEmptyTab(browser, browser->profile()->GetOriginalProfile());
}
void NewIncognitoTab(Browser* browser){
  // よくわからないフラグなのでコピーだけしておく
  #if 0
  #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
    feature_engagement::IncognitoWindowTrackerFactory::GetInstance()
        ->GetForProfile(browser->profile())
        ->OnIncognitoWindowOpened();
  #endif
  #endif
  NewEmptyTab(browser, browser->profile()->GetOffTheRecordProfile());
}
    
void NewEmptyTab(Browser* browser, Profile* profile){
  // incognitoとbrowser->profile()を一致させる?
  bool incognito = profile->IsOffTheRecord();
  PrefService* prefs = profile->GetPrefs();
  if (incognito) {
    if (IncognitoModePrefs::GetAvailability(prefs) ==
          IncognitoModePrefs::DISABLED) {
      incognito = false;
    }
  } else if (profile->IsGuestSession() ||
             (browser_defaults::kAlwaysOpenIncognitoWindow &&
              IncognitoModePrefs::ShouldLaunchIncognito(
                  *base::CommandLine::ForCurrentProcess(), prefs))) {
    incognito = true;
  }

  if (incognito){
      base::RecordAction(UserMetricsAction("NewIncognitoTab"));
      // TODO(asvitkine): This is invoked programmatically from several places.
      // Audit the code and change it so that the histogram only gets collected for
      // user-initiated commands.
      UMA_HISTOGRAM_ENUMERATION("Tab.NewIncognitoTab", TabStripModel::NEW_TAB_COMMAND,
                                TabStripModel::NEW_TAB_ENUM_COUNT);
      
      SetTabProfile(profile()->GetOffTheRecordProfile());
      
      if (browser->is_type_tabbed()) {
          AddTabAt(browser, GURL(), -1, true);
          browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
      } else {
          ScopedTabbedBrowserDisplayer displayer(browser->profile());
          Browser* b = displayer.browser();
          AddTabAt(b, GURL(), -1, true);
          b->window()->Show();
          // The call to AddBlankTabAt above did not set the focus to the tab as its
          // window was not active, so we have to do it explicitly.
          // See http://crbug.com/6380.
          b->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
      }
  }else{
      base::RecordAction(UserMetricsAction("NewTab"));
      // TODO(asvitkine): This is invoked programmatically from several places.
      // Audit the code and change it so that the histogram only gets collected for
      // user-initiated commands.
      UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
                                TabStripModel::NEW_TAB_ENUM_COUNT);
      
      SessionService* session_service =
      SessionServiceFactory::GetForProfileForSessionRestore(profile->GetOriginalProfile());
      if (!session_service ||
          !session_service->RestoreIfNecessary(std::vector<GURL>())) {
          
          SetTabProfile(profile()->GetOriginalProfile());
          
          if (browser->is_type_tabbed()) {
              AddTabAt(browser, GURL(), -1, true);
              browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
          } else {
              ScopedTabbedBrowserDisplayer displayer(browser->profile());
              Browser* b = displayer.browser();
              AddTabAt(b, GURL(), -1, true);
              b->window()->Show();
              // The call to AddBlankTabAt above did not set the focus to the tab as its
              // window was not active, so we have to do it explicitly.
              // See http://crbug.com/6380.
              b->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
          }
      }
  }
}
Browser* SetTabProfile(Profile* profile) {
    Browser* browser =
    new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true));
    return browser;
}

当然ヘッダーにも新しく作った関数を入れておきます。

これで後はシークレットタブを開くGUIやらショートカットーキーを用意すれば大丈夫だとこの時は信じていました。

Chromiumのメニューにボタンを追加

chrome_command_ids.h に大量のIDC_...が定義されているので

#define IDC_NEW_INCOGNITO_TAB 34002

を追加。
ここからは chrome code searchIDC_NEW_TAB を検索してヒットしたところを全部読んで必要な関数とかをどんどん追記していきます。(以下長くなります)

browser_command_controller.cc

bool BrowserCommandController::IsReservedCommandOrKey(
    int command_id,
    const content::NativeWebKeyboardEvent& event) {
 ・・・
 return command_id == IDC_CLOSE_TAB ||
         command_id == IDC_CLOSE_WINDOW ||
         command_id == IDC_NEW_INCOGNITO_TAB ||
    ・・・       
}

bool BrowserCommandController::ExecuteCommandWithDisposition(
    int id, WindowOpenDisposition disposition) {
 ・・・
 switch (id) {
  ・・・
  case IDC_NEW_INCOGNITO_TAB: {
   NewIncognitoTab(browser_);
#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
   // This is not in NewTab() to avoid tracking programmatic creation of new
   // tabs by extensions.
        auto* new_tab_tracker =
           feature_engagement::NewTabTrackerFactory::GetInstance()
                  ->GetForProfile(profile());

          new_tab_tracker->OnNewTabOpened();
          new_tab_tracker->CloseBubble();
#endif
          break;
       }
void BrowserCommandController::InitCommandState() {
 ・・・
 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_TAB, true);
 ・・・
}

Cmd + Shift + T で新しいシークレットタブを開きたかったので accelerator.cc

namespace{
 ・・・
 const AcceleratorMapping kAcceleratorMap[] = {
  ・・・
  #if 1
  {ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR,
  IDC_NEW_INCOGNITO_TAB},
     #else
     {ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR,
      IDC_RESTORE_TAB},
     #endif
  ・・・
 }
・・・
}

とし、タブ修復のキーを消す形にしました。

tab_strip_model.cc

// static
bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id,
                                                       int* browser_cmd) {
  switch (cmd_id) {
    case CommandNewTab:
      *browser_cmd = IDC_NEW_TAB;
      break;
    case CommandNewIncognitoTab:
      *browser_cmd = IDC_NEW_INCOGNITO_TAB;
      break;
    ・・・
  }
  return true;
}

ちゃんとヘッダーにも CommandNewIncognitoTab を追加しています。

app_menu_model.cc

void AppMenuModel::LogMenuMetrics(int command_id) {
    base::TimeDelta delta = timer_.Elapsed();

    switch (command_id) {
 ・・・
    case IDC_NEW_INCOGNITO_TAB:
        if (!uma_action_recorded_) {
            UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewIncognitoTab",
                                   delta);
        }
        LogMenuAction(MENU_ACTION_NEW_INCOGNITO_TAB);
        break;
 ・・・
 }
・・・
}
void AppMenuModel::Build() {
 ・・・
 if (ShouldShowNewIncognitoWindowMenuItem()){
  AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
  AddItemWithStringId(IDC_NEW_INCOGNITO_TAB, IDS_NEW_INCOGNITO_TAB);
    }
・・・
}

MENU_ACTION_NEW_INCOGNITO_TAB を定義したいので、app_menu_model.h

enum AppMenuAction {
 ・・・
 MENU_ACTION_NEW_INCOGNITO_TAB = 10,
 ・・・
}

を追加。
IDS_NEW_INCOGNITO_TAB を定義したいので、global_menu_bar_x11.cc

namespace{
・・・
 GlobalMenuBarCommand file_menu[] = {
 ・・・
 { IDS_NEW_INCOGNITO_TAB, IDC_NEW_INCOGNITO_TAB },
 ・・・
 }
・・・
}

を追加。
system_menu_model_builder.cc

void SystemMenuModelBuilder::BuildSystemMenuForBrowserWindow(
    ui::SimpleMenuModel* model) {
  ・・・
  model->AddItemWithStringId(IDC_NEW_INCOGNITO_TAB, IDS_NEW_INCOGNITO_TAB);
  ・・・
}

新しい定数が出てきたので startup_resources_mac.txt

IDS_NEW_INCOGNITO_TAB_MAC 366 

を追加。
generated_resources.grd

・・・
<grit base_dir="." latest_public_release="0" current_release="1"
      output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
  <outputs>
  ・・・
  <release seq="1" allow_pseudo="false">
    <messages fallback_to_english="true">
      ・・・
      <if expr="not is_android">
        <if expr="not use_titlecase">
          ・・・
          <message name="IDS_NEW_INCOGNITO_TAB" desc="The text label of a menu item for opening a new incognito tab">
            New &amp;incognito tab
          </message>
    ・・・
        </if>
        <if expr="use_titlecase">
          ・・・
          <message name="IDS_NEW_INCOGNITO_TAB" desc="In Title Case: The text label of a menu item for opening a new incognito tab">
            New &amp;Incognito Tab
          </message>
          ・・・
        </if>
      </if>
      ・・・
      <if expr="is_macosx">
        ・・・
        <message name="IDS_NEW_INCOGNITO_TAB_MAC" desc="The Mac menu item for opening a new incognito tab in the file menu.">
          New Incognito Tab
        </message>
        ・・・
      </if>
      ・・・  
    </messages>
  </release>
</grit>

app_controller_mac.mm

- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
  ・・・
  if (action == @selector(commandDispatch:) ||
      action == @selector(commandFromDock:)) {
    ・・・
    if (menuState_ &&  // NULL in tests.
        menuState_->SupportsCommand(tag)) {
      switch (tag) {
        ・・・
        case IDC_NEW_INCOGNITO_TAB:
        ・・・
      }
    }
    ・・・
  }
  ・・・
}

- (void)commandDispatch:(id)sender {
  ・・・
  switch (tag) {
    ・・・
    case IDC_NEW_INCOGNITO_TAB:
      // Create a new tab in an existing browser window (which we activate) if
      // possible.
      if (Browser* browser = ActivateBrowser(lastProfile->GetOffTheRecordProfile())) {
        chrome::ExecuteCommand(browser, IDC_NEW_INCOGNITO_TAB);
        break;
      }
      FALLTHROUGH;  // To create new window.
  }
}
- (void)initMenuState {
  menuState_ = std::make_unique<CommandUpdaterImpl>(nullptr);
  menuState_->UpdateCommandEnabled(IDC_NEW_TAB, true);
  menuState_->UpdateCommandEnabled(IDC_NEW_INCOGNITO_TAB, true);
 ・・・
}

cocoa とかいう macOS でしか使わなさそうなファイルの中にも aceelerator がいたので編集します。
accelerators_cocoa.mm にて

namespace {

const struct AcceleratorMapping {
  int command_id;
  int modifiers;              // The ui::EventFlag modifiers
  ui::KeyboardCode key_code;  // The key used for cross-platform compatibility.
} kAcceleratorMap[] = {
    ・・・
    #if 1
    {IDC_NEW_INCOGNITO_TAB, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN,
     ui::VKEY_T},
    #else
    {IDC_RESTORE_TAB, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_T},
    #endif
 ・・・
}
・・・
}

今度は NEW_TAB で当たってみました。
ash なので意味がないかもしれませんが、accelerators.h

namespace ash{

enum AcceleratorAction{
 ・・・
 NEW_INCOGNITO_TAB,
 ・・・
}
}

accelerators.cc

namespace ash {

const AcceleratorData kAcceleratorData[] = {
 ・・・
 #if  1
    {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
     NEW_INCOGNITO_TAB},
    #else
    {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, RESTORE_TAB},
    #endif
 ・・・
}
const size_t kAcceleratorDataLength = arraysize(kAcceleratorData);
}  

ビルドしてみたが...?

おそらく大体の変更が終了したのでひとまずビルドしてみることに。
1回目は上記の全てをきちんと行えていたわけではないので、出てくるエラーを修正しながら根性でビルドビルドビルド......

ついにビルドが終わった!!といって意気揚々と起動してみるわけですよ。
読者の方々は察していると思いますが、ね。。。

メニューには "New Incognito Tab" と表示されますが、クリックしても普通のタブが開かれてしまいます。 (スクショ撮り忘れたのでお見せできなくて申し訳ない)


果たして原因はなんなのでしょうか...次回へ続く。