void DesktopNotificationController::Toast::UpdateBufferSize()

in shell/browser/notifications/win/win32_desktop_notifications/toast.cc [519:637]


void DesktopNotificationController::Toast::UpdateBufferSize() {
  if (hdc_) {
    SIZE new_size;
    {
      TEXTMETRIC tm_cap = {};
      HFONT font = data_->controller->GetCaptionFont();
      if (font) {
        SelectFont(hdc_, font);
        if (!GetTextMetrics(hdc_, &tm_cap))
          return;
      }

      TEXTMETRIC tm_body = {};
      font = data_->controller->GetBodyFont();
      if (font) {
        SelectFont(hdc_, font);
        if (!GetTextMetrics(hdc_, &tm_body))
          return;
      }

      this->margin_ = {tm_cap.tmAveCharWidth * 2, tm_cap.tmAscent / 2};

      new_size.cx = margin_.cx + (32 * tm_cap.tmAveCharWidth) + margin_.cx;
      new_size.cy = margin_.cy + (tm_cap.tmHeight) + margin_.cy;

      if (!data_->body_text.empty())
        new_size.cy += margin_.cy + (3 * tm_body.tmHeight);

      if (data_->image) {
        BITMAP bm;
        if (GetObject(data_->image, sizeof(bm), &bm)) {
          // cap the image size
          const int max_dim_size = 80;

          auto width = bm.bmWidth;
          auto height = bm.bmHeight;
          if (width < height) {
            if (height > max_dim_size) {
              width = width * max_dim_size / height;
              height = max_dim_size;
            }
          } else {
            if (width > max_dim_size) {
              height = height * max_dim_size / width;
              width = max_dim_size;
            }
          }

          ScreenMetrics scr;
          SIZE image_draw_size = {scr.X(width), scr.Y(height)};

          new_size.cx += image_draw_size.cx + margin_.cx;

          auto height_with_image =
              margin_.cy + (image_draw_size.cy) + margin_.cy;

          if (new_size.cy < height_with_image)
            new_size.cy = height_with_image;

          UpdateScaledImage(image_draw_size);
        }
      }
    }

    if (new_size.cx != this->toast_size_.cx ||
        new_size.cy != this->toast_size_.cy) {
      HDC hdc_screen = GetDC(NULL);
      auto* new_bitmap =
          CreateCompatibleBitmap(hdc_screen, new_size.cx, new_size.cy);
      ReleaseDC(NULL, hdc_screen);

      if (new_bitmap) {
        if (SelectBitmap(hdc_, new_bitmap)) {
          RECT dirty1 = {}, dirty2 = {};
          if (toast_size_.cx < new_size.cx) {
            dirty1 = {toast_size_.cx, 0, new_size.cx, toast_size_.cy};
          }
          if (toast_size_.cy < new_size.cy) {
            dirty2 = {0, toast_size_.cy, new_size.cx, new_size.cy};
          }

          if (this->bitmap_)
            DeleteBitmap(this->bitmap_);
          this->bitmap_ = new_bitmap;
          this->toast_size_ = new_size;

          Invalidate();

          // Resize also the DWM buffer to prevent flicker during
          // window resizing. Make sure any existing data is not
          // overwritten by marking the dirty region.
          {
            POINT origin = {0, 0};

            UPDATELAYEREDWINDOWINFO ulw;
            ulw.cbSize = sizeof(ulw);
            ulw.hdcDst = NULL;
            ulw.pptDst = nullptr;
            ulw.psize = &toast_size_;
            ulw.hdcSrc = hdc_;
            ulw.pptSrc = &origin;
            ulw.crKey = 0;
            ulw.pblend = nullptr;
            ulw.dwFlags = 0;
            ulw.prcDirty = &dirty1;
            auto b1 = UpdateLayeredWindowIndirect(hwnd_, &ulw);
            ulw.prcDirty = &dirty2;
            auto b2 = UpdateLayeredWindowIndirect(hwnd_, &ulw);
            DCHECK(b1 && b2);
          }

          return;
        }

        DeleteBitmap(new_bitmap);
      }
    }
  }
}