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 "core/fxcrt/css/cfx_cssstyleselector.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/css/cfx_csscolorvalue.h"
13 #include "core/fxcrt/css/cfx_csscomputedstyle.h"
14 #include "core/fxcrt/css/cfx_csscustomproperty.h"
15 #include "core/fxcrt/css/cfx_cssdeclaration.h"
16 #include "core/fxcrt/css/cfx_cssenumvalue.h"
17 #include "core/fxcrt/css/cfx_csspropertyholder.h"
18 #include "core/fxcrt/css/cfx_cssselector.h"
19 #include "core/fxcrt/css/cfx_cssstylesheet.h"
20 #include "core/fxcrt/css/cfx_csssyntaxparser.h"
21 #include "core/fxcrt/css/cfx_cssvaluelist.h"
22 #include "third_party/base/logging.h"
23 #include "third_party/base/ptr_util.h"
24 
CFX_CSSStyleSelector()25 CFX_CSSStyleSelector::CFX_CSSStyleSelector() : m_fDefFontSize(12.0f) {}
26 
~CFX_CSSStyleSelector()27 CFX_CSSStyleSelector::~CFX_CSSStyleSelector() {}
28 
SetDefFontSize(float fFontSize)29 void CFX_CSSStyleSelector::SetDefFontSize(float fFontSize) {
30   ASSERT(fFontSize > 0);
31   m_fDefFontSize = fFontSize;
32 }
33 
CreateComputedStyle(CFX_CSSComputedStyle * pParentStyle)34 RetainPtr<CFX_CSSComputedStyle> CFX_CSSStyleSelector::CreateComputedStyle(
35     CFX_CSSComputedStyle* pParentStyle) {
36   auto pStyle = pdfium::MakeRetain<CFX_CSSComputedStyle>();
37   if (pParentStyle)
38     pStyle->m_InheritedData = pParentStyle->m_InheritedData;
39   return pStyle;
40 }
41 
SetUAStyleSheet(std::unique_ptr<CFX_CSSStyleSheet> pSheet)42 void CFX_CSSStyleSelector::SetUAStyleSheet(
43     std::unique_ptr<CFX_CSSStyleSheet> pSheet) {
44   m_UAStyles = std::move(pSheet);
45 }
46 
UpdateStyleIndex()47 void CFX_CSSStyleSelector::UpdateStyleIndex() {
48   m_UARules.Clear();
49   m_UARules.AddRulesFrom(m_UAStyles.get());
50 }
51 
MatchDeclarations(const WideString & tagname)52 std::vector<const CFX_CSSDeclaration*> CFX_CSSStyleSelector::MatchDeclarations(
53     const WideString& tagname) {
54   std::vector<const CFX_CSSDeclaration*> matchedDecls;
55   if (m_UARules.CountSelectors() == 0 || tagname.IsEmpty())
56     return matchedDecls;
57 
58   auto* rules = m_UARules.GetTagRuleData(tagname);
59   if (!rules)
60     return matchedDecls;
61 
62   for (const auto& d : *rules) {
63     if (MatchSelector(tagname, d->pSelector))
64       matchedDecls.push_back(d->pDeclaration);
65   }
66   return matchedDecls;
67 }
68 
MatchSelector(const WideString & tagname,CFX_CSSSelector * pSel)69 bool CFX_CSSStyleSelector::MatchSelector(const WideString& tagname,
70                                          CFX_CSSSelector* pSel) {
71   // TODO(dsinclair): The code only supports a single level of selector at this
72   // point. None of the code using selectors required the complexity so lets
73   // just say we don't support them to simplify the code for now.
74   if (!pSel || pSel->GetNextSelector() ||
75       pSel->GetType() == CFX_CSSSelectorType::Descendant) {
76     return false;
77   }
78   return pSel->GetNameHash() == FX_HashCode_GetW(tagname.AsStringView(), true);
79 }
80 
ComputeStyle(const std::vector<const CFX_CSSDeclaration * > & declArray,const WideString & styleString,const WideString & alignString,CFX_CSSComputedStyle * pDest)81 void CFX_CSSStyleSelector::ComputeStyle(
82     const std::vector<const CFX_CSSDeclaration*>& declArray,
83     const WideString& styleString,
84     const WideString& alignString,
85     CFX_CSSComputedStyle* pDest) {
86   std::unique_ptr<CFX_CSSDeclaration> pDecl;
87   if (!styleString.IsEmpty() || !alignString.IsEmpty()) {
88     pDecl = pdfium::MakeUnique<CFX_CSSDeclaration>();
89 
90     if (!styleString.IsEmpty())
91       AppendInlineStyle(pDecl.get(), styleString);
92     if (!alignString.IsEmpty()) {
93       pDecl->AddProperty(
94           CFX_CSSData::GetPropertyByEnum(CFX_CSSProperty::TextAlign),
95           alignString.AsStringView());
96     }
97   }
98   ApplyDeclarations(declArray, pDecl.get(), pDest);
99 }
100 
ApplyDeclarations(const std::vector<const CFX_CSSDeclaration * > & declArray,const CFX_CSSDeclaration * extraDecl,CFX_CSSComputedStyle * pComputedStyle)101 void CFX_CSSStyleSelector::ApplyDeclarations(
102     const std::vector<const CFX_CSSDeclaration*>& declArray,
103     const CFX_CSSDeclaration* extraDecl,
104     CFX_CSSComputedStyle* pComputedStyle) {
105   std::vector<const CFX_CSSPropertyHolder*> importants;
106   std::vector<const CFX_CSSPropertyHolder*> normals;
107   std::vector<const CFX_CSSCustomProperty*> customs;
108 
109   for (auto* decl : declArray)
110     ExtractValues(decl, &importants, &normals, &customs);
111 
112   if (extraDecl)
113     ExtractValues(extraDecl, &importants, &normals, &customs);
114 
115   for (auto* prop : normals)
116     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
117 
118   for (auto* prop : customs)
119     pComputedStyle->AddCustomStyle(*prop);
120 
121   for (auto* prop : importants)
122     ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle);
123 }
124 
ExtractValues(const CFX_CSSDeclaration * decl,std::vector<const CFX_CSSPropertyHolder * > * importants,std::vector<const CFX_CSSPropertyHolder * > * normals,std::vector<const CFX_CSSCustomProperty * > * custom)125 void CFX_CSSStyleSelector::ExtractValues(
126     const CFX_CSSDeclaration* decl,
127     std::vector<const CFX_CSSPropertyHolder*>* importants,
128     std::vector<const CFX_CSSPropertyHolder*>* normals,
129     std::vector<const CFX_CSSCustomProperty*>* custom) {
130   for (const auto& holder : *decl) {
131     if (holder->bImportant)
132       importants->push_back(holder.get());
133     else
134       normals->push_back(holder.get());
135   }
136   for (auto it = decl->custom_begin(); it != decl->custom_end(); it++)
137     custom->push_back(it->get());
138 }
139 
AppendInlineStyle(CFX_CSSDeclaration * pDecl,const WideString & style)140 void CFX_CSSStyleSelector::AppendInlineStyle(CFX_CSSDeclaration* pDecl,
141                                              const WideString& style) {
142   ASSERT(pDecl);
143   ASSERT(!style.IsEmpty());
144 
145   auto pSyntax = pdfium::MakeUnique<CFX_CSSSyntaxParser>(
146       style.c_str(), style.GetLength(), 32, true);
147   int32_t iLen2 = 0;
148   const CFX_CSSData::Property* property = nullptr;
149   WideString wsName;
150   while (1) {
151     CFX_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse();
152     if (eStatus == CFX_CSSSyntaxStatus::PropertyName) {
153       WideStringView strValue = pSyntax->GetCurrentString();
154       property = CFX_CSSData::GetPropertyByName(strValue);
155       if (!property)
156         wsName = WideString(strValue);
157     } else if (eStatus == CFX_CSSSyntaxStatus::PropertyValue) {
158       if (property || iLen2 > 0) {
159         WideStringView strValue = pSyntax->GetCurrentString();
160         if (!strValue.IsEmpty()) {
161           if (property)
162             pDecl->AddProperty(property, strValue);
163           else if (iLen2 > 0)
164             pDecl->AddProperty(wsName, WideString(strValue));
165         }
166       }
167     } else {
168       break;
169     }
170   }
171 }
172 
ApplyProperty(CFX_CSSProperty eProperty,const RetainPtr<CFX_CSSValue> & pValue,CFX_CSSComputedStyle * pComputedStyle)173 void CFX_CSSStyleSelector::ApplyProperty(CFX_CSSProperty eProperty,
174                                          const RetainPtr<CFX_CSSValue>& pValue,
175                                          CFX_CSSComputedStyle* pComputedStyle) {
176   if (pValue->GetType() != CFX_CSSPrimitiveType::List) {
177     CFX_CSSPrimitiveType eType = pValue->GetType();
178     switch (eProperty) {
179       case CFX_CSSProperty::Display:
180         if (eType == CFX_CSSPrimitiveType::Enum) {
181           pComputedStyle->m_NonInheritedData.m_eDisplay =
182               ToDisplay(pValue.As<CFX_CSSEnumValue>()->Value());
183         }
184         break;
185       case CFX_CSSProperty::FontSize: {
186         float& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize;
187         if (eType == CFX_CSSPrimitiveType::Number) {
188           fFontSize = pValue.As<CFX_CSSNumberValue>()->Apply(fFontSize);
189         } else if (eType == CFX_CSSPrimitiveType::Enum) {
190           fFontSize =
191               ToFontSize(pValue.As<CFX_CSSEnumValue>()->Value(), fFontSize);
192         }
193       } break;
194       case CFX_CSSProperty::LineHeight:
195         if (eType == CFX_CSSPrimitiveType::Number) {
196           RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
197           if (v->Kind() == CFX_CSSNumberType::Number) {
198             pComputedStyle->m_InheritedData.m_fLineHeight =
199                 v->Value() * pComputedStyle->m_InheritedData.m_fFontSize;
200           } else {
201             pComputedStyle->m_InheritedData.m_fLineHeight =
202                 v->Apply(pComputedStyle->m_InheritedData.m_fFontSize);
203           }
204         }
205         break;
206       case CFX_CSSProperty::TextAlign:
207         if (eType == CFX_CSSPrimitiveType::Enum) {
208           pComputedStyle->m_InheritedData.m_eTextAlign =
209               ToTextAlign(pValue.As<CFX_CSSEnumValue>()->Value());
210         }
211         break;
212       case CFX_CSSProperty::TextIndent:
213         SetLengthWithPercent(pComputedStyle->m_InheritedData.m_TextIndent,
214                              eType, pValue,
215                              pComputedStyle->m_InheritedData.m_fFontSize);
216         break;
217       case CFX_CSSProperty::FontWeight:
218         if (eType == CFX_CSSPrimitiveType::Enum) {
219           pComputedStyle->m_InheritedData.m_wFontWeight =
220               ToFontWeight(pValue.As<CFX_CSSEnumValue>()->Value());
221         } else if (eType == CFX_CSSPrimitiveType::Number) {
222           int32_t iValue =
223               (int32_t)pValue.As<CFX_CSSNumberValue>()->Value() / 100;
224           if (iValue >= 1 && iValue <= 9) {
225             pComputedStyle->m_InheritedData.m_wFontWeight = iValue * 100;
226           }
227         }
228         break;
229       case CFX_CSSProperty::FontStyle:
230         if (eType == CFX_CSSPrimitiveType::Enum) {
231           pComputedStyle->m_InheritedData.m_eFontStyle =
232               ToFontStyle(pValue.As<CFX_CSSEnumValue>()->Value());
233         }
234         break;
235       case CFX_CSSProperty::Color:
236         if (eType == CFX_CSSPrimitiveType::RGB) {
237           pComputedStyle->m_InheritedData.m_dwFontColor =
238               pValue.As<CFX_CSSColorValue>()->Value();
239         }
240         break;
241       case CFX_CSSProperty::MarginLeft:
242         if (SetLengthWithPercent(
243                 pComputedStyle->m_NonInheritedData.m_MarginWidth.left, eType,
244                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
245           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
246         }
247         break;
248       case CFX_CSSProperty::MarginTop:
249         if (SetLengthWithPercent(
250                 pComputedStyle->m_NonInheritedData.m_MarginWidth.top, eType,
251                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
252           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
253         }
254         break;
255       case CFX_CSSProperty::MarginRight:
256         if (SetLengthWithPercent(
257                 pComputedStyle->m_NonInheritedData.m_MarginWidth.right, eType,
258                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
259           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
260         }
261         break;
262       case CFX_CSSProperty::MarginBottom:
263         if (SetLengthWithPercent(
264                 pComputedStyle->m_NonInheritedData.m_MarginWidth.bottom, eType,
265                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
266           pComputedStyle->m_NonInheritedData.m_bHasMargin = true;
267         }
268         break;
269       case CFX_CSSProperty::PaddingLeft:
270         if (SetLengthWithPercent(
271                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.left, eType,
272                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
273           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
274         }
275         break;
276       case CFX_CSSProperty::PaddingTop:
277         if (SetLengthWithPercent(
278                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.top, eType,
279                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
280           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
281         }
282         break;
283       case CFX_CSSProperty::PaddingRight:
284         if (SetLengthWithPercent(
285                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.right, eType,
286                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
287           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
288         }
289         break;
290       case CFX_CSSProperty::PaddingBottom:
291         if (SetLengthWithPercent(
292                 pComputedStyle->m_NonInheritedData.m_PaddingWidth.bottom, eType,
293                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
294           pComputedStyle->m_NonInheritedData.m_bHasPadding = true;
295         }
296         break;
297       case CFX_CSSProperty::BorderLeftWidth:
298         if (SetLengthWithPercent(
299                 pComputedStyle->m_NonInheritedData.m_BorderWidth.left, eType,
300                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
301           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
302         }
303         break;
304       case CFX_CSSProperty::BorderTopWidth:
305         if (SetLengthWithPercent(
306                 pComputedStyle->m_NonInheritedData.m_BorderWidth.top, eType,
307                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
308           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
309         }
310         break;
311       case CFX_CSSProperty::BorderRightWidth:
312         if (SetLengthWithPercent(
313                 pComputedStyle->m_NonInheritedData.m_BorderWidth.right, eType,
314                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
315           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
316         }
317         break;
318       case CFX_CSSProperty::BorderBottomWidth:
319         if (SetLengthWithPercent(
320                 pComputedStyle->m_NonInheritedData.m_BorderWidth.bottom, eType,
321                 pValue, pComputedStyle->m_InheritedData.m_fFontSize)) {
322           pComputedStyle->m_NonInheritedData.m_bHasBorder = true;
323         }
324         break;
325       case CFX_CSSProperty::VerticalAlign:
326         if (eType == CFX_CSSPrimitiveType::Enum) {
327           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
328               ToVerticalAlign(pValue.As<CFX_CSSEnumValue>()->Value());
329         } else if (eType == CFX_CSSPrimitiveType::Number) {
330           pComputedStyle->m_NonInheritedData.m_eVerticalAlign =
331               CFX_CSSVerticalAlign::Number;
332           pComputedStyle->m_NonInheritedData.m_fVerticalAlign =
333               pValue.As<CFX_CSSNumberValue>()->Apply(
334                   pComputedStyle->m_InheritedData.m_fFontSize);
335         }
336         break;
337       case CFX_CSSProperty::FontVariant:
338         if (eType == CFX_CSSPrimitiveType::Enum) {
339           pComputedStyle->m_InheritedData.m_eFontVariant =
340               ToFontVariant(pValue.As<CFX_CSSEnumValue>()->Value());
341         }
342         break;
343       case CFX_CSSProperty::LetterSpacing:
344         if (eType == CFX_CSSPrimitiveType::Enum) {
345           pComputedStyle->m_InheritedData.m_LetterSpacing.Set(
346               CFX_CSSLengthUnit::Normal);
347         } else if (eType == CFX_CSSPrimitiveType::Number) {
348           if (pValue.As<CFX_CSSNumberValue>()->Kind() ==
349               CFX_CSSNumberType::Percent) {
350             break;
351           }
352 
353           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_LetterSpacing,
354                                eType, pValue,
355                                pComputedStyle->m_InheritedData.m_fFontSize);
356         }
357         break;
358       case CFX_CSSProperty::WordSpacing:
359         if (eType == CFX_CSSPrimitiveType::Enum) {
360           pComputedStyle->m_InheritedData.m_WordSpacing.Set(
361               CFX_CSSLengthUnit::Normal);
362         } else if (eType == CFX_CSSPrimitiveType::Number) {
363           if (pValue.As<CFX_CSSNumberValue>()->Kind() ==
364               CFX_CSSNumberType::Percent) {
365             break;
366           }
367           SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing,
368                                eType, pValue,
369                                pComputedStyle->m_InheritedData.m_fFontSize);
370         }
371         break;
372       case CFX_CSSProperty::Top:
373         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Top, eType,
374                              pValue,
375                              pComputedStyle->m_InheritedData.m_fFontSize);
376         break;
377       case CFX_CSSProperty::Bottom:
378         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Bottom, eType,
379                              pValue,
380                              pComputedStyle->m_InheritedData.m_fFontSize);
381         break;
382       case CFX_CSSProperty::Left:
383         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Left, eType,
384                              pValue,
385                              pComputedStyle->m_InheritedData.m_fFontSize);
386         break;
387       case CFX_CSSProperty::Right:
388         SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Right, eType,
389                              pValue,
390                              pComputedStyle->m_InheritedData.m_fFontSize);
391         break;
392       default:
393         break;
394     }
395   } else if (pValue->GetType() == CFX_CSSPrimitiveType::List) {
396     RetainPtr<CFX_CSSValueList> pList = pValue.As<CFX_CSSValueList>();
397     int32_t iCount = pList->CountValues();
398     if (iCount > 0) {
399       switch (eProperty) {
400         case CFX_CSSProperty::FontFamily:
401           pComputedStyle->m_InheritedData.m_pFontFamily = pList;
402           break;
403         case CFX_CSSProperty::TextDecoration:
404           pComputedStyle->m_NonInheritedData.m_dwTextDecoration =
405               ToTextDecoration(pList);
406           break;
407         default:
408           break;
409       }
410     }
411   } else {
412     NOTREACHED();
413   }
414 }
415 
ToDisplay(CFX_CSSPropertyValue eValue)416 CFX_CSSDisplay CFX_CSSStyleSelector::ToDisplay(CFX_CSSPropertyValue eValue) {
417   switch (eValue) {
418     case CFX_CSSPropertyValue::Block:
419       return CFX_CSSDisplay::Block;
420     case CFX_CSSPropertyValue::None:
421       return CFX_CSSDisplay::None;
422     case CFX_CSSPropertyValue::ListItem:
423       return CFX_CSSDisplay::ListItem;
424     case CFX_CSSPropertyValue::InlineTable:
425       return CFX_CSSDisplay::InlineTable;
426     case CFX_CSSPropertyValue::InlineBlock:
427       return CFX_CSSDisplay::InlineBlock;
428     case CFX_CSSPropertyValue::Inline:
429     default:
430       return CFX_CSSDisplay::Inline;
431   }
432 }
433 
ToTextAlign(CFX_CSSPropertyValue eValue)434 CFX_CSSTextAlign CFX_CSSStyleSelector::ToTextAlign(
435     CFX_CSSPropertyValue eValue) {
436   switch (eValue) {
437     case CFX_CSSPropertyValue::Center:
438       return CFX_CSSTextAlign::Center;
439     case CFX_CSSPropertyValue::Right:
440       return CFX_CSSTextAlign::Right;
441     case CFX_CSSPropertyValue::Justify:
442       return CFX_CSSTextAlign::Justify;
443     case CFX_CSSPropertyValue::Left:
444     default:
445       return CFX_CSSTextAlign::Left;
446   }
447 }
448 
ToFontWeight(CFX_CSSPropertyValue eValue)449 uint16_t CFX_CSSStyleSelector::ToFontWeight(CFX_CSSPropertyValue eValue) {
450   switch (eValue) {
451     case CFX_CSSPropertyValue::Bold:
452       return 700;
453     case CFX_CSSPropertyValue::Bolder:
454       return 900;
455     case CFX_CSSPropertyValue::Lighter:
456       return 200;
457     case CFX_CSSPropertyValue::Normal:
458     default:
459       return 400;
460   }
461 }
462 
ToFontStyle(CFX_CSSPropertyValue eValue)463 CFX_CSSFontStyle CFX_CSSStyleSelector::ToFontStyle(
464     CFX_CSSPropertyValue eValue) {
465   switch (eValue) {
466     case CFX_CSSPropertyValue::Italic:
467     case CFX_CSSPropertyValue::Oblique:
468       return CFX_CSSFontStyle::Italic;
469     default:
470       return CFX_CSSFontStyle::Normal;
471   }
472 }
473 
SetLengthWithPercent(CFX_CSSLength & width,CFX_CSSPrimitiveType eType,const RetainPtr<CFX_CSSValue> & pValue,float fFontSize)474 bool CFX_CSSStyleSelector::SetLengthWithPercent(
475     CFX_CSSLength& width,
476     CFX_CSSPrimitiveType eType,
477     const RetainPtr<CFX_CSSValue>& pValue,
478     float fFontSize) {
479   if (eType == CFX_CSSPrimitiveType::Number) {
480     RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>();
481     if (v->Kind() == CFX_CSSNumberType::Percent) {
482       width.Set(CFX_CSSLengthUnit::Percent,
483                 pValue.As<CFX_CSSNumberValue>()->Value() / 100.0f);
484       return width.NonZero();
485     }
486 
487     float fValue = v->Apply(fFontSize);
488     width.Set(CFX_CSSLengthUnit::Point, fValue);
489     return width.NonZero();
490   } else if (eType == CFX_CSSPrimitiveType::Enum) {
491     switch (pValue.As<CFX_CSSEnumValue>()->Value()) {
492       case CFX_CSSPropertyValue::Auto:
493         width.Set(CFX_CSSLengthUnit::Auto);
494         return true;
495       case CFX_CSSPropertyValue::None:
496         width.Set(CFX_CSSLengthUnit::None);
497         return true;
498       case CFX_CSSPropertyValue::Thin:
499         width.Set(CFX_CSSLengthUnit::Point, 2);
500         return true;
501       case CFX_CSSPropertyValue::Medium:
502         width.Set(CFX_CSSLengthUnit::Point, 3);
503         return true;
504       case CFX_CSSPropertyValue::Thick:
505         width.Set(CFX_CSSLengthUnit::Point, 4);
506         return true;
507       default:
508         return false;
509     }
510   }
511   return false;
512 }
513 
ToFontSize(CFX_CSSPropertyValue eValue,float fCurFontSize)514 float CFX_CSSStyleSelector::ToFontSize(CFX_CSSPropertyValue eValue,
515                                        float fCurFontSize) {
516   switch (eValue) {
517     case CFX_CSSPropertyValue::XxSmall:
518       return m_fDefFontSize / 1.2f / 1.2f / 1.2f;
519     case CFX_CSSPropertyValue::XSmall:
520       return m_fDefFontSize / 1.2f / 1.2f;
521     case CFX_CSSPropertyValue::Small:
522       return m_fDefFontSize / 1.2f;
523     case CFX_CSSPropertyValue::Medium:
524       return m_fDefFontSize;
525     case CFX_CSSPropertyValue::Large:
526       return m_fDefFontSize * 1.2f;
527     case CFX_CSSPropertyValue::XLarge:
528       return m_fDefFontSize * 1.2f * 1.2f;
529     case CFX_CSSPropertyValue::XxLarge:
530       return m_fDefFontSize * 1.2f * 1.2f * 1.2f;
531     case CFX_CSSPropertyValue::Larger:
532       return fCurFontSize * 1.2f;
533     case CFX_CSSPropertyValue::Smaller:
534       return fCurFontSize / 1.2f;
535     default:
536       return fCurFontSize;
537   }
538 }
539 
ToVerticalAlign(CFX_CSSPropertyValue eValue)540 CFX_CSSVerticalAlign CFX_CSSStyleSelector::ToVerticalAlign(
541     CFX_CSSPropertyValue eValue) {
542   switch (eValue) {
543     case CFX_CSSPropertyValue::Middle:
544       return CFX_CSSVerticalAlign::Middle;
545     case CFX_CSSPropertyValue::Bottom:
546       return CFX_CSSVerticalAlign::Bottom;
547     case CFX_CSSPropertyValue::Super:
548       return CFX_CSSVerticalAlign::Super;
549     case CFX_CSSPropertyValue::Sub:
550       return CFX_CSSVerticalAlign::Sub;
551     case CFX_CSSPropertyValue::Top:
552       return CFX_CSSVerticalAlign::Top;
553     case CFX_CSSPropertyValue::TextTop:
554       return CFX_CSSVerticalAlign::TextTop;
555     case CFX_CSSPropertyValue::TextBottom:
556       return CFX_CSSVerticalAlign::TextBottom;
557     case CFX_CSSPropertyValue::Baseline:
558     default:
559       return CFX_CSSVerticalAlign::Baseline;
560   }
561 }
562 
ToTextDecoration(const RetainPtr<CFX_CSSValueList> & pValue)563 uint32_t CFX_CSSStyleSelector::ToTextDecoration(
564     const RetainPtr<CFX_CSSValueList>& pValue) {
565   uint32_t dwDecoration = 0;
566   for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) {
567     const RetainPtr<CFX_CSSValue> pVal = pValue->GetValue(i);
568     if (pVal->GetType() != CFX_CSSPrimitiveType::Enum)
569       continue;
570 
571     switch (pVal.As<CFX_CSSEnumValue>()->Value()) {
572       case CFX_CSSPropertyValue::Underline:
573         dwDecoration |= CFX_CSSTEXTDECORATION_Underline;
574         break;
575       case CFX_CSSPropertyValue::LineThrough:
576         dwDecoration |= CFX_CSSTEXTDECORATION_LineThrough;
577         break;
578       case CFX_CSSPropertyValue::Overline:
579         dwDecoration |= CFX_CSSTEXTDECORATION_Overline;
580         break;
581       case CFX_CSSPropertyValue::Blink:
582         dwDecoration |= CFX_CSSTEXTDECORATION_Blink;
583         break;
584       case CFX_CSSPropertyValue::Double:
585         dwDecoration |= CFX_CSSTEXTDECORATION_Double;
586         break;
587       default:
588         break;
589     }
590   }
591   return dwDecoration;
592 }
593 
ToFontVariant(CFX_CSSPropertyValue eValue)594 CFX_CSSFontVariant CFX_CSSStyleSelector::ToFontVariant(
595     CFX_CSSPropertyValue eValue) {
596   return eValue == CFX_CSSPropertyValue::SmallCaps
597              ? CFX_CSSFontVariant::SmallCaps
598              : CFX_CSSFontVariant::Normal;
599 }
600