void DesktopNotificationController::Toast::Draw()

in shell/browser/notifications/win/win32_desktop_notifications/toast.cc [367:509]


void DesktopNotificationController::Toast::Draw() {
  const COLORREF accent = GetAccentColor();

  COLORREF back_color;
  {
    // base background color is 2/3 of accent
    // highlighted adds a bit of intensity to every channel

    int h = is_highlighted_ ? (0xff / 20) : 0;

    back_color = RGB(min(0xff, (GetRValue(accent) * 2 / 3) + h),
                     min(0xff, (GetGValue(accent) * 2 / 3) + h),
                     min(0xff, (GetBValue(accent) * 2 / 3) + h));
  }

  const float back_luma = (GetRValue(back_color) * 0.299f / 255) +
                          (GetGValue(back_color) * 0.587f / 255) +
                          (GetBValue(back_color) * 0.114f / 255);

  const struct {
    float r, g, b;
  } back_f = {
      GetRValue(back_color) / 255.0f,
      GetGValue(back_color) / 255.0f,
      GetBValue(back_color) / 255.0f,
  };

  COLORREF fore_color, dimmed_color;
  {
    // based on the lightness of background, we draw foreground in light
    // or dark shades of gray blended onto the background with slight
    // transparency to avoid sharp contrast

    constexpr float alpha = 0.9f;
    constexpr float intensity_light[] = {(1.0f * alpha), (0.8f * alpha)};
    constexpr float intensity_dark[] = {(0.1f * alpha), (0.3f * alpha)};

    // select foreground intensity values (light or dark)
    auto& i = (back_luma < 0.6f) ? intensity_light : intensity_dark;

    float r, g, b;

    r = i[0] + back_f.r * (1 - alpha);
    g = i[0] + back_f.g * (1 - alpha);
    b = i[0] + back_f.b * (1 - alpha);
    fore_color = RGB(r * 0xff, g * 0xff, b * 0xff);

    r = i[1] + back_f.r * (1 - alpha);
    g = i[1] + back_f.g * (1 - alpha);
    b = i[1] + back_f.b * (1 - alpha);
    dimmed_color = RGB(r * 0xff, g * 0xff, b * 0xff);
  }

  // Draw background
  {
    auto* brush = CreateSolidBrush(back_color);

    RECT rc = {0, 0, toast_size_.cx, toast_size_.cy};
    FillRect(hdc_, &rc, brush);

    DeleteBrush(brush);
  }

  SetBkMode(hdc_, TRANSPARENT);

  const auto close = L'\x2715';
  auto* caption_font = data_->controller->GetCaptionFont();
  auto* body_font = data_->controller->GetBodyFont();

  TEXTMETRIC tm_cap;
  SelectFont(hdc_, caption_font);
  GetTextMetrics(hdc_, &tm_cap);

  auto text_offset_x = margin_.cx;

  BITMAP image_info = {};
  if (scaled_image_) {
    GetObject(scaled_image_, sizeof(image_info), &image_info);

    text_offset_x += margin_.cx + image_info.bmWidth;
  }

  // calculate close button rect
  POINT close_pos;
  {
    SIZE extent = {};
    GetTextExtentPoint32W(hdc_, &close, 1, &extent);

    close_button_rect_.right = toast_size_.cx;
    close_button_rect_.top = 0;

    close_pos.x = close_button_rect_.right - margin_.cy - extent.cx;
    close_pos.y = close_button_rect_.top + margin_.cy;

    close_button_rect_.left = close_pos.x - margin_.cy;
    close_button_rect_.bottom = close_pos.y + extent.cy + margin_.cy;
  }

  // image
  if (scaled_image_) {
    HDC hdc_image = CreateCompatibleDC(NULL);
    SelectBitmap(hdc_image, scaled_image_);
    BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    AlphaBlend(hdc_, margin_.cx, margin_.cy, image_info.bmWidth,
               image_info.bmHeight, hdc_image, 0, 0, image_info.bmWidth,
               image_info.bmHeight, blend);
    DeleteDC(hdc_image);
  }

  // caption
  {
    RECT rc = {text_offset_x, margin_.cy, close_button_rect_.left,
               toast_size_.cy};

    SelectFont(hdc_, caption_font);
    SetTextColor(hdc_, fore_color);
    DrawText(hdc_, base::as_wcstr(data_->caption),
             (UINT)data_->caption.length(), &rc,
             DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
  }

  // body text
  if (!data_->body_text.empty()) {
    RECT rc = {text_offset_x, 2 * margin_.cy + tm_cap.tmAscent,
               toast_size_.cx - margin_.cx, toast_size_.cy - margin_.cy};

    SelectFont(hdc_, body_font);
    SetTextColor(hdc_, dimmed_color);
    DrawText(hdc_, base::as_wcstr(data_->body_text),
             (UINT)data_->body_text.length(), &rc,
             DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | DT_END_ELLIPSIS |
                 DT_EDITCONTROL);
  }

  // close button
  {
    SelectFont(hdc_, caption_font);
    SetTextColor(hdc_, is_close_hot_ ? fore_color : dimmed_color);
    ExtTextOut(hdc_, close_pos.x, close_pos.y, 0, nullptr, &close, 1, nullptr);
  }

  is_content_updated_ = true;
}