• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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