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"
10static void FWL_SetChildThemeID(IFWL_Widget* pParent, FX_DWORD dwThemeID) {
11  IFWL_WidgetMgr* pWidgetMgr = FWL_GetWidgetMgr();
12  IFWL_Widget* pChild =
13      pWidgetMgr->GetWidget(pParent, FWL_WGTRELATION_FirstChild);
14  while (pChild) {
15    IFWL_ThemeProvider* pTheme = pChild->GetThemeProvider();
16    if (pTheme) {
17      pTheme->SetThemeID(pChild, dwThemeID, FALSE);
18    }
19    FWL_SetChildThemeID(pChild, dwThemeID);
20    pChild = pWidgetMgr->GetWidget(pChild, FWL_WGTRELATION_NextSibling);
21  }
22}
23FX_BOOL CFWL_WidgetTP::IsValidWidget(IFWL_Widget* pWidget) {
24  return FALSE;
25}
26FX_DWORD CFWL_WidgetTP::GetThemeID(IFWL_Widget* pWidget) {
27  return m_dwThemeID;
28}
29FX_DWORD CFWL_WidgetTP::SetThemeID(IFWL_Widget* pWidget,
30                                   FX_DWORD dwThemeID,
31                                   FX_BOOL bChildren) {
32  FX_DWORD dwOld = m_dwThemeID;
33  m_dwThemeID = dwThemeID;
34  if (CFWL_ArrowData::IsInstance()) {
35    CFWL_ArrowData::GetInstance()->SetColorData(FWL_GetThemeColor(dwThemeID));
36  }
37  if (bChildren) {
38    FWL_SetChildThemeID(pWidget, dwThemeID);
39  }
40  return dwOld;
41}
42FWL_ERR CFWL_WidgetTP::GetThemeMatrix(IFWL_Widget* pWidget,
43                                      CFX_Matrix& matrix) {
44  matrix.Set(_ctm.a, _ctm.b, _ctm.c, _ctm.d, _ctm.e, _ctm.f);
45  return FWL_ERR_Succeeded;
46}
47FWL_ERR CFWL_WidgetTP::SetThemeMatrix(IFWL_Widget* pWidget,
48                                      const CFX_Matrix& matrix) {
49  _ctm.Set(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);
50  return FWL_ERR_Succeeded;
51}
52FX_BOOL CFWL_WidgetTP::DrawBackground(CFWL_ThemeBackground* pParams) {
53  return TRUE;
54}
55FX_BOOL CFWL_WidgetTP::DrawText(CFWL_ThemeText* pParams) {
56  if (!m_pTextOut) {
57    InitTTO();
58  }
59  int32_t iLen = pParams->m_wsText.GetLength();
60  if (iLen <= 0)
61    return FALSE;
62  CFX_Graphics* pGraphics = pParams->m_pGraphics;
63  m_pTextOut->SetRenderDevice(pGraphics->GetRenderDevice());
64  m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
65  m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
66  CFX_Matrix* pMatrix = &pParams->m_matrix;
67  pMatrix->Concat(*pGraphics->GetMatrix());
68  m_pTextOut->SetMatrix(*pMatrix);
69  m_pTextOut->DrawLogicText(pParams->m_wsText, iLen, pParams->m_rtPart);
70  return TRUE;
71}
72void* CFWL_WidgetTP::GetCapacity(CFWL_ThemePart* pThemePart,
73                                 FX_DWORD dwCapacity) {
74  switch (dwCapacity) {
75    case FWL_WGTCAPACITY_CXBorder: {
76      m_fValue = FWLTHEME_CAPACITY_CXBorder;
77      break;
78    }
79    case FWL_WGTCAPACITY_CYBorder: {
80      m_fValue = FWLTHEME_CAPACITY_CYBorder;
81      break;
82    }
83    case FWL_WGTCAPACITY_EdgeFlat: {
84      m_fValue = FWLTHEME_CAPACITY_EdgeFlat;
85      break;
86    }
87    case FWL_WGTCAPACITY_EdgeRaised: {
88      m_fValue = FWLTHEME_CAPACITY_EdgeRaised;
89      break;
90    }
91    case FWL_WGTCAPACITY_EdgeSunken: {
92      m_fValue = FWLTHEME_CAPACITY_EdgeSunken;
93      break;
94    }
95    case FWL_WGTCAPACITY_FontSize: {
96      m_fValue = FWLTHEME_CAPACITY_FontSize;
97      break;
98    }
99    case FWL_WGTCAPACITY_TextColor: {
100      m_dwValue = FWLTHEME_CAPACITY_TextColor;
101      return &m_dwValue;
102    }
103    case FWL_WGTCAPACITY_ScrollBarWidth: {
104      m_fValue = FWLTHEME_CAPACITY_ScrollBarWidth;
105      break;
106    }
107    case FWL_WGTCAPACITY_Font: {
108      return m_pFDEFont;
109    }
110    case FWL_WGTCAPACITY_TextSelColor: {
111      m_dwValue = (m_dwThemeID == 0) ? FWLTHEME_CAPACITY_TextSelColor
112                                     : FWLTHEME_COLOR_Green_BKSelected;
113      return &m_dwValue;
114    }
115    case FWL_WGTCAPACITY_LineHeight: {
116      m_fValue = FWLTHEME_CAPACITY_LineHeight;
117      break;
118    }
119    case FWL_WGTCAPACITY_UIMargin: {
120      m_rtMargin.Set(0, 0, 0, 0);
121      return &m_rtMargin;
122    }
123    default: { return NULL; }
124  }
125  return &m_fValue;
126}
127FX_BOOL CFWL_WidgetTP::IsCustomizedLayout(IFWL_Widget* pWidget) {
128  return FWL_GetThemeLayout(m_dwThemeID);
129}
130FWL_ERR CFWL_WidgetTP::GetPartRect(CFWL_ThemePart* pThemePart,
131                                   CFX_RectF& rect) {
132  return FWL_ERR_Succeeded;
133}
134FX_BOOL CFWL_WidgetTP::IsInPart(CFWL_ThemePart* pThemePart,
135                                FX_FLOAT fx,
136                                FX_FLOAT fy) {
137  return TRUE;
138}
139FX_BOOL CFWL_WidgetTP::CalcTextRect(CFWL_ThemeText* pParams, CFX_RectF& rect) {
140  if (!pParams)
141    return FALSE;
142  if (!m_pTextOut)
143    return FALSE;
144  m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
145  m_pTextOut->SetStyles(pParams->m_dwTTOStyles | FDE_TTOSTYLE_ArabicContext);
146  m_pTextOut->CalcLogicSize(pParams->m_wsText, pParams->m_wsText.GetLength(),
147                            rect);
148  return TRUE;
149}
150FWL_ERR CFWL_WidgetTP::Initialize() {
151  m_dwThemeID = 0;
152  _ctm.SetIdentity();
153  return FWL_ERR_Succeeded;
154}
155FWL_ERR CFWL_WidgetTP::Finalize() {
156  if (!m_pTextOut) {
157    FinalizeTTO();
158  }
159  return FWL_ERR_Succeeded;
160}
161CFWL_WidgetTP::~CFWL_WidgetTP() {}
162FWL_ERR CFWL_WidgetTP::SetFont(IFWL_Widget* pWidget,
163                               const FX_WCHAR* strFont,
164                               FX_FLOAT fFontSize,
165                               FX_ARGB rgbFont) {
166  if (!m_pTextOut) {
167    return FWL_ERR_Succeeded;
168  }
169  m_pFDEFont = FWL_GetFontManager()->FindFont(strFont, 0, 0);
170  m_pTextOut->SetFont(m_pFDEFont);
171  m_pTextOut->SetFontSize(fFontSize);
172  m_pTextOut->SetTextColor(rgbFont);
173  return FWL_ERR_Succeeded;
174}
175FWL_ERR CFWL_WidgetTP::SetFont(IFWL_Widget* pWidget,
176                               IFX_Font* pFont,
177                               FX_FLOAT fFontSize,
178                               FX_ARGB rgbFont) {
179  if (!m_pTextOut) {
180    return FWL_ERR_Succeeded;
181  }
182  m_pTextOut->SetFont(pFont);
183  m_pTextOut->SetFontSize(fFontSize);
184  m_pTextOut->SetTextColor(rgbFont);
185  return FWL_ERR_Succeeded;
186}
187IFX_Font* CFWL_WidgetTP::GetFont(IFWL_Widget* pWidget) {
188  return m_pFDEFont;
189}
190CFWL_WidgetTP::CFWL_WidgetTP()
191    : m_dwRefCount(1), m_pTextOut(NULL), m_pFDEFont(NULL), m_dwThemeID(0) {}
192FX_ERR CFWL_WidgetTP::InitTTO() {
193  if (m_pTextOut) {
194    return FWL_ERR_Succeeded;
195  }
196  m_pFDEFont = FWL_GetFontManager()->FindFont(FX_WSTRC(L"Helvetica"), 0, 0);
197  m_pTextOut = IFDE_TextOut::Create();
198  m_pTextOut->SetFont(m_pFDEFont);
199  m_pTextOut->SetFontSize(FWLTHEME_CAPACITY_FontSize);
200  m_pTextOut->SetTextColor(FWLTHEME_CAPACITY_TextColor);
201  m_pTextOut->SetEllipsisString(L"...");
202  return FWL_ERR_Succeeded;
203}
204FX_ERR CFWL_WidgetTP::FinalizeTTO() {
205  if (m_pTextOut) {
206    m_pTextOut->Release();
207    m_pTextOut = NULL;
208  }
209  return FWL_ERR_Succeeded;
210}
211#ifdef THEME_XPSimilar
212void CFWL_WidgetTP::DrawEdge(CFX_Graphics* pGraphics,
213                             FX_DWORD dwStyles,
214                             const CFX_RectF* pRect,
215                             CFX_Matrix* pMatrix) {
216  if (!pGraphics)
217    return;
218  if (!pRect)
219    return;
220  pGraphics->SaveGraphState();
221  CFX_Color crStroke(FWL_GetThemeColor(m_dwThemeID) == 0
222                         ? ArgbEncode(255, 127, 157, 185)
223                         : FWLTHEME_COLOR_Green_BKSelected);
224  pGraphics->SetStrokeColor(&crStroke);
225  CFX_Path path;
226  path.Create();
227  path.AddRectangle(pRect->left, pRect->top, pRect->width - 1,
228                    pRect->height - 1);
229  pGraphics->StrokePath(&path, pMatrix);
230  path.Clear();
231  crStroke = ArgbEncode(255, 255, 255, 255);
232  pGraphics->SetStrokeColor(&crStroke);
233  path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 3,
234                    pRect->height - 3);
235  pGraphics->StrokePath(&path, pMatrix);
236  pGraphics->RestoreGraphState();
237}
238#else
239void CFWL_WidgetTP::DrawEdge(CFX_Graphics* pGraphics,
240                             FX_DWORD dwStyles,
241                             const CFX_RectF* pRect,
242                             CFX_Matrix* pMatrix) {
243  if (!pGraphics)
244    return;
245  if (!pRect)
246    return;
247  FWLTHEME_EDGE eType;
248  FX_FLOAT fWidth;
249  switch (dwStyles & FWL_WGTSTYLE_EdgeMask) {
250    case FWL_WGTSTYLE_EdgeRaised: {
251      eType = FWLTHEME_EDGE_Raised, fWidth = FWLTHEME_CAPACITY_EdgeRaised;
252      break;
253    }
254    case FWL_WGTSTYLE_EdgeSunken: {
255      eType = FWLTHEME_EDGE_Sunken, fWidth = FWLTHEME_CAPACITY_EdgeSunken;
256      break;
257    }
258    case FWL_WGTSTYLE_EdgeFlat:
259    default: { return; }
260  }
261  Draw3DRect(pGraphics, eType, fWidth, pRect, FWLTHEME_COLOR_EDGELT1,
262             FWLTHEME_COLOR_EDGELT2, FWLTHEME_COLOR_EDGERB1,
263             FWLTHEME_COLOR_EDGERB2, pMatrix);
264}
265#endif
266void CFWL_WidgetTP::Draw3DRect(CFX_Graphics* pGraphics,
267                               FWLTHEME_EDGE eType,
268                               FX_FLOAT fWidth,
269                               const CFX_RectF* pRect,
270                               FX_ARGB cr1,
271                               FX_ARGB cr2,
272                               FX_ARGB cr3,
273                               FX_ARGB cr4,
274                               CFX_Matrix* pMatrix) {
275  if (!pGraphics)
276    return;
277  if (!pRect)
278    return;
279  pGraphics->SaveGraphState();
280  if (eType == FWLTHEME_EDGE_Flat) {
281    CFX_Path path;
282    path.Create();
283    path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
284    path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 2,
285                      pRect->height - 2);
286    CFX_Color cr(ArgbEncode(255, 100, 100, 100));
287    pGraphics->SetFillColor(&cr);
288    pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
289    path.Clear();
290    path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 2,
291                      pRect->height - 2);
292    path.AddRectangle(pRect->left + 2, pRect->top + 2, pRect->width - 4,
293                      pRect->height - 4);
294    cr.Set(0xFFFFFFFF);
295    pGraphics->SetFillColor(&cr);
296    pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
297  } else {
298    FX_FLOAT fLeft = pRect->left;
299    FX_FLOAT fRight = pRect->right();
300    FX_FLOAT fTop = pRect->top;
301    FX_FLOAT fBottom = pRect->bottom();
302    FX_FLOAT fHalfWidth = fWidth / 2.0f;
303    CFX_Color crLT(eType == FWLTHEME_EDGE_Raised ? cr4 : cr1);
304    pGraphics->SetFillColor(&crLT);
305    CFX_Path pathLT;
306    pathLT.Create();
307    pathLT.MoveTo(fLeft, fBottom - fHalfWidth);
308    pathLT.LineTo(fLeft, fTop);
309    pathLT.LineTo(fRight - fHalfWidth, fTop);
310    pathLT.LineTo(fRight - fHalfWidth, fTop + fHalfWidth);
311    pathLT.LineTo(fLeft + fHalfWidth, fTop + fHalfWidth);
312    pathLT.LineTo(fLeft + fHalfWidth, fBottom - fHalfWidth);
313    pathLT.LineTo(fLeft, fBottom - fHalfWidth);
314    pGraphics->FillPath(&pathLT, FXFILL_WINDING, pMatrix);
315    crLT = CFX_Color(eType == FWLTHEME_EDGE_Raised ? cr3 : cr2);
316    pGraphics->SetFillColor(&crLT);
317    pathLT.Clear();
318    pathLT.MoveTo(fLeft + fHalfWidth, fBottom - fWidth);
319    pathLT.LineTo(fLeft + fHalfWidth, fTop + fHalfWidth);
320    pathLT.LineTo(fRight - fWidth, fTop + fHalfWidth);
321    pathLT.LineTo(fRight - fWidth, fTop + fWidth);
322    pathLT.LineTo(fLeft + fWidth, fTop + fWidth);
323    pathLT.LineTo(fLeft + fWidth, fBottom - fWidth);
324    pathLT.LineTo(fLeft + fHalfWidth, fBottom - fWidth);
325    pGraphics->FillPath(&pathLT, FXFILL_WINDING, pMatrix);
326    CFX_Color crRB(eType == FWLTHEME_EDGE_Raised ? cr1 : cr3);
327    pGraphics->SetFillColor(&crRB);
328    CFX_Path pathRB;
329    pathRB.Create();
330    pathRB.MoveTo(fRight - fHalfWidth, fTop + fHalfWidth);
331    pathRB.LineTo(fRight - fHalfWidth, fBottom - fHalfWidth);
332    pathRB.LineTo(fLeft + fHalfWidth, fBottom - fHalfWidth);
333    pathRB.LineTo(fLeft + fHalfWidth, fBottom - fWidth);
334    pathRB.LineTo(fRight - fWidth, fBottom - fWidth);
335    pathRB.LineTo(fRight - fWidth, fTop + fHalfWidth);
336    pathRB.LineTo(fRight - fHalfWidth, fTop + fHalfWidth);
337    pGraphics->FillPath(&pathRB, FXFILL_WINDING, pMatrix);
338    crRB = CFX_Color(eType == FWLTHEME_EDGE_Raised ? cr2 : cr4);
339    pGraphics->SetFillColor(&crRB);
340    pathRB.Clear();
341    pathRB.MoveTo(fRight, fTop);
342    pathRB.LineTo(fRight, fBottom);
343    pathRB.LineTo(fLeft, fBottom);
344    pathRB.LineTo(fLeft, fBottom - fHalfWidth);
345    pathRB.LineTo(fRight - fHalfWidth, fBottom - fHalfWidth);
346    pathRB.LineTo(fRight - fHalfWidth, fTop);
347    pathRB.LineTo(fRight, fTop);
348    pGraphics->FillPath(&pathRB, FXFILL_WINDING, pMatrix);
349  }
350  pGraphics->RestoreGraphState();
351}
352void CFWL_WidgetTP::Draw3DCircle(CFX_Graphics* pGraphics,
353                                 FWLTHEME_EDGE eType,
354                                 FX_FLOAT fWidth,
355                                 const CFX_RectF* pRect,
356                                 FX_ARGB cr1,
357                                 FX_ARGB cr2,
358                                 FX_ARGB cr3,
359                                 FX_ARGB cr4,
360                                 CFX_Matrix* pMatrix) {
361  if (!pGraphics)
362    return;
363  if (!pRect)
364    return;
365  pGraphics->SaveGraphState();
366  CFX_Path path;
367  path.Create();
368  path.AddArc(pRect->left, pRect->top, pRect->width, pRect->height,
369              FWLTHEME_PI * 3 / 4, FWLTHEME_PI);
370  CFX_Color crFill1(eType == FWLTHEME_EDGE_Raised ? cr4 : cr1);
371  pGraphics->SetStrokeColor(&crFill1);
372  pGraphics->StrokePath(&path, pMatrix);
373  CFX_RectF rtInner(*pRect);
374  rtInner.Deflate(pRect->width / 4, pRect->height / 4);
375  path.Clear();
376  path.AddArc(rtInner.left, rtInner.top, rtInner.width, rtInner.height,
377              FWLTHEME_PI * 3 / 4, FWLTHEME_PI);
378  CFX_Color crFill2(eType == FWLTHEME_EDGE_Raised ? cr3 : cr2);
379  pGraphics->SetStrokeColor(&crFill2);
380  pGraphics->StrokePath(&path, pMatrix);
381  path.Clear();
382  path.AddArc(pRect->left, pRect->top, pRect->width, pRect->height,
383              FWLTHEME_PI * 7 / 4, FWLTHEME_PI);
384  CFX_Color crFill3(eType == FWLTHEME_EDGE_Raised ? cr1 : cr3);
385  pGraphics->SetStrokeColor(&crFill3);
386  pGraphics->StrokePath(&path, pMatrix);
387  path.AddArc(rtInner.left, rtInner.top, rtInner.width, rtInner.height,
388              FWLTHEME_PI * 7 / 4, FWLTHEME_PI);
389  CFX_Color crFill4(eType == FWLTHEME_EDGE_Raised ? cr2 : cr4);
390  pGraphics->SetStrokeColor(&crFill4);
391  pGraphics->StrokePath(&path, pMatrix);
392  pGraphics->RestoreGraphState();
393}
394void CFWL_WidgetTP::DrawBorder(CFX_Graphics* pGraphics,
395                               const CFX_RectF* pRect,
396                               CFX_Matrix* pMatrix) {
397  if (!pGraphics)
398    return;
399  if (!pRect)
400    return;
401  CFX_Path path;
402  path.Create();
403  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
404  path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 2,
405                    pRect->height - 2);
406  pGraphics->SaveGraphState();
407  CFX_Color crFill(ArgbEncode(255, 0, 0, 0));
408  pGraphics->SetFillColor(&crFill);
409  pGraphics->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
410  pGraphics->RestoreGraphState();
411}
412void CFWL_WidgetTP::FillBackground(CFX_Graphics* pGraphics,
413                                   const CFX_RectF* pRect,
414                                   CFX_Matrix* pMatrix) {
415  FillSoildRect(pGraphics, FWLTHEME_COLOR_Background, pRect, pMatrix);
416}
417void CFWL_WidgetTP::FillSoildRect(CFX_Graphics* pGraphics,
418                                  FX_ARGB fillColor,
419                                  const CFX_RectF* pRect,
420                                  CFX_Matrix* pMatrix) {
421  if (!pGraphics)
422    return;
423  if (!pRect)
424    return;
425  pGraphics->SaveGraphState();
426  CFX_Color crFill(fillColor);
427  pGraphics->SetFillColor(&crFill);
428  CFX_Path path;
429  path.Create();
430  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
431  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
432  pGraphics->RestoreGraphState();
433}
434void CFWL_WidgetTP::DrawAxialShading(CFX_Graphics* pGraphics,
435                                     FX_FLOAT fx1,
436                                     FX_FLOAT fy1,
437                                     FX_FLOAT fx2,
438                                     FX_FLOAT fy2,
439                                     FX_ARGB beginColor,
440                                     FX_ARGB endColor,
441                                     CFX_Path* path,
442                                     int32_t fillMode,
443                                     CFX_Matrix* pMatrix) {
444  if (!pGraphics)
445    return;
446  if (!path)
447    return;
448  CFX_PointF begPoint, endPoint;
449  begPoint.Set(fx1, fy1);
450  endPoint.Set(fx2, fy2);
451  CFX_Shading shading;
452  shading.CreateAxial(begPoint, endPoint, FALSE, FALSE, beginColor, endColor);
453  pGraphics->SaveGraphState();
454  CFX_Color color1(&shading);
455  pGraphics->SetFillColor(&color1);
456  pGraphics->FillPath(path, fillMode, pMatrix);
457  pGraphics->RestoreGraphState();
458}
459void CFWL_WidgetTP::DrawAnnulusRect(CFX_Graphics* pGraphics,
460                                    FX_ARGB fillColor,
461                                    const CFX_RectF* pRect,
462                                    FX_FLOAT fRingWidth,
463                                    CFX_Matrix* pMatrix) {
464  if (!pGraphics)
465    return;
466  if (!pRect)
467    return;
468  pGraphics->SaveGraphState();
469  CFX_Color cr(fillColor);
470  pGraphics->SetFillColor(&cr);
471  CFX_Path path;
472  path.Create();
473  CFX_RectF rtInner(*pRect);
474  rtInner.Deflate(fRingWidth, fRingWidth);
475  path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
476  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
477  pGraphics->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
478  pGraphics->RestoreGraphState();
479}
480void CFWL_WidgetTP::DrawAnnulusCircle(CFX_Graphics* pGraphics,
481                                      FX_ARGB fillColor,
482                                      const CFX_RectF* pRect,
483                                      FX_FLOAT fWidth,
484                                      CFX_Matrix* pMatrix) {
485  if (!pGraphics)
486    return;
487  if (!pRect)
488    return;
489  if (fWidth > pRect->width / 2) {
490    return;
491  }
492  pGraphics->SaveGraphState();
493  CFX_Color cr(fillColor);
494  pGraphics->SetFillColor(&cr);
495  CFX_Path path;
496  path.Create();
497  path.AddEllipse(*pRect);
498  CFX_RectF rtIn(*pRect);
499  rtIn.Inflate(-fWidth, -fWidth);
500  path.AddEllipse(rtIn);
501  pGraphics->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
502  pGraphics->RestoreGraphState();
503}
504void CFWL_WidgetTP::DrawFocus(CFX_Graphics* pGraphics,
505                              const CFX_RectF* pRect,
506                              CFX_Matrix* pMatrix) {
507  if (!pGraphics)
508    return;
509  if (!pRect)
510    return;
511  pGraphics->SaveGraphState();
512  CFX_Color cr(0xFF000000);
513  pGraphics->SetStrokeColor(&cr);
514  FX_FLOAT DashPattern[2] = {1, 1};
515  pGraphics->SetLineDash(0.0f, DashPattern, 2);
516  CFX_Path path;
517  path.Create();
518  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
519  pGraphics->StrokePath(&path, pMatrix);
520  pGraphics->RestoreGraphState();
521}
522#define FWLTHEME_ARROW_Denominator 3
523void CFWL_WidgetTP::DrawArrow(CFX_Graphics* pGraphics,
524                              const CFX_RectF* pRect,
525                              FWLTHEME_DIRECTION eDict,
526                              FX_ARGB argbFill,
527                              FX_BOOL bPressed,
528                              CFX_Matrix* pMatrix) {
529  CFX_RectF rtArrow(*pRect);
530  CFX_Path path;
531  path.Create();
532  FX_FLOAT fBtn =
533      std::min(pRect->width, pRect->height) / FWLTHEME_ARROW_Denominator;
534  rtArrow.left = pRect->left + (pRect->width - fBtn) / 2;
535  rtArrow.top = pRect->top + (pRect->height - fBtn) / 2;
536  rtArrow.width = fBtn;
537  rtArrow.height = fBtn;
538  if (bPressed) {
539    rtArrow.Offset(1, 1);
540  }
541  switch (eDict) {
542    case FWLTHEME_DIRECTION_Up: {
543      path.MoveTo(rtArrow.left, rtArrow.bottom());
544      path.LineTo(rtArrow.right(), rtArrow.bottom());
545      path.LineTo(rtArrow.left + fBtn / 2, rtArrow.top);
546      path.LineTo(rtArrow.left, rtArrow.bottom());
547      break;
548    }
549    case FWLTHEME_DIRECTION_Left: {
550      path.MoveTo(rtArrow.right(), rtArrow.top);
551      path.LineTo(rtArrow.right(), rtArrow.bottom());
552      path.LineTo(rtArrow.left, rtArrow.top + fBtn / 2);
553      path.LineTo(rtArrow.right(), rtArrow.top);
554      break;
555    }
556    case FWLTHEME_DIRECTION_Right: {
557      path.MoveTo(rtArrow.left, rtArrow.top);
558      path.LineTo(rtArrow.left, rtArrow.bottom());
559      path.LineTo(rtArrow.right(), rtArrow.top + fBtn / 2);
560      path.LineTo(rtArrow.left, rtArrow.top);
561      break;
562    }
563    case FWLTHEME_DIRECTION_Down:
564    default: {
565      path.MoveTo(rtArrow.left, rtArrow.top);
566      path.LineTo(rtArrow.right(), rtArrow.top);
567      path.LineTo(rtArrow.left + fBtn / 2, rtArrow.bottom());
568      path.LineTo(rtArrow.left, rtArrow.top);
569    }
570  }
571  pGraphics->SaveGraphState();
572  CFX_Color cr(argbFill);
573  pGraphics->SetFillColor(&cr);
574  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
575  pGraphics->RestoreGraphState();
576}
577void CFWL_WidgetTP::DrawArrow(CFX_Graphics* pGraphics,
578                              const CFX_RectF* pRect,
579                              FWLTHEME_DIRECTION eDict,
580                              FX_ARGB argSign,
581                              CFX_Matrix* pMatrix) {
582  FX_BOOL bVert =
583      (eDict == FWLTHEME_DIRECTION_Up || eDict == FWLTHEME_DIRECTION_Down);
584  FX_FLOAT fLeft =
585      (FX_FLOAT)(((pRect->width - (bVert ? 9 : 6)) / 2 + pRect->left) + 0.5);
586  FX_FLOAT fTop =
587      (FX_FLOAT)(((pRect->height - (bVert ? 6 : 9)) / 2 + pRect->top) + 0.5);
588  CFX_Path path;
589  path.Create();
590  switch (eDict) {
591    case FWLTHEME_DIRECTION_Down: {
592      path.MoveTo(fLeft, fTop + 1);
593      path.LineTo(fLeft + 4, fTop + 5);
594      path.LineTo(fLeft + 8, fTop + 1);
595      path.LineTo(fLeft + 7, fTop);
596      path.LineTo(fLeft + 4, fTop + 3);
597      path.LineTo(fLeft + 1, fTop);
598      break;
599    }
600    case FWLTHEME_DIRECTION_Up: {
601      path.MoveTo(fLeft, fTop + 4);
602      path.LineTo(fLeft + 4, fTop);
603      path.LineTo(fLeft + 8, fTop + 4);
604      path.LineTo(fLeft + 7, fTop + 5);
605      path.LineTo(fLeft + 4, fTop + 2);
606      path.LineTo(fLeft + 1, fTop + 5);
607      break;
608    }
609    case FWLTHEME_DIRECTION_Right: {
610      path.MoveTo(fLeft + 1, fTop);
611      path.LineTo(fLeft + 5, fTop + 4);
612      path.LineTo(fLeft + 1, fTop + 8);
613      path.LineTo(fLeft, fTop + 7);
614      path.LineTo(fLeft + 3, fTop + 4);
615      path.LineTo(fLeft, fTop + 1);
616      break;
617    }
618    case FWLTHEME_DIRECTION_Left: {
619      path.MoveTo(fLeft, fTop + 4);
620      path.LineTo(fLeft + 4, fTop);
621      path.LineTo(fLeft + 5, fTop + 1);
622      path.LineTo(fLeft + 2, fTop + 4);
623      path.LineTo(fLeft + 5, fTop + 7);
624      path.LineTo(fLeft + 4, fTop + 8);
625      break;
626    }
627  }
628  CFX_Color cr(argSign);
629  pGraphics->SetFillColor(&cr);
630  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
631}
632void CFWL_WidgetTP::DrawBtn(CFX_Graphics* pGraphics,
633                            const CFX_RectF* pRect,
634                            FWLTHEME_STATE eState,
635                            CFX_Matrix* pMatrix) {
636  CFX_Path path;
637  path.Create();
638  if (!CFWL_ArrowData::IsInstance()) {
639    CFWL_ArrowData::GetInstance()->SetColorData(FWL_GetThemeColor(m_dwThemeID));
640  }
641  CFWL_ArrowData::CColorData* pColorData =
642      CFWL_ArrowData::GetInstance()->m_pColorData;
643  FX_FLOAT fRight = pRect->right();
644  FX_FLOAT fBottom = pRect->bottom();
645  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
646  DrawAxialShading(pGraphics, pRect->left, pRect->top, fRight, fBottom,
647                   pColorData->clrStart[eState - 1],
648                   pColorData->clrEnd[eState - 1], &path, FXFILL_WINDING,
649                   pMatrix);
650  CFX_Color rcStroke;
651  rcStroke.Set(pColorData->clrBorder[eState - 1]);
652  pGraphics->SetStrokeColor(&rcStroke);
653  pGraphics->StrokePath(&path, pMatrix);
654}
655void CFWL_WidgetTP::DrawArrowBtn(CFX_Graphics* pGraphics,
656                                 const CFX_RectF* pRect,
657                                 FWLTHEME_DIRECTION eDict,
658                                 FWLTHEME_STATE eState,
659                                 CFX_Matrix* pMatrix) {
660  DrawBtn(pGraphics, pRect, eState, pMatrix);
661  if (!CFWL_ArrowData::IsInstance()) {
662    CFWL_ArrowData::GetInstance()->SetColorData(FWL_GetThemeColor(m_dwThemeID));
663  }
664  CFWL_ArrowData::CColorData* pColorData =
665      CFWL_ArrowData::GetInstance()->m_pColorData;
666  DrawArrow(pGraphics, pRect, eDict, pColorData->clrSign[eState - 1], pMatrix);
667}
668FWLCOLOR CFWL_WidgetTP::BlendColor(FWLCOLOR srcColor,
669                                   FWLCOLOR renderColor,
670                                   uint8_t scale) {
671  FWLCOLOR dstColor;
672  uint8_t n = 255 - scale;
673  dstColor.a = (uint8_t)(
674      ((FX_WORD)srcColor.a * n + (FX_WORD)renderColor.a * scale) >> 8);
675  dstColor.r = (uint8_t)(
676      ((FX_WORD)srcColor.r * n + (FX_WORD)renderColor.r * scale) >> 8);
677  dstColor.g = (uint8_t)(
678      ((FX_WORD)srcColor.g * n + (FX_WORD)renderColor.g * scale) >> 8);
679  dstColor.b = (uint8_t)(
680      ((FX_WORD)srcColor.b * n + (FX_WORD)renderColor.b * scale) >> 8);
681  return dstColor;
682}
683CFWL_ArrowData::CFWL_ArrowData() : m_pColorData(NULL) {
684  SetColorData(0);
685}
686CFWL_FontManager* FWL_GetFontManager() {
687  static CFWL_FontManager* _fontManager = NULL;
688  if (_fontManager == NULL) {
689    _fontManager = new CFWL_FontManager;
690  }
691  return _fontManager;
692}
693void FWL_ReleaseFontManager() {
694  CFWL_FontManager* fontManager = FWL_GetFontManager();
695  delete fontManager;
696}
697CFWL_FontData::CFWL_FontData()
698    : m_dwStyles(0),
699      m_dwCodePage(0),
700      m_pFont(0),
701      m_pFontMgr(NULL)
702#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
703      ,
704      m_pFontSource(NULL)
705#endif
706{
707}
708CFWL_FontData::~CFWL_FontData() {
709  if (m_pFont) {
710    m_pFont->Release();
711  }
712  if (m_pFontMgr) {
713    m_pFontMgr->Release();
714  }
715#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_
716  if (m_pFontSource != NULL) {
717    m_pFontSource->Release();
718  }
719#endif
720}
721FX_BOOL CFWL_FontData::Equal(const CFX_WideStringC& wsFontFamily,
722                             FX_DWORD dwFontStyles,
723                             FX_WORD wCodePage) {
724  return m_wsFamily == wsFontFamily && m_dwStyles == dwFontStyles &&
725         m_dwCodePage == wCodePage;
726}
727FX_BOOL CFWL_FontData::LoadFont(const CFX_WideStringC& wsFontFamily,
728                                FX_DWORD dwFontStyles,
729                                FX_WORD dwCodePage) {
730  m_wsFamily = wsFontFamily;
731  m_dwStyles = dwFontStyles;
732  m_dwCodePage = dwCodePage;
733  if (!m_pFontMgr) {
734#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
735    m_pFontMgr = IFX_FontMgr::Create(FX_GetDefFontEnumerator());
736#else
737    m_pFontSource = FX_CreateDefaultFontSourceEnum();
738    m_pFontMgr = IFX_FontMgr::Create(m_pFontSource);
739#endif
740  }
741  m_pFont = IFX_Font::LoadFont(wsFontFamily.GetPtr(), dwFontStyles, dwCodePage,
742                               m_pFontMgr);
743  return m_pFont != NULL;
744}
745CFWL_FontManager::CFWL_FontManager() {}
746CFWL_FontManager::~CFWL_FontManager() {
747  for (int32_t i = 0; i < m_arrFonts.GetSize(); i++) {
748    delete static_cast<CFWL_FontData*>(m_arrFonts[i]);
749  }
750  m_arrFonts.RemoveAll();
751}
752IFX_Font* CFWL_FontManager::FindFont(const CFX_WideStringC& wsFontFamily,
753                                     FX_DWORD dwFontStyles,
754                                     FX_WORD wCodePage) {
755  for (int32_t i = 0; i < m_arrFonts.GetSize(); i++) {
756    CFWL_FontData* data = static_cast<CFWL_FontData*>(m_arrFonts[i]);
757    if (data->Equal(wsFontFamily, dwFontStyles, wCodePage)) {
758      return data->GetFont();
759    }
760  }
761  CFWL_FontData* fontData = new CFWL_FontData;
762  if (!fontData->LoadFont(wsFontFamily, dwFontStyles, wCodePage)) {
763    delete fontData;
764    return NULL;
765  }
766  m_arrFonts.Add(fontData);
767  return fontData->GetFont();
768}
769FX_BOOL FWLTHEME_Init() {
770  return TRUE;
771}
772void FWLTHEME_Release() {
773  CFWL_ArrowData::DestroyInstance();
774  FWL_ReleaseFontManager();
775}
776FX_DWORD FWL_GetThemeLayout(FX_DWORD dwThemeID) {
777  return 0xffff0000 & dwThemeID;
778}
779FX_DWORD FWL_GetThemeColor(FX_DWORD dwThemeID) {
780  return 0x0000ffff & dwThemeID;
781}
782FX_DWORD FWL_MakeThemeID(FX_DWORD dwLayout, FX_DWORD dwColor) {
783  return (dwLayout << 16) | (0x0000FFFF & dwColor);
784}
785CFWL_ArrowData* CFWL_ArrowData::m_pInstance = NULL;
786CFWL_ArrowData* CFWL_ArrowData::GetInstance() {
787  if (!m_pInstance) {
788    m_pInstance = new CFWL_ArrowData;
789  }
790  return m_pInstance;
791}
792FX_BOOL CFWL_ArrowData::IsInstance() {
793  return (m_pInstance != NULL);
794}
795void CFWL_ArrowData::DestroyInstance() {
796  if (m_pInstance) {
797    delete m_pInstance;
798    m_pInstance = NULL;
799  }
800}
801CFWL_ArrowData::~CFWL_ArrowData() {
802  if (m_pColorData) {
803    delete m_pColorData;
804    m_pColorData = NULL;
805  }
806}
807void CFWL_ArrowData::SetColorData(FX_DWORD dwID) {
808  if (!m_pColorData) {
809    m_pColorData = new CColorData;
810  }
811  if (dwID) {
812    m_pColorData->clrBorder[0] = ArgbEncode(255, 142, 153, 125);
813    m_pColorData->clrBorder[1] = ArgbEncode(255, 157, 171, 119);
814    m_pColorData->clrBorder[2] = ArgbEncode(255, 118, 131, 97);
815    m_pColorData->clrBorder[3] = ArgbEncode(255, 172, 168, 153);
816    m_pColorData->clrStart[0] = ArgbEncode(255, 203, 215, 186);
817    m_pColorData->clrStart[1] = ArgbEncode(255, 218, 232, 185);
818    m_pColorData->clrStart[2] = ArgbEncode(255, 203, 215, 186);
819    m_pColorData->clrStart[3] = ArgbEncode(255, 254, 254, 251);
820    m_pColorData->clrEnd[0] = ArgbEncode(255, 149, 167, 117);
821    m_pColorData->clrEnd[1] = ArgbEncode(255, 198, 211, 155);
822    m_pColorData->clrEnd[2] = ArgbEncode(255, 149, 167, 117);
823    m_pColorData->clrEnd[3] = ArgbEncode(255, 243, 241, 236);
824    m_pColorData->clrSign[0] = ArgbEncode(255, 255, 255, 255);
825    m_pColorData->clrSign[1] = ArgbEncode(255, 255, 255, 255);
826    m_pColorData->clrSign[2] = ArgbEncode(255, 255, 255, 255);
827    m_pColorData->clrSign[3] = ArgbEncode(255, 128, 128, 128);
828  } else {
829    m_pColorData->clrBorder[0] = ArgbEncode(255, 202, 216, 249);
830    m_pColorData->clrBorder[1] = ArgbEncode(255, 171, 190, 233);
831    m_pColorData->clrBorder[2] = ArgbEncode(255, 135, 147, 219);
832    m_pColorData->clrBorder[3] = ArgbEncode(255, 172, 168, 153);
833    m_pColorData->clrStart[0] = ArgbEncode(255, 225, 234, 254);
834    m_pColorData->clrStart[1] = ArgbEncode(255, 253, 255, 255);
835    m_pColorData->clrStart[2] = ArgbEncode(255, 110, 142, 241);
836    m_pColorData->clrStart[3] = ArgbEncode(255, 254, 254, 251);
837    m_pColorData->clrEnd[0] = ArgbEncode(255, 175, 204, 251);
838    m_pColorData->clrEnd[1] = ArgbEncode(255, 185, 218, 251);
839    m_pColorData->clrEnd[2] = ArgbEncode(255, 210, 222, 235);
840    m_pColorData->clrEnd[3] = ArgbEncode(255, 243, 241, 236);
841    m_pColorData->clrSign[0] = ArgbEncode(255, 77, 97, 133);
842    m_pColorData->clrSign[1] = ArgbEncode(255, 77, 97, 133);
843    m_pColorData->clrSign[2] = ArgbEncode(255, 77, 97, 133);
844    m_pColorData->clrSign[3] = ArgbEncode(255, 128, 128, 128);
845  }
846}
847