7#include "core/fxge/win32/cgdi_device_driver.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fixed_size_data_vector.h"
20#include "core/fxcrt/fx_string.h"
21#include "core/fxcrt/notreached.h"
22#include "core/fxcrt/numerics/safe_conversions.h"
23#include "core/fxge/agg/cfx_agg_devicedriver.h"
24#include "core/fxge/cfx_defaultrenderdevice.h"
25#include "core/fxge/cfx_fillrenderoptions.h"
26#include "core/fxge/cfx_graphstatedata.h"
27#include "core/fxge/cfx_path.h"
28#include "core/fxge/dib/cfx_dibbase.h"
29#include "core/fxge/dib/cfx_dibitmap.h"
30#include "core/fxge/render_defines.h"
31#include "core/fxge/win32/cwin32_platform.h"
32#include "third_party/agg23/agg_clip_liang_barsky.h"
37 return static_cast<
int>(fill_type);
40static_assert(FillTypeToGdiFillType(
41 CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
42 "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
45 FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
46 "CFX_FillRenderOptions::FillType::kWinding value mismatch");
55 scale = fabs(pMatrix
->a) > fabs(pMatrix
->b) ? fabs(pMatrix
->a)
60 uint32_t PenStyle = PS_GEOMETRIC;
61 if (!pGraphState->m_DashArray.empty())
62 PenStyle |= PS_USERSTYLE;
67 case CFX_GraphStateData::LineCap::kButt:
68 PenStyle |= PS_ENDCAP_FLAT;
70 case CFX_GraphStateData::LineCap::kRound:
71 PenStyle |= PS_ENDCAP_ROUND;
73 case CFX_GraphStateData::LineCap::kSquare:
74 PenStyle |= PS_ENDCAP_SQUARE;
78 case CFX_GraphStateData::LineJoin::kMiter:
79 PenStyle |= PS_JOIN_MITER;
81 case CFX_GraphStateData::LineJoin::kRound:
82 PenStyle |= PS_JOIN_ROUND;
84 case CFX_GraphStateData::LineJoin::kBevel:
85 PenStyle |= PS_JOIN_BEVEL;
91 lb.lbColor = colorref;
92 lb.lbStyle = BS_SOLID;
94 std::vector<uint32_t> dashes;
95 if (!pGraphState->m_DashArray.empty()) {
96 dashes.resize(pGraphState->m_DashArray.size());
97 for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
98 dashes[i] = FXSYS_roundf(
100 : pGraphState->m_DashArray[i]);
101 dashes[i] =
std::max(dashes[i], 1U);
105 PenStyle, (DWORD)ceil(width), &lb,
106 pdfium::checked_cast<DWORD>(pGraphState->m_DashArray.size()),
107 reinterpret_cast<
const DWORD*>(dashes.data()));
110HBRUSH CreateBrush(uint32_t argb) {
117 pdfium::span<
const CFX_Path::Point> points = path.GetPoints();
118 for (size_t i = 0; i < points.size(); ++i) {
123 CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
126 MoveToEx(hDC, screen.x, screen.y,
nullptr);
128 if (points[i].m_Point == points[i - 1].m_Point)
131 LineTo(hDC, screen.x, screen.y);
134 lppt[0].x = screen.x;
135 lppt[0].y = screen.y;
137 pos = points[i + 1].m_Point;
141 lppt[1].x = FXSYS_roundf(pos.x);
142 lppt[1].y = FXSYS_roundf(pos.y);
144 pos = points[i + 2].m_Point;
148 lppt[2].x = FXSYS_roundf(pos.x);
149 lppt[2].y = FXSYS_roundf(pos.y);
150 PolyBezierTo(hDC, lppt, 3);
153 if (points[i].m_CloseFigure)
159FixedSizeDataVector<uint8_t> GetBitmapInfoHeader(
161 size_t len =
sizeof(BITMAPINFOHEADER);
162 if (source->GetBPP() == 1 || source->GetBPP() == 8) {
163 len +=
sizeof(DWORD) * (
int)(1 << source->GetBPP());
166 auto result = FixedSizeDataVector<uint8_t>::Zeroed(len);
167 auto* pbmih =
reinterpret_cast<BITMAPINFOHEADER*>(result.span().data());
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();
175 if (source->GetBPP() == 8) {
176 uint32_t* palette = (uint32_t*)(pbmih + 1);
177 if (source->HasPalette()) {
178 pdfium::span<
const uint32_t> palette_span = source->GetPaletteSpan();
179 for (
int i = 0; i < 256; i++) {
180 palette[i] = palette_span[i];
183 for (
int i = 0; i < 256; i++) {
188 if (source->GetBPP() == 1) {
189 uint32_t* palette = (uint32_t*)(pbmih + 1);
190 if (source->HasPalette()) {
191 pdfium::span<
const uint32_t> palette_span = source->GetPaletteSpan();
192 palette[0] = palette_span[0];
193 palette[1] = palette_span[1];
196 palette[1] = 0xffffff;
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;
268 float toutx = (xout - x1) / deltax;
269 float touty = (yout - y1) / deltay;
270 float tout1 = (toutx < touty) ? toutx : touty;
271 if (tin2 > 0 || tout1 > 0) {
277 *y++ = y1 + (deltay * tinx);
281 *x++ = x1 + (deltax * tiny);
291 *y++ = y1 + (deltay * toutx);
295 *x++ = x1 + (deltax * touty);
327unsigned LineClip(
float w,
335#if defined(PDF_USE_SKIA)
336 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
339 rect_base rect = {0.0f, 0.0f, w, h};
340 return clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
343 pdfium::
agg::rect_base<
float> rect(0.0f, 0.0f, w, h);
344 return pdfium::
agg::clip_liang_barsky<
float>(x1, y1, x2, y2, rect, x, y);
351 SetStretchBltMode(m_hDC, HALFTONE);
352 DWORD obj_type = GetObjectType(m_hDC);
353 m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
354 if (obj_type == OBJ_MEMDC) {
355 HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1,
nullptr);
356 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
358 GetObject(hBitmap,
sizeof(bitmap), &bitmap);
362 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
363 DeleteObject(hBitmap);
365 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
366 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
367 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
402 RestoreDC(m_hDC, -1);
411 if (m_DeviceType == DeviceType::kPrinter) {
412 RetainPtr<
const CFX_DIBitmap> flipped_source =
413 source->FlipImage(
false,
true);
414 if (!flipped_source) {
418 CHECK(!flipped_source->GetBuffer().empty());
419 FixedSizeDataVector<uint8_t> info = GetBitmapInfoHeader(flipped_source);
420 auto* header =
reinterpret_cast<BITMAPINFOHEADER*>(info.span().data());
421 header->biHeight *= -1;
423 dst_rect.Intersect(0, 0, flipped_source->GetWidth(),
424 flipped_source->GetHeight());
427 ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
428 dst_height, flipped_source->GetBuffer().data(),
429 reinterpret_cast<BITMAPINFO*>(header), DIB_RGB_COLORS,
434 RetainPtr<
const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
435 if (!realized_source) {
438 FixedSizeDataVector<uint8_t> info = GetBitmapInfoHeader(realized_source);
439 auto* header =
reinterpret_cast<BITMAPINFOHEADER*>(info.span().data());
441 m_hDC, left, top, src_rect.Width(), src_rect.Height(), src_rect.left,
442 realized_source->GetHeight() - src_rect.bottom, 0,
443 realized_source->GetHeight(), realized_source->GetBuffer().data(),
444 reinterpret_cast<BITMAPINFO*>(header), DIB_RGB_COLORS);
454 if (!source || dest_width == 0 || dest_height == 0) {
458 if ((int64_t)abs(dest_width) * abs(dest_height) <
459 (int64_t)source->GetWidth() * source->GetHeight() * 4 ||
461 SetStretchBltMode(m_hDC, HALFTONE);
463 SetStretchBltMode(m_hDC, COLORONCOLOR);
466 RetainPtr<
const CFX_DIBitmap> realized_source;
467 if (m_DeviceType == DeviceType::kPrinter &&
468 ((int64_t)source->GetWidth() * source->GetHeight() >
469 (int64_t)abs(dest_width) * abs(dest_height))) {
470 realized_source = source->StretchTo(dest_width, dest_height,
473 realized_source = source->RealizeIfNeeded();
475 if (!realized_source) {
479 CHECK(!realized_source->GetBuffer().empty());
480 FixedSizeDataVector<uint8_t> info = GetBitmapInfoHeader(realized_source);
481 auto* header =
reinterpret_cast<BITMAPINFOHEADER*>(info.span().data());
482 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
483 realized_source->GetWidth(), realized_source->GetHeight(),
484 realized_source->GetBuffer().data(),
485 reinterpret_cast<BITMAPINFO*>(header), DIB_RGB_COLORS,
495 uint32_t bitmap_color) {
496 if (!source || dest_width == 0 || dest_height == 0) {
500 RetainPtr<
const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
501 if (!realized_source) {
505 int width = realized_source->GetWidth();
506 int height = realized_source->GetHeight();
508 BITMAPINFOHEADER bmiHeader;
509 std::array<uint32_t, 2> bmiColors;
511 bmi.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
512 bmi.bmiHeader.biBitCount = 1;
513 bmi.bmiHeader.biCompression = BI_RGB;
514 bmi.bmiHeader.biHeight = -height;
515 bmi.bmiHeader.biPlanes = 1;
516 bmi.bmiHeader.biWidth = width;
518 SetStretchBltMode(m_hDC, HALFTONE);
520 bmi.bmiColors[0] = 0xffffff;
521 bmi.bmiColors[1] = 0;
523 HBRUSH hPattern = CreateBrush(bitmap_color);
524 HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
531
532
533
534
535
536
537
538
539
544 ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
545 width, height, realized_source->GetBuffer().data(),
546 (BITMAPINFO*)&bmi, DIB_RGB_COLORS, 0xB8074A);
548 SelectObject(m_hDC, hOld);
549 DeleteObject(hPattern);
556 if (::GetClipBox(m_hDC,
reinterpret_cast<RECT*>(&rect))) {
576 int startOutOfBoundsFlag = (x1 < 0) | ((x1 >
m_Width) << 1) |
577 ((y1 < 0) << 2) | ((y1 >
m_Height) << 3);
578 int endOutOfBoundsFlag = (x2 < 0) | ((x2 >
m_Width) << 1) |
579 ((y2 < 0) << 2) | ((y2 >
m_Height) << 3);
580 if (startOutOfBoundsFlag & endOutOfBoundsFlag)
583 if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
603 MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1),
nullptr);
604 LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
611 uint32_t stroke_color,
615 if (!(pGraphState || stroke_color == 0) &&
616 !pPlatform->m_GdiplusExt.IsAvailable()) {
632 int fill_alpha =
FXARGB_A(fill_color);
633 int stroke_alpha =
FXARGB_A(stroke_color);
634 bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
635 (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
636 if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
639 if (pPlatform->m_GdiplusExt.IsAvailable()) {
641 ((m_DeviceType != DeviceType::kPrinter && !fill_options.full_cover) ||
642 (pGraphState && !pGraphState->m_DashArray.empty()))) {
645 if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, path, pMatrix, pGraphState,
646 fill_color, stroke_color,
656 HBRUSH hBrush =
nullptr;
657 if (pGraphState && stroke_alpha) {
658 SetMiterLimit(m_hDC, pGraphState->m_MiterLimit,
nullptr);
659 hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
660 hPen = (HPEN)SelectObject(m_hDC, hPen);
662 if (fill && fill_alpha) {
663 SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
664 hBrush = CreateBrush(fill_color);
665 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
667 if (path.GetPoints().size() == 2 && pGraphState &&
668 !pGraphState->m_DashArray.empty()) {
677 SetPathToDC(m_hDC, path, pMatrix);
678 if (pGraphState && stroke_alpha) {
679 if (fill && fill_alpha) {
681 StrokeAndFillPath(m_hDC);
684 SetPathToDC(m_hDC, path, pMatrix);
690 }
else if (fill && fill_alpha) {
695 hPen = (HPEN)SelectObject(m_hDC, hPen);
699 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
700 DeleteObject(hBrush);
706 auto [alpha, colorref] = ArgbToAlphaAndColorRef(fill_color);
715 HBRUSH hBrush = CreateSolidBrush(colorref);
716 const RECT* pRect =
reinterpret_cast<
const RECT*>(&rect);
717 ::FillRect(m_hDC, pRect, hBrush);
718 DeleteObject(hBrush);
723 m_BaseClipBox = rect;
731 if (maybe_rectf.has_value()) {
732 FX_RECT rect = maybe_rectf.value().GetOuterRect();
735 if (m_BaseClipBox.has_value())
736 rect.Intersect(m_BaseClipBox.value());
737 return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
738 rect.bottom) != ERROR;
740 SetPathToDC(m_hDC, path, pMatrix);
741 SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
742 SelectClipPath(m_hDC, RGN_AND);
750 HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
751 hPen = (HPEN)SelectObject(m_hDC, hPen);
752 SetPathToDC(m_hDC, path, pMatrix);
754 SetPolyFillMode(m_hDC, WINDING);
755 bool ret = !!SelectClipPath(m_hDC, RGN_AND);
756 hPen = (HPEN)SelectObject(m_hDC, hPen);
764 auto [alpha, colorref] = ArgbToAlphaAndColorRef(color);
769 HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
770 hPen = (HPEN)SelectObject(m_hDC, hPen);
771 MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y),
nullptr);
772 LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
773 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 GDI_SetDIBits(RetainPtr< const CFX_DIBBase > source, const FX_RECT &src_rect, int left, int top)
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)
bool FillRect(const FX_RECT &rect, uint32_t fill_color) override
~CGdiDeviceDriver() override
bool SetClip_PathFill(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_FillRenderOptions &fill_options) 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 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) override
int GetDeviceCaps(int caps_id) const override
FX_RECT GetClipBox() const override
bool MultiplyAlpha(float alpha) override
CGdiDeviceDriver(HDC hDC, DeviceType device_type)
void RestoreState(bool bKeepSaved) override
DeviceType GetDeviceType() const override
bool MultiplyAlphaMask(RetainPtr< const CFX_DIBitmap > mask) override
void SaveState() 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)
bool DrawCosmeticLine(const CFX_PointF &ptMoveTo, const CFX_PointF &ptLineTo, uint32_t color) override
CFX_PTemplate< int32_t > CFX_Point
CFX_PTemplate< float > CFX_PointF
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
FX_COLORREF ArgbToColorRef(FX_ARGB argb)
#define NOTREACHED_NORETURN()
#define FXDC_PIXEL_HEIGHT
bool bInterpolateBilinear
constexpr FX_RECT(int l, int t, int r, int b)