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 #include "core/include/fxge/fx_ge.h"
6 
7 #if defined(_SKIA_SUPPORT_)
8 #include "core/include/fxcodec/fx_codec.h"
9 
10 #include "SkDashPathEffect.h"
11 #include "SkTLazy.h"
12 #include "SkScan.h"
13 #include "SkRasterClip.h"
14 #include "SkStroke.h"
15 
16 #include "core/src/fxge/agg/include/fx_agg_driver.h"
17 #include "fx_skia_blitter_new.h"
18 #include "fx_skia_device.h"
19 
20 extern "C" {
21 extern void FX_OUTPUT_LOG_FUNC(const char*, ...);
22 extern int FX_GET_TICK_FUNC();
23 };
24 
25 #ifdef _FOXIT_DEBUG_
26 #define FOXIT_DEBUG1(msg) FX_OUTPUT_LOG_FUNC(msg)
27 #define FOXIT_DEBUG2(msg, para) FX_OUTPUT_LOG_FUNC(msg, para)
28 #define FOXIT_DEBUG3(msg, para1, para2) FX_OUTPUT_LOG_FUNC(msg, para1, para2)
29 #define FOXIT_DEBUG4(msg, para1, para2, para3) \
30   FX_OUTPUT_LOG_FUNC(msg, para1, para2, para3)
31 #define FOXIT_DEBUG5(msg, para1, para2, para3, param4) \
32   FX_OUTPUT_LOG_FUNC(msg, para1, para2, para3, param4)
33 #else
34 #define FOXIT_DEBUG1(msg)
35 #define FOXIT_DEBUG2(msg, para)
36 #define FOXIT_DEBUG3(msg, para1, para2)
37 #define FOXIT_DEBUG4(msg, para1, para2, para3)
38 #define FOXIT_DEBUG5(msg, para1, para2, para3, param4)
39 #endif
40 
41 /// Run-length-encoded supersampling antialiased blitter.
42 class SuperBlitter_skia {
43  public:
44   static void DrawPath(const SkPath& srcPath,
45                        SkBlitter* blitter,
46                        const SkRasterClip& rect,
47                        const SkPaint& origPaint);
48 };
FxSkDrawTreatAsHairline(const SkPaint & paint,SkScalar * coverage)49 FX_BOOL FxSkDrawTreatAsHairline(const SkPaint& paint, SkScalar* coverage) {
50   if (SkPaint::kStroke_Style != paint.getStyle())
51     return FALSE;
52   FXSYS_assert(coverage);
53   SkScalar strokeWidth = paint.getStrokeWidth();
54   if (0 == strokeWidth) {
55     *coverage = SK_Scalar1;
56     return TRUE;
57   }
58   // if we get here, we need to try to fake a thick-stroke with a modulated
59   // hairline
60   if (!paint.isAntiAlias())
61     return FALSE;
62   if (strokeWidth <= SK_Scalar1) {
63     *coverage = strokeWidth;
64     return TRUE;
65   }
66   return FALSE;
67 }
68 
DrawPath(const SkPath & srcPath,SkBlitter * blitter,const SkRasterClip & rect,const SkPaint & origPaint)69 void SuperBlitter_skia::DrawPath(const SkPath& srcPath,
70                                  SkBlitter* blitter,
71                                  const SkRasterClip& rect,
72                                  const SkPaint& origPaint) {
73   SkPath* pathPtr = (SkPath*)&srcPath;
74   bool doFill = true;
75   SkPath tmpPath;
76   SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
77   {
78     SkScalar coverage;
79     if (FxSkDrawTreatAsHairline(origPaint, &coverage)) {
80       if (SK_Scalar1 == coverage) {
81         paint.writable()->setStrokeWidth(0);
82       } else if (1) {  // xfermodeSupportsCoverageAsAlpha(xfer), we not use
83                        // blend mode here, xfer aways NULL.
84         U8CPU newAlpha;
85         // this is the old technique, which we preserve for now so
86         // we don't change previous results (testing)
87         // the new way seems fine, its just (a tiny bit) different
88         int scale = (int)SkScalarMul(coverage, 256);
89         newAlpha = origPaint.getAlpha() * scale >> 8;
90         SkPaint* writablePaint = paint.writable();
91         writablePaint->setStrokeWidth(0);
92         writablePaint->setAlpha(newAlpha);
93       }
94     }
95   }
96   if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
97     SkIRect devBounds = rect.getBounds();
98     // outset to have slop for antialasing and hairlines
99     devBounds.outset(1, 1);
100     SkRect cullRect = SkRect::Make(devBounds);
101     doFill = paint->getFillPath(*pathPtr, &tmpPath, &cullRect);
102     pathPtr = &tmpPath;
103   }
104   // avoid possibly allocating a new path in transform if we can
105   SkPath* devPathPtr = pathPtr;
106   void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
107   if (doFill) {
108     if (paint->isAntiAlias()) {
109       proc = SkScan::AntiFillPath;
110     } else {
111       proc = SkScan::FillPath;
112     }
113   } else {  // hairline
114     if (paint->isAntiAlias()) {
115       proc = SkScan::AntiHairPath;
116     } else {
117       proc = SkScan::HairPath;
118     }
119   }
120   proc(*devPathPtr, rect, blitter);
121 }
122 
123 class CSkia_PathData {
124  public:
CSkia_PathData()125   CSkia_PathData() {}
~CSkia_PathData()126   ~CSkia_PathData() {}
127   SkPath m_PathData;
128 
129   void BuildPath(const CFX_PathData* pPathData,
130                  const CFX_Matrix* pObject2Device);
131 };
132 
BuildPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device)133 void CSkia_PathData::BuildPath(const CFX_PathData* pPathData,
134                                const CFX_Matrix* pObject2Device) {
135   const CFX_PathData* pFPath = pPathData;
136   int nPoints = pFPath->GetPointCount();
137   FX_PATHPOINT* pPoints = pFPath->GetPoints();
138   for (int i = 0; i < nPoints; i++) {
139     FX_FIXFLOAT x = pPoints[i].m_PointX, y = pPoints[i].m_PointY;
140     if (pObject2Device)
141       pObject2Device->Transform(x, y);
142     int point_type = pPoints[i].m_Flag & FXPT_TYPE;
143     if (point_type == FXPT_MOVETO) {
144       m_PathData.moveTo(x, y);
145     } else if (point_type == FXPT_LINETO) {
146       if (pPoints[i - 1].m_Flag == FXPT_MOVETO &&
147           (i == nPoints - 1 || pPoints[i + 1].m_Flag == FXPT_MOVETO) &&
148           FXSYS_abs(pPoints[i].m_PointX - pPoints[i - 1].m_PointX) < 0.4f &&
149           FXSYS_abs(pPoints[i].m_PointY - pPoints[i - 1].m_PointY) < 0.4f)
150         // PDF line includes the destination point, unlike Windows line.
151         // We received some PDF which actually draws zero length lines. TESTDOC:
152         // summer cha show.pdf
153         // Therefore, we have to extend the line by 0.4 pixel here.
154         // But only for standalone segment. TESTDOC: bug #1434 - maze.pdf;
155         // TESTDOC: bug#1508 di704P_QIG_111.pdf
156         x += 0.4;
157       // TODO: we should actually tell skia vertex generator to process zero
158       // length stroked line
159       // (only butts are drawn)
160       m_PathData.lineTo(x, y);
161     } else if (point_type == FXPT_BEZIERTO) {
162       FX_FIXFLOAT x2 = pPoints[i + 1].m_PointX, y2 = pPoints[i + 1].m_PointY;
163       FX_FIXFLOAT x3 = pPoints[i + 2].m_PointX, y3 = pPoints[i + 2].m_PointY;
164       if (pObject2Device) {
165         pObject2Device->Transform(x2, y2);
166         pObject2Device->Transform(x3, y3);
167       }
168       m_PathData.cubicTo(x, y, x2, y2, x3, y3);
169       i += 2;
170     }
171     if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
172       m_PathData.close();
173   }
174 }
175 
176 // convert a stroking path to scanlines
SkRasterizeStroke(SkPaint & spaint,SkPath * dstPathData,SkPath & path_data,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,FX_FIXFLOAT scale=FIX8_ONE,FX_BOOL bStrokeAdjust=FALSE,FX_BOOL bTextMode=FALSE)177 static void SkRasterizeStroke(SkPaint& spaint,
178                               SkPath* dstPathData,
179                               SkPath& path_data,
180                               const CFX_Matrix* pObject2Device,
181                               const CFX_GraphStateData* pGraphState,
182                               FX_FIXFLOAT scale = FIX8_ONE,
183                               FX_BOOL bStrokeAdjust = FALSE,
184                               FX_BOOL bTextMode = FALSE) {
185   SkPaint::Cap cap;
186   switch (pGraphState->m_LineCap) {
187     case CFX_GraphStateData::LineCapRound:
188       cap = SkPaint::kRound_Cap;
189       break;
190     case CFX_GraphStateData::LineCapSquare:
191       cap = SkPaint::kSquare_Cap;
192       break;
193     default:
194       cap = SkPaint::kButt_Cap;
195       break;
196   }
197   SkPaint::Join join;
198   switch (pGraphState->m_LineJoin) {
199     case CFX_GraphStateData::LineJoinRound:
200       join = SkPaint::kRound_Join;
201       break;
202     case CFX_GraphStateData::LineJoinBevel:
203       join = SkPaint::kBevel_Join;
204       break;
205     default:
206       join = SkPaint::kMiter_Join;
207       break;
208   }
209   FX_FIXFLOAT width = pGraphState->m_LineWidth * scale;
210   FX_FIXFLOAT unit = fix32_to_8(fixdiv_8_8_to_32(
211       FIX8_ONE, (pObject2Device->GetXUnit() + pObject2Device->GetYUnit()) / 2));
212   if (width <= unit)
213     width = unit;
214 
215   if (pGraphState->m_DashArray) {
216     int count = (pGraphState->m_DashCount + 1) / 2;
217     SkScalar* intervals = FX_Alloc2D(SkScalar, count, sizeof(SkScalar));
218     // Set dash pattern
219     for (int i = 0; i < count; i++) {
220       FX_FIXFLOAT on = pGraphState->m_DashArray[i * 2];
221       if (on <= 0.000001f)
222         on = FIX8_ONE / 10;
223       FX_FIXFLOAT off = i * 2 + 1 == pGraphState->m_DashCount
224                             ? on
225                             : pGraphState->m_DashArray[i * 2 + 1];
226       if (off < 0)
227         off = 0;
228       intervals[i * 2] = on * scale;
229       intervals[i * 2 + 1] = off * scale;
230     }
231     SkDashPathEffect* pEffect = new SkDashPathEffect(
232         intervals, count * 2, pGraphState->m_DashPhase * scale);
233     spaint.setPathEffect(pEffect)->unref();
234     spaint.setStrokeWidth(width);
235     spaint.setStrokeMiter(pGraphState->m_MiterLimit);
236     spaint.setStrokeCap(cap);
237     spaint.setStrokeJoin(join);
238     spaint.getFillPath(path_data, dstPathData);
239     SkMatrix smatrix;
240     smatrix.setAll(pObject2Device->a, pObject2Device->c, pObject2Device->e,
241                    pObject2Device->b, pObject2Device->d, pObject2Device->f, 0,
242                    0, 1);
243     dstPathData->transform(smatrix);
244     FX_Free(intervals);
245   } else {
246     SkStroke stroker;
247     stroker.setCap(cap);
248     stroker.setJoin(join);
249     stroker.setMiterLimit(pGraphState->m_MiterLimit);
250     stroker.setWidth(width);
251     stroker.setDoFill(FALSE);
252     stroker.strokePath(path_data, dstPathData);
253     SkMatrix smatrix;
254     smatrix.setAll(pObject2Device->a, pObject2Device->c, pObject2Device->e,
255                    pObject2Device->b, pObject2Device->d, pObject2Device->f, 0,
256                    0, 1);
257     dstPathData->transform(smatrix);
258   }
259 }
260 
CFX_SkiaDeviceDriver(CFX_DIBitmap * pBitmap,int dither_bits,FX_BOOL bRgbByteOrder,CFX_DIBitmap * pOriDevice,FX_BOOL bGroupKnockout)261 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap,
262                                            int dither_bits,
263                                            FX_BOOL bRgbByteOrder,
264                                            CFX_DIBitmap* pOriDevice,
265                                            FX_BOOL bGroupKnockout) {
266   m_pAggDriver = new CFX_AggDeviceDriver(pBitmap, dither_bits, bRgbByteOrder,
267                                          pOriDevice, bGroupKnockout);
268 }
~CFX_SkiaDeviceDriver()269 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
270   delete m_pAggDriver;
271 }
DrawDeviceText(int nChars,const FXTEXT_CHARPOS * pCharPos,CFX_Font * pFont,CFX_FontCache * pCache,const CFX_Matrix * pObject2Device,FX_FIXFLOAT font_size,FX_DWORD color,int alpha_flag,void * pIccTransform)272 FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars,
273                                              const FXTEXT_CHARPOS* pCharPos,
274                                              CFX_Font* pFont,
275                                              CFX_FontCache* pCache,
276                                              const CFX_Matrix* pObject2Device,
277                                              FX_FIXFLOAT font_size,
278                                              FX_DWORD color,
279                                              int alpha_flag,
280                                              void* pIccTransform) {
281   return m_pAggDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache,
282                                       pObject2Device, font_size, color,
283                                       alpha_flag, pIccTransform);
284 }
GetDeviceCaps(int caps_id)285 int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) {
286   return m_pAggDriver->GetDeviceCaps(caps_id);
287 }
SaveState()288 void CFX_SkiaDeviceDriver::SaveState() {
289   m_pAggDriver->SaveState();
290 }
291 
RestoreState(FX_BOOL bKeepSaved)292 void CFX_SkiaDeviceDriver::RestoreState(FX_BOOL bKeepSaved) {
293   m_pAggDriver->RestoreState(bKeepSaved);
294 }
SetClipMask(rasterizer_scanline_aa & rasterizer)295 void CFX_SkiaDeviceDriver::SetClipMask(rasterizer_scanline_aa& rasterizer) {
296   m_pAggDriver->SetClipMask(rasterizer);
297 }
SetClipMask(SkPath & skPath,SkPaint * spaint)298 void CFX_SkiaDeviceDriver::SetClipMask(SkPath& skPath, SkPaint* spaint) {
299   SkIRect clip_box;
300   clip_box.set(0, 0, fix0_to_8(GetDeviceCaps(FXDC_PIXEL_WIDTH)),
301                fix0_to_8(GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
302   clip_box.intersect(m_pAggDriver->m_pClipRgn->GetBox().left,
303                      m_pAggDriver->m_pClipRgn->GetBox().top,
304                      m_pAggDriver->m_pClipRgn->GetBox().right,
305                      m_pAggDriver->m_pClipRgn->GetBox().bottom);
306 
307   SkPath* pathPtr = &skPath;
308 
309   SkRect path_rect = skPath.getBounds();
310 
311   clip_box.intersect(FXSYS_floor(path_rect.fLeft), FXSYS_floor(path_rect.fTop),
312                      FXSYS_floor(path_rect.fRight) + 1,
313                      FXSYS_floor(path_rect.fBottom) + 1);
314   CFX_DIBitmapRef mask;
315   CFX_DIBitmap* pThisLayer = mask.New();
316   pThisLayer->Create(clip_box.width(), clip_box.height(), FXDIB_8bppMask);
317   pThisLayer->Clear(0);
318 
319   CFX_SkiaA8Renderer render;
320   render.Init(pThisLayer, clip_box.fLeft, clip_box.fTop);
321 
322   SkRasterClip rasterClip(clip_box);
323   SuperBlitter_skia::DrawPath(skPath, (SkBlitter*)&render, rasterClip, *spaint);
324 
325   // Finally, we have got the mask that we need, intersect with current clip
326   // region
327   m_pAggDriver->m_pClipRgn->IntersectMaskF(clip_box.fLeft, clip_box.fTop, mask);
328 }
SetClip_PathFill(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,int fill_mode)329 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill(
330     const CFX_PathData* pPathData,     // path info
331     const CFX_Matrix* pObject2Device,  // optional transformation
332     int fill_mode                      // fill mode, WINDING or ALTERNATE
333     ) {
334   if (!m_pAggDriver->m_pClipRgn) {
335     m_pAggDriver->m_pClipRgn = new CFX_ClipRgn(
336         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
337   }
338 
339   if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) {
340     CFX_FloatRect rectf;
341     if (pPathData->IsRect(pObject2Device, &rectf)) {
342       rectf.Intersect(
343           CFX_FloatRect(0, 0, (FX_FIXFLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH),
344                         (FX_FIXFLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
345       FX_RECT rect = rectf.GetOutterRect();
346       m_pAggDriver->m_pClipRgn->IntersectRect(rect);
347       return TRUE;
348     }
349   }
350   CSkia_PathData path_data;
351   path_data.BuildPath(pPathData, pObject2Device);
352   path_data.m_PathData.close();
353   path_data.m_PathData.setFillType((fill_mode & 3) == FXFILL_WINDING
354                                        ? SkPath::kWinding_FillType
355                                        : SkPath::kEvenOdd_FillType);
356 
357   SkPaint spaint;
358   spaint.setColor(0xffffffff);
359   spaint.setAntiAlias(TRUE);
360   spaint.setStyle(SkPaint::kFill_Style);
361 
362   SetClipMask(path_data.m_PathData, &spaint);
363 
364   return TRUE;
365 }
366 
SetClip_PathStroke(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState)367 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke(
368     const CFX_PathData* pPathData,         // path info
369     const CFX_Matrix* pObject2Device,      // optional transformation
370     const CFX_GraphStateData* pGraphState  // graphic state, for pen attributes
371     ) {
372   if (!m_pAggDriver->m_pClipRgn) {
373     m_pAggDriver->m_pClipRgn = new CFX_ClipRgn(
374         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
375   }
376 
377   // build path data
378   CSkia_PathData path_data;
379   path_data.BuildPath(pPathData, NULL);
380   path_data.m_PathData.setFillType(SkPath::kWinding_FillType);
381 
382   SkPaint spaint;
383   spaint.setColor(0xffffffff);
384   spaint.setStyle(SkPaint::kStroke_Style);
385   spaint.setAntiAlias(TRUE);
386 
387   SkPath dst_path;
388   SkRasterizeStroke(spaint, &dst_path, path_data.m_PathData, pObject2Device,
389                     pGraphState, 1, FALSE, 0);
390   spaint.setStyle(SkPaint::kFill_Style);
391   SetClipMask(dst_path, &spaint);
392 
393   return TRUE;
394 }
RenderRasterizer(rasterizer_scanline_aa & rasterizer,FX_DWORD color,FX_BOOL bFullCover,FX_BOOL bGroupKnockout,int alpha_flag,void * pIccTransform)395 FX_BOOL CFX_SkiaDeviceDriver::RenderRasterizer(
396     rasterizer_scanline_aa& rasterizer,
397     FX_DWORD color,
398     FX_BOOL bFullCover,
399     FX_BOOL bGroupKnockout,
400     int alpha_flag,
401     void* pIccTransform) {
402   return m_pAggDriver->RenderRasterizer(
403       rasterizer, color, bFullCover, bGroupKnockout, alpha_flag, pIccTransform);
404 }
RenderRasterizerSkia(SkPath & skPath,const SkPaint & origPaint,SkIRect & rect,FX_DWORD color,FX_BOOL bFullCover,FX_BOOL bGroupKnockout,int alpha_flag,void * pIccTransform,FX_BOOL bFill)405 FX_BOOL CFX_SkiaDeviceDriver::RenderRasterizerSkia(SkPath& skPath,
406                                                    const SkPaint& origPaint,
407                                                    SkIRect& rect,
408                                                    FX_DWORD color,
409                                                    FX_BOOL bFullCover,
410                                                    FX_BOOL bGroupKnockout,
411                                                    int alpha_flag,
412                                                    void* pIccTransform,
413                                                    FX_BOOL bFill) {
414   CFX_DIBitmap* pt = bGroupKnockout ? m_pAggDriver->GetBackDrop() : NULL;
415   CFX_SkiaRenderer render;
416   if (!render.Init(m_pAggDriver->m_pBitmap, pt, m_pAggDriver->m_pClipRgn, color,
417                    bFullCover, m_pAggDriver->m_bRgbByteOrder, alpha_flag,
418                    pIccTransform))
419     return FALSE;
420 
421   SkRasterClip rasterClip(rect);
422   SuperBlitter_skia::DrawPath(skPath, (SkBlitter*)&render, rasterClip,
423                               origPaint);
424 
425   return TRUE;
426 }
427 
DrawPath(const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,FX_DWORD fill_color,FX_DWORD stroke_color,int fill_mode,int alpha_flag,void * pIccTransform)428 FX_BOOL CFX_SkiaDeviceDriver::DrawPath(
429     const CFX_PathData* pPathData,          // path info
430     const CFX_Matrix* pObject2Device,       // optional transformation
431     const CFX_GraphStateData* pGraphState,  // graphic state, for pen attributes
432     FX_DWORD fill_color,                    // fill color
433     FX_DWORD stroke_color,                  // stroke color
434     int fill_mode,  // fill mode, WINDING or ALTERNATE. 0 for not filled
435     int alpha_flag,
436     void* pIccTransform) {
437   if (!GetBuffer())
438     return TRUE;
439   FOXIT_DEBUG1("CFX_SkiaDeviceDriver::DrawPath: entering");
440   SkIRect rect;
441   rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
442            GetDeviceCaps(FXDC_PIXEL_HEIGHT));
443   if ((fill_mode & 3) && fill_color) {
444     // We have to transform before building path data, otherwise we'll have
445     // flatting problem
446     // when we enlarge a small path (flatten before transformed)
447     // TESTDOC: Bug #5115 - DS_S1Dimpact_lr.pdf
448     // build path data
449     CSkia_PathData path_data;
450     path_data.BuildPath(pPathData, pObject2Device);
451     // path_data.m_PathData.close();
452     path_data.m_PathData.setFillType((fill_mode & 3) == FXFILL_WINDING
453                                          ? SkPath::kWinding_FillType
454                                          : SkPath::kEvenOdd_FillType);
455 
456     SkPaint spaint;
457     spaint.setAntiAlias(TRUE);
458     spaint.setStyle(SkPaint::kFill_Style);
459     spaint.setColor(fill_color);
460     if (!RenderRasterizerSkia(path_data.m_PathData, spaint, rect, fill_color,
461                               fill_mode & FXFILL_FULLCOVER, FALSE, alpha_flag,
462                               pIccTransform))
463       return FALSE;
464   }
465 
466   int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag)
467                          ? FXGETFLAG_ALPHA_STROKE(alpha_flag)
468                          : FXARGB_A(stroke_color);
469 
470   if (pGraphState && stroke_alpha) {
471     // We split the matrix into two parts: first part doing the scaling, so we
472     // won't have the
473     // flatness problem, second part doing the transformation, so we don't have
474     // stroking geo problem.
475     // TESTDOC: Bug #5253 - test[1].pdf
476     CFX_Matrix matrix1, matrix2;
477     if (pObject2Device) {
478       matrix1.a = FXSYS_fabs(pObject2Device->a) > FXSYS_fabs(pObject2Device->b)
479                       ? FXSYS_fabs(pObject2Device->a)
480                       : FXSYS_fabs(pObject2Device->b);
481       matrix1.d = matrix1.a;  // FXSYS_fabs(pObject2Device->c) >
482                               // FXSYS_fabs(pObject2Device->d) ?
483       // pObject2Device->c : pObject2Device->d;
484       matrix2.Set(pObject2Device->a / matrix1.a, pObject2Device->b / matrix1.a,
485                   pObject2Device->c / matrix1.d, pObject2Device->d / matrix1.d,
486                   pObject2Device->e, pObject2Device->f);
487     }
488     // build path data
489     CSkia_PathData path_data;
490     path_data.BuildPath(pPathData, &matrix1);
491     path_data.m_PathData.setFillType(SkPath::kWinding_FillType);
492 
493     SkPaint spaint;
494     spaint.setColor(stroke_color);
495     spaint.setStyle(SkPaint::kStroke_Style);
496     spaint.setAntiAlias(TRUE);
497     SkPath dst_path;
498     SkRasterizeStroke(spaint, &dst_path, path_data.m_PathData, &matrix2,
499                       pGraphState, matrix1.a, FALSE, 0);
500     spaint.setStyle(SkPaint::kFill_Style);
501     int fill_flag = FXGETFLAG_COLORTYPE(alpha_flag) << 8 |
502                     FXGETFLAG_ALPHA_STROKE(alpha_flag);
503 
504     if (!RenderRasterizerSkia(dst_path, spaint, rect, stroke_color,
505                               fill_mode & FXFILL_FULLCOVER, FALSE, fill_flag,
506                               pIccTransform, FALSE))
507       return FALSE;
508   }
509 
510   return TRUE;
511 }
512 
SetPixel(int x,int y,FX_DWORD color,int alpha_flag,void * pIccTransform)513 FX_BOOL CFX_SkiaDeviceDriver::SetPixel(int x,
514                                        int y,
515                                        FX_DWORD color,
516                                        int alpha_flag,
517                                        void* pIccTransform) {
518   return m_pAggDriver->SetPixel(x, y, color, alpha_flag, pIccTransform);
519 }
520 
FillRect(const FX_RECT * pRect,FX_DWORD fill_color,int alpha_flag,void * pIccTransform)521 FX_BOOL CFX_SkiaDeviceDriver::FillRect(const FX_RECT* pRect,
522                                        FX_DWORD fill_color,
523                                        int alpha_flag,
524                                        void* pIccTransform) {
525   return m_pAggDriver->FillRect(pRect, fill_color, alpha_flag, pIccTransform);
526 }
527 
GetClipBox(FX_RECT * pRect)528 FX_BOOL CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) {
529   return m_pAggDriver->GetClipBox(pRect);
530 }
531 
GetDIBits(CFX_DIBitmap * pBitmap,int left,int top,void * pIccTransform,FX_BOOL bDEdge)532 FX_BOOL CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap,
533                                         int left,
534                                         int top,
535                                         void* pIccTransform,
536                                         FX_BOOL bDEdge) {
537   return m_pAggDriver->GetDIBits(pBitmap, left, top, pIccTransform, bDEdge);
538 }
539 
SetDIBits(const CFX_DIBSource * pBitmap,FX_DWORD argb,const FX_RECT * pSrcRect,int left,int top,int blend_type,int alpha_flag,void * pIccTransform)540 FX_BOOL CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap,
541                                         FX_DWORD argb,
542                                         const FX_RECT* pSrcRect,
543                                         int left,
544                                         int top,
545                                         int blend_type,
546                                         int alpha_flag,
547                                         void* pIccTransform) {
548   return m_pAggDriver->SetDIBits(pBitmap, argb, pSrcRect, left, top, blend_type,
549                                  alpha_flag, pIccTransform);
550 }
551 
StretchDIBits(const CFX_DIBSource * pSource,FX_DWORD argb,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,FX_DWORD flags,int alpha_flag,void * pIccTransform)552 FX_BOOL CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource,
553                                             FX_DWORD argb,
554                                             int dest_left,
555                                             int dest_top,
556                                             int dest_width,
557                                             int dest_height,
558                                             const FX_RECT* pClipRect,
559                                             FX_DWORD flags,
560                                             int alpha_flag,
561                                             void* pIccTransform) {
562   return m_pAggDriver->StretchDIBits(pSource, argb, dest_left, dest_top,
563                                      dest_width, dest_height, pClipRect, flags,
564                                      alpha_flag, pIccTransform);
565 }
566 
StartDIBits(const CFX_DIBSource * pSource,int bitmap_alpha,FX_DWORD argb,const CFX_Matrix * pMatrix,FX_DWORD render_flags,void * & handle,int alpha_flag,void * pIccTransform)567 FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
568                                           int bitmap_alpha,
569                                           FX_DWORD argb,
570                                           const CFX_Matrix* pMatrix,
571                                           FX_DWORD render_flags,
572                                           void*& handle,
573                                           int alpha_flag,
574                                           void* pIccTransform) {
575   return m_pAggDriver->StartDIBits(pSource, bitmap_alpha, argb, pMatrix,
576                                    render_flags, handle, alpha_flag,
577                                    pIccTransform);
578 }
579 
ContinueDIBits(void * pHandle,IFX_Pause * pPause)580 FX_BOOL CFX_SkiaDeviceDriver::ContinueDIBits(void* pHandle, IFX_Pause* pPause) {
581   return m_pAggDriver->ContinueDIBits(pHandle, pPause);
582 }
583 
CancelDIBits(void * pHandle)584 void CFX_SkiaDeviceDriver::CancelDIBits(void* pHandle) {
585   m_pAggDriver->CancelDIBits(pHandle);
586 }
587 
CFX_SkiaDevice()588 CFX_SkiaDevice::CFX_SkiaDevice() {
589   m_bOwnedBitmap = FALSE;
590 }
591 
Attach(CFX_DIBitmap * pBitmap,int dither_bits,FX_BOOL bRgbByteOrder,CFX_DIBitmap * pOriDevice,FX_BOOL bGroupKnockout)592 FX_BOOL CFX_SkiaDevice::Attach(CFX_DIBitmap* pBitmap,
593                                int dither_bits,
594                                FX_BOOL bRgbByteOrder,
595                                CFX_DIBitmap* pOriDevice,
596                                FX_BOOL bGroupKnockout) {
597   if (!pBitmap)
598     return FALSE;
599   SetBitmap(pBitmap);
600   CFX_SkiaDeviceDriver* pDriver = new CFX_SkiaDeviceDriver(
601       pBitmap, dither_bits, bRgbByteOrder, pOriDevice, bGroupKnockout);
602   SetDeviceDriver(pDriver);
603   return TRUE;
604 }
605 
Create(int width,int height,FXDIB_Format format,int dither_bits,CFX_DIBitmap * pOriDevice)606 FX_BOOL CFX_SkiaDevice::Create(int width,
607                                int height,
608                                FXDIB_Format format,
609                                int dither_bits,
610                                CFX_DIBitmap* pOriDevice) {
611   m_bOwnedBitmap = TRUE;
612   CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
613   if (!pBitmap->Create(width, height, format)) {
614     delete pBitmap;
615     return FALSE;
616   }
617   SetBitmap(pBitmap);
618   CFX_SkiaDeviceDriver* pDriver =
619       new CFX_SkiaDeviceDriver(pBitmap, dither_bits, FALSE, pOriDevice, FALSE);
620   SetDeviceDriver(pDriver);
621   return TRUE;
622 }
~CFX_SkiaDevice()623 CFX_SkiaDevice::~CFX_SkiaDevice() {
624   if (m_bOwnedBitmap && GetBitmap())
625     delete GetBitmap();
626 }
627 
628 #endif
629