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