Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cgdi_device_driver.cpp
Go to the documentation of this file.
1// Copyright 2020 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fxge/win32/cgdi_device_driver.h"
8
9#include <math.h>
10#include <windows.h>
11
12#include <algorithm>
13#include <array>
14#include <vector>
15
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"
33
34namespace {
35
36constexpr int FillTypeToGdiFillType(CFX_FillRenderOptions::FillType fill_type) {
37 return static_cast<int>(fill_type);
38}
39
40static_assert(FillTypeToGdiFillType(
41 CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
42 "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
43
44static_assert(
45 FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
46 "CFX_FillRenderOptions::FillType::kWinding value mismatch");
47
48HPEN CreateExtPen(const CFX_GraphStateData* pGraphState,
49 const CFX_Matrix* pMatrix,
50 uint32_t argb) {
51 DCHECK(pGraphState);
52
53 float scale = 1.0f;
54 if (pMatrix) {
55 scale = fabs(pMatrix->a) > fabs(pMatrix->b) ? fabs(pMatrix->a)
56 : fabs(pMatrix->b);
57 }
58 float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
59
60 uint32_t PenStyle = PS_GEOMETRIC;
61 if (!pGraphState->m_DashArray.empty())
62 PenStyle |= PS_USERSTYLE;
63 else
64 PenStyle |= PS_SOLID;
65
66 switch (pGraphState->m_LineCap) {
67 case CFX_GraphStateData::LineCap::kButt:
68 PenStyle |= PS_ENDCAP_FLAT;
69 break;
70 case CFX_GraphStateData::LineCap::kRound:
71 PenStyle |= PS_ENDCAP_ROUND;
72 break;
73 case CFX_GraphStateData::LineCap::kSquare:
74 PenStyle |= PS_ENDCAP_SQUARE;
75 break;
76 }
77 switch (pGraphState->m_LineJoin) {
78 case CFX_GraphStateData::LineJoin::kMiter:
79 PenStyle |= PS_JOIN_MITER;
80 break;
81 case CFX_GraphStateData::LineJoin::kRound:
82 PenStyle |= PS_JOIN_ROUND;
83 break;
84 case CFX_GraphStateData::LineJoin::kBevel:
85 PenStyle |= PS_JOIN_BEVEL;
86 break;
87 }
88
89 FX_COLORREF colorref = ArgbToColorRef(argb);
90 LOGBRUSH lb;
91 lb.lbColor = colorref;
92 lb.lbStyle = BS_SOLID;
93 lb.lbHatch = 0;
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(
99 pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
100 : pGraphState->m_DashArray[i]);
101 dashes[i] = std::max(dashes[i], 1U);
102 }
103 }
104 return ExtCreatePen(
105 PenStyle, (DWORD)ceil(width), &lb,
106 pdfium::checked_cast<DWORD>(pGraphState->m_DashArray.size()),
107 reinterpret_cast<const DWORD*>(dashes.data()));
108}
109
110HBRUSH CreateBrush(uint32_t argb) {
111 return CreateSolidBrush(ArgbToColorRef(argb));
112}
113
114void SetPathToDC(HDC hDC, const CFX_Path& path, const CFX_Matrix* pMatrix) {
115 BeginPath(hDC);
116
117 pdfium::span<const CFX_Path::Point> points = path.GetPoints();
118 for (size_t i = 0; i < points.size(); ++i) {
119 CFX_PointF pos = points[i].m_Point;
120 if (pMatrix)
121 pos = pMatrix->Transform(pos);
122
123 CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
124 CFX_Path::Point::Type point_type = points[i].m_Type;
125 if (point_type == CFX_Path::Point::Type::kMove) {
126 MoveToEx(hDC, screen.x, screen.y, nullptr);
127 } else if (point_type == CFX_Path::Point::Type::kLine) {
128 if (points[i].m_Point == points[i - 1].m_Point)
129 screen.x++;
130
131 LineTo(hDC, screen.x, screen.y);
132 } else if (point_type == CFX_Path::Point::Type::kBezier) {
133 POINT lppt[3];
134 lppt[0].x = screen.x;
135 lppt[0].y = screen.y;
136
137 pos = points[i + 1].m_Point;
138 if (pMatrix)
139 pos = pMatrix->Transform(pos);
140
141 lppt[1].x = FXSYS_roundf(pos.x);
142 lppt[1].y = FXSYS_roundf(pos.y);
143
144 pos = points[i + 2].m_Point;
145 if (pMatrix)
146 pos = pMatrix->Transform(pos);
147
148 lppt[2].x = FXSYS_roundf(pos.x);
149 lppt[2].y = FXSYS_roundf(pos.y);
150 PolyBezierTo(hDC, lppt, 3);
151 i += 2;
152 }
153 if (points[i].m_CloseFigure)
154 CloseFigure(hDC);
155 }
156 EndPath(hDC);
157}
158
159FixedSizeDataVector<uint8_t> GetBitmapInfoHeader(
160 const RetainPtr<const CFX_DIBBase>& source) {
161 size_t len = sizeof(BITMAPINFOHEADER);
162 if (source->GetBPP() == 1 || source->GetBPP() == 8) {
163 len += sizeof(DWORD) * (int)(1 << source->GetBPP());
164 }
165
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();
172 pbmih->biPlanes = 1;
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];
181 }
182 } else {
183 for (int i = 0; i < 256; i++) {
184 palette[i] = ArgbEncode(0, i, i, i);
185 }
186 }
187 }
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];
194 } else {
195 palette[0] = 0;
196 palette[1] = 0xffffff;
197 }
198 }
199 });
200 return result;
201}
202
203#if defined(PDF_USE_SKIA)
204// TODO(caryclark) This antigrain function is duplicated here to permit
205// removing the last remaining dependency. Eventually, this will be elminiated
206// altogether and replace by Skia code.
207
208struct rect_base {
209 float x1;
210 float y1;
211 float x2;
212 float y2;
213};
214
215unsigned clip_liang_barsky(float x1,
216 float y1,
217 float x2,
218 float y2,
219 const rect_base& clip_box,
220 float* x,
221 float* y) {
222 const float nearzero = 1e-30f;
223 float deltax = x2 - x1;
224 float deltay = y2 - y1;
225 unsigned np = 0;
226 if (deltax == 0)
227 deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
228 float xin;
229 float xout;
230 if (deltax > 0) {
231 xin = clip_box.x1;
232 xout = clip_box.x2;
233 } else {
234 xin = clip_box.x2;
235 xout = clip_box.x1;
236 }
237 float tinx = (xin - x1) / deltax;
238 if (deltay == 0)
239 deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
240 float yin;
241 float yout;
242 if (deltay > 0) {
243 yin = clip_box.y1;
244 yout = clip_box.y2;
245 } else {
246 yin = clip_box.y2;
247 yout = clip_box.y1;
248 }
249 float tiny = (yin - y1) / deltay;
250 float tin1;
251 float tin2;
252 if (tinx < tiny) {
253 tin1 = tinx;
254 tin2 = tiny;
255 } else {
256 tin1 = tiny;
257 tin2 = tinx;
258 }
259 if (tin1 <= 1.0f) {
260 if (0 < tin1) {
261 UNSAFE_TODO({
262 *x++ = xin;
263 *y++ = yin;
264 });
265 ++np;
266 }
267 if (tin2 <= 1.0f) {
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) {
272 if (tin2 <= tout1) {
273 if (tin2 > 0) {
274 if (tinx > tiny) {
275 UNSAFE_TODO({
276 *x++ = xin;
277 *y++ = y1 + (deltay * tinx);
278 });
279 } else {
280 UNSAFE_TODO({
281 *x++ = x1 + (deltax * tiny);
282 *y++ = yin;
283 });
284 }
285 ++np;
286 }
287 if (tout1 < 1.0f) {
288 if (toutx < touty) {
289 UNSAFE_TODO({
290 *x++ = xout;
291 *y++ = y1 + (deltay * toutx);
292 });
293 } else {
294 UNSAFE_TODO({
295 *x++ = x1 + (deltax * touty);
296 *y++ = yout;
297 });
298 }
299 } else {
300 UNSAFE_TODO({
301 *x++ = x2;
302 *y++ = y2;
303 });
304 }
305 ++np;
306 } else {
307 if (tinx > tiny) {
308 UNSAFE_TODO({
309 *x++ = xin;
310 *y++ = yout;
311 });
312 } else {
313 UNSAFE_TODO({
314 *x++ = xout;
315 *y++ = yin;
316 });
317 }
318 ++np;
319 }
320 }
321 }
322 }
323 return np;
324}
325#endif // defined(PDF_USE_SKIA)
326
327unsigned LineClip(float w,
328 float h,
329 float x1,
330 float y1,
331 float x2,
332 float y2,
333 float* x,
334 float* y) {
335#if defined(PDF_USE_SKIA)
336 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
337 // TODO(caryclark) temporary replacement of antigrain in line function to
338 // permit removing antigrain altogether
339 rect_base rect = {0.0f, 0.0f, w, h};
340 return clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
341 }
342#endif
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);
345}
346
347} // namespace
348
350 : m_hDC(hDC), m_DeviceType(device_type) {
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);
357 BITMAP bitmap;
358 GetObject(hBitmap, sizeof(bitmap), &bitmap);
359 m_nBitsPerPixel = bitmap.bmBitsPixel;
360 m_Width = bitmap.bmWidth;
361 m_Height = abs(bitmap.bmHeight);
362 hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
363 DeleteObject(hBitmap);
364 } else {
365 m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
366 m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
367 m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
368 }
371 } else {
372 m_RenderCaps = 0;
373 }
374}
375
377
381
382int CGdiDeviceDriver::GetDeviceCaps(int caps_id) const {
383 switch (caps_id) {
384 case FXDC_PIXEL_WIDTH:
385 return m_Width;
387 return m_Height;
388 case FXDC_BITS_PIXEL:
389 return m_nBitsPerPixel;
390 case FXDC_RENDER_CAPS:
391 return m_RenderCaps;
392 default:
394 }
395}
396
398 SaveDC(m_hDC);
399}
400
401void CGdiDeviceDriver::RestoreState(bool bKeepSaved) {
402 RestoreDC(m_hDC, -1);
403 if (bKeepSaved)
404 SaveDC(m_hDC);
405}
406
408 const FX_RECT& src_rect,
409 int left,
410 int top) {
411 if (m_DeviceType == DeviceType::kPrinter) {
412 RetainPtr<const CFX_DIBitmap> flipped_source =
413 source->FlipImage(/*bXFlip=*/false, /*bYFlip=*/true);
414 if (!flipped_source) {
415 return false;
416 }
417
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;
422 FX_RECT dst_rect(0, 0, src_rect.Width(), src_rect.Height());
423 dst_rect.Intersect(0, 0, flipped_source->GetWidth(),
424 flipped_source->GetHeight());
425 int dst_width = dst_rect.Width();
426 int dst_height = dst_rect.Height();
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,
430 SRCCOPY);
431 return true;
432 }
433
434 RetainPtr<const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
435 if (!realized_source) {
436 return false;
437 }
438 FixedSizeDataVector<uint8_t> info = GetBitmapInfoHeader(realized_source);
439 auto* header = reinterpret_cast<BITMAPINFOHEADER*>(info.span().data());
440 ::SetDIBitsToDevice(
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);
445 return true;
446}
447
449 int dest_left,
450 int dest_top,
451 int dest_width,
452 int dest_height,
453 const FXDIB_ResampleOptions& options) {
454 if (!source || dest_width == 0 || dest_height == 0) {
455 return false;
456 }
457
458 if ((int64_t)abs(dest_width) * abs(dest_height) <
459 (int64_t)source->GetWidth() * source->GetHeight() * 4 ||
460 options.bInterpolateBilinear) {
461 SetStretchBltMode(m_hDC, HALFTONE);
462 } else {
463 SetStretchBltMode(m_hDC, COLORONCOLOR);
464 }
465
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,
471 FXDIB_ResampleOptions(), nullptr);
472 } else {
473 realized_source = source->RealizeIfNeeded();
474 }
475 if (!realized_source) {
476 return false;
477 }
478
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,
486 SRCCOPY);
487 return true;
488}
489
491 int dest_left,
492 int dest_top,
493 int dest_width,
494 int dest_height,
495 uint32_t bitmap_color) {
496 if (!source || dest_width == 0 || dest_height == 0) {
497 return false;
498 }
499
500 RetainPtr<const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
501 if (!realized_source) {
502 return false;
503 }
504
505 int width = realized_source->GetWidth();
506 int height = realized_source->GetHeight();
507 struct {
508 BITMAPINFOHEADER bmiHeader;
509 std::array<uint32_t, 2> bmiColors;
510 } bmi = {};
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;
517 if (m_nBitsPerPixel != 1) {
518 SetStretchBltMode(m_hDC, HALFTONE);
519 }
520 bmi.bmiColors[0] = 0xffffff;
521 bmi.bmiColors[1] = 0;
522
523 HBRUSH hPattern = CreateBrush(bitmap_color);
524 HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
525
526 // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush
527 // bitmap.
528 // A complete list of the boolen operations is as follows:
529
530 /* P(bitmap_color) S(ImageMask) D(DeviceBitmap) Result
531 * 0 0 0 0
532 * 0 0 1 0
533 * 0 1 0 0
534 * 0 1 1 1
535 * 1 0 0 1
536 * 1 0 1 1
537 * 1 1 0 0
538 * 1 1 1 1
539 */
540 // The boolen codes is B8. Based on
541 // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is
542 // 0xB8074A
543
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);
547
548 SelectObject(m_hDC, hOld);
549 DeleteObject(hPattern);
550
551 return true;
552}
553
555 FX_RECT rect;
556 if (::GetClipBox(m_hDC, reinterpret_cast<RECT*>(&rect))) {
557 return rect;
558 }
559 return FX_RECT(0, 0, m_Width, m_Height);
560}
561
562bool CGdiDeviceDriver::MultiplyAlpha(float alpha) {
563 // Not implemented. All callers are using `CFX_DIBitmap`-backed raster devices
564 // anyway.
566}
567
568bool CGdiDeviceDriver::MultiplyAlphaMask(RetainPtr<const CFX_DIBitmap> mask) {
569 // Not implemented. All callers are using `CFX_DIBitmap`-backed raster devices
570 // anyway.
572}
573
574void CGdiDeviceDriver::DrawLine(float x1, float y1, float x2, float y2) {
575 if (!m_bMetafileDCType) { // EMF drawing is not bound to the DC.
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)
581 return;
582
583 if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
584 float x[2];
585 float y[2];
586 unsigned np = LineClip(m_Width, m_Height, x1, y1, x2, y2, x, y);
587 if (np == 0)
588 return;
589
590 if (np == 1) {
591 x2 = x[0];
592 y2 = y[0];
593 } else {
594 DCHECK_EQ(np, 2);
595 x1 = x[0];
596 y1 = y[0];
597 x2 = x[1];
598 y2 = y[1];
599 }
600 }
601 }
602
603 MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1), nullptr);
604 LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
605}
606
608 const CFX_Matrix* pMatrix,
609 const CFX_GraphStateData* pGraphState,
610 uint32_t fill_color,
611 uint32_t stroke_color,
612 const CFX_FillRenderOptions& fill_options) {
613 auto* pPlatform =
614 static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
615 if (!(pGraphState || stroke_color == 0) &&
616 !pPlatform->m_GdiplusExt.IsAvailable()) {
617 CFX_FloatRect bbox_f = path.GetBoundingBox();
618 if (pMatrix)
619 bbox_f = pMatrix->TransformRect(bbox_f);
620
621 FX_RECT bbox = bbox_f.GetInnerRect();
622 if (bbox.Width() <= 0) {
623 return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
624 CFX_PointF(bbox.left, bbox.bottom + 1),
625 fill_color);
626 }
627 if (bbox.Height() <= 0) {
628 return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
629 CFX_PointF(bbox.right + 1, bbox.top), fill_color);
630 }
631 }
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)
637 return false;
638
639 if (pPlatform->m_GdiplusExt.IsAvailable()) {
640 if (bDrawAlpha ||
641 ((m_DeviceType != DeviceType::kPrinter && !fill_options.full_cover) ||
642 (pGraphState && !pGraphState->m_DashArray.empty()))) {
643 if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
644 pGraphState->m_LineWidth == 1.0f && path.IsRect())) {
645 if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, path, pMatrix, pGraphState,
646 fill_color, stroke_color,
647 fill_options)) {
648 return true;
649 }
650 }
651 }
652 }
653 const bool fill =
655 HPEN hPen = nullptr;
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);
661 }
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);
666 }
667 if (path.GetPoints().size() == 2 && pGraphState &&
668 !pGraphState->m_DashArray.empty()) {
669 CFX_PointF pos1 = path.GetPoint(0);
670 CFX_PointF pos2 = path.GetPoint(1);
671 if (pMatrix) {
672 pos1 = pMatrix->Transform(pos1);
673 pos2 = pMatrix->Transform(pos2);
674 }
675 DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
676 } else {
677 SetPathToDC(m_hDC, path, pMatrix);
678 if (pGraphState && stroke_alpha) {
679 if (fill && fill_alpha) {
680 if (fill_options.text_mode) {
681 StrokeAndFillPath(m_hDC);
682 } else {
683 FillPath(m_hDC);
684 SetPathToDC(m_hDC, path, pMatrix);
685 StrokePath(m_hDC);
686 }
687 } else {
688 StrokePath(m_hDC);
689 }
690 } else if (fill && fill_alpha) {
691 FillPath(m_hDC);
692 }
693 }
694 if (hPen) {
695 hPen = (HPEN)SelectObject(m_hDC, hPen);
696 DeleteObject(hPen);
697 }
698 if (hBrush) {
699 hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
700 DeleteObject(hBrush);
701 }
702 return true;
703}
704
705bool CGdiDeviceDriver::FillRect(const FX_RECT& rect, uint32_t fill_color) {
706 auto [alpha, colorref] = ArgbToAlphaAndColorRef(fill_color);
707 if (alpha == 0) {
708 return true;
709 }
710
711 if (alpha < 255) {
712 return false;
713 }
714
715 HBRUSH hBrush = CreateSolidBrush(colorref);
716 const RECT* pRect = reinterpret_cast<const RECT*>(&rect);
717 ::FillRect(m_hDC, pRect, hBrush);
718 DeleteObject(hBrush);
719 return true;
720}
721
723 m_BaseClipBox = rect;
724}
725
727 const CFX_Path& path,
728 const CFX_Matrix* pMatrix,
729 const CFX_FillRenderOptions& fill_options) {
730 std::optional<CFX_FloatRect> maybe_rectf = path.GetRect(pMatrix);
731 if (maybe_rectf.has_value()) {
732 FX_RECT rect = maybe_rectf.value().GetOuterRect();
733 // Can easily apply base clip to protect against wildly large rectangular
734 // clips. crbug.com/1019026
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;
739 }
740 SetPathToDC(m_hDC, path, pMatrix);
741 SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
742 SelectClipPath(m_hDC, RGN_AND);
743 return true;
744}
745
747 const CFX_Path& path,
748 const CFX_Matrix* pMatrix,
749 const CFX_GraphStateData* pGraphState) {
750 HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
751 hPen = (HPEN)SelectObject(m_hDC, hPen);
752 SetPathToDC(m_hDC, path, pMatrix);
753 WidenPath(m_hDC);
754 SetPolyFillMode(m_hDC, WINDING);
755 bool ret = !!SelectClipPath(m_hDC, RGN_AND);
756 hPen = (HPEN)SelectObject(m_hDC, hPen);
757 DeleteObject(hPen);
758 return ret;
759}
760
762 const CFX_PointF& ptLineTo,
763 uint32_t color) {
764 auto [alpha, colorref] = ArgbToAlphaAndColorRef(color);
765 if (alpha == 0) {
766 return true;
767 }
768
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);
774 DeleteObject(hPen);
775 return true;
776}
#define DCHECK
Definition check.h:33
#define DCHECK_EQ(x, y)
Definition check_op.h:17
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
bool WillScale() const
CFX_FloatRect GetBoundingBox() const
Definition cfx_path.cpp:323
bool IsRect() const
Definition cfx_path.cpp:398
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
#define UNSAFE_TODO(...)
CFX_PTemplate< int32_t > CFX_Point
CFX_PTemplate< float > CFX_PointF
#define FXARGB_A(argb)
Definition fx_dib.h:196
uint32_t FX_COLORREF
Definition fx_dib.h:42
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
Definition fx_dib.h:188
FX_COLORREF ArgbToColorRef(FX_ARGB argb)
Definition fx_dib.cpp:60
#define NOTREACHED_NORETURN()
Definition notreached.h:22
#define CHECK(cvref)
#define FXDC_BITS_PIXEL
#define FXDC_RENDER_CAPS
#define FXDC_PIXEL_WIDTH
#define FXDC_PIXEL_HEIGHT
#define FXRC_GET_BITS
int Height() const
int32_t bottom
int32_t right
int Width() const
int32_t top
int32_t left
constexpr FX_RECT(int l, int t, int r, int b)