7#include "core/fxge/win32/cgdi_device_driver.h"
15#include "core/fxcrt/fx_string.h"
16#include "core/fxge/agg/fx_agg_driver.h"
17#include "core/fxge/cfx_defaultrenderdevice.h"
18#include "core/fxge/cfx_fillrenderoptions.h"
19#include "core/fxge/cfx_graphstatedata.h"
20#include "core/fxge/cfx_path.h"
21#include "core/fxge/dib/cfx_dibbase.h"
22#include "core/fxge/dib/cfx_dibitmap.h"
23#include "core/fxge/render_defines.h"
24#include "core/fxge/win32/cwin32_platform.h"
25#include "third_party/agg23/agg_clip_liang_barsky.h"
26#include "third_party/base/check.h"
27#include "third_party/base/check_op.h"
28#include "third_party/base/notreached.h"
29#include "third_party/base/numerics/safe_conversions.h"
34 return static_cast<
int>(fill_type);
37static_assert(FillTypeToGdiFillType(
38 CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
39 "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
42 FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
43 "CFX_FillRenderOptions::FillType::kWinding value mismatch");
52 scale = fabs(pMatrix
->a) > fabs(pMatrix
->b) ? fabs(pMatrix
->a)
57 uint32_t PenStyle = PS_GEOMETRIC;
58 if (!pGraphState->m_DashArray.empty())
59 PenStyle |= PS_USERSTYLE;
64 case CFX_GraphStateData::LineCap::kButt:
65 PenStyle |= PS_ENDCAP_FLAT;
67 case CFX_GraphStateData::LineCap::kRound:
68 PenStyle |= PS_ENDCAP_ROUND;
70 case CFX_GraphStateData::LineCap::kSquare:
71 PenStyle |= PS_ENDCAP_SQUARE;
75 case CFX_GraphStateData::LineJoin::kMiter:
76 PenStyle |= PS_JOIN_MITER;
78 case CFX_GraphStateData::LineJoin::kRound:
79 PenStyle |= PS_JOIN_ROUND;
81 case CFX_GraphStateData::LineJoin::kBevel:
82 PenStyle |= PS_JOIN_BEVEL;
88 lb.lbColor = colorref;
89 lb.lbStyle = BS_SOLID;
91 std::vector<uint32_t> dashes;
92 if (!pGraphState->m_DashArray.empty()) {
93 dashes.resize(pGraphState->m_DashArray.size());
94 for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
95 dashes[i] = FXSYS_roundf(
97 : pGraphState->m_DashArray[i]);
98 dashes[i] =
std::max(dashes[i], 1U);
102 PenStyle, (DWORD)ceil(width), &lb,
103 pdfium::base::checked_cast<DWORD>(pGraphState->m_DashArray.size()),
104 reinterpret_cast<
const DWORD*>(dashes.data()));
107HBRUSH CreateBrush(uint32_t argb) {
114 pdfium::span<
const CFX_Path::
Point> points = path.GetPoints();
115 for (size_t i = 0; i < points.size(); ++i) {
116 CFX_PointF pos = points[i].m_Point;
120 CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
123 MoveToEx(hDC, screen.x, screen.y,
nullptr);
125 if (points[i].m_Point == points[i - 1].m_Point)
128 LineTo(hDC, screen.x, screen.y);
131 lppt[0].x = screen.x;
132 lppt[0].y = screen.y;
134 pos = points[i + 1].m_Point;
138 lppt[1].x = FXSYS_roundf(pos.x);
139 lppt[1].y = FXSYS_roundf(pos.y);
141 pos = points[i + 2].m_Point;
145 lppt[2].x = FXSYS_roundf(pos.x);
146 lppt[2].y = FXSYS_roundf(pos.y);
147 PolyBezierTo(hDC, lppt, 3);
150 if (points[i].m_CloseFigure)
157 int len =
sizeof(BITMAPINFOHEADER);
158 if (source->GetBPP() == 1 || source->GetBPP() == 8) {
159 len +=
sizeof(DWORD) * (
int)(1 << source->GetBPP());
165 pdfium::span<
char> cspan = result.GetBuffer(len);
166 BITMAPINFOHEADER* pbmih =
reinterpret_cast<BITMAPINFOHEADER*>(cspan.data());
167 memset(pbmih, 0,
sizeof(BITMAPINFOHEADER));
168 pbmih->biSize =
sizeof(BITMAPINFOHEADER);
169 pbmih->biBitCount = source->GetBPP();
170 pbmih->biCompression = BI_RGB;
171 pbmih->biHeight = -(
int)source->GetHeight();
173 pbmih->biWidth = source->GetWidth();
174 if (source->GetBPP() == 8) {
175 uint32_t* palette = (uint32_t*)(pbmih + 1);
176 if (source->HasPalette()) {
177 pdfium::span<
const uint32_t> palette_span = source->GetPaletteSpan();
178 for (
int i = 0; i < 256; i++) {
179 palette[i] = palette_span[i];
182 for (
int i = 0; i < 256; i++) {
187 if (source->GetBPP() == 1) {
188 uint32_t* palette = (uint32_t*)(pbmih + 1);
189 if (source->HasPalette()) {
190 pdfium::span<
const uint32_t> palette_span = source->GetPaletteSpan();
191 palette[0] = palette_span[0];
192 palette[1] = palette_span[1];
195 palette[1] = 0xffffff;
199 result.ReleaseBuffer(len);
203#if defined(PDF_USE_SKIA)
215unsigned clip_liang_barsky(
float x1,
219 const rect_base& clip_box,
222 const float nearzero = 1e-30f;
223 float deltax = x2 - x1;
224 float deltay = y2 - y1;
227 deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
237 float tinx = (xin - x1) / deltax;
239 deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
249 float tiny = (yin - y1) / deltay;
266 float toutx = (xout - x1) / deltax;
267 float touty = (yout - y1) / deltay;
268 float tout1 = (toutx < touty) ? toutx : touty;
269 if (tin2 > 0 || tout1 > 0) {
274 *y++ = y1 + (deltay * tinx);
276 *x++ = x1 + (deltax * tiny);
284 *y++ = y1 + (deltay * toutx);
286 *x++ = x1 + (deltax * touty);
311unsigned LineClip(
float w,
319#if defined(PDF_USE_SKIA)
320 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
323 rect_base rect = {0.0f, 0.0f, w, h};
324 return clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
327 pdfium::
agg::rect_base<
float> rect(0.0f, 0.0f, w, h);
328 return pdfium::
agg::clip_liang_barsky<
float>(x1, y1, x2, y2, rect, x, y);
335 SetStretchBltMode(m_hDC, HALFTONE);
336 DWORD obj_type = GetObjectType(m_hDC);
337 m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
338 if (obj_type == OBJ_MEMDC) {
339 HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1,
nullptr);
340 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
342 GetObject(hBitmap,
sizeof bitmap, &bitmap);
346 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
347 DeleteObject(hBitmap);
349 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
350 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
351 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
377 NOTREACHED_NORETURN();
386 RestoreDC(m_hDC, -1);
396 RetainPtr<
const CFX_DIBitmap> flipped_source =
397 source->FlipImage(
false,
true);
398 if (!flipped_source) {
402 CHECK(!flipped_source->GetBuffer().empty());
403 ByteString info = GetBitmapInfo(flipped_source);
404 ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
406 dst_rect.Intersect(0, 0, flipped_source->GetWidth(),
407 flipped_source->GetHeight());
410 ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
411 dst_height, flipped_source->GetBuffer().data(),
412 (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS, SRCCOPY);
416 RetainPtr<
const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
417 if (!realized_source) {
420 ByteString info = GetBitmapInfo(realized_source);
422 m_hDC, left, top, src_rect.Width(), src_rect.Height(), src_rect.left,
423 realized_source->GetHeight() - src_rect.bottom, 0,
424 realized_source->GetHeight(), realized_source->GetBuffer().data(),
425 (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS);
435 if (!source || dest_width == 0 || dest_height == 0) {
439 if ((int64_t)abs(dest_width) * abs(dest_height) <
440 (int64_t)source->GetWidth() * source->GetHeight() * 4 ||
442 SetStretchBltMode(m_hDC, HALFTONE);
444 SetStretchBltMode(m_hDC, COLORONCOLOR);
447 RetainPtr<
const CFX_DIBitmap> realized_source;
449 ((int64_t)source->GetWidth() * source->GetHeight() >
450 (int64_t)abs(dest_width) * abs(dest_height))) {
451 realized_source = source->StretchTo(dest_width, dest_height,
454 realized_source = source->RealizeIfNeeded();
456 if (!realized_source) {
460 CHECK(!realized_source->GetBuffer().empty());
461 ByteString info = GetBitmapInfo(realized_source);
462 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
463 realized_source->GetWidth(), realized_source->GetHeight(),
464 realized_source->GetBuffer().data(),
465 (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS, SRCCOPY);
474 uint32_t bitmap_color) {
475 if (!source || dest_width == 0 || dest_height == 0) {
479 RetainPtr<
const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
480 if (!realized_source) {
484 int width = realized_source->GetWidth();
485 int height = realized_source->GetHeight();
487 BITMAPINFOHEADER bmiHeader;
488 uint32_t bmiColors[2];
490 memset(&bmi.bmiHeader, 0,
sizeof(BITMAPINFOHEADER));
491 bmi.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
492 bmi.bmiHeader.biBitCount = 1;
493 bmi.bmiHeader.biCompression = BI_RGB;
494 bmi.bmiHeader.biHeight = -height;
495 bmi.bmiHeader.biPlanes = 1;
496 bmi.bmiHeader.biWidth = width;
498 SetStretchBltMode(m_hDC, HALFTONE);
500 bmi.bmiColors[0] = 0xffffff;
501 bmi.bmiColors[1] = 0;
503 HBRUSH hPattern = CreateBrush(bitmap_color);
504 HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
511
512
513
514
515
516
517
518
519
524 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
525 width, height, realized_source->GetBuffer().data(),
526 (BITMAPINFO*)&bmi, DIB_RGB_COLORS, 0xB8074A);
528 SelectObject(m_hDC, hOld);
529 DeleteObject(hPattern);
535 return !!(::GetClipBox(m_hDC, (RECT*)pRect));
541 NOTREACHED_NORETURN();
548 NOTREACHED_NORETURN();
553 int startOutOfBoundsFlag = (x1 < 0) | ((x1 >
m_Width) << 1) |
554 ((y1 < 0) << 2) | ((y1 >
m_Height) << 3);
555 int endOutOfBoundsFlag = (x2 < 0) | ((x2 >
m_Width) << 1) |
556 ((y2 < 0) << 2) | ((y2 >
m_Height) << 3);
557 if (startOutOfBoundsFlag & endOutOfBoundsFlag)
560 if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
580 MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1),
nullptr);
581 LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
588 uint32_t stroke_color,
596 if (!(pGraphState || stroke_color == 0) &&
597 !pPlatform->m_GdiplusExt.IsAvailable()) {
614 int fill_alpha =
FXARGB_A(fill_color);
615 int stroke_alpha =
FXARGB_A(stroke_color);
616 bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
617 (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
618 if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
621 if (pPlatform->m_GdiplusExt.IsAvailable()) {
624 (pGraphState && !pGraphState->m_DashArray.empty()))) {
627 if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, path, pMatrix, pGraphState,
628 fill_color, stroke_color,
638 HBRUSH hBrush =
nullptr;
639 if (pGraphState && stroke_alpha) {
640 SetMiterLimit(m_hDC, pGraphState->m_MiterLimit,
nullptr);
641 hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
642 hPen = (HPEN)SelectObject(m_hDC, hPen);
644 if (fill && fill_alpha) {
645 SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
646 hBrush = CreateBrush(fill_color);
647 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
649 if (path.GetPoints().size() == 2 && pGraphState &&
650 !pGraphState->m_DashArray.empty()) {
651 CFX_PointF pos1 = path.GetPoint(0);
652 CFX_PointF pos2 = path.GetPoint(1);
659 SetPathToDC(m_hDC, path, pMatrix);
660 if (pGraphState && stroke_alpha) {
661 if (fill && fill_alpha) {
663 StrokeAndFillPath(m_hDC);
666 SetPathToDC(m_hDC, path, pMatrix);
672 }
else if (fill && fill_alpha) {
677 hPen = (HPEN)SelectObject(m_hDC, hPen);
681 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
682 DeleteObject(hBrush);
694 FX_COLORREF colorref;
695 std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(fill_color);
702 HBRUSH hBrush = CreateSolidBrush(colorref);
703 const RECT* pRect =
reinterpret_cast<
const RECT*>(&rect);
704 ::FillRect(m_hDC, pRect, hBrush);
705 DeleteObject(hBrush);
710 m_BaseClipBox = rect;
717 absl::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pMatrix);
718 if (maybe_rectf.has_value()) {
719 FX_RECT rect = maybe_rectf.value().GetOuterRect();
722 if (m_BaseClipBox.has_value())
723 rect.Intersect(m_BaseClipBox.value());
724 return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
725 rect.bottom) != ERROR;
727 SetPathToDC(m_hDC, path, pMatrix);
728 SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
729 SelectClipPath(m_hDC, RGN_AND);
737 HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
738 hPen = (HPEN)SelectObject(m_hDC, hPen);
739 SetPathToDC(m_hDC, path, pMatrix);
741 SetPolyFillMode(m_hDC, WINDING);
742 bool ret = !!SelectClipPath(m_hDC, RGN_AND);
743 hPen = (HPEN)SelectObject(m_hDC, hPen);
749 const CFX_PointF& ptLineTo,
756 FX_COLORREF colorref;
757 std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(color);
761 HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
762 hPen = (HPEN)SelectObject(m_hDC, hPen);
763 MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y),
nullptr);
764 LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
765 hPen = (HPEN)SelectObject(m_hDC, hPen);
FX_RECT GetInnerRect() const
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
PlatformIface * GetPlatform() const
static CFX_GEModule * Get()
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
float TransformDistance(float distance) const
CFX_PointF Transform(const CFX_PointF &point) const
CFX_FloatRect GetBoundingBox() const
bool MultiplyAlphaMask(const RetainPtr< const CFX_DIBBase > &mask) override
void SetBaseClip(const FX_RECT &rect) override
const DeviceType m_DeviceType
bool SetClip_PathStroke(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState) override
void DrawLine(float x1, float y1, float x2, float y2)
~CGdiDeviceDriver() override
bool SetClip_PathFill(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_FillRenderOptions &fill_options) override
bool DrawPath(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState, uint32_t fill_color, uint32_t stroke_color, const CFX_FillRenderOptions &fill_options, BlendMode blend_type) override
bool GDI_SetDIBits(const RetainPtr< const CFX_DIBBase > &source, const FX_RECT &src_rect, int left, int top)
bool GetClipBox(FX_RECT *pRect) override
bool GDI_StretchDIBits(RetainPtr< const CFX_DIBBase > source, int dest_left, int dest_top, int dest_width, int dest_height, const FXDIB_ResampleOptions &options)
bool DrawCosmeticLine(const CFX_PointF &ptMoveTo, const CFX_PointF &ptLineTo, uint32_t color, BlendMode blend_type) override
int GetDeviceCaps(int caps_id) const override
bool MultiplyAlpha(float alpha) override
CGdiDeviceDriver(HDC hDC, DeviceType device_type)
void RestoreState(bool bKeepSaved) override
DeviceType GetDeviceType() const override
void SaveState() override
bool FillRectWithBlend(const FX_RECT &rect, uint32_t fill_color, BlendMode blend_type) override
bool GDI_StretchBitMask(RetainPtr< const CFX_DIBBase > source, int dest_left, int dest_top, int dest_width, int dest_height, uint32_t bitmap_color)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
FX_COLORREF ArgbToColorRef(FX_ARGB argb)
#define FXDC_PIXEL_HEIGHT
bool bInterpolateBilinear
constexpr FX_RECT(int l, int t, int r, int b)