1 // Copyright 2014 PDFium Authors. All rights reserved.
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 "xfa/fxgraphics/cfx_graphics.h"
8
9 #include <memory>
10
11 #include "core/fxge/cfx_fxgedevice.h"
12 #include "core/fxge/cfx_gemodule.h"
13 #include "core/fxge/cfx_renderdevice.h"
14 #include "core/fxge/cfx_unicodeencoding.h"
15 #include "third_party/base/ptr_util.h"
16 #include "xfa/fxgraphics/cfx_color.h"
17 #include "xfa/fxgraphics/cfx_path.h"
18 #include "xfa/fxgraphics/cfx_pattern.h"
19 #include "xfa/fxgraphics/cfx_shading.h"
20
21 namespace {
22
23 enum {
24 FX_CONTEXT_None = 0,
25 FX_CONTEXT_Device,
26 };
27
28 #define FX_HATCHSTYLE_Total 53
29
30 struct FX_HATCHDATA {
31 int32_t width;
32 int32_t height;
33 uint8_t maskBits[64];
34 };
35
36 const FX_HATCHDATA hatchBitmapData[FX_HATCHSTYLE_Total] = {
37 {16, // Horizontal
38 16,
39 {
40 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
43 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 }},
47 {16, // Vertical
48 16,
49 {
50 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
51 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
52 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80,
53 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
54 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
55 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
56 }},
57 {16, // ForwardDiagonal
58 16,
59 {
60 0x80, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00,
61 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04,
62 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x80,
63 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00,
64 0x10, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
65 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
66 }},
67 {16, // BackwardDiagonal
68 16,
69 {
70 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00,
71 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20,
72 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x01,
73 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
74 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
75 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
76 }},
77 {16, // Cross
78 16,
79 {
80 0xff, 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
81 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80,
82 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xff,
83 0xff, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
84 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00,
85 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
86 }},
87 {16, // DiagonalCross
88 16,
89 {
90 0x81, 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00,
91 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24,
92 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x81,
93 0x81, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00,
94 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x24, 0x24, 0x00,
95 0x00, 0x42, 0x42, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00,
96 }},
97 };
98
99 } // namespace
100
CFX_Graphics(CFX_RenderDevice * renderDevice)101 CFX_Graphics::CFX_Graphics(CFX_RenderDevice* renderDevice)
102 : m_type(FX_CONTEXT_None), m_renderDevice(renderDevice) {
103 if (!renderDevice)
104 return;
105 m_type = FX_CONTEXT_Device;
106 }
107
~CFX_Graphics()108 CFX_Graphics::~CFX_Graphics() {}
109
SaveGraphState()110 void CFX_Graphics::SaveGraphState() {
111 if (m_type != FX_CONTEXT_Device || !m_renderDevice)
112 return;
113
114 m_renderDevice->SaveState();
115 m_infoStack.push_back(pdfium::MakeUnique<TInfo>(m_info));
116 }
117
RestoreGraphState()118 void CFX_Graphics::RestoreGraphState() {
119 if (m_type != FX_CONTEXT_Device || !m_renderDevice)
120 return;
121
122 m_renderDevice->RestoreState(false);
123 if (m_infoStack.empty() || !m_infoStack.back())
124 return;
125
126 m_info = *m_infoStack.back();
127 m_infoStack.pop_back();
128 return;
129 }
130
SetLineCap(CFX_GraphStateData::LineCap lineCap)131 void CFX_Graphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) {
132 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
133 m_info.graphState.m_LineCap = lineCap;
134 }
135 }
136
SetLineDash(FX_FLOAT dashPhase,FX_FLOAT * dashArray,int32_t dashCount)137 void CFX_Graphics::SetLineDash(FX_FLOAT dashPhase,
138 FX_FLOAT* dashArray,
139 int32_t dashCount) {
140 if (dashCount > 0 && !dashArray)
141 return;
142
143 dashCount = dashCount < 0 ? 0 : dashCount;
144 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
145 FX_FLOAT scale = 1.0;
146 if (m_info.isActOnDash) {
147 scale = m_info.graphState.m_LineWidth;
148 }
149 m_info.graphState.m_DashPhase = dashPhase;
150 m_info.graphState.SetDashCount(dashCount);
151 for (int32_t i = 0; i < dashCount; i++) {
152 m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
153 }
154 }
155 }
156
SetLineDash(FX_DashStyle dashStyle)157 void CFX_Graphics::SetLineDash(FX_DashStyle dashStyle) {
158 if (m_type == FX_CONTEXT_Device && m_renderDevice)
159 RenderDeviceSetLineDash(dashStyle);
160 }
161
SetLineWidth(FX_FLOAT lineWidth,bool isActOnDash)162 void CFX_Graphics::SetLineWidth(FX_FLOAT lineWidth, bool isActOnDash) {
163 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
164 m_info.graphState.m_LineWidth = lineWidth;
165 m_info.isActOnDash = isActOnDash;
166 }
167 }
168
SetStrokeColor(CFX_Color * color)169 void CFX_Graphics::SetStrokeColor(CFX_Color* color) {
170 if (!color)
171 return;
172 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
173 m_info.strokeColor = color;
174 }
175 }
176
SetFillColor(CFX_Color * color)177 void CFX_Graphics::SetFillColor(CFX_Color* color) {
178 if (!color)
179 return;
180 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
181 m_info.fillColor = color;
182 }
183 }
184
StrokePath(CFX_Path * path,CFX_Matrix * matrix)185 void CFX_Graphics::StrokePath(CFX_Path* path, CFX_Matrix* matrix) {
186 if (!path)
187 return;
188 if (m_type == FX_CONTEXT_Device && m_renderDevice)
189 RenderDeviceStrokePath(path, matrix);
190 }
191
FillPath(CFX_Path * path,FX_FillMode fillMode,CFX_Matrix * matrix)192 void CFX_Graphics::FillPath(CFX_Path* path,
193 FX_FillMode fillMode,
194 CFX_Matrix* matrix) {
195 if (!path)
196 return;
197 if (m_type == FX_CONTEXT_Device && m_renderDevice)
198 RenderDeviceFillPath(path, fillMode, matrix);
199 }
200
StretchImage(CFX_DIBSource * source,const CFX_RectF & rect,CFX_Matrix * matrix)201 void CFX_Graphics::StretchImage(CFX_DIBSource* source,
202 const CFX_RectF& rect,
203 CFX_Matrix* matrix) {
204 if (!source)
205 return;
206 if (m_type == FX_CONTEXT_Device && m_renderDevice)
207 RenderDeviceStretchImage(source, rect, matrix);
208 }
209
ConcatMatrix(const CFX_Matrix * matrix)210 void CFX_Graphics::ConcatMatrix(const CFX_Matrix* matrix) {
211 if (!matrix)
212 return;
213 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
214 m_info.CTM.Concat(*matrix);
215 }
216 }
217
GetMatrix()218 CFX_Matrix* CFX_Graphics::GetMatrix() {
219 if (m_type == FX_CONTEXT_Device && m_renderDevice)
220 return &m_info.CTM;
221 return nullptr;
222 }
223
GetClipRect() const224 CFX_RectF CFX_Graphics::GetClipRect() const {
225 if (m_type != FX_CONTEXT_Device || !m_renderDevice)
226 return CFX_RectF();
227
228 FX_RECT r = m_renderDevice->GetClipBox();
229 return CFX_Rect(r.left, r.top, r.Width(), r.Height()).As<FX_FLOAT>();
230 }
231
SetClipRect(const CFX_RectF & rect)232 void CFX_Graphics::SetClipRect(const CFX_RectF& rect) {
233 if (m_type == FX_CONTEXT_Device && m_renderDevice) {
234 m_renderDevice->SetClip_Rect(
235 FX_RECT(FXSYS_round(rect.left), FXSYS_round(rect.top),
236 FXSYS_round(rect.right()), FXSYS_round(rect.bottom())));
237 }
238 }
239
GetRenderDevice()240 CFX_RenderDevice* CFX_Graphics::GetRenderDevice() {
241 return m_renderDevice;
242 }
243
RenderDeviceSetLineDash(FX_DashStyle dashStyle)244 void CFX_Graphics::RenderDeviceSetLineDash(FX_DashStyle dashStyle) {
245 switch (dashStyle) {
246 case FX_DASHSTYLE_Solid: {
247 m_info.graphState.SetDashCount(0);
248 return;
249 }
250 case FX_DASHSTYLE_Dash: {
251 FX_FLOAT dashArray[] = {3, 1};
252 SetLineDash(0, dashArray, 2);
253 return;
254 }
255 case FX_DASHSTYLE_Dot: {
256 FX_FLOAT dashArray[] = {1, 1};
257 SetLineDash(0, dashArray, 2);
258 return;
259 }
260 case FX_DASHSTYLE_DashDot: {
261 FX_FLOAT dashArray[] = {3, 1, 1, 1};
262 SetLineDash(0, dashArray, 4);
263 return;
264 }
265 case FX_DASHSTYLE_DashDotDot: {
266 FX_FLOAT dashArray[] = {4, 1, 2, 1, 2, 1};
267 SetLineDash(0, dashArray, 6);
268 return;
269 }
270 default:
271 return;
272 }
273 }
274
RenderDeviceStrokePath(CFX_Path * path,CFX_Matrix * matrix)275 void CFX_Graphics::RenderDeviceStrokePath(CFX_Path* path, CFX_Matrix* matrix) {
276 if (!m_info.strokeColor)
277 return;
278 CFX_Matrix m(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
279 m_info.CTM.e, m_info.CTM.f);
280 if (matrix) {
281 m.Concat(*matrix);
282 }
283 switch (m_info.strokeColor->m_type) {
284 case FX_COLOR_Solid: {
285 m_renderDevice->DrawPath(path->GetPathData(), &m, &m_info.graphState, 0x0,
286 m_info.strokeColor->m_info.argb, 0);
287 return;
288 }
289 default:
290 return;
291 }
292 }
293
RenderDeviceFillPath(CFX_Path * path,FX_FillMode fillMode,CFX_Matrix * matrix)294 void CFX_Graphics::RenderDeviceFillPath(CFX_Path* path,
295 FX_FillMode fillMode,
296 CFX_Matrix* matrix) {
297 if (!m_info.fillColor)
298 return;
299 CFX_Matrix m(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
300 m_info.CTM.e, m_info.CTM.f);
301 if (matrix) {
302 m.Concat(*matrix);
303 }
304 switch (m_info.fillColor->m_type) {
305 case FX_COLOR_Solid: {
306 m_renderDevice->DrawPath(path->GetPathData(), &m, &m_info.graphState,
307 m_info.fillColor->m_info.argb, 0x0, fillMode);
308 return;
309 }
310 case FX_COLOR_Pattern:
311 FillPathWithPattern(path, fillMode, &m);
312 return;
313 case FX_COLOR_Shading:
314 FillPathWithShading(path, fillMode, &m);
315 return;
316 default:
317 return;
318 }
319 }
320
RenderDeviceStretchImage(CFX_DIBSource * source,const CFX_RectF & rect,CFX_Matrix * matrix)321 void CFX_Graphics::RenderDeviceStretchImage(CFX_DIBSource* source,
322 const CFX_RectF& rect,
323 CFX_Matrix* matrix) {
324 CFX_Matrix m1(m_info.CTM.a, m_info.CTM.b, m_info.CTM.c, m_info.CTM.d,
325 m_info.CTM.e, m_info.CTM.f);
326 if (matrix) {
327 m1.Concat(*matrix);
328 }
329 std::unique_ptr<CFX_DIBitmap> bmp1 =
330 source->StretchTo((int32_t)rect.Width(), (int32_t)rect.Height());
331 CFX_Matrix m2(rect.Width(), 0.0, 0.0, rect.Height(), rect.left, rect.top);
332 m2.Concat(m1);
333
334 int32_t left;
335 int32_t top;
336 std::unique_ptr<CFX_DIBitmap> bmp2 = bmp1->FlipImage(false, true);
337 std::unique_ptr<CFX_DIBitmap> bmp3 = bmp2->TransformTo(&m2, left, top);
338 CFX_RectF r = GetClipRect();
339 CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
340 bitmap->CompositeBitmap(FXSYS_round(r.left), FXSYS_round(r.top),
341 FXSYS_round(r.Width()), FXSYS_round(r.Height()),
342 bmp3.get(), FXSYS_round(r.left - left),
343 FXSYS_round(r.top - top));
344 }
345
FillPathWithPattern(CFX_Path * path,FX_FillMode fillMode,CFX_Matrix * matrix)346 void CFX_Graphics::FillPathWithPattern(CFX_Path* path,
347 FX_FillMode fillMode,
348 CFX_Matrix* matrix) {
349 CFX_Pattern* pattern = m_info.fillColor->m_info.pattern;
350 CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
351 int32_t width = bitmap->GetWidth();
352 int32_t height = bitmap->GetHeight();
353 CFX_DIBitmap bmp;
354 bmp.Create(width, height, FXDIB_Argb);
355 m_renderDevice->GetDIBits(&bmp, 0, 0);
356
357 FX_HatchStyle hatchStyle = m_info.fillColor->m_info.pattern->m_hatchStyle;
358 const FX_HATCHDATA& data = hatchBitmapData[static_cast<int>(hatchStyle)];
359
360 CFX_DIBitmap mask;
361 mask.Create(data.width, data.height, FXDIB_1bppMask);
362 FXSYS_memcpy(mask.GetBuffer(), data.maskBits, mask.GetPitch() * data.height);
363 CFX_FloatRect rectf = path->GetPathData()->GetBoundingBox();
364 if (matrix)
365 matrix->TransformRect(rectf);
366
367 FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top),
368 FXSYS_round(rectf.right), FXSYS_round(rectf.bottom));
369 CFX_FxgeDevice device;
370 device.Attach(&bmp, false, nullptr, false);
371 device.FillRect(&rect, m_info.fillColor->m_info.pattern->m_backArgb);
372 for (int32_t j = rect.bottom; j < rect.top; j += mask.GetHeight()) {
373 for (int32_t i = rect.left; i < rect.right; i += mask.GetWidth()) {
374 device.SetBitMask(&mask, i, j,
375 m_info.fillColor->m_info.pattern->m_foreArgb);
376 }
377 }
378
379 m_renderDevice->SaveState();
380 m_renderDevice->SetClip_PathFill(path->GetPathData(), matrix, fillMode);
381 SetDIBitsWithMatrix(&bmp, &pattern->m_matrix);
382 m_renderDevice->RestoreState(false);
383 }
384
FillPathWithShading(CFX_Path * path,FX_FillMode fillMode,CFX_Matrix * matrix)385 void CFX_Graphics::FillPathWithShading(CFX_Path* path,
386 FX_FillMode fillMode,
387 CFX_Matrix* matrix) {
388 CFX_DIBitmap* bitmap = m_renderDevice->GetBitmap();
389 int32_t width = bitmap->GetWidth();
390 int32_t height = bitmap->GetHeight();
391 FX_FLOAT start_x = m_info.fillColor->m_shading->m_beginPoint.x;
392 FX_FLOAT start_y = m_info.fillColor->m_shading->m_beginPoint.y;
393 FX_FLOAT end_x = m_info.fillColor->m_shading->m_endPoint.x;
394 FX_FLOAT end_y = m_info.fillColor->m_shading->m_endPoint.y;
395 CFX_DIBitmap bmp;
396 bmp.Create(width, height, FXDIB_Argb);
397 m_renderDevice->GetDIBits(&bmp, 0, 0);
398 int32_t pitch = bmp.GetPitch();
399 bool result = false;
400 switch (m_info.fillColor->m_shading->m_type) {
401 case FX_SHADING_Axial: {
402 FX_FLOAT x_span = end_x - start_x;
403 FX_FLOAT y_span = end_y - start_y;
404 FX_FLOAT axis_len_square = (x_span * x_span) + (y_span * y_span);
405 for (int32_t row = 0; row < height; row++) {
406 uint32_t* dib_buf = (uint32_t*)(bmp.GetBuffer() + row * pitch);
407 for (int32_t column = 0; column < width; column++) {
408 FX_FLOAT x = (FX_FLOAT)(column);
409 FX_FLOAT y = (FX_FLOAT)(row);
410 FX_FLOAT scale =
411 (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
412 axis_len_square;
413 if (scale < 0) {
414 if (!m_info.fillColor->m_shading->m_isExtendedBegin) {
415 continue;
416 }
417 scale = 0;
418 } else if (scale > 1.0f) {
419 if (!m_info.fillColor->m_shading->m_isExtendedEnd) {
420 continue;
421 }
422 scale = 1.0f;
423 }
424 int32_t index = (int32_t)(scale * (FX_SHADING_Steps - 1));
425 dib_buf[column] = m_info.fillColor->m_shading->m_argbArray[index];
426 }
427 }
428 result = true;
429 break;
430 }
431 case FX_SHADING_Radial: {
432 FX_FLOAT start_r = m_info.fillColor->m_shading->m_beginRadius;
433 FX_FLOAT end_r = m_info.fillColor->m_shading->m_endRadius;
434 FX_FLOAT a = ((start_x - end_x) * (start_x - end_x)) +
435 ((start_y - end_y) * (start_y - end_y)) -
436 ((start_r - end_r) * (start_r - end_r));
437 for (int32_t row = 0; row < height; row++) {
438 uint32_t* dib_buf = (uint32_t*)(bmp.GetBuffer() + row * pitch);
439 for (int32_t column = 0; column < width; column++) {
440 FX_FLOAT x = (FX_FLOAT)(column);
441 FX_FLOAT y = (FX_FLOAT)(row);
442 FX_FLOAT b = -2 * (((x - start_x) * (end_x - start_x)) +
443 ((y - start_y) * (end_y - start_y)) +
444 (start_r * (end_r - start_r)));
445 FX_FLOAT c = ((x - start_x) * (x - start_x)) +
446 ((y - start_y) * (y - start_y)) - (start_r * start_r);
447 FX_FLOAT s;
448 if (a == 0) {
449 s = -c / b;
450 } else {
451 FX_FLOAT b2_4ac = (b * b) - 4 * (a * c);
452 if (b2_4ac < 0) {
453 continue;
454 }
455 FX_FLOAT root = (FXSYS_sqrt(b2_4ac));
456 FX_FLOAT s1, s2;
457 if (a > 0) {
458 s1 = (-b - root) / (2 * a);
459 s2 = (-b + root) / (2 * a);
460 } else {
461 s2 = (-b - root) / (2 * a);
462 s1 = (-b + root) / (2 * a);
463 }
464 if (s2 <= 1.0f || m_info.fillColor->m_shading->m_isExtendedEnd) {
465 s = (s2);
466 } else {
467 s = (s1);
468 }
469 if ((start_r) + s * (end_r - start_r) < 0) {
470 continue;
471 }
472 }
473 if (s < 0) {
474 if (!m_info.fillColor->m_shading->m_isExtendedBegin) {
475 continue;
476 }
477 s = 0;
478 }
479 if (s > 1.0f) {
480 if (!m_info.fillColor->m_shading->m_isExtendedEnd) {
481 continue;
482 }
483 s = 1.0f;
484 }
485 int index = (int32_t)(s * (FX_SHADING_Steps - 1));
486 dib_buf[column] = m_info.fillColor->m_shading->m_argbArray[index];
487 }
488 }
489 result = true;
490 break;
491 }
492 default: {
493 result = false;
494 break;
495 }
496 }
497 if (result) {
498 m_renderDevice->SaveState();
499 m_renderDevice->SetClip_PathFill(path->GetPathData(), matrix, fillMode);
500 SetDIBitsWithMatrix(&bmp, matrix);
501 m_renderDevice->RestoreState(false);
502 }
503 }
504
SetDIBitsWithMatrix(CFX_DIBSource * source,CFX_Matrix * matrix)505 void CFX_Graphics::SetDIBitsWithMatrix(CFX_DIBSource* source,
506 CFX_Matrix* matrix) {
507 if (matrix->IsIdentity()) {
508 m_renderDevice->SetDIBits(source, 0, 0);
509 } else {
510 CFX_Matrix m((FX_FLOAT)source->GetWidth(), 0, 0,
511 (FX_FLOAT)source->GetHeight(), 0, 0);
512 m.Concat(*matrix);
513 int32_t left;
514 int32_t top;
515 std::unique_ptr<CFX_DIBitmap> bmp1 = source->FlipImage(false, true);
516 std::unique_ptr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(&m, left, top);
517 m_renderDevice->SetDIBits(bmp2.get(), left, top);
518 }
519 }
520
TInfo()521 CFX_Graphics::TInfo::TInfo()
522 : isActOnDash(false), strokeColor(nullptr), fillColor(nullptr) {}
523
TInfo(const TInfo & info)524 CFX_Graphics::TInfo::TInfo(const TInfo& info)
525 : graphState(info.graphState),
526 CTM(info.CTM),
527 isActOnDash(info.isActOnDash),
528 strokeColor(info.strokeColor),
529 fillColor(info.fillColor) {}
530
operator =(const TInfo & other)531 CFX_Graphics::TInfo& CFX_Graphics::TInfo::operator=(const TInfo& other) {
532 graphState.Copy(other.graphState);
533 CTM = other.CTM;
534 isActOnDash = other.isActOnDash;
535 strokeColor = other.strokeColor;
536 fillColor = other.fillColor;
537 return *this;
538 }
539