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 <algorithm>
8 
9 #include "xfa/src/foxitlib.h"
10 #include "fde_gedevice.h"
11 #include "fde_geobject.h"
12 #include "fde_devbasic.h"
13 #ifndef _FDEPLUS
14 #ifdef _cplusplus
15 exten "C" {
16 #endif
FDE_GetStockHatchMask(int32_t iHatchStyle,CFX_DIBitmap & hatchMask)17   FX_BOOL FDE_GetStockHatchMask(int32_t iHatchStyle, CFX_DIBitmap & hatchMask) {
18     FDE_LPCHATCHDATA pData = FDE_DEVGetHatchData(iHatchStyle);
19     if (!pData) {
20       return FALSE;
21     }
22     hatchMask.Create(pData->iWidth, pData->iHeight, FXDIB_1bppMask);
23     FXSYS_memcpy(hatchMask.GetBuffer(), pData->MaskBits,
24                  hatchMask.GetPitch() * pData->iHeight);
25     return TRUE;
26   }
27 #ifdef _cplusplus
28 }
29 #endif
Create(CFX_DIBitmap * pBitmap,FX_BOOL bRgbByteOrder)30 IFDE_RenderDevice* IFDE_RenderDevice::Create(CFX_DIBitmap* pBitmap,
31                                              FX_BOOL bRgbByteOrder) {
32   if (pBitmap == NULL) {
33     return NULL;
34   }
35   CFX_FxgeDevice* pDevice = new CFX_FxgeDevice;
36   pDevice->Attach(pBitmap, 0, bRgbByteOrder);
37   return new CFDE_FxgeDevice(pDevice, TRUE);
38 }
Create(CFX_RenderDevice * pDevice)39 IFDE_RenderDevice* IFDE_RenderDevice::Create(CFX_RenderDevice* pDevice) {
40   return pDevice ? new CFDE_FxgeDevice(pDevice, FALSE) : nullptr;
41 }
CFDE_FxgeDevice(CFX_RenderDevice * pDevice,FX_BOOL bOwnerDevice)42 CFDE_FxgeDevice::CFDE_FxgeDevice(CFX_RenderDevice* pDevice,
43                                  FX_BOOL bOwnerDevice)
44     : m_pDevice(pDevice),
45       m_bOwnerDevice(bOwnerDevice),
46       m_pCharPos(NULL),
47       m_iCharCount(0) {
48   FXSYS_assert(pDevice != NULL);
49   FX_RECT rt = m_pDevice->GetClipBox();
50   m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
51                (FX_FLOAT)rt.Height());
52 }
~CFDE_FxgeDevice()53 CFDE_FxgeDevice::~CFDE_FxgeDevice() {
54   FX_Free(m_pCharPos);
55   if (m_bOwnerDevice)
56     delete m_pDevice;
57 }
GetWidth() const58 int32_t CFDE_FxgeDevice::GetWidth() const {
59   return m_pDevice->GetWidth();
60 }
GetHeight() const61 int32_t CFDE_FxgeDevice::GetHeight() const {
62   return m_pDevice->GetHeight();
63 }
SaveState()64 FDE_HDEVICESTATE CFDE_FxgeDevice::SaveState() {
65   m_pDevice->SaveState();
66   return NULL;
67 }
RestoreState(FDE_HDEVICESTATE hState)68 void CFDE_FxgeDevice::RestoreState(FDE_HDEVICESTATE hState) {
69   m_pDevice->RestoreState();
70   const FX_RECT& rt = m_pDevice->GetClipBox();
71   m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(),
72                (FX_FLOAT)rt.Height());
73 }
SetClipRect(const CFX_RectF & rtClip)74 FX_BOOL CFDE_FxgeDevice::SetClipRect(const CFX_RectF& rtClip) {
75   m_rtClip = rtClip;
76   FX_RECT rt((int32_t)FXSYS_floor(rtClip.left),
77              (int32_t)FXSYS_floor(rtClip.top),
78              (int32_t)FXSYS_ceil(rtClip.right()),
79              (int32_t)FXSYS_ceil(rtClip.bottom()));
80   return m_pDevice->SetClip_Rect(&rt);
81 }
GetClipRect()82 const CFX_RectF& CFDE_FxgeDevice::GetClipRect() {
83   return m_rtClip;
84 }
SetClipPath(const IFDE_Path * pClip)85 FX_BOOL CFDE_FxgeDevice::SetClipPath(const IFDE_Path* pClip) {
86   return FALSE;
87 }
GetClipPath() const88 IFDE_Path* CFDE_FxgeDevice::GetClipPath() const {
89   return NULL;
90 }
GetDpiX() const91 FX_FLOAT CFDE_FxgeDevice::GetDpiX() const {
92   return 96;
93 }
GetDpiY() const94 FX_FLOAT CFDE_FxgeDevice::GetDpiY() const {
95   return 96;
96 }
DrawImage(CFX_DIBSource * pDib,const CFX_RectF * pSrcRect,const CFX_RectF & dstRect,const CFX_Matrix * pImgMatrix,const CFX_Matrix * pDevMatrix)97 FX_BOOL CFDE_FxgeDevice::DrawImage(CFX_DIBSource* pDib,
98                                    const CFX_RectF* pSrcRect,
99                                    const CFX_RectF& dstRect,
100                                    const CFX_Matrix* pImgMatrix,
101                                    const CFX_Matrix* pDevMatrix) {
102   FXSYS_assert(pDib != NULL);
103   CFX_RectF srcRect;
104   if (pSrcRect) {
105     srcRect = *pSrcRect;
106   } else {
107     srcRect.Set(0, 0, (FX_FLOAT)pDib->GetWidth(), (FX_FLOAT)pDib->GetHeight());
108   }
109   if (srcRect.IsEmpty()) {
110     return FALSE;
111   }
112   CFX_Matrix dib2fxdev;
113   if (pImgMatrix) {
114     dib2fxdev = *pImgMatrix;
115   } else {
116     dib2fxdev.SetIdentity();
117   }
118   dib2fxdev.a = dstRect.width;
119   dib2fxdev.d = -dstRect.height;
120   dib2fxdev.e = dstRect.left;
121   dib2fxdev.f = dstRect.bottom();
122   if (pDevMatrix) {
123     dib2fxdev.Concat(*pDevMatrix);
124   }
125   void* handle = NULL;
126   m_pDevice->StartDIBits(pDib, 255, 0, (const CFX_Matrix*)&dib2fxdev, 0,
127                          handle);
128   while (m_pDevice->ContinueDIBits(handle, NULL)) {
129   }
130   m_pDevice->CancelDIBits(handle);
131   return handle != NULL;
132 }
DrawString(IFDE_Brush * pBrush,IFX_Font * pFont,const FXTEXT_CHARPOS * pCharPos,int32_t iCount,FX_FLOAT fFontSize,const CFX_Matrix * pMatrix)133 FX_BOOL CFDE_FxgeDevice::DrawString(IFDE_Brush* pBrush,
134                                     IFX_Font* pFont,
135                                     const FXTEXT_CHARPOS* pCharPos,
136                                     int32_t iCount,
137                                     FX_FLOAT fFontSize,
138                                     const CFX_Matrix* pMatrix) {
139   FXSYS_assert(pBrush != NULL && pFont != NULL && pCharPos != NULL &&
140                iCount > 0);
141   CFX_FontCache* pCache = CFX_GEModule::Get()->GetFontCache();
142   CFX_Font* pFxFont = (CFX_Font*)pFont->GetDevFont();
143   switch (pBrush->GetType()) {
144     case FDE_BRUSHTYPE_Solid: {
145       FX_ARGB argb = ((IFDE_SolidBrush*)pBrush)->GetColor();
146       if ((pFont->GetFontStyles() & FX_FONTSTYLE_Italic) != 0 &&
147           !pFxFont->IsItalic()) {
148         FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos;
149         FX_FLOAT* pAM;
150         for (int32_t i = 0; i < iCount; ++i) {
151           static const FX_FLOAT mc = 0.267949f;
152           pAM = pCP->m_AdjustMatrix;
153           pAM[2] = mc * pAM[0] + pAM[2];
154           pAM[3] = mc * pAM[1] + pAM[3];
155           pCP++;
156         }
157       }
158       FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos;
159       IFX_Font* pCurFont = NULL;
160       IFX_Font* pSTFont = NULL;
161       FXTEXT_CHARPOS* pCurCP = NULL;
162       int32_t iCurCount = 0;
163 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
164       FX_DWORD dwFontStyle = pFont->GetFontStyles();
165       CFX_Font FxFont;
166       CFX_SubstFont SubstFxFont;
167       FxFont.SetSubstFont(&SubstFxFont);
168       SubstFxFont.m_Weight = dwFontStyle & FX_FONTSTYLE_Bold ? 700 : 400;
169       SubstFxFont.m_WeightCJK = SubstFxFont.m_Weight;
170       SubstFxFont.m_ItalicAngle = dwFontStyle & FX_FONTSTYLE_Italic ? -12 : 0;
171       SubstFxFont.m_bItlicCJK = !!(dwFontStyle & FX_FONTSTYLE_Italic);
172 #endif
173       for (int32_t i = 0; i < iCount; ++i) {
174         pSTFont = pFont->GetSubstFont((int32_t)pCP->m_GlyphIndex);
175         pCP->m_GlyphIndex &= 0x00FFFFFF;
176         pCP->m_bFontStyle = FALSE;
177         if (pCurFont != pSTFont) {
178           if (pCurFont != NULL) {
179             pFxFont = (CFX_Font*)pCurFont->GetDevFont();
180 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
181             FxFont.SetFace(pFxFont->GetFace());
182             m_pDevice->DrawNormalText(iCurCount, pCurCP, &FxFont, pCache,
183                                       -fFontSize, (const CFX_Matrix*)pMatrix,
184                                       argb, FXTEXT_CLEARTYPE);
185 #else
186             m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, pCache,
187                                       -fFontSize, (const CFX_Matrix*)pMatrix,
188                                       argb, FXTEXT_CLEARTYPE);
189 #endif
190           }
191           pCurFont = pSTFont;
192           pCurCP = pCP;
193           iCurCount = 1;
194         } else {
195           iCurCount++;
196         }
197         pCP++;
198       }
199       if (pCurFont != NULL && iCurCount) {
200         pFxFont = (CFX_Font*)pCurFont->GetDevFont();
201 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
202         FxFont.SetFace(pFxFont->GetFace());
203         FX_BOOL bRet = m_pDevice->DrawNormalText(
204             iCurCount, pCurCP, &FxFont, pCache, -fFontSize,
205             (const CFX_Matrix*)pMatrix, argb, FXTEXT_CLEARTYPE);
206         FxFont.SetSubstFont(nullptr);
207         FxFont.SetFace(nullptr);
208         return bRet;
209 #else
210         return m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, pCache,
211                                          -fFontSize, (const CFX_Matrix*)pMatrix,
212                                          argb, FXTEXT_CLEARTYPE);
213 #endif
214       }
215 #if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
216       FxFont.SetSubstFont(nullptr);
217       FxFont.SetFace(nullptr);
218 #endif
219       return TRUE;
220     } break;
221     default:
222       return FALSE;
223   }
224 }
DrawBezier(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_PointF & pt1,const CFX_PointF & pt2,const CFX_PointF & pt3,const CFX_PointF & pt4,const CFX_Matrix * pMatrix)225 FX_BOOL CFDE_FxgeDevice::DrawBezier(IFDE_Pen* pPen,
226                                     FX_FLOAT fPenWidth,
227                                     const CFX_PointF& pt1,
228                                     const CFX_PointF& pt2,
229                                     const CFX_PointF& pt3,
230                                     const CFX_PointF& pt4,
231                                     const CFX_Matrix* pMatrix) {
232   CFX_PointsF points;
233   points.Add(pt1);
234   points.Add(pt2);
235   points.Add(pt3);
236   points.Add(pt4);
237   CFDE_Path path;
238   path.AddBezier(points);
239   return DrawPath(pPen, fPenWidth, &path, pMatrix);
240 }
DrawCurve(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_PointsF & points,FX_BOOL bClosed,FX_FLOAT fTension,const CFX_Matrix * pMatrix)241 FX_BOOL CFDE_FxgeDevice::DrawCurve(IFDE_Pen* pPen,
242                                    FX_FLOAT fPenWidth,
243                                    const CFX_PointsF& points,
244                                    FX_BOOL bClosed,
245                                    FX_FLOAT fTension,
246                                    const CFX_Matrix* pMatrix) {
247   CFDE_Path path;
248   path.AddCurve(points, bClosed, fTension);
249   return DrawPath(pPen, fPenWidth, &path, pMatrix);
250 }
DrawEllipse(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_RectF & rect,const CFX_Matrix * pMatrix)251 FX_BOOL CFDE_FxgeDevice::DrawEllipse(IFDE_Pen* pPen,
252                                      FX_FLOAT fPenWidth,
253                                      const CFX_RectF& rect,
254                                      const CFX_Matrix* pMatrix) {
255   CFDE_Path path;
256   path.AddEllipse(rect);
257   return DrawPath(pPen, fPenWidth, &path, pMatrix);
258 }
DrawLines(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_PointsF & points,const CFX_Matrix * pMatrix)259 FX_BOOL CFDE_FxgeDevice::DrawLines(IFDE_Pen* pPen,
260                                    FX_FLOAT fPenWidth,
261                                    const CFX_PointsF& points,
262                                    const CFX_Matrix* pMatrix) {
263   CFDE_Path path;
264   path.AddLines(points);
265   return DrawPath(pPen, fPenWidth, &path, pMatrix);
266 }
DrawLine(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_PointF & pt1,const CFX_PointF & pt2,const CFX_Matrix * pMatrix)267 FX_BOOL CFDE_FxgeDevice::DrawLine(IFDE_Pen* pPen,
268                                   FX_FLOAT fPenWidth,
269                                   const CFX_PointF& pt1,
270                                   const CFX_PointF& pt2,
271                                   const CFX_Matrix* pMatrix) {
272   CFDE_Path path;
273   path.AddLine(pt1, pt2);
274   return DrawPath(pPen, fPenWidth, &path, pMatrix);
275 }
DrawPath(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const IFDE_Path * pPath,const CFX_Matrix * pMatrix)276 FX_BOOL CFDE_FxgeDevice::DrawPath(IFDE_Pen* pPen,
277                                   FX_FLOAT fPenWidth,
278                                   const IFDE_Path* pPath,
279                                   const CFX_Matrix* pMatrix) {
280   CFDE_Path* pGePath = (CFDE_Path*)pPath;
281   if (pGePath == NULL) {
282     return FALSE;
283   }
284   CFX_GraphStateData graphState;
285   if (!CreatePen(pPen, fPenWidth, graphState)) {
286     return FALSE;
287   }
288   return m_pDevice->DrawPath(&pGePath->m_Path, (const CFX_Matrix*)pMatrix,
289                              &graphState, 0, pPen->GetColor(), 0);
290 }
DrawPolygon(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_PointsF & points,const CFX_Matrix * pMatrix)291 FX_BOOL CFDE_FxgeDevice::DrawPolygon(IFDE_Pen* pPen,
292                                      FX_FLOAT fPenWidth,
293                                      const CFX_PointsF& points,
294                                      const CFX_Matrix* pMatrix) {
295   CFDE_Path path;
296   path.AddPolygon(points);
297   return DrawPath(pPen, fPenWidth, &path, pMatrix);
298 }
DrawRectangle(IFDE_Pen * pPen,FX_FLOAT fPenWidth,const CFX_RectF & rect,const CFX_Matrix * pMatrix)299 FX_BOOL CFDE_FxgeDevice::DrawRectangle(IFDE_Pen* pPen,
300                                        FX_FLOAT fPenWidth,
301                                        const CFX_RectF& rect,
302                                        const CFX_Matrix* pMatrix) {
303   CFDE_Path path;
304   path.AddRectangle(rect);
305   return DrawPath(pPen, fPenWidth, &path, pMatrix);
306 }
FillClosedCurve(IFDE_Brush * pBrush,const CFX_PointsF & points,FX_FLOAT fTension,const CFX_Matrix * pMatrix)307 FX_BOOL CFDE_FxgeDevice::FillClosedCurve(IFDE_Brush* pBrush,
308                                          const CFX_PointsF& points,
309                                          FX_FLOAT fTension,
310                                          const CFX_Matrix* pMatrix) {
311   CFDE_Path path;
312   path.AddCurve(points, TRUE, fTension);
313   return FillPath(pBrush, &path, pMatrix);
314 }
FillEllipse(IFDE_Brush * pBrush,const CFX_RectF & rect,const CFX_Matrix * pMatrix)315 FX_BOOL CFDE_FxgeDevice::FillEllipse(IFDE_Brush* pBrush,
316                                      const CFX_RectF& rect,
317                                      const CFX_Matrix* pMatrix) {
318   CFDE_Path path;
319   path.AddEllipse(rect);
320   return FillPath(pBrush, &path, pMatrix);
321 }
FillPolygon(IFDE_Brush * pBrush,const CFX_PointsF & points,const CFX_Matrix * pMatrix)322 FX_BOOL CFDE_FxgeDevice::FillPolygon(IFDE_Brush* pBrush,
323                                      const CFX_PointsF& points,
324                                      const CFX_Matrix* pMatrix) {
325   CFDE_Path path;
326   path.AddPolygon(points);
327   return FillPath(pBrush, &path, pMatrix);
328 }
FillRectangle(IFDE_Brush * pBrush,const CFX_RectF & rect,const CFX_Matrix * pMatrix)329 FX_BOOL CFDE_FxgeDevice::FillRectangle(IFDE_Brush* pBrush,
330                                        const CFX_RectF& rect,
331                                        const CFX_Matrix* pMatrix) {
332   CFDE_Path path;
333   path.AddRectangle(rect);
334   return FillPath(pBrush, &path, pMatrix);
335 }
CreatePen(IFDE_Pen * pPen,FX_FLOAT fPenWidth,CFX_GraphStateData & graphState)336 FX_BOOL CFDE_FxgeDevice::CreatePen(IFDE_Pen* pPen,
337                                    FX_FLOAT fPenWidth,
338                                    CFX_GraphStateData& graphState) {
339   if (pPen == NULL) {
340     return FALSE;
341   }
342   graphState.m_LineCap = (CFX_GraphStateData::LineCap)pPen->GetLineCap();
343   graphState.m_LineJoin = (CFX_GraphStateData::LineJoin)pPen->GetLineJoin();
344   graphState.m_LineWidth = fPenWidth;
345   graphState.m_MiterLimit = pPen->GetMiterLimit();
346   graphState.m_DashPhase = pPen->GetDashPhase();
347   CFX_FloatArray dashArray;
348   switch (pPen->GetDashStyle()) {
349     case FDE_DASHSTYLE_Dash:
350       dashArray.Add(3);
351       dashArray.Add(1);
352       break;
353     case FDE_DASHSTYLE_Dot:
354       dashArray.Add(1);
355       dashArray.Add(1);
356       break;
357     case FDE_DASHSTYLE_DashDot:
358       dashArray.Add(3);
359       dashArray.Add(1);
360       dashArray.Add(1);
361       dashArray.Add(1);
362       break;
363     case FDE_DASHSTYLE_DashDotDot:
364       dashArray.Add(3);
365       dashArray.Add(1);
366       dashArray.Add(1);
367       dashArray.Add(1);
368       dashArray.Add(1);
369       dashArray.Add(1);
370       break;
371     case FDE_DASHSTYLE_Customized:
372       pPen->GetDashArray(dashArray);
373       break;
374   }
375   int32_t iDashCount = dashArray.GetSize();
376   if (iDashCount > 0) {
377     graphState.SetDashCount(iDashCount);
378     for (int32_t i = 0; i < iDashCount; ++i) {
379       graphState.m_DashArray[i] = dashArray[i] * fPenWidth;
380     }
381   }
382   return TRUE;
383 }
384 typedef FX_BOOL (CFDE_FxgeDevice::*pfFillPath)(IFDE_Brush* pBrush,
385                                                const CFX_PathData* pPath,
386                                                const CFX_Matrix* pMatrix);
387 static const pfFillPath gs_FillPath[] = {
388     &CFDE_FxgeDevice::FillSolidPath, &CFDE_FxgeDevice::FillHatchPath,
389     &CFDE_FxgeDevice::FillTexturePath, &CFDE_FxgeDevice::FillLinearGradientPath,
390 };
FillPath(IFDE_Brush * pBrush,const IFDE_Path * pPath,const CFX_Matrix * pMatrix)391 FX_BOOL CFDE_FxgeDevice::FillPath(IFDE_Brush* pBrush,
392                                   const IFDE_Path* pPath,
393                                   const CFX_Matrix* pMatrix) {
394   CFDE_Path* pGePath = (CFDE_Path*)pPath;
395   if (pGePath == NULL) {
396     return FALSE;
397   }
398   if (pBrush == NULL) {
399     return FALSE;
400   }
401   int32_t iType = pBrush->GetType();
402   if (iType < 0 || iType > FDE_BRUSHTYPE_MAX) {
403     return FALSE;
404   }
405   return (this->*gs_FillPath[iType])(pBrush, &pGePath->m_Path, pMatrix);
406 }
FillSolidPath(IFDE_Brush * pBrush,const CFX_PathData * pPath,const CFX_Matrix * pMatrix)407 FX_BOOL CFDE_FxgeDevice::FillSolidPath(IFDE_Brush* pBrush,
408                                        const CFX_PathData* pPath,
409                                        const CFX_Matrix* pMatrix) {
410   FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Solid);
411   IFDE_SolidBrush* pSolidBrush = (IFDE_SolidBrush*)pBrush;
412   return m_pDevice->DrawPath(pPath, (const CFX_Matrix*)pMatrix, NULL,
413                              pSolidBrush->GetColor(), 0, FXFILL_WINDING);
414 }
FillHatchPath(IFDE_Brush * pBrush,const CFX_PathData * pPath,const CFX_Matrix * pMatrix)415 FX_BOOL CFDE_FxgeDevice::FillHatchPath(IFDE_Brush* pBrush,
416                                        const CFX_PathData* pPath,
417                                        const CFX_Matrix* pMatrix) {
418   FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Hatch);
419   IFDE_HatchBrush* pHatchBrush = (IFDE_HatchBrush*)pBrush;
420   int32_t iStyle = pHatchBrush->GetHatchStyle();
421   if (iStyle < FDE_HATCHSTYLE_Min || iStyle > FDE_HATCHSTYLE_Max) {
422     return FALSE;
423   }
424   CFX_DIBitmap mask;
425   if (!FDE_GetStockHatchMask(iStyle, mask)) {
426     return FALSE;
427   }
428   FX_ARGB dwForeColor = pHatchBrush->GetColor(TRUE);
429   FX_ARGB dwBackColor = pHatchBrush->GetColor(FALSE);
430   CFX_FloatRect rectf = pPath->GetBoundingBox();
431   if (pMatrix) {
432     rectf.Transform((const CFX_Matrix*)pMatrix);
433   }
434   FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top),
435                FXSYS_round(rectf.right), FXSYS_round(rectf.bottom));
436   m_pDevice->SaveState();
437   m_pDevice->StartRendering();
438   m_pDevice->SetClip_PathFill(pPath, (const CFX_Matrix*)pMatrix,
439                               FXFILL_WINDING);
440   m_pDevice->FillRect(&rect, dwBackColor);
441   for (int32_t j = rect.bottom; j < rect.top; j += mask.GetHeight())
442     for (int32_t i = rect.left; i < rect.right; i += mask.GetWidth()) {
443       m_pDevice->SetBitMask(&mask, i, j, dwForeColor);
444     }
445   m_pDevice->EndRendering();
446   m_pDevice->RestoreState();
447   return TRUE;
448 }
FillTexturePath(IFDE_Brush * pBrush,const CFX_PathData * pPath,const CFX_Matrix * pMatrix)449 FX_BOOL CFDE_FxgeDevice::FillTexturePath(IFDE_Brush* pBrush,
450                                          const CFX_PathData* pPath,
451                                          const CFX_Matrix* pMatrix) {
452   FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Texture);
453   IFDE_TextureBrush* pTextureBrush = (IFDE_TextureBrush*)pBrush;
454   IFDE_Image* pImage = (IFDE_Image*)pTextureBrush->GetImage();
455   if (pImage == NULL) {
456     return FALSE;
457   }
458   CFX_Size size;
459   size.Set(pImage->GetImageWidth(), pImage->GetImageHeight());
460   CFX_DIBitmap bmp;
461   bmp.Create(size.x, size.y, FXDIB_Argb);
462   if (!pImage->StartLoadImage(&bmp, 0, 0, size.x, size.y, 0, 0, size.x,
463                               size.y)) {
464     return FALSE;
465   }
466   if (pImage->DoLoadImage() < 100) {
467     return FALSE;
468   }
469   pImage->StopLoadImage();
470   return WrapTexture(pTextureBrush->GetWrapMode(), &bmp, pPath, pMatrix);
471 }
WrapTexture(int32_t iWrapMode,const CFX_DIBitmap * pBitmap,const CFX_PathData * pPath,const CFX_Matrix * pMatrix)472 FX_BOOL CFDE_FxgeDevice::WrapTexture(int32_t iWrapMode,
473                                      const CFX_DIBitmap* pBitmap,
474                                      const CFX_PathData* pPath,
475                                      const CFX_Matrix* pMatrix) {
476   CFX_FloatRect rectf = pPath->GetBoundingBox();
477   if (pMatrix) {
478     rectf.Transform((const CFX_Matrix*)pMatrix);
479   }
480   FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top),
481                FXSYS_round(rectf.right), FXSYS_round(rectf.bottom));
482   rect.Normalize();
483   if (rect.IsEmpty()) {
484     return FALSE;
485   }
486   m_pDevice->SaveState();
487   m_pDevice->StartRendering();
488   m_pDevice->SetClip_PathFill(pPath, (const CFX_Matrix*)pMatrix,
489                               FXFILL_WINDING);
490   switch (iWrapMode) {
491     case FDE_WRAPMODE_Tile:
492     case FDE_WRAPMODE_TileFlipX:
493     case FDE_WRAPMODE_TileFlipY:
494     case FDE_WRAPMODE_TileFlipXY: {
495       FX_BOOL bFlipX = iWrapMode == FDE_WRAPMODE_TileFlipXY ||
496                        iWrapMode == FDE_WRAPMODE_TileFlipX;
497       FX_BOOL bFlipY = iWrapMode == FDE_WRAPMODE_TileFlipXY ||
498                        iWrapMode == FDE_WRAPMODE_TileFlipY;
499       const CFX_DIBitmap* pFlip[2][2];
500       pFlip[0][0] = pBitmap;
501       pFlip[0][1] = bFlipX ? pBitmap->FlipImage(TRUE, FALSE) : pBitmap;
502       pFlip[1][0] = bFlipY ? pBitmap->FlipImage(FALSE, TRUE) : pBitmap;
503       pFlip[1][1] =
504           (bFlipX || bFlipY) ? pBitmap->FlipImage(bFlipX, bFlipY) : pBitmap;
505       int32_t iCounterY = 0;
506       for (int32_t j = rect.top; j < rect.bottom; j += pBitmap->GetHeight()) {
507         int32_t indexY = iCounterY++ % 2;
508         int32_t iCounterX = 0;
509         for (int32_t i = rect.left; i < rect.right; i += pBitmap->GetWidth()) {
510           int32_t indexX = iCounterX++ % 2;
511           m_pDevice->SetDIBits(pFlip[indexY][indexX], i, j);
512         }
513       }
514       if (pFlip[0][1] != pFlip[0][0]) {
515         delete pFlip[0][1];
516       }
517       if (pFlip[1][0] != pFlip[0][0]) {
518         delete pFlip[1][0];
519       }
520       if (pFlip[1][1] != pFlip[0][0]) {
521         delete pFlip[1][1];
522       }
523     } break;
524     case FDE_WRAPMODE_Clamp: {
525       m_pDevice->SetDIBits(pBitmap, rect.left, rect.bottom);
526     } break;
527   }
528   m_pDevice->EndRendering();
529   m_pDevice->RestoreState();
530   return TRUE;
531 }
FillLinearGradientPath(IFDE_Brush * pBrush,const CFX_PathData * pPath,const CFX_Matrix * pMatrix)532 FX_BOOL CFDE_FxgeDevice::FillLinearGradientPath(IFDE_Brush* pBrush,
533                                                 const CFX_PathData* pPath,
534                                                 const CFX_Matrix* pMatrix) {
535   FXSYS_assert(pPath && pBrush &&
536                pBrush->GetType() == FDE_BRUSHTYPE_LinearGradient);
537   IFDE_LinearGradientBrush* pLinearBrush = (IFDE_LinearGradientBrush*)pBrush;
538   CFX_PointF pt0, pt1;
539   pLinearBrush->GetLinearPoints(pt0, pt1);
540   CFX_VectorF fDiagonal;
541   fDiagonal.Set(pt0, pt1);
542   FX_FLOAT fTheta = FXSYS_atan2(fDiagonal.y, fDiagonal.x);
543   FX_FLOAT fLength = fDiagonal.Length();
544   FX_FLOAT fTotalX = fLength / FXSYS_cos(fTheta);
545   FX_FLOAT fTotalY = fLength / FXSYS_cos(FX_PI / 2 - fTheta);
546   FX_FLOAT fSteps = std::max(fTotalX, fTotalY);
547   FX_FLOAT dx = fTotalX / fSteps;
548   FX_FLOAT dy = fTotalY / fSteps;
549   FX_ARGB cr0, cr1;
550   pLinearBrush->GetLinearColors(cr0, cr1);
551   FX_FLOAT a0 = FXARGB_A(cr0);
552   FX_FLOAT r0 = FXARGB_R(cr0);
553   FX_FLOAT g0 = FXARGB_G(cr0);
554   FX_FLOAT b0 = FXARGB_B(cr0);
555   FX_FLOAT da = (FXARGB_A(cr1) - a0) / fSteps;
556   FX_FLOAT dr = (FXARGB_R(cr1) - r0) / fSteps;
557   FX_FLOAT dg = (FXARGB_G(cr1) - g0) / fSteps;
558   FX_FLOAT db = (FXARGB_B(cr1) - b0) / fSteps;
559   CFX_DIBitmap bmp;
560   bmp.Create(FXSYS_round(FXSYS_fabs(fDiagonal.x)),
561              FXSYS_round(FXSYS_fabs(fDiagonal.y)), FXDIB_Argb);
562   CFX_FxgeDevice dev;
563   dev.Attach(&bmp);
564   pt1 = pt0;
565   int32_t iSteps = FXSYS_round(FXSYS_ceil(fSteps));
566   while (--iSteps >= 0) {
567     cr0 = ArgbEncode(FXSYS_round(a0), FXSYS_round(r0), FXSYS_round(g0),
568                      FXSYS_round(b0));
569     dev.DrawCosmeticLine(pt0.x, pt0.y, pt1.x, pt1.y, cr0);
570     pt1.x += dx;
571     pt0.y += dy;
572     a0 += da;
573     r0 += dr;
574     g0 += dg;
575     b0 += db;
576   }
577   return WrapTexture(pLinearBrush->GetWrapMode(), &bmp, pPath, pMatrix);
578 }
579 #endif
580