Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fdp / src / fde / fde_gdidevice.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 "stdafx.h"\r
8 #include "fde_gdidevice.h"\r
9 #include "fde_gdiobject.h"\r
10 #ifdef _FDEPLUS\r
11 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_\r
12 IFDE_RenderDevice*      IFDE_RenderDevice::Create(CFX_DIBitmap *pBitmap, FX_BOOL bRgbByteOrder )\r
13 {\r
14     return FDE_New CFDE_GdiDevice(pBitmap);\r
15 }\r
16 IFDE_RenderDevice*      IFDE_RenderDevice::Create(CFX_RenderDevice *pDevice)\r
17 {\r
18     return NULL;\r
19 }\r
20 CFDE_GdiDevice::CFDE_GdiDevice(CFX_DIBitmap *pBitmap)\r
21     : m_dwGlyphLen(0)\r
22     , m_pGlyphBuf(NULL)\r
23     , m_pGraphics(NULL)\r
24     , m_pBitmap(NULL)\r
25     , m_pClipPath(NULL)\r
26 {\r
27     FXSYS_assert(pBitmap != NULL);\r
28     BITMAPINFO bmi;\r
29     FXSYS_memset(&bmi, 0, sizeof(BITMAPINFOHEADER));\r
30     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
31     bmi.bmiHeader.biWidth = pBitmap->GetWidth();\r
32     bmi.bmiHeader.biHeight = -pBitmap->GetHeight();\r
33     bmi.bmiHeader.biPlanes = 1;\r
34     bmi.bmiHeader.biBitCount = pBitmap->GetBPP();\r
35     m_pBitmap = Gdiplus::Bitmap::FromBITMAPINFO(&bmi, pBitmap->GetBuffer());\r
36     FXSYS_assert(m_pBitmap != NULL);\r
37     m_pGraphics = Gdiplus::Graphics::FromImage(m_pBitmap);\r
38     FXSYS_assert(m_pGraphics != NULL);\r
39     m_rtClipRect.Set(0, 0, (FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)pBitmap->GetHeight());\r
40     m_pGraphics->SetClip((const Gdiplus::RectF&)m_rtClipRect);\r
41 }\r
42 CFDE_GdiDevice::~CFDE_GdiDevice()\r
43 {\r
44     delete m_pGraphics;\r
45     delete m_pBitmap;\r
46     if (m_pGlyphBuf) {\r
47         FDE_Free(m_pGlyphBuf);\r
48     }\r
49 }\r
50 FX_INT32 CFDE_GdiDevice::GetWidth() const\r
51 {\r
52     return m_pBitmap->GetWidth();\r
53 }\r
54 FX_INT32 CFDE_GdiDevice::GetHeight() const\r
55 {\r
56     return m_pBitmap->GetHeight();\r
57 }\r
58 FDE_HDEVICESTATE CFDE_GdiDevice::SaveState()\r
59 {\r
60     return (FDE_HDEVICESTATE)m_pGraphics->Save();\r
61 }\r
62 void CFDE_GdiDevice::RestoreState(FDE_HDEVICESTATE hState)\r
63 {\r
64     Gdiplus::Status eRet = m_pGraphics->Restore((Gdiplus::GraphicsState)hState);\r
65     if (eRet == Gdiplus::Ok) {\r
66         Gdiplus::Rect rt;\r
67         eRet = m_pGraphics->GetClipBounds(&rt);\r
68         if (eRet == Gdiplus::Ok) {\r
69             m_rtClipRect.Set((FX_FLOAT)rt.X, (FX_FLOAT)rt.Y, (FX_FLOAT)rt.Width, (FX_FLOAT)rt.Height);\r
70         }\r
71     }\r
72 }\r
73 FX_BOOL CFDE_GdiDevice::SetClipRect(const CFX_RectF &rtClip)\r
74 {\r
75     m_rtClipRect = rtClip;\r
76     return m_pGraphics->SetClip((const Gdiplus::RectF&)rtClip) == Gdiplus::Ok;\r
77 }\r
78 const CFX_RectF& CFDE_GdiDevice::GetClipRect()\r
79 {\r
80     return m_rtClipRect;\r
81 }\r
82 FX_BOOL CFDE_GdiDevice::SetClipPath(const IFDE_Path *pClip)\r
83 {\r
84     m_pClipPath = (CFDE_GdiPath*)pClip;\r
85     Gdiplus::GraphicsPath *pPath = m_pClipPath ? &m_pClipPath->m_Path : NULL;\r
86     return m_pGraphics->SetClip(pPath) == Gdiplus::Ok;\r
87 }\r
88 IFDE_Path* CFDE_GdiDevice::GetClipPath() const\r
89 {\r
90     return m_pClipPath;\r
91 }\r
92 FX_FLOAT CFDE_GdiDevice::GetDpiX() const\r
93 {\r
94     return m_pGraphics->GetDpiX();\r
95 }\r
96 FX_FLOAT CFDE_GdiDevice::GetDpiY() const\r
97 {\r
98     return m_pGraphics->GetDpiY();\r
99 }\r
100 FX_BOOL CFDE_GdiDevice::DrawImage(IFDE_Image *pImg, const CFX_RectF *pSrcRect, const CFX_RectF &dstRect, const CFX_Matrix *pImgMatrix, const CFX_Matrix *pDevMatrix)\r
101 {\r
102     CFDE_GdiImage *pGdiImg = (CFDE_GdiImage*)pImg;\r
103     FXSYS_assert(pGdiImg != NULL && pGdiImg->m_pImage != NULL);\r
104     CFX_RectF srcRect;\r
105     if (pSrcRect) {\r
106         srcRect = *pSrcRect;\r
107     } else {\r
108         srcRect.left = srcRect.top = 0;\r
109         srcRect.width = (FX_FLOAT)pImg->GetImageWidth();\r
110         srcRect.height = (FX_FLOAT)pImg->GetImageHeight();\r
111     }\r
112     CFX_Matrix matrix;\r
113     if (pImgMatrix) {\r
114         matrix = *pImgMatrix;\r
115     } else {\r
116         matrix.Reset();\r
117     }\r
118     matrix.Translate(dstRect.left, dstRect.top);\r
119     matrix.Scale((dstRect.width / srcRect.width), (dstRect.height / srcRect.height), TRUE);\r
120     if (pDevMatrix) {\r
121         matrix.Concat(*pDevMatrix);\r
122     }\r
123     CFX_PointF dstPoints[3];\r
124     dstPoints[0].Set(0, 0);\r
125     dstPoints[1].Set(srcRect.width, 0);\r
126     dstPoints[2].Set(0, srcRect.height);\r
127     matrix.TransformPoints(dstPoints, 3);\r
128     m_pGraphics->DrawImage(pGdiImg->m_pImage, (Gdiplus::PointF*)dstPoints, 3,\r
129                            srcRect.left, srcRect.top, srcRect.width, srcRect.height,\r
130                            Gdiplus::UnitPixel, NULL, NULL, NULL);\r
131     return TRUE;\r
132 }\r
133 FX_BOOL CFDE_GdiDevice::DrawImage(CFX_DIBSource *pDib, const CFX_RectF *pSrcRect, const CFX_RectF &dstRect, const CFX_Matrix *pImgMatrix, const CFX_Matrix *pDevMatrix)\r
134 {\r
135     FXSYS_assert(pDib != NULL);\r
136     BITMAPINFO bmi;\r
137     FXSYS_memset(&bmi, 0, sizeof(BITMAPINFOHEADER));\r
138     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
139     bmi.bmiHeader.biWidth = pDib->GetWidth();\r
140     bmi.bmiHeader.biHeight = pDib->GetHeight();\r
141     bmi.bmiHeader.biPlanes = 1;\r
142     bmi.bmiHeader.biBitCount = pDib->GetBPP();\r
143     Gdiplus::Bitmap bmp(&bmi, pDib->GetBuffer());\r
144     CFDE_GdiImage img(&bmp);\r
145     return DrawImage(&img, pSrcRect, dstRect, pImgMatrix, pDevMatrix);\r
146 }\r
147 FX_BOOL CFDE_GdiDevice::DrawString(IFDE_Brush *pBrush, IFX_Font *pFont, const FXTEXT_CHARPOS *pCharPos, FX_INT32 iCount, FX_FLOAT fFontSize, const CFX_Matrix *pMatrix)\r
148 {\r
149     FXSYS_assert(pBrush != NULL && pFont != NULL && pCharPos != NULL);\r
150     FX_ARGB argb = 0xFF000000;\r
151     if (pBrush->GetType() == FDE_BRUSHTYPE_Solid) {\r
152         argb = ((IFDE_SolidBrush*)pBrush)->GetColor();\r
153     }\r
154     CFDE_GdiFont *pGdiFont = (CFDE_GdiFont*)pFont;\r
155     GLYPHMETRICS gm;\r
156     MAT2 mat2;\r
157     FX_FLOAT fScale = fFontSize / 1000.0f;\r
158     FX_FLOAT ma, mb, mc, md;\r
159     FX_FLOAT fx, fy;\r
160     while (--iCount >= 0) {\r
161         mb = mc = 0;\r
162         ma = md = fScale;\r
163         if (pCharPos->m_bGlyphAdjust) {\r
164             FX_FLOAT aa = ma * -pCharPos->m_AdjustMatrix[0] + mb * pCharPos->m_AdjustMatrix[2];\r
165             FX_FLOAT bb = -ma * pCharPos->m_AdjustMatrix[1] + mb * pCharPos->m_AdjustMatrix[3];\r
166             FX_FLOAT cc = mc * -pCharPos->m_AdjustMatrix[0] + md * pCharPos->m_AdjustMatrix[2];\r
167             FX_FLOAT dd = -mc * pCharPos->m_AdjustMatrix[1] + md * pCharPos->m_AdjustMatrix[3];\r
168             ma = aa;\r
169             mb = bb;\r
170             mc = cc;\r
171             md = dd;\r
172         }\r
173         if (pMatrix) {\r
174             FX_FLOAT aa = ma * pMatrix->a + mb * pMatrix->c;\r
175             FX_FLOAT bb = ma * pMatrix->b + mb * pMatrix->d;\r
176             FX_FLOAT cc = mc * pMatrix->a + md * pMatrix->c;\r
177             FX_FLOAT dd = mc * pMatrix->b + md * pMatrix->d;\r
178             ma = aa;\r
179             mb = bb;\r
180             mc = cc;\r
181             md = dd;\r
182         }\r
183         *(long*)(&mat2.eM11) = (long)(ma * 65536);\r
184         *(long*)(&mat2.eM21) = (long)(mb * 65536);\r
185         *(long*)(&mat2.eM12) = (long)(mc * 65536);\r
186         *(long*)(&mat2.eM22) = (long)(md * 65536);\r
187         FX_DWORD dwSize = pGdiFont->GetGlyphDIBits(pCharPos->m_GlyphIndex, argb, &mat2, gm, NULL, 0);\r
188         if (dwSize > 0) {\r
189             if (m_pGlyphBuf == NULL) {\r
190                 m_pGlyphBuf = FDE_Alloc(dwSize);\r
191                 m_dwGlyphLen = dwSize;\r
192             } else if (m_dwGlyphLen < dwSize) {\r
193                 m_pGlyphBuf = FDE_Realloc(m_pGlyphBuf, dwSize);\r
194                 m_dwGlyphLen = dwSize;\r
195             }\r
196             pGdiFont->GetGlyphDIBits(pCharPos->m_GlyphIndex, argb, &mat2, gm, m_pGlyphBuf, m_dwGlyphLen);\r
197             Gdiplus::Bitmap bmp(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmBlackBoxX * 4, PixelFormat32bppARGB, m_pGlyphBuf);\r
198             if (pMatrix) {\r
199                 fx = pMatrix->a * pCharPos->m_OriginX + pMatrix->c * pCharPos->m_OriginY + pMatrix->e;\r
200                 fy = pMatrix->b * pCharPos->m_OriginX + pMatrix->d * pCharPos->m_OriginY + pMatrix->f;\r
201             } else {\r
202                 fx = pCharPos->m_OriginX;\r
203                 fy = pCharPos->m_OriginY;\r
204             }\r
205             m_pGraphics->DrawImage(&bmp, (FXSYS_round(fx) + gm.gmptGlyphOrigin.x), (FXSYS_round(fy) - gm.gmptGlyphOrigin.y));\r
206         }\r
207         pCharPos++;\r
208     }\r
209     return TRUE;\r
210 }\r
211 FX_BOOL CFDE_GdiDevice::DrawArc(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, FX_FLOAT startAngle, FX_FLOAT sweepAngle, const CFX_Matrix *pMatrix )\r
212 {\r
213     startAngle = FX_RAD2DEG(startAngle);\r
214     sweepAngle = FX_RAD2DEG(sweepAngle);\r
215     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
216     if (pGdiPen == NULL) {\r
217         return FALSE;\r
218     }\r
219     ApplyMatrix(pMatrix);\r
220     Gdiplus::Status ret = m_pGraphics->DrawArc(pGdiPen, rect.left, rect.top, rect.width, rect.height, startAngle, sweepAngle);\r
221     RestoreMatrix(pMatrix);\r
222     ReleaseGdiPen(pGdiPen);\r
223     return ret == Gdiplus::Ok;\r
224 }\r
225 FX_BOOL CFDE_GdiDevice::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
226 {\r
227     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
228     if (pGdiPen == NULL) {\r
229         return FALSE;\r
230     }\r
231     ApplyMatrix(pMatrix);\r
232     Gdiplus::Status ret = m_pGraphics->DrawBezier(pGdiPen, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y, pt4.x, pt4.y);\r
233     RestoreMatrix(pMatrix);\r
234     ReleaseGdiPen(pGdiPen);\r
235     return ret == Gdiplus::Ok;\r
236 }\r
237 FX_BOOL CFDE_GdiDevice::DrawCurve(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_PointsF &points, FX_BOOL bClosed, FX_FLOAT fTension , const CFX_Matrix *pMatrix )\r
238 {\r
239     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
240     if (pGdiPen == NULL) {\r
241         return FALSE;\r
242     }\r
243     ApplyMatrix(pMatrix);\r
244     Gdiplus::Status ret = bClosed\r
245                           ? m_pGraphics->DrawClosedCurve(pGdiPen, (const Gdiplus::PointF*)points.GetData(), points.GetSize(), fTension)\r
246                           : m_pGraphics->DrawCurve(pGdiPen, (const Gdiplus::PointF*)points.GetData(), points.GetSize(), fTension);\r
247     RestoreMatrix(pMatrix);\r
248     ReleaseGdiPen(pGdiPen);\r
249     return ret == Gdiplus::Ok;\r
250 }\r
251 FX_BOOL CFDE_GdiDevice::DrawEllipse(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, const CFX_Matrix *pMatrix )\r
252 {\r
253     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
254     if (pGdiPen == NULL) {\r
255         return FALSE;\r
256     }\r
257     ApplyMatrix(pMatrix);\r
258     Gdiplus::Status ret = m_pGraphics->DrawEllipse(pGdiPen, rect.left, rect.top, rect.width, rect.height);\r
259     RestoreMatrix(pMatrix);\r
260     ReleaseGdiPen(pGdiPen);\r
261     return ret == Gdiplus::Ok;\r
262 }\r
263 FX_BOOL CFDE_GdiDevice::DrawLines(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_PointsF &points, const CFX_Matrix *pMatrix )\r
264 {\r
265     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
266     if (pGdiPen == NULL) {\r
267         return FALSE;\r
268     }\r
269     ApplyMatrix(pMatrix);\r
270     Gdiplus::Status ret = m_pGraphics->DrawLines(pGdiPen, (const Gdiplus::PointF*)points.GetData(), points.GetSize());\r
271     ApplyMatrix(pMatrix);\r
272     ReleaseGdiPen(pGdiPen);\r
273     return ret == Gdiplus::Ok;\r
274 }\r
275 FX_BOOL CFDE_GdiDevice::DrawLine(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_PointF &pt1, const CFX_PointF &pt2, const CFX_Matrix *pMatrix )\r
276 {\r
277     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
278     if (pGdiPen == NULL) {\r
279         return FALSE;\r
280     }\r
281     ApplyMatrix(pMatrix);\r
282     Gdiplus::Status ret = m_pGraphics->DrawLine(pGdiPen, pt1.x, pt1.y, pt2.x, pt2.y);\r
283     RestoreMatrix(pMatrix);\r
284     ReleaseGdiPen(pGdiPen);\r
285     return ret == Gdiplus::Ok;\r
286 }\r
287 FX_BOOL CFDE_GdiDevice::DrawPath(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const IFDE_Path *pPath, const CFX_Matrix *pMatrix )\r
288 {\r
289     CFDE_GdiPath *pGdiPath = (CFDE_GdiPath*)pPath;\r
290     if (pGdiPath == NULL) {\r
291         return FALSE;\r
292     }\r
293     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
294     if (pGdiPen == NULL) {\r
295         return FALSE;\r
296     }\r
297     ApplyMatrix(pMatrix);\r
298     Gdiplus::Status ret = m_pGraphics->DrawPath(pGdiPen, &pGdiPath->m_Path);\r
299     RestoreMatrix(pMatrix);\r
300     ReleaseGdiPen(pGdiPen);\r
301     return ret == Gdiplus::Ok;\r
302 }\r
303 FX_BOOL CFDE_GdiDevice::DrawPie(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, FX_FLOAT startAngle, FX_FLOAT sweepAngle, const CFX_Matrix *pMatrix )\r
304 {\r
305     startAngle = FX_RAD2DEG(startAngle);\r
306     sweepAngle = FX_RAD2DEG(sweepAngle);\r
307     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
308     if (pGdiPen == NULL) {\r
309         return FALSE;\r
310     }\r
311     ApplyMatrix(pMatrix);\r
312     Gdiplus::Status ret = m_pGraphics->DrawPie(pGdiPen, rect.left, rect.top, rect.width, rect.height, startAngle, sweepAngle);\r
313     RestoreMatrix(pMatrix);\r
314     ReleaseGdiPen(pGdiPen);\r
315     return ret == Gdiplus::Ok;\r
316 }\r
317 FX_BOOL CFDE_GdiDevice::DrawChord(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, FX_FLOAT startAngle, FX_FLOAT sweepAngle, const CFX_Matrix *pMatrix )\r
318 {\r
319     CFX_ArcF chord;\r
320     chord.Set(rect, startAngle, sweepAngle);\r
321     CFDE_GdiPath path;\r
322     path.AddChord(chord);\r
323     return DrawPath(pPen, fPenWidth, &path, pMatrix);\r
324 }\r
325 FX_BOOL CFDE_GdiDevice::DrawPolygon(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_PointsF &points, const CFX_Matrix *pMatrix )\r
326 {\r
327     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
328     if (pGdiPen == NULL) {\r
329         return FALSE;\r
330     }\r
331     ApplyMatrix(pMatrix);\r
332     Gdiplus::Status ret = m_pGraphics->DrawPolygon(pGdiPen, (const Gdiplus::PointF*)points.GetData(), points.GetSize());\r
333     RestoreMatrix(pMatrix);\r
334     ReleaseGdiPen(pGdiPen);\r
335     return ret == Gdiplus::Ok;\r
336 }\r
337 FX_BOOL CFDE_GdiDevice::DrawRectangle(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, const CFX_Matrix *pMatrix )\r
338 {\r
339     Gdiplus::Pen *pGdiPen = CreateGdiPen(pPen, fPenWidth);\r
340     if (pGdiPen == NULL) {\r
341         return FALSE;\r
342     }\r
343     ApplyMatrix(pMatrix);\r
344     Gdiplus::Status ret = m_pGraphics->DrawRectangle(pGdiPen, rect.left, rect.top, rect.width, rect.height);\r
345     RestoreMatrix(pMatrix);\r
346     ReleaseGdiPen(pGdiPen);\r
347     return ret == Gdiplus::Ok;\r
348 }\r
349 FX_BOOL CFDE_GdiDevice::DrawRoundRectangle(IFDE_Pen *pPen, FX_FLOAT fPenWidth, const CFX_RectF &rect, const CFX_SizeF &round, const CFX_Matrix *pMatrix )\r
350 {\r
351     CFDE_GdiPath path;\r
352     path.AddRoundRectangle(rect, round);\r
353     return DrawPath(pPen, fPenWidth, &path, pMatrix);\r
354 }\r
355 FX_BOOL CFDE_GdiDevice::FillClosedCurve(IFDE_Brush *pBrush, const CFX_PointsF &points, FX_FLOAT fTension , const CFX_Matrix *pMatrix )\r
356 {\r
357     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
358     if (pGdiBrush == NULL) {\r
359         return FALSE;\r
360     }\r
361     ApplyMatrix(pMatrix);\r
362     Gdiplus::Status ret = m_pGraphics->FillClosedCurve(pGdiBrush, (const Gdiplus::PointF*)points.GetData(), points.GetSize(), Gdiplus::FillModeAlternate, fTension);\r
363     RestoreMatrix(pMatrix);\r
364     ReleaseGdiBrush(pGdiBrush);\r
365     return ret == Gdiplus::Ok;\r
366 }\r
367 FX_BOOL CFDE_GdiDevice::FillEllipse(IFDE_Brush* pBrush, const CFX_RectF& rect, const CFX_Matrix *pMatrix )\r
368 {\r
369     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
370     if (pGdiBrush == NULL) {\r
371         return FALSE;\r
372     }\r
373     ApplyMatrix(pMatrix);\r
374     Gdiplus::Status ret = m_pGraphics->FillEllipse(pGdiBrush, rect.left, rect.top, rect.width, rect.height);\r
375     RestoreMatrix(pMatrix);\r
376     ReleaseGdiBrush(pGdiBrush);\r
377     return ret == Gdiplus::Ok;\r
378 }\r
379 FX_BOOL CFDE_GdiDevice::FillPath(IFDE_Brush *pBrush, const IFDE_Path *pPath, const CFX_Matrix *pMatrix )\r
380 {\r
381     CFDE_GdiPath *pGdiPath = (CFDE_GdiPath*)pPath;\r
382     if (pGdiPath == NULL) {\r
383         return FALSE;\r
384     }\r
385     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
386     if (pGdiBrush == NULL) {\r
387         return FALSE;\r
388     }\r
389     ApplyMatrix(pMatrix);\r
390     Gdiplus::Status ret = m_pGraphics->FillPath(pGdiBrush, &pGdiPath->m_Path);\r
391     RestoreMatrix(pMatrix);\r
392     ReleaseGdiBrush(pGdiBrush);\r
393     return ret == Gdiplus::Ok;\r
394 }\r
395 FX_BOOL CFDE_GdiDevice::FillPie(IFDE_Brush *pBrush, const CFX_RectF &rect, FX_FLOAT startAngle, FX_FLOAT sweepAngle, const CFX_Matrix *pMatrix )\r
396 {\r
397     startAngle = FX_RAD2DEG(startAngle);\r
398     sweepAngle = FX_RAD2DEG(sweepAngle);\r
399     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
400     if (pGdiBrush == NULL) {\r
401         return FALSE;\r
402     }\r
403     ApplyMatrix(pMatrix);\r
404     Gdiplus::Status ret = m_pGraphics->FillPie(pGdiBrush, rect.left, rect.top, rect.width, rect.height, startAngle, sweepAngle);\r
405     RestoreMatrix(pMatrix);\r
406     ReleaseGdiBrush(pGdiBrush);\r
407     return ret == Gdiplus::Ok;\r
408 }\r
409 FX_BOOL CFDE_GdiDevice::FillChord(IFDE_Brush *pBrush, const CFX_RectF &rect, FX_FLOAT startAngle, FX_FLOAT sweepAngle, const CFX_Matrix *pMatrix )\r
410 {\r
411     CFX_ArcF chord;\r
412     chord.Set(rect, startAngle, sweepAngle);\r
413     CFDE_GdiPath path;\r
414     path.AddChord(chord);\r
415     return FillPath(pBrush, &path, pMatrix);\r
416 }\r
417 FX_BOOL CFDE_GdiDevice::FillPolygon(IFDE_Brush *pBrush, const CFX_PointsF &points, const CFX_Matrix *pMatrix )\r
418 {\r
419     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
420     if (pGdiBrush == NULL) {\r
421         return FALSE;\r
422     }\r
423     ApplyMatrix(pMatrix);\r
424     Gdiplus::Status ret = m_pGraphics->FillPolygon(pGdiBrush, (const Gdiplus::PointF*)points.GetData(), points.GetSize());\r
425     RestoreMatrix(pMatrix);\r
426     ReleaseGdiBrush(pGdiBrush);\r
427     return ret == Gdiplus::Ok;\r
428 }\r
429 FX_BOOL CFDE_GdiDevice::FillRectangle(IFDE_Brush *pBrush, const CFX_RectF &rect, const CFX_Matrix *pMatrix )\r
430 {\r
431     Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pBrush);\r
432     if (pGdiBrush == NULL) {\r
433         return FALSE;\r
434     }\r
435     ApplyMatrix(pMatrix);\r
436     Gdiplus::Status ret = m_pGraphics->FillRectangle(pGdiBrush, rect.left, rect.top, rect.width, rect.height);\r
437     RestoreMatrix(pMatrix);\r
438     ReleaseGdiBrush(pGdiBrush);\r
439     return ret == Gdiplus::Ok;\r
440 }\r
441 FX_BOOL CFDE_GdiDevice::FillRoundRectangle(IFDE_Brush *pBrush, const CFX_RectF &rect, const CFX_SizeF &round, const CFX_Matrix *pMatrix )\r
442 {\r
443     CFDE_GdiPath path;\r
444     path.AddRoundRectangle(rect, round);\r
445     return FillPath(pBrush, &path, pMatrix);\r
446 }\r
447 Gdiplus::Pen* CFDE_GdiDevice::CreateGdiPen(IFDE_Pen *pPen, FX_FLOAT fPenWidth)\r
448 {\r
449     if (pPen == NULL || fPenWidth < 0.01f) {\r
450         return NULL;\r
451     }\r
452     Gdiplus::Pen *pGdiPen = NULL;\r
453     switch (pPen->GetType()) {\r
454         case FDE_PENTYPE_SolidColor: {\r
455                 Gdiplus::Color gdiColor((Gdiplus::ARGB)pPen->GetColor());\r
456                 pGdiPen = new Gdiplus::Pen(gdiColor, fPenWidth);\r
457             }\r
458             break;\r
459         case FDE_PENTYPE_HatchBrush:\r
460         case FDE_PENTYPE_TextureBrush:\r
461         case FDE_PENTYPE_LinearGradient: {\r
462                 Gdiplus::Brush *pGdiBrush = CreateGdiBrush(pPen->GetBrush());\r
463                 if (pGdiBrush) {\r
464                     pGdiPen = new Gdiplus::Pen(pGdiBrush, fPenWidth);\r
465                 }\r
466             }\r
467             break;\r
468     }\r
469     if (pGdiPen) {\r
470         CFX_FloatArray dashArray;\r
471         pPen->GetDashArray(dashArray);\r
472         pGdiPen->SetDashPattern(dashArray.GetData(), dashArray.GetSize());\r
473         pGdiPen->SetDashOffset(pPen->GetDashPhase());\r
474         pGdiPen->SetDashStyle((Gdiplus::DashStyle)pPen->GetDashStyle());\r
475         pGdiPen->SetStartCap((Gdiplus::LineCap)pPen->GetLineCap());\r
476         pGdiPen->SetEndCap((Gdiplus::LineCap)pPen->GetLineCap());\r
477         pGdiPen->SetLineJoin((Gdiplus::LineJoin)pPen->GetLineJoin());\r
478         pGdiPen->SetMiterLimit(pPen->GetMiterLimit());\r
479     }\r
480     return pGdiPen;\r
481 }\r
482 void CFDE_GdiDevice::ReleaseGdiPen(Gdiplus::Pen *pGdiPen)\r
483 {\r
484     if (pGdiPen) {\r
485         ReleaseGdiBrush(pGdiPen->GetBrush());\r
486         delete pGdiPen;\r
487     }\r
488 }\r
489 Gdiplus::Brush* CFDE_GdiDevice::CreateGdiBrush(IFDE_Brush *pBrush)\r
490 {\r
491     if (pBrush == NULL) {\r
492         return NULL;\r
493     }\r
494     Gdiplus::Brush *pGdiBrush = NULL;\r
495     switch (pBrush->GetType()) {\r
496         case FDE_BRUSHTYPE_Solid: {\r
497                 IFDE_SolidBrush *pSolidBrush = (IFDE_SolidBrush*)pBrush;\r
498                 Gdiplus::Color gdiColor((Gdiplus::ARGB)pSolidBrush->GetColor());\r
499                 pGdiBrush = new Gdiplus::SolidBrush(gdiColor);\r
500             }\r
501             break;\r
502         case FDE_BRUSHTYPE_Hatch: {\r
503                 IFDE_HatchBrush *pHatchBrush = (IFDE_HatchBrush*)pBrush;\r
504                 Gdiplus::Color foreColor((Gdiplus::ARGB)pHatchBrush->GetColor(TRUE));\r
505                 Gdiplus::Color backColor((Gdiplus::ARGB)pHatchBrush->GetColor(FALSE));\r
506                 Gdiplus::HatchStyle hatchStyle = (Gdiplus::HatchStyle)pHatchBrush->GetHatchStyle();\r
507                 pGdiBrush = new Gdiplus::HatchBrush(hatchStyle, foreColor, backColor);\r
508             }\r
509             break;\r
510         case FDE_BRUSHTYPE_Texture: {\r
511                 IFDE_TextureBrush *pTextureBrush = (IFDE_TextureBrush*)pBrush;\r
512                 CFDE_GdiImage *pImgHolder = (CFDE_GdiImage*)pTextureBrush->GetImage();\r
513                 Gdiplus::Image *pGdiImage = pImgHolder ? pImgHolder->m_pImage : NULL;\r
514                 Gdiplus::WrapMode wrapMode = (Gdiplus::WrapMode)pTextureBrush->GetWrapMode();\r
515                 pGdiBrush = new Gdiplus::TextureBrush(pGdiImage, wrapMode);\r
516             }\r
517             break;\r
518         case FDE_BRUSHTYPE_LinearGradient: {\r
519                 IFDE_LinearGradientBrush *pLinearBrush = (IFDE_LinearGradientBrush*)pBrush;\r
520                 Gdiplus::WrapMode wrapMode = (Gdiplus::WrapMode)pLinearBrush->GetWrapMode();\r
521                 CFX_PointF ptStart, ptEnd;\r
522                 pLinearBrush->GetLinearPoints(ptStart, ptEnd);\r
523                 FX_ARGB crStart, crEnd;\r
524                 pLinearBrush->GetLinearColors(crStart, crEnd);\r
525                 pGdiBrush = new Gdiplus::LinearGradientBrush((const Gdiplus::PointF&)ptStart,\r
526                         (const Gdiplus::PointF&)ptEnd,\r
527                         (const Gdiplus::Color&)crStart,\r
528                         (const Gdiplus::Color&)crEnd);\r
529             }\r
530             break;\r
531     }\r
532     return pGdiBrush;\r
533 }\r
534 void CFDE_GdiDevice::ReleaseGdiBrush(Gdiplus::Brush *pGdiBrush)\r
535 {\r
536     if (pGdiBrush) {\r
537         delete pGdiBrush;\r
538     }\r
539 }\r
540 void CFDE_GdiDevice::ApplyMatrix(const CFX_Matrix *pMatrix)\r
541 {\r
542     if (pMatrix) {\r
543         m_GraphicsState = m_pGraphics->Save();\r
544         Gdiplus::Matrix gdiMatrix(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, pMatrix->e, pMatrix->f);\r
545         m_pGraphics->SetTransform(&gdiMatrix);\r
546     }\r
547 }\r
548 void CFDE_GdiDevice::RestoreMatrix(const CFX_Matrix *pMatrix)\r
549 {\r
550     if (pMatrix) {\r
551         m_pGraphics->Restore(m_GraphicsState);\r
552     }\r
553 }\r
554 #endif\r
555 #endif\r