7#include "core/fxge/win32/cgdi_plus_ext.h"
18#include "core/fxcrt/fx_memory.h"
19#include "core/fxcrt/fx_string.h"
20#include "core/fxcrt/fx_string_wrappers.h"
21#include "core/fxcrt/fx_system.h"
22#include "core/fxge/cfx_fillrenderoptions.h"
23#include "core/fxge/cfx_gemodule.h"
24#include "core/fxge/cfx_graphstatedata.h"
25#include "core/fxge/cfx_path.h"
26#include "core/fxge/dib/cfx_dibbase.h"
27#include "core/fxge/dib/cfx_dibitmap.h"
28#include "core/fxge/win32/cwin32_platform.h"
29#include "third_party/base/containers/span.h"
30#include "third_party/base/notreached.h"
31#include "third_party/base/numerics/safe_conversions.h"
44 FuncId_GdipCreatePath2,
45 FuncId_GdipSetPenDashArray,
46 FuncId_GdipSetPenLineJoin,
47 FuncId_GdipCreateFromHDC,
48 FuncId_GdipSetPageUnit,
49 FuncId_GdipSetSmoothingMode,
50 FuncId_GdipCreateSolidFill,
52 FuncId_GdipDeleteBrush,
53 FuncId_GdipCreatePen1,
54 FuncId_GdipSetPenMiterLimit,
57 FuncId_GdipDeletePath,
58 FuncId_GdipDeleteGraphics,
59 FuncId_GdipDisposeImage,
60 FuncId_GdipCreateBitmapFromScan0,
61 FuncId_GdipSetImagePalette,
62 FuncId_GdipSetInterpolationMode,
63 FuncId_GdipDrawImagePointsI,
64 FuncId_GdiplusStartup,
66 FuncId_GdipCreatePath,
67 FuncId_GdipSetPathFillMode,
68 FuncId_GdipSetClipRegion,
70 FuncId_GdipAddPathLine,
71 FuncId_GdipAddPathRectangle,
72 FuncId_GdipDeleteRegion,
73 FuncId_GdipSetPenLineCap197819,
74 FuncId_GdipSetPenDashOffset,
75 FuncId_GdipCreateMatrix2,
76 FuncId_GdipDeleteMatrix,
77 FuncId_GdipSetWorldTransform,
78 FuncId_GdipSetPixelOffsetMode,
81LPCSTR g_GdipFuncNames[] = {
83 "GdipSetPenDashArray",
87 "GdipSetSmoothingMode",
88 "GdipCreateSolidFill",
92 "GdipSetPenMiterLimit",
98 "GdipCreateBitmapFromScan0",
99 "GdipSetImagePalette",
100 "GdipSetInterpolationMode",
101 "GdipDrawImagePointsI",
105 "GdipSetPathFillMode",
109 "GdipAddPathRectangle",
111 "GdipSetPenLineCap197819",
112 "GdipSetPenDashOffset",
115 "GdipSetWorldTransform",
116 "GdipSetPixelOffsetMode",
118static_assert(
std::size(g_GdipFuncNames) ==
119 static_cast<size_t>(FuncId_GdipSetPixelOffsetMode) + 1,
120 "g_GdipFuncNames has wrong size");
122using FuncType_GdipCreatePath2 =
123 decltype(&Gdiplus::DllExports::GdipCreatePath2);
124using FuncType_GdipSetPenDashArray =
125 decltype(&Gdiplus::DllExports::GdipSetPenDashArray);
126using FuncType_GdipSetPenLineJoin =
127 decltype(&Gdiplus::DllExports::GdipSetPenLineJoin);
128using FuncType_GdipCreateFromHDC =
129 decltype(&Gdiplus::DllExports::GdipCreateFromHDC);
130using FuncType_GdipSetPageUnit =
131 decltype(&Gdiplus::DllExports::GdipSetPageUnit);
132using FuncType_GdipSetSmoothingMode =
133 decltype(&Gdiplus::DllExports::GdipSetSmoothingMode);
134using FuncType_GdipCreateSolidFill =
135 decltype(&Gdiplus::DllExports::GdipCreateSolidFill);
136using FuncType_GdipFillPath =
decltype(&Gdiplus::DllExports::GdipFillPath);
137using FuncType_GdipDeleteBrush =
138 decltype(&Gdiplus::DllExports::GdipDeleteBrush);
139using FuncType_GdipCreatePen1 =
decltype(&Gdiplus::DllExports::GdipCreatePen1);
140using FuncType_GdipSetPenMiterLimit =
141 decltype(&Gdiplus::DllExports::GdipSetPenMiterLimit);
142using FuncType_GdipDrawPath =
decltype(&Gdiplus::DllExports::GdipDrawPath);
143using FuncType_GdipDeletePen =
decltype(&Gdiplus::DllExports::GdipDeletePen);
144using FuncType_GdipDeletePath =
decltype(&Gdiplus::DllExports::GdipDeletePath);
145using FuncType_GdipDeleteGraphics =
146 decltype(&Gdiplus::DllExports::GdipDeleteGraphics);
147using FuncType_GdipDisposeImage =
148 decltype(&Gdiplus::DllExports::GdipDisposeImage);
149using FuncType_GdipCreateBitmapFromScan0 =
150 decltype(&Gdiplus::DllExports::GdipCreateBitmapFromScan0);
151using FuncType_GdipSetImagePalette =
152 decltype(&Gdiplus::DllExports::GdipSetImagePalette);
153using FuncType_GdipSetInterpolationMode =
154 decltype(&Gdiplus::DllExports::GdipSetInterpolationMode);
155using FuncType_GdipDrawImagePointsI =
156 decltype(&Gdiplus::DllExports::GdipDrawImagePointsI);
157using FuncType_GdiplusStartup =
decltype(&Gdiplus::GdiplusStartup);
158using FuncType_GdipDrawLineI =
decltype(&Gdiplus::DllExports::GdipDrawLineI);
159using FuncType_GdipCreatePath =
decltype(&Gdiplus::DllExports::GdipCreatePath);
160using FuncType_GdipSetPathFillMode =
161 decltype(&Gdiplus::DllExports::GdipSetPathFillMode);
162using FuncType_GdipSetClipRegion =
163 decltype(&Gdiplus::DllExports::GdipSetClipRegion);
164using FuncType_GdipWidenPath =
decltype(&Gdiplus::DllExports::GdipWidenPath);
165using FuncType_GdipAddPathLine =
166 decltype(&Gdiplus::DllExports::GdipAddPathLine);
167using FuncType_GdipAddPathRectangle =
168 decltype(&Gdiplus::DllExports::GdipAddPathRectangle);
169using FuncType_GdipDeleteRegion =
170 decltype(&Gdiplus::DllExports::GdipDeleteRegion);
171using FuncType_GdipSetPenLineCap197819 =
172 decltype(&Gdiplus::DllExports::GdipSetPenLineCap197819);
173using FuncType_GdipSetPenDashOffset =
174 decltype(&Gdiplus::DllExports::GdipSetPenDashOffset);
175using FuncType_GdipCreateMatrix2 =
176 decltype(&Gdiplus::DllExports::GdipCreateMatrix2);
177using FuncType_GdipDeleteMatrix =
178 decltype(&Gdiplus::DllExports::GdipDeleteMatrix);
179using FuncType_GdipSetWorldTransform =
180 decltype(&Gdiplus::DllExports::GdipSetWorldTransform);
181using FuncType_GdipSetPixelOffsetMode =
182 decltype(&Gdiplus::DllExports::GdipSetPixelOffsetMode);
183#define CallFunc(funcname)
184 reinterpret_cast<FuncType_##funcname>(
185 GdiplusExt.functions()[FuncId_##funcname])
188 return fill_type == CFX_FillRenderOptions::FillType::kEvenOdd
189 ? Gdiplus::FillModeAlternate
190 : Gdiplus::FillModeWinding;
196 return pData->m_GdiplusExt;
199Gdiplus::GpBrush* GdipCreateBrushImpl(DWORD argb) {
201 Gdiplus::GpSolidFill* solidBrush =
nullptr;
202 CallFunc(GdipCreateSolidFill)((Gdiplus::ARGB)argb, &solidBrush);
206void OutputImage(Gdiplus::GpGraphics* pGraphics,
216 if (source->GetBPP() == 1 && (src_rect
.left % 8)) {
218 source = source->ClipTo(src_rect);
222 OutputImage(pGraphics,
std::move(source), new_rect, dest_left, dest_top,
223 dest_width, dest_height);
227 RetainPtr<
const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
228 if (!realized_source) {
232 int src_pitch = realized_source->GetPitch();
237 uint8_t* scan0 =
const_cast<uint8_t*>(
238 realized_source->GetBuffer()
239 .subspan(src_rect
.top * src_pitch +
240 realized_source->GetBPP() * src_rect
.left / 8)
242 Gdiplus::GpBitmap* bitmap =
nullptr;
243 switch (source->GetFormat()) {
244 case FXDIB_Format::kArgb:
245 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
246 PixelFormat32bppARGB, scan0, &bitmap);
248 case FXDIB_Format::kRgb32:
249 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
250 PixelFormat32bppRGB, scan0, &bitmap);
252 case FXDIB_Format::kRgb:
253 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
254 PixelFormat24bppRGB, scan0, &bitmap);
257 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
258 PixelFormat8bppIndexed, scan0,
263 for (
int i = 0; i < 256; i++)
264 pal[i + 2] = realized_source->GetPaletteArgb(i);
265 CallFunc(GdipSetImagePalette)(bitmap, (Gdiplus::ColorPalette*)pal);
269 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
270 PixelFormat1bppIndexed, scan0,
277 NOTREACHED_NORETURN();
279 if (dest_height < 0) {
282 if (dest_width < 0) {
285 Gdiplus::Point destinationPoints[] = {
286 Gdiplus::Point(dest_left, dest_top),
287 Gdiplus::Point(dest_left + dest_width, dest_top),
288 Gdiplus::Point(dest_left, dest_top + dest_height)};
289 CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3);
303 width =
std::max(width, unit);
305 Gdiplus::GpPen* pPen =
nullptr;
306 CallFunc(GdipCreatePen1)((Gdiplus::ARGB)argb, width, Gdiplus::UnitWorld,
308 Gdiplus::LineCap lineCap = Gdiplus::LineCapFlat;
309 Gdiplus::DashCap dashCap = Gdiplus::DashCapFlat;
310 bool bDashExtend =
false;
312 case CFX_GraphStateData::LineCap::kButt:
313 lineCap = Gdiplus::LineCapFlat;
315 case CFX_GraphStateData::LineCap::kRound:
316 lineCap = Gdiplus::LineCapRound;
317 dashCap = Gdiplus::DashCapRound;
320 case CFX_GraphStateData::LineCap::kSquare:
321 lineCap = Gdiplus::LineCapSquare;
325 CallFunc(GdipSetPenLineCap197819)(pPen, lineCap, lineCap, dashCap);
326 Gdiplus::LineJoin lineJoin = Gdiplus::LineJoinMiterClipped;
328 case CFX_GraphStateData::LineJoin::kMiter:
329 lineJoin = Gdiplus::LineJoinMiterClipped;
331 case CFX_GraphStateData::LineJoin::kRound:
332 lineJoin = Gdiplus::LineJoinRound;
334 case CFX_GraphStateData::LineJoin::kBevel:
335 lineJoin = Gdiplus::LineJoinBevel;
338 CallFunc(GdipSetPenLineJoin)(pPen, lineJoin);
339 if (!pGraphState->m_DashArray.empty()) {
341 FX_Alloc(
float, FxAlignToBoundary<2>(pGraphState->m_DashArray.size()));
343 float on_leftover = 0;
344 float off_leftover = 0;
345 for (size_t i = 0; i < pGraphState->m_DashArray.size(); i += 2) {
346 float on_phase = pGraphState->m_DashArray[i];
348 if (i + 1 < pGraphState->m_DashArray.size()) {
349 off_phase = pGraphState->m_DashArray[i + 1];
351 off_phase = on_phase;
355 if (on_phase + off_phase <= 0.00002f) {
366 if (on_phase == 0 || off_phase == 0) {
368 on_leftover += on_phase;
369 off_leftover += off_phase;
371 pDashArray[nCount - 2] += on_phase;
372 pDashArray[nCount - 1] += off_phase;
375 pDashArray[nCount++] = on_phase + on_leftover;
377 pDashArray[nCount++] = off_phase + off_leftover;
381 CallFunc(GdipSetPenDashArray)(pPen, pDashArray, nCount);
389 CallFunc(GdipSetPenDashOffset)(pPen, phase);
391 pDashArray =
nullptr;
397absl::optional<std::pair<size_t, size_t>> IsSmallTriangle(
398 pdfium::span<
const Gdiplus::PointF> points,
400 static constexpr size_t kPairs[3][2] = {{1, 2}, {0, 2}, {0, 1}};
401 for (size_t i = 0; i <
std::size(kPairs); ++i) {
402 size_t pair1 = kPairs[i][0];
403 size_t pair2 = kPairs[i][1];
405 CFX_PointF p1(points[pair1].X, points[pair1].Y);
406 CFX_PointF p2(points[pair2].X, points[pair2].Y);
412 CFX_PointF diff = p1 - p2;
413 float distance_square = (diff.x * diff.x) + (diff.y * diff.y);
414 if (distance_square < 2.25f)
415 return std::make_pair(i, pair1);
417 return absl::nullopt;
420class GpStream
final :
public IStream {
422 GpStream() =
default;
423 ~GpStream() =
default;
426 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
427 void** ppvObject) override {
428 if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) ||
429 iid == __uuidof(ISequentialStream)) {
430 *ppvObject =
static_cast<IStream*>(
this);
434 return E_NOINTERFACE;
436 ULONG STDMETHODCALLTYPE AddRef() override {
437 return (ULONG)InterlockedIncrement(&m_RefCount);
439 ULONG STDMETHODCALLTYPE Release() override {
440 ULONG res = (ULONG)InterlockedDecrement(&m_RefCount);
448 HRESULT STDMETHODCALLTYPE Read(
void* output,
450 ULONG* pcbRead) override {
454 if (m_ReadPos >= m_InterStream.tellp())
455 return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA);
457 size_t bytes_left = pdfium::base::checked_cast<size_t>(
458 std::streamoff(m_InterStream.tellp()) - m_ReadPos);
460 std::min(pdfium::base::checked_cast<size_t>(cb), bytes_left);
461 memcpy(output, m_InterStream.str().c_str() + m_ReadPos, bytes_out);
462 m_ReadPos += bytes_out;
464 *pcbRead = (ULONG)bytes_out;
468 HRESULT STDMETHODCALLTYPE Write(
const void* input,
470 ULONG* pcbWritten) override {
476 m_InterStream.write(
reinterpret_cast<
const char*>(input), cb);
483 HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) override {
486 HRESULT STDMETHODCALLTYPE CopyTo(IStream*,
489 ULARGE_INTEGER*) override {
492 HRESULT STDMETHODCALLTYPE Commit(DWORD) override {
return E_NOTIMPL; }
493 HRESULT STDMETHODCALLTYPE Revert() override {
return E_NOTIMPL; }
494 HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
499 HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
504 HRESULT STDMETHODCALLTYPE Clone(IStream** stream) override {
507 HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
509 ULARGE_INTEGER* lpNewFilePointer) override {
510 std::streamoff start;
511 std::streamoff new_read_position;
513 case STREAM_SEEK_SET:
516 case STREAM_SEEK_CUR:
519 case STREAM_SEEK_END:
520 if (m_InterStream.tellp() < 0)
521 return STG_E_SEEKERROR;
522 start = m_InterStream.tellp();
525 return STG_E_INVALIDFUNCTION;
527 new_read_position = start + liDistanceToMove.QuadPart;
528 if (new_read_position > m_InterStream.tellp())
529 return STG_E_SEEKERROR;
531 m_ReadPos = new_read_position;
532 if (lpNewFilePointer)
533 lpNewFilePointer->QuadPart = m_ReadPos;
537 HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg,
538 DWORD grfStatFlag) override {
540 return STG_E_INVALIDFUNCTION;
542 ZeroMemory(pStatstg,
sizeof(STATSTG));
544 if (m_InterStream.tellp() < 0)
545 return STG_E_SEEKERROR;
547 pStatstg->cbSize.QuadPart = m_InterStream.tellp();
553 std::streamoff m_ReadPos = 0;
554 fxcrt::ostringstream m_InterStream;
562 FreeLibrary(gdiplus_module_);
567 GetSystemDirectoryA(buf, MAX_PATH);
568 ByteString dllpath = buf;
569 dllpath
+= "\\GDIPLUS.DLL";
570 gdiplus_module_ = LoadLibraryA(dllpath.c_str());
571 if (!gdiplus_module_) {
575 gdiplus_functions_.resize(std::size(g_GdipFuncNames));
576 for (size_t i = 0; i <
std::size(g_GdipFuncNames); ++i) {
577 gdiplus_functions_[i] = GetProcAddress(gdiplus_module_, g_GdipFuncNames[i]);
578 if (!gdiplus_functions_[i]) {
579 FreeLibrary(gdiplus_module_);
580 gdiplus_module_ =
nullptr;
585 ULONG_PTR gdiplus_token;
586 Gdiplus::GdiplusStartupInput gdiplus_startup_input;
587 ((FuncType_GdiplusStartup)gdiplus_functions_[FuncId_GdiplusStartup])(
588 &gdiplus_token, &gdiplus_startup_input,
nullptr);
599 Gdiplus::GpGraphics* pGraphics;
601 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics);
602 CallFunc(GdipSetPageUnit)(pGraphics, Gdiplus::UnitPixel);
605 pGraphics, Gdiplus::InterpolationModeNearestNeighbor);
606 }
else if (source->GetWidth() > abs(dest_width) / 2 ||
607 source->GetHeight() > abs(dest_height) / 2) {
608 CallFunc(GdipSetInterpolationMode)(pGraphics,
609 Gdiplus::InterpolationModeHighQuality);
611 CallFunc(GdipSetInterpolationMode)(pGraphics,
612 Gdiplus::InterpolationModeBilinear);
614 FX_RECT src_rect(0, 0, source->GetWidth(), source->GetHeight());
615 OutputImage(pGraphics,
std::move(source), src_rect, dest_left, dest_top,
616 dest_width, dest_height);
617 CallFunc(GdipDeleteGraphics)(pGraphics);
618 CallFunc(GdipDeleteGraphics)(pGraphics);
627 uint32_t stroke_argb,
629 pdfium::span<
const CFX_Path::
Point> points = path.GetPoints();
633 Gdiplus::GpGraphics* pGraphics =
nullptr;
635 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics);
636 CallFunc(GdipSetPageUnit)(pGraphics, Gdiplus::UnitPixel);
637 CallFunc(GdipSetPixelOffsetMode)(pGraphics, Gdiplus::PixelOffsetModeHalf);
638 Gdiplus::GpMatrix* pMatrix =
nullptr;
639 if (pObject2Device) {
641 pObject2Device
->c, pObject2Device
->d,
642 pObject2Device
->e, pObject2Device
->f, &pMatrix);
643 CallFunc(GdipSetWorldTransform)(pGraphics, pMatrix);
645 std::vector<Gdiplus::PointF> gp_points(points.size());
646 std::vector<BYTE> gp_types(points.size());
648 bool bSubClose =
false;
649 bool bSmooth =
false;
650 size_t pos_subclose = 0;
651 size_t startpoint = 0;
652 for (size_t i = 0; i < points.size(); ++i) {
653 gp_points[i].X = points[i].m_Point.x;
654 gp_points[i].Y = points[i].m_Point.y;
656 CFX_PointF pos = points[i].m_Point;
660 if (pos.x > 50000.0f)
661 gp_points[i].X = 50000.0f;
662 if (pos.x < -50000.0f)
663 gp_points[i].X = -50000.0f;
664 if (pos.y > 50000.0f)
665 gp_points[i].Y = 50000.0f;
666 if (pos.y < -50000.0f)
667 gp_points[i].Y = -50000.0f;
671 gp_types[i] = Gdiplus::PathPointTypeStart;
676 gp_types[i] = Gdiplus::PathPointTypeLine;
678 (i + 1 == points.size() ||
680 gp_points[i].Y == gp_points[i - 1].Y &&
681 gp_points[i].X == gp_points[i - 1].X) {
682 gp_points[i].X += 0.01f;
685 if (!bSmooth && gp_points[i].X != gp_points[i - 1].X &&
686 gp_points[i].Y != gp_points[i - 1].Y) {
690 gp_types[i] = Gdiplus::PathPointTypeBezier;
693 if (points[i].m_CloseFigure) {
695 gp_types[pos_subclose] &= ~Gdiplus::PathPointTypeCloseSubpath;
699 gp_types[i] |= Gdiplus::PathPointTypeCloseSubpath;
700 if (!bSmooth && gp_points[i].X != gp_points[startpoint].X &&
701 gp_points[i].Y != gp_points[startpoint].Y) {
710 CallFunc(GdipSetSmoothingMode)(pGraphics, Gdiplus::SmoothingModeNone);
712 if (!bSmooth && fill)
715 if (bSmooth || (pGraphState && pGraphState
->m_LineWidth > 2)) {
716 CallFunc(GdipSetSmoothingMode)(pGraphics,
717 Gdiplus::SmoothingModeAntiAlias);
720 if (points.size() == 4 && !pGraphState) {
721 auto indices = IsSmallTriangle(gp_points, pObject2Device);
722 if (indices.has_value()) {
725 std::tie(v1, v2) = indices.value();
726 Gdiplus::GpPen* pPen =
nullptr;
727 CallFunc(GdipCreatePen1)(fill_argb, 1.0f, Gdiplus::UnitPixel, &pPen);
728 CallFunc(GdipDrawLineI)(pGraphics, pPen, FXSYS_roundf(gp_points[v1].X),
729 FXSYS_roundf(gp_points[v1].Y),
730 FXSYS_roundf(gp_points[v2].X),
731 FXSYS_roundf(gp_points[v2].Y));
736 Gdiplus::GpPath* pGpPath =
nullptr;
737 const Gdiplus::GpFillMode gp_fill_mode =
738 FillType2Gdip(fill_options.fill_type);
739 CallFunc(GdipCreatePath2)(gp_points.data(), gp_types.data(),
740 pdfium::base::checked_cast<
int>(points.size()),
741 gp_fill_mode, &pGpPath);
744 CallFunc(GdipDeleteMatrix)(pMatrix);
746 CallFunc(GdipDeleteGraphics)(pGraphics);
750 Gdiplus::GpBrush* pBrush = GdipCreateBrushImpl(fill_argb);
751 CallFunc(GdipSetPathFillMode)(pGpPath, gp_fill_mode);
752 CallFunc(GdipFillPath)(pGraphics, pBrush, pGpPath);
755 if (pGraphState && stroke_argb) {
756 Gdiplus::GpPen* pPen =
757 GdipCreatePenImpl(pGraphState, pObject2Device, stroke_argb,
758 fill_options.stroke_text_mode);
759 if (nSubPathes == 1) {
760 CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath);
763 for (size_t i = 0; i < points.size(); ++i) {
764 if (i + 1 == points.size() ||
765 gp_types[i + 1] == Gdiplus::PathPointTypeStart) {
766 Gdiplus::GpPath* pSubPath;
768 &gp_points[iStart], &gp_types[iStart],
769 pdfium::base::checked_cast<
int>(i - iStart + 1), gp_fill_mode,
772 CallFunc(GdipDrawPath)(pGraphics, pPen, pSubPath);
780 CallFunc(GdipDeleteMatrix)(pMatrix);
782 CallFunc(GdipDeleteGraphics)(pGraphics);
#define CallFunc(funcname)
PlatformIface * GetPlatform() const
static CFX_GEModule * Get()
CFX_PointF Transform(const CFX_PointF &point) const
bool DrawPath(HDC hDC, const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState, uint32_t fill_argb, uint32_t stroke_argb, const CFX_FillRenderOptions &fill_options)
bool StretchDIBits(HDC hDC, RetainPtr< const CFX_DIBBase > source, int dest_left, int dest_top, int dest_width, int dest_height, const FX_RECT *pClipRect, const FXDIB_ResampleOptions &options)
ByteString & operator+=(const char *str)
constexpr FX_RECT(int l, int t, int r, int b)