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