void OnDrawItem()

in libcef/browser/native/native_menu_win.cc [226:386]


  void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
    HDC dc = draw_item_struct->hDC;
    COLORREF prev_bg_color, prev_text_color;

    // Set background color and text color
    if (draw_item_struct->itemState & ODS_SELECTED) {
      prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
      prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
    } else {
      prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
      if (draw_item_struct->itemState & ODS_DISABLED)
        prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
      else
        prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
    }

    if (draw_item_struct->itemData) {
      CefNativeMenuWin::ItemData* data =
          GetItemData(draw_item_struct->itemData);
      // Draw the background.
      HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
      FillRect(dc, &draw_item_struct->rcItem, hbr);
      DeleteObject(hbr);

      // Draw the label.
      RECT rect = draw_item_struct->rcItem;
      rect.top += kItemTopMargin;
      // Should we add kIconWidth only when icon.width() != 0 ?
      rect.left += kItemLeftMargin + kIconWidth;
      rect.right -= kItemLabelSpacing;
      UINT format = DT_TOP | DT_SINGLELINE;
      // Check whether the mnemonics should be underlined.
      BOOL underline_mnemonics;
      SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
      if (!underline_mnemonics)
        format |= DT_HIDEPREFIX;
      gfx::FontList font_list;
      HFONT new_font = CreateNativeFont(font_list.GetPrimaryFont());
      HGDIOBJ old_font = SelectObject(dc, new_font);

      // If an accelerator is specified (with a tab delimiting the rest of the
      // label from the accelerator), we have to justify the fist part on the
      // left and the accelerator on the right.
      // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
      //                 window system UI font and will not hit here.
      std::wstring label = data->label;
      std::wstring accel;
      std::wstring::size_type tab_pos = label.find(L'\t');
      if (tab_pos != std::wstring::npos) {
        accel = label.substr(tab_pos);
        label = label.substr(0, tab_pos);
      }
      DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
                 static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
      if (!accel.empty()) {
        DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
                   static_cast<int>(accel.size()), &rect, format | DT_RIGHT,
                   NULL);
      }
      SelectObject(dc, old_font);
      DeleteObject(new_font);

      ui::MenuModel::ItemType type =
          data->native_menu_win->model_->GetTypeAt(data->model_index);

      // Draw the icon after the label, otherwise it would be covered
      // by the label.
      ui::ImageModel icon =
          data->native_menu_win->model_->GetIconAt(data->model_index);
      if (icon.IsImage() || icon.IsVectorIcon()) {
        ui::NativeTheme* native_theme =
            ui::NativeTheme::GetInstanceForNativeUi();

        // Logic from Widget::GetColorProviderKey() prior to
        // https://crrev.com/e24ffe177b.
        // TODO(cef): Use |native_theme->GetColorProviderKey(nullptr)| after M97
        // Chromium update.
        const auto color_scheme = native_theme->GetDefaultSystemColorScheme();
        ui::ColorProviderManager::Key color_provider_key(
            (color_scheme == ui::NativeTheme::ColorScheme::kDark)
                ? ui::ColorProviderManager::ColorMode::kDark
                : ui::ColorProviderManager::ColorMode::kLight,
            (color_scheme ==
             ui::NativeTheme::ColorScheme::kPlatformHighContrast)
                ? ui::ColorProviderManager::ContrastMode::kHigh
                : ui::ColorProviderManager::ContrastMode::kNormal,
            native_theme->is_custom_system_theme()
                ? ui::ColorProviderManager::SystemTheme::kCustom
                : ui::ColorProviderManager::SystemTheme::kDefault,
            /*custom_theme=*/nullptr);

        auto* color_provider =
            ui::ColorProviderManager::Get().GetColorProviderFor(
                color_provider_key);

        // We currently don't support items with both icons and checkboxes.
        const gfx::ImageSkia skia_icon =
            icon.IsImage() ? icon.GetImage().AsImageSkia()
                           : ui::ThemedVectorIcon(icon.GetVectorIcon())
                                 .GetImageSkia(color_provider, 16);

        DCHECK(type != ui::MenuModel::TYPE_CHECK);
        std::unique_ptr<SkCanvas> canvas = skia::CreatePlatformCanvas(
            skia_icon.width(), skia_icon.height(), false);
        canvas->drawImage(skia_icon.bitmap()->asImage(), 0, 0);
        DrawToNativeContext(
            canvas.get(), dc, draw_item_struct->rcItem.left + kItemLeftMargin,
            draw_item_struct->rcItem.top +
                (draw_item_struct->rcItem.bottom -
                 draw_item_struct->rcItem.top - skia_icon.height()) /
                    2,
            NULL);
      } else if (type == ui::MenuModel::TYPE_CHECK &&
                 data->native_menu_win->model_->IsItemCheckedAt(
                     data->model_index)) {
        // Manually render a checkbox.
        const MenuConfig& config = MenuConfig::instance();
        NativeTheme::State state;
        if (draw_item_struct->itemState & ODS_DISABLED) {
          state = NativeTheme::kDisabled;
        } else {
          state = draw_item_struct->itemState & ODS_SELECTED
                      ? NativeTheme::kHovered
                      : NativeTheme::kNormal;
        }

        std::unique_ptr<SkCanvas> canvas = skia::CreatePlatformCanvas(
            config.check_width, config.check_height, false);
        cc::SkiaPaintCanvas paint_canvas(canvas.get());

        NativeTheme::ExtraParams extra;
        extra.menu_check.is_radio = false;
        gfx::Rect bounds(0, 0, config.check_width, config.check_height);

        // Draw the background and the check.
        ui::NativeTheme* native_theme =
            ui::NativeTheme::GetInstanceForNativeUi();
        native_theme->Paint(&paint_canvas, NativeTheme::kMenuCheckBackground,
                            state, bounds, extra);
        native_theme->Paint(&paint_canvas, NativeTheme::kMenuCheck, state,
                            bounds, extra);

        // Draw checkbox to menu.
        DrawToNativeContext(
            canvas.get(), dc, draw_item_struct->rcItem.left + kItemLeftMargin,
            draw_item_struct->rcItem.top +
                (draw_item_struct->rcItem.bottom -
                 draw_item_struct->rcItem.top - config.check_height) /
                    2,
            NULL);
      }
    } else {
      // Draw the separator
      draw_item_struct->rcItem.top +=
          (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
      DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
    }

    SetBkColor(dc, prev_bg_color);
    SetTextColor(dc, prev_text_color);
  }