diff options
Diffstat (limited to 'core/fxcrt')
44 files changed, 4117 insertions, 0 deletions
diff --git a/core/fxcrt/css/cfx_css.h b/core/fxcrt/css/cfx_css.h new file mode 100644 index 0000000000..7b1d7d3f99 --- /dev/null +++ b/core/fxcrt/css/cfx_css.h @@ -0,0 +1,242 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSS_H_ +#define CORE_FXCRT_CSS_CFX_CSS_H_ + +#include "core/fxcrt/cfx_seekablestreamproxy.h" +#include "core/fxge/fx_dib.h" + +enum CFX_CSSVALUETYPE { + CFX_CSSVALUETYPE_Primitive = 1 << 0, + CFX_CSSVALUETYPE_List = 1 << 1, + CFX_CSSVALUETYPE_Shorthand = 1 << 2, + // Note the values below this comment must be > 0x0F so we can mask the above. + CFX_CSSVALUETYPE_MaybeNumber = 1 << 4, + CFX_CSSVALUETYPE_MaybeEnum = 1 << 5, + CFX_CSSVALUETYPE_MaybeString = 1 << 7, + CFX_CSSVALUETYPE_MaybeColor = 1 << 8 +}; + +enum class CFX_CSSPrimitiveType : uint8_t { + Unknown = 0, + Number, + String, + RGB, + Enum, + Function, + List, +}; + +enum class CFX_CSSPropertyValue : uint8_t { + Bolder = 0, + None, + Dot, + Sub, + Top, + Right, + Normal, + Auto, + Text, + XSmall, + Thin, + Small, + Bottom, + Underline, + Double, + Lighter, + Oblique, + Super, + Center, + XxLarge, + Smaller, + Baseline, + Thick, + Justify, + Middle, + Medium, + ListItem, + XxSmall, + Bold, + SmallCaps, + Inline, + Overline, + TextBottom, + Larger, + InlineTable, + InlineBlock, + Blink, + Block, + Italic, + LineThrough, + XLarge, + Large, + Left, + TextTop, + LAST_MARKER +}; + +enum class CFX_CSSProperty : uint8_t { + BorderLeft = 0, + Top, + Margin, + TextIndent, + Right, + PaddingLeft, + MarginLeft, + Border, + BorderTop, + Bottom, + PaddingRight, + BorderBottom, + FontFamily, + FontWeight, + Color, + LetterSpacing, + TextAlign, + BorderRightWidth, + VerticalAlign, + PaddingTop, + FontVariant, + BorderWidth, + BorderBottomWidth, + BorderRight, + FontSize, + BorderSpacing, + FontStyle, + Font, + LineHeight, + MarginRight, + BorderLeftWidth, + Display, + PaddingBottom, + BorderTopWidth, + WordSpacing, + Left, + TextDecoration, + Padding, + MarginBottom, + MarginTop, + LAST_MARKER +}; + +enum class CFX_CSSSelectorType : uint8_t { Element = 0, Descendant }; + +enum class CFX_CSSLengthUnit : uint8_t { + Auto, + None, + Normal, + Point, + Percent, +}; + +enum class CFX_CSSDisplay : uint8_t { + None, + ListItem, + Block, + Inline, + InlineBlock, + InlineTable, +}; + +enum class CFX_CSSFontStyle : uint8_t { + Normal, + Italic, +}; + +enum class CFX_CSSTextAlign : uint8_t { + Left, + Right, + Center, + Justify, + JustifyAll, +}; + +enum class CFX_CSSVerticalAlign : uint8_t { + Baseline, + Sub, + Super, + Top, + TextTop, + Middle, + Bottom, + TextBottom, + Number, +}; + +enum class CFX_CSSFontVariant : uint8_t { + Normal, + SmallCaps, +}; + +enum CFX_CSSTEXTDECORATION { + CFX_CSSTEXTDECORATION_None = 0, + CFX_CSSTEXTDECORATION_Underline = 1 << 0, + CFX_CSSTEXTDECORATION_Overline = 1 << 1, + CFX_CSSTEXTDECORATION_LineThrough = 1 << 2, + CFX_CSSTEXTDECORATION_Blink = 1 << 3, + CFX_CSSTEXTDECORATION_Double = 1 << 4, +}; + +class CFX_CSSLength { + public: + CFX_CSSLength() {} + + explicit CFX_CSSLength(CFX_CSSLengthUnit eUnit) : m_unit(eUnit) {} + + CFX_CSSLength(CFX_CSSLengthUnit eUnit, float fValue) + : m_unit(eUnit), m_fValue(fValue) {} + + CFX_CSSLength& Set(CFX_CSSLengthUnit eUnit) { + m_unit = eUnit; + return *this; + } + + CFX_CSSLength& Set(CFX_CSSLengthUnit eUnit, float fValue) { + m_unit = eUnit; + m_fValue = fValue; + return *this; + } + + CFX_CSSLengthUnit GetUnit() const { return m_unit; } + + float GetValue() const { return m_fValue; } + bool NonZero() const { return static_cast<int>(m_fValue) != 0; } + + private: + CFX_CSSLengthUnit m_unit; + float m_fValue; +}; + +class CFX_CSSRect { + public: + CFX_CSSRect() {} + + CFX_CSSRect(CFX_CSSLengthUnit eUnit, float val) + : left(eUnit, val), + top(eUnit, val), + right(eUnit, val), + bottom(eUnit, val) {} + + CFX_CSSRect& Set(CFX_CSSLengthUnit eUnit) { + left.Set(eUnit); + top.Set(eUnit); + right.Set(eUnit); + bottom.Set(eUnit); + return *this; + } + CFX_CSSRect& Set(CFX_CSSLengthUnit eUnit, float fValue) { + left.Set(eUnit, fValue); + top.Set(eUnit, fValue); + right.Set(eUnit, fValue); + bottom.Set(eUnit, fValue); + return *this; + } + + CFX_CSSLength left, top, right, bottom; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSS_H_ diff --git a/core/fxcrt/css/cfx_csscolorvalue.cpp b/core/fxcrt/css/cfx_csscolorvalue.cpp new file mode 100644 index 0000000000..8c5473b329 --- /dev/null +++ b/core/fxcrt/css/cfx_csscolorvalue.cpp @@ -0,0 +1,12 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_csscolorvalue.h" + +CFX_CSSColorValue::CFX_CSSColorValue(FX_ARGB value) + : CFX_CSSValue(CFX_CSSPrimitiveType::RGB), value_(value) {} + +CFX_CSSColorValue::~CFX_CSSColorValue() {} diff --git a/core/fxcrt/css/cfx_csscolorvalue.h b/core/fxcrt/css/cfx_csscolorvalue.h new file mode 100644 index 0000000000..f59c0c5d3d --- /dev/null +++ b/core/fxcrt/css/cfx_csscolorvalue.h @@ -0,0 +1,23 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSCOLORVALUE_H_ +#define CORE_FXCRT_CSS_CFX_CSSCOLORVALUE_H_ + +#include "core/fxcrt/css/cfx_cssvalue.h" + +class CFX_CSSColorValue : public CFX_CSSValue { + public: + explicit CFX_CSSColorValue(FX_ARGB color); + ~CFX_CSSColorValue() override; + + FX_ARGB Value() const { return value_; } + + private: + FX_ARGB value_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSCOLORVALUE_H_ diff --git a/core/fxcrt/css/cfx_csscomputedstyle.cpp b/core/fxcrt/css/cfx_csscomputedstyle.cpp new file mode 100644 index 0000000000..953c107ec3 --- /dev/null +++ b/core/fxcrt/css/cfx_csscomputedstyle.cpp @@ -0,0 +1,195 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_csscomputedstyle.h" + +#include "core/fxcrt/css/cfx_cssstringvalue.h" +#include "core/fxcrt/css/cfx_cssvaluelist.h" +#include "third_party/base/stl_util.h" + +CFX_CSSComputedStyle::CFX_CSSComputedStyle() {} + +CFX_CSSComputedStyle::~CFX_CSSComputedStyle() {} + +bool CFX_CSSComputedStyle::GetCustomStyle(const CFX_WideString& wsName, + CFX_WideString& wsValue) const { + for (auto iter = m_CustomProperties.rbegin(); + iter != m_CustomProperties.rend(); iter++) { + if (wsName == iter->name()) { + wsValue = iter->value(); + return true; + } + } + return false; +} + +int32_t CFX_CSSComputedStyle::CountFontFamilies() const { + return m_InheritedData.m_pFontFamily + ? m_InheritedData.m_pFontFamily->CountValues() + : 0; +} + +const CFX_WideString CFX_CSSComputedStyle::GetFontFamily(int32_t index) const { + return m_InheritedData.m_pFontFamily->GetValue(index) + .As<CFX_CSSStringValue>() + ->Value(); +} + +uint16_t CFX_CSSComputedStyle::GetFontWeight() const { + return m_InheritedData.m_wFontWeight; +} + +CFX_CSSFontVariant CFX_CSSComputedStyle::GetFontVariant() const { + return m_InheritedData.m_eFontVariant; +} + +CFX_CSSFontStyle CFX_CSSComputedStyle::GetFontStyle() const { + return m_InheritedData.m_eFontStyle; +} + +float CFX_CSSComputedStyle::GetFontSize() const { + return m_InheritedData.m_fFontSize; +} + +FX_ARGB CFX_CSSComputedStyle::GetColor() const { + return m_InheritedData.m_dwFontColor; +} + +void CFX_CSSComputedStyle::SetFontWeight(uint16_t wFontWeight) { + m_InheritedData.m_wFontWeight = wFontWeight; +} + +void CFX_CSSComputedStyle::SetFontVariant(CFX_CSSFontVariant eFontVariant) { + m_InheritedData.m_eFontVariant = eFontVariant; +} + +void CFX_CSSComputedStyle::SetFontStyle(CFX_CSSFontStyle eFontStyle) { + m_InheritedData.m_eFontStyle = eFontStyle; +} + +void CFX_CSSComputedStyle::SetFontSize(float fFontSize) { + m_InheritedData.m_fFontSize = fFontSize; +} + +void CFX_CSSComputedStyle::SetColor(FX_ARGB dwFontColor) { + m_InheritedData.m_dwFontColor = dwFontColor; +} + +const CFX_CSSRect* CFX_CSSComputedStyle::GetBorderWidth() const { + return m_NonInheritedData.m_bHasBorder ? &(m_NonInheritedData.m_BorderWidth) + : nullptr; +} + +const CFX_CSSRect* CFX_CSSComputedStyle::GetMarginWidth() const { + return m_NonInheritedData.m_bHasMargin ? &(m_NonInheritedData.m_MarginWidth) + : nullptr; +} + +const CFX_CSSRect* CFX_CSSComputedStyle::GetPaddingWidth() const { + return m_NonInheritedData.m_bHasPadding ? &(m_NonInheritedData.m_PaddingWidth) + : nullptr; +} + +void CFX_CSSComputedStyle::SetMarginWidth(const CFX_CSSRect& rect) { + m_NonInheritedData.m_MarginWidth = rect; + m_NonInheritedData.m_bHasMargin = true; +} + +void CFX_CSSComputedStyle::SetPaddingWidth(const CFX_CSSRect& rect) { + m_NonInheritedData.m_PaddingWidth = rect; + m_NonInheritedData.m_bHasPadding = true; +} + +CFX_CSSDisplay CFX_CSSComputedStyle::GetDisplay() const { + return m_NonInheritedData.m_eDisplay; +} + +float CFX_CSSComputedStyle::GetLineHeight() const { + return m_InheritedData.m_fLineHeight; +} + +const CFX_CSSLength& CFX_CSSComputedStyle::GetTextIndent() const { + return m_InheritedData.m_TextIndent; +} + +CFX_CSSTextAlign CFX_CSSComputedStyle::GetTextAlign() const { + return m_InheritedData.m_eTextAlign; +} + +CFX_CSSVerticalAlign CFX_CSSComputedStyle::GetVerticalAlign() const { + return m_NonInheritedData.m_eVerticalAlign; +} + +float CFX_CSSComputedStyle::GetNumberVerticalAlign() const { + return m_NonInheritedData.m_fVerticalAlign; +} + +uint32_t CFX_CSSComputedStyle::GetTextDecoration() const { + return m_NonInheritedData.m_dwTextDecoration; +} + +const CFX_CSSLength& CFX_CSSComputedStyle::GetLetterSpacing() const { + return m_InheritedData.m_LetterSpacing; +} + +void CFX_CSSComputedStyle::SetLineHeight(float fLineHeight) { + m_InheritedData.m_fLineHeight = fLineHeight; +} + +void CFX_CSSComputedStyle::SetTextIndent(const CFX_CSSLength& textIndent) { + m_InheritedData.m_TextIndent = textIndent; +} + +void CFX_CSSComputedStyle::SetTextAlign(CFX_CSSTextAlign eTextAlign) { + m_InheritedData.m_eTextAlign = eTextAlign; +} + +void CFX_CSSComputedStyle::SetNumberVerticalAlign(float fAlign) { + m_NonInheritedData.m_eVerticalAlign = CFX_CSSVerticalAlign::Number, + m_NonInheritedData.m_fVerticalAlign = fAlign; +} + +void CFX_CSSComputedStyle::SetTextDecoration(uint32_t dwTextDecoration) { + m_NonInheritedData.m_dwTextDecoration = dwTextDecoration; +} + +void CFX_CSSComputedStyle::SetLetterSpacing( + const CFX_CSSLength& letterSpacing) { + m_InheritedData.m_LetterSpacing = letterSpacing; +} + +void CFX_CSSComputedStyle::AddCustomStyle(const CFX_CSSCustomProperty& prop) { + // Force the property to be copied so we aren't dependent on the lifetime + // of whatever currently owns it. + m_CustomProperties.push_back(prop); +} + +CFX_CSSComputedStyle::InheritedData::InheritedData() + : m_LetterSpacing(CFX_CSSLengthUnit::Normal), + m_WordSpacing(CFX_CSSLengthUnit::Normal), + m_TextIndent(CFX_CSSLengthUnit::Point, 0), + m_pFontFamily(nullptr), + m_fFontSize(12.0f), + m_fLineHeight(14.0f), + m_dwFontColor(0xFF000000), + m_wFontWeight(400), + m_eFontVariant(CFX_CSSFontVariant::Normal), + m_eFontStyle(CFX_CSSFontStyle::Normal), + m_eTextAlign(CFX_CSSTextAlign::Left) {} + +CFX_CSSComputedStyle::InheritedData::~InheritedData() {} + +CFX_CSSComputedStyle::NonInheritedData::NonInheritedData() + : m_MarginWidth(CFX_CSSLengthUnit::Point, 0), + m_BorderWidth(CFX_CSSLengthUnit::Point, 0), + m_PaddingWidth(CFX_CSSLengthUnit::Point, 0), + m_fVerticalAlign(0.0f), + m_eDisplay(CFX_CSSDisplay::Inline), + m_eVerticalAlign(CFX_CSSVerticalAlign::Baseline), + m_dwTextDecoration(0), + m_bHasMargin(false), + m_bHasBorder(false), + m_bHasPadding(false) {} diff --git a/core/fxcrt/css/cfx_csscomputedstyle.h b/core/fxcrt/css/cfx_csscomputedstyle.h new file mode 100644 index 0000000000..bd7cd8268b --- /dev/null +++ b/core/fxcrt/css/cfx_csscomputedstyle.h @@ -0,0 +1,111 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSCOMPUTEDSTYLE_H_ +#define CORE_FXCRT_CSS_CFX_CSSCOMPUTEDSTYLE_H_ + +#include <vector> + +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/css/cfx_csscustomproperty.h" +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_string.h" + +class CFX_CSSValueList; + +class CFX_CSSComputedStyle : public CFX_Retainable { + public: + class InheritedData { + public: + InheritedData(); + ~InheritedData(); + + CFX_CSSLength m_LetterSpacing; + CFX_CSSLength m_WordSpacing; + CFX_CSSLength m_TextIndent; + CFX_RetainPtr<CFX_CSSValueList> m_pFontFamily; + float m_fFontSize; + float m_fLineHeight; + FX_ARGB m_dwFontColor; + uint16_t m_wFontWeight; + CFX_CSSFontVariant m_eFontVariant; + CFX_CSSFontStyle m_eFontStyle; + CFX_CSSTextAlign m_eTextAlign; + }; + + class NonInheritedData { + public: + NonInheritedData(); + + CFX_CSSRect m_MarginWidth; + CFX_CSSRect m_BorderWidth; + CFX_CSSRect m_PaddingWidth; + CFX_CSSLength m_Top; + CFX_CSSLength m_Bottom; + CFX_CSSLength m_Left; + CFX_CSSLength m_Right; + float m_fVerticalAlign; + CFX_CSSDisplay m_eDisplay; + CFX_CSSVerticalAlign m_eVerticalAlign; + uint8_t m_dwTextDecoration; + bool m_bHasMargin; + bool m_bHasBorder; + bool m_bHasPadding; + }; + + int32_t CountFontFamilies() const; + const CFX_WideString GetFontFamily(int32_t index) const; + uint16_t GetFontWeight() const; + CFX_CSSFontVariant GetFontVariant() const; + CFX_CSSFontStyle GetFontStyle() const; + float GetFontSize() const; + FX_ARGB GetColor() const; + void SetFontWeight(uint16_t wFontWeight); + void SetFontVariant(CFX_CSSFontVariant eFontVariant); + void SetFontStyle(CFX_CSSFontStyle eFontStyle); + void SetFontSize(float fFontSize); + void SetColor(FX_ARGB dwFontColor); + + const CFX_CSSRect* GetBorderWidth() const; + const CFX_CSSRect* GetMarginWidth() const; + const CFX_CSSRect* GetPaddingWidth() const; + void SetMarginWidth(const CFX_CSSRect& rect); + void SetPaddingWidth(const CFX_CSSRect& rect); + + CFX_CSSDisplay GetDisplay() const; + + float GetLineHeight() const; + const CFX_CSSLength& GetTextIndent() const; + CFX_CSSTextAlign GetTextAlign() const; + CFX_CSSVerticalAlign GetVerticalAlign() const; + float GetNumberVerticalAlign() const; + uint32_t GetTextDecoration() const; + const CFX_CSSLength& GetLetterSpacing() const; + void SetLineHeight(float fLineHeight); + void SetTextIndent(const CFX_CSSLength& textIndent); + void SetTextAlign(CFX_CSSTextAlign eTextAlign); + void SetNumberVerticalAlign(float fAlign); + void SetTextDecoration(uint32_t dwTextDecoration); + void SetLetterSpacing(const CFX_CSSLength& letterSpacing); + void AddCustomStyle(const CFX_CSSCustomProperty& prop); + + bool GetCustomStyle(const CFX_WideString& wsName, + CFX_WideString& wsValue) const; + + InheritedData m_InheritedData; + NonInheritedData m_NonInheritedData; + + private: + template <typename T, typename... Args> + friend CFX_RetainPtr<T> pdfium::MakeRetain(Args&&... args); + + CFX_CSSComputedStyle(); + ~CFX_CSSComputedStyle() override; + + std::vector<CFX_CSSCustomProperty> m_CustomProperties; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSCOMPUTEDSTYLE_H_ diff --git a/core/fxcrt/css/cfx_csscustomproperty.cpp b/core/fxcrt/css/cfx_csscustomproperty.cpp new file mode 100644 index 0000000000..8bfb9d961e --- /dev/null +++ b/core/fxcrt/css/cfx_csscustomproperty.cpp @@ -0,0 +1,14 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fxcrt/css/cfx_csscustomproperty.h" + +CFX_CSSCustomProperty::CFX_CSSCustomProperty(const CFX_WideString& name, + const CFX_WideString& value) + : name_(name), value_(value) {} + +CFX_CSSCustomProperty::CFX_CSSCustomProperty(const CFX_CSSCustomProperty& prop) + : name_(prop.name_), value_(prop.value_) {} + +CFX_CSSCustomProperty::~CFX_CSSCustomProperty() {} diff --git a/core/fxcrt/css/cfx_csscustomproperty.h b/core/fxcrt/css/cfx_csscustomproperty.h new file mode 100644 index 0000000000..e062c3e953 --- /dev/null +++ b/core/fxcrt/css/cfx_csscustomproperty.h @@ -0,0 +1,27 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSCUSTOMPROPERTY_H_ +#define CORE_FXCRT_CSS_CFX_CSSCUSTOMPROPERTY_H_ + +#include "core/fxcrt/fx_string.h" + +class CFX_CSSCustomProperty { + public: + CFX_CSSCustomProperty(const CFX_WideString& name, + const CFX_WideString& value); + CFX_CSSCustomProperty(const CFX_CSSCustomProperty& prop); + ~CFX_CSSCustomProperty(); + + CFX_WideString name() const { return name_; } + CFX_WideString value() const { return value_; } + + private: + CFX_WideString name_; + CFX_WideString value_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSCUSTOMPROPERTY_H_ diff --git a/core/fxcrt/css/cfx_cssdatatable.cpp b/core/fxcrt/css/cfx_cssdatatable.cpp new file mode 100644 index 0000000000..ef555b395f --- /dev/null +++ b/core/fxcrt/css/cfx_cssdatatable.cpp @@ -0,0 +1,285 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssdatatable.h" + +#include <utility> + +#include "core/fxcrt/css/cfx_cssstyleselector.h" +#include "core/fxcrt/css/cfx_cssvaluelistparser.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/fx_extension.h" + +static const CFX_CSSPropertyTable g_CFX_CSSProperties[] = { + {CFX_CSSProperty::BorderLeft, L"border-left", 0x04080036, + CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::Top, L"top", 0x0BEDAF33, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::Margin, L"margin", 0x0CB016BE, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::TextIndent, L"text-indent", 0x169ADB74, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::Right, L"right", 0x193ADE3E, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::PaddingLeft, L"padding-left", 0x228CF02F, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::MarginLeft, L"margin-left", 0x297C5656, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber | + CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::Border, L"border", 0x2A23349E, + CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::BorderTop, L"border-top", 0x2B866ADE, + CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::Bottom, L"bottom", 0x399F02B5, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::PaddingRight, L"padding-right", 0x3F616AC2, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::BorderBottom, L"border-bottom", 0x452CE780, + CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::FontFamily, L"font-family", 0x574686E6, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeString}, + {CFX_CSSProperty::FontWeight, L"font-weight", 0x6692F60C, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::Color, L"color", 0x6E67921F, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeColor}, + {CFX_CSSProperty::LetterSpacing, L"letter-spacing", 0x70536102, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::TextAlign, L"text-align", 0x7553F1BD, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::BorderRightWidth, L"border-right-width", 0x8F5A6036, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::VerticalAlign, L"vertical-align", 0x934A87D2, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::PaddingTop, L"padding-top", 0x959D22B7, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::FontVariant, L"font-variant", 0x9C785779, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::BorderWidth, L"border-width", 0xA8DE4FEB, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::BorderBottomWidth, L"border-bottom-width", 0xAE41204D, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::BorderRight, L"border-right", 0xB78E9EA9, + CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::FontSize, L"font-size", 0xB93956DF, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::BorderSpacing, L"border-spacing", 0xC72030F0, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::FontStyle, L"font-style", 0xCB1950F5, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::Font, L"font", 0xCD308B77, CFX_CSSVALUETYPE_Shorthand}, + {CFX_CSSProperty::LineHeight, L"line-height", 0xCFCACE2E, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::MarginRight, L"margin-right", 0xD13C58C9, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber | + CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::BorderLeftWidth, L"border-left-width", 0xD1E93D83, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::Display, L"display", 0xD4224C36, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::PaddingBottom, L"padding-bottom", 0xE555B3B9, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::BorderTopWidth, L"border-top-width", 0xED2CB62B, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::WordSpacing, L"word-spacing", 0xEDA63BAE, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::Left, L"left", 0xF5AD782B, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeEnum | + CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::TextDecoration, L"text-decoration", 0xF7C634BA, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::Padding, L"padding", 0xF8C373F7, + CFX_CSSVALUETYPE_List | CFX_CSSVALUETYPE_MaybeNumber}, + {CFX_CSSProperty::MarginBottom, L"margin-bottom", 0xF93485A0, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber | + CFX_CSSVALUETYPE_MaybeEnum}, + {CFX_CSSProperty::MarginTop, L"margin-top", 0xFE51DCFE, + CFX_CSSVALUETYPE_Primitive | CFX_CSSVALUETYPE_MaybeNumber | + CFX_CSSVALUETYPE_MaybeEnum}, +}; +const int32_t g_iCSSPropertyCount = + sizeof(g_CFX_CSSProperties) / sizeof(CFX_CSSPropertyTable); +static_assert(g_iCSSPropertyCount == + static_cast<int32_t>(CFX_CSSProperty::LAST_MARKER), + "Property table differs in size from property enum"); + +static const CFX_CSSPropertyValueTable g_CFX_CSSPropertyValues[] = { + {CFX_CSSPropertyValue::Bolder, L"bolder", 0x009F1058}, + {CFX_CSSPropertyValue::None, L"none", 0x048B6670}, + {CFX_CSSPropertyValue::Dot, L"dot", 0x0A48CB27}, + {CFX_CSSPropertyValue::Sub, L"sub", 0x0BD37FAA}, + {CFX_CSSPropertyValue::Top, L"top", 0x0BEDAF33}, + {CFX_CSSPropertyValue::Right, L"right", 0x193ADE3E}, + {CFX_CSSPropertyValue::Normal, L"normal", 0x247CF3E9}, + {CFX_CSSPropertyValue::Auto, L"auto", 0x2B35B6D9}, + {CFX_CSSPropertyValue::Text, L"text", 0x2D08AF85}, + {CFX_CSSPropertyValue::XSmall, L"x-small", 0x2D2FCAFE}, + {CFX_CSSPropertyValue::Thin, L"thin", 0x2D574D53}, + {CFX_CSSPropertyValue::Small, L"small", 0x316A3739}, + {CFX_CSSPropertyValue::Bottom, L"bottom", 0x399F02B5}, + {CFX_CSSPropertyValue::Underline, L"underline", 0x3A0273A6}, + {CFX_CSSPropertyValue::Double, L"double", 0x3D98515B}, + {CFX_CSSPropertyValue::Lighter, L"lighter", 0x45BEB7AF}, + {CFX_CSSPropertyValue::Oblique, L"oblique", 0x53EBDDB1}, + {CFX_CSSPropertyValue::Super, L"super", 0x6A4F842F}, + {CFX_CSSPropertyValue::Center, L"center", 0x6C51AFC1}, + {CFX_CSSPropertyValue::XxLarge, L"xx-large", 0x70BB1508}, + {CFX_CSSPropertyValue::Smaller, L"smaller", 0x849769F0}, + {CFX_CSSPropertyValue::Baseline, L"baseline", 0x87436BA3}, + {CFX_CSSPropertyValue::Thick, L"thick", 0x8CC35EB3}, + {CFX_CSSPropertyValue::Justify, L"justify", 0x8D269CAE}, + {CFX_CSSPropertyValue::Middle, L"middle", 0x947FA00F}, + {CFX_CSSPropertyValue::Medium, L"medium", 0xA084A381}, + {CFX_CSSPropertyValue::ListItem, L"list-item", 0xA32382B8}, + {CFX_CSSPropertyValue::XxSmall, L"xx-small", 0xADE1FC76}, + {CFX_CSSPropertyValue::Bold, L"bold", 0xB18313A1}, + {CFX_CSSPropertyValue::SmallCaps, L"small-caps", 0xB299428D}, + {CFX_CSSPropertyValue::Inline, L"inline", 0xC02D649F}, + {CFX_CSSPropertyValue::Overline, L"overline", 0xC0EC9FA4}, + {CFX_CSSPropertyValue::TextBottom, L"text-bottom", 0xC7D08D87}, + {CFX_CSSPropertyValue::Larger, L"larger", 0xCD3C409D}, + {CFX_CSSPropertyValue::InlineTable, L"inline-table", 0xD131F494}, + {CFX_CSSPropertyValue::InlineBlock, L"inline-block", 0xD26A8BD7}, + {CFX_CSSPropertyValue::Blink, L"blink", 0xDC36E390}, + {CFX_CSSPropertyValue::Block, L"block", 0xDCD480AB}, + {CFX_CSSPropertyValue::Italic, L"italic", 0xE31D5396}, + {CFX_CSSPropertyValue::LineThrough, L"line-through", 0xE4C5A276}, + {CFX_CSSPropertyValue::XLarge, L"x-large", 0xF008E390}, + {CFX_CSSPropertyValue::Large, L"large", 0xF4434FCB}, + {CFX_CSSPropertyValue::Left, L"left", 0xF5AD782B}, + {CFX_CSSPropertyValue::TextTop, L"text-top", 0xFCB58D45}, +}; +const int32_t g_iCSSPropertyValueCount = + sizeof(g_CFX_CSSPropertyValues) / sizeof(CFX_CSSPropertyValueTable); +static_assert(g_iCSSPropertyValueCount == + static_cast<int32_t>(CFX_CSSPropertyValue::LAST_MARKER), + "Property value table differs in size from property value enum"); + +static const CFX_CSSLengthUnitTable g_CFX_CSSLengthUnits[] = { + {0x0672, CFX_CSSNumberType::EMS}, + {0x067D, CFX_CSSNumberType::EXS}, + {0x1AF7, CFX_CSSNumberType::Inches}, + {0x2F7A, CFX_CSSNumberType::MilliMeters}, + {0x3ED3, CFX_CSSNumberType::Picas}, + {0x3EE4, CFX_CSSNumberType::Points}, + {0x3EE8, CFX_CSSNumberType::Pixels}, + {0xFC30, CFX_CSSNumberType::CentiMeters}, +}; + +static const CFX_CSSCOLORTABLE g_CFX_CSSColors[] = { + {0x031B47FE, 0xff000080}, {0x0BB8DF5B, 0xffff0000}, + {0x0D82A78C, 0xff800000}, {0x2ACC82E8, 0xff00ffff}, + {0x2D083986, 0xff008080}, {0x4A6A6195, 0xffc0c0c0}, + {0x546A8EF3, 0xff808080}, {0x65C9169C, 0xffffa500}, + {0x8422BB61, 0xffffffff}, {0x9271A558, 0xff800080}, + {0xA65A3EE3, 0xffff00ff}, {0xB1345708, 0xff0000ff}, + {0xB6D2CF1F, 0xff808000}, {0xD19B5E1C, 0xffffff00}, + {0xDB64391D, 0xff000000}, {0xF616D507, 0xff00ff00}, + {0xF6EFFF31, 0xff008000}, +}; + +const CFX_CSSPropertyTable* CFX_GetCSSPropertyByName( + const CFX_WideStringC& wsName) { + ASSERT(!wsName.IsEmpty()); + uint32_t dwHash = FX_HashCode_GetW(wsName, true); + int32_t iEnd = g_iCSSPropertyCount; + int32_t iMid, iStart = 0; + uint32_t dwMid; + do { + iMid = (iStart + iEnd) / 2; + dwMid = g_CFX_CSSProperties[iMid].dwHash; + if (dwHash == dwMid) { + return g_CFX_CSSProperties + iMid; + } else if (dwHash > dwMid) { + iStart = iMid + 1; + } else { + iEnd = iMid - 1; + } + } while (iStart <= iEnd); + return nullptr; +} + +const CFX_CSSPropertyTable* CFX_GetCSSPropertyByEnum(CFX_CSSProperty eName) { + return g_CFX_CSSProperties + static_cast<int>(eName); +} + +const CFX_CSSPropertyValueTable* CFX_GetCSSPropertyValueByName( + const CFX_WideStringC& wsName) { + ASSERT(!wsName.IsEmpty()); + uint32_t dwHash = FX_HashCode_GetW(wsName, true); + int32_t iEnd = g_iCSSPropertyValueCount; + int32_t iMid, iStart = 0; + uint32_t dwMid; + do { + iMid = (iStart + iEnd) / 2; + dwMid = g_CFX_CSSPropertyValues[iMid].dwHash; + if (dwHash == dwMid) { + return g_CFX_CSSPropertyValues + iMid; + } else if (dwHash > dwMid) { + iStart = iMid + 1; + } else { + iEnd = iMid - 1; + } + } while (iStart <= iEnd); + return nullptr; +} + +const CFX_CSSLengthUnitTable* CFX_GetCSSLengthUnitByName( + const CFX_WideStringC& wsName) { + ASSERT(!wsName.IsEmpty()); + uint16_t wHash = FX_HashCode_GetW(wsName, true); + int32_t iEnd = + sizeof(g_CFX_CSSLengthUnits) / sizeof(CFX_CSSLengthUnitTable) - 1; + int32_t iMid, iStart = 0; + uint16_t wMid; + do { + iMid = (iStart + iEnd) / 2; + wMid = g_CFX_CSSLengthUnits[iMid].wHash; + if (wHash == wMid) { + return g_CFX_CSSLengthUnits + iMid; + } else if (wHash > wMid) { + iStart = iMid + 1; + } else { + iEnd = iMid - 1; + } + } while (iStart <= iEnd); + return nullptr; +} + +const CFX_CSSCOLORTABLE* CFX_GetCSSColorByName(const CFX_WideStringC& wsName) { + ASSERT(!wsName.IsEmpty()); + uint32_t dwHash = FX_HashCode_GetW(wsName, true); + int32_t iEnd = sizeof(g_CFX_CSSColors) / sizeof(CFX_CSSCOLORTABLE) - 1; + int32_t iMid, iStart = 0; + uint32_t dwMid; + do { + iMid = (iStart + iEnd) / 2; + dwMid = g_CFX_CSSColors[iMid].dwHash; + if (dwHash == dwMid) { + return g_CFX_CSSColors + iMid; + } else if (dwHash > dwMid) { + iStart = iMid + 1; + } else { + iEnd = iMid - 1; + } + } while (iStart <= iEnd); + return nullptr; +} diff --git a/core/fxcrt/css/cfx_cssdatatable.h b/core/fxcrt/css/cfx_cssdatatable.h new file mode 100644 index 0000000000..b6188f93bb --- /dev/null +++ b/core/fxcrt/css/cfx_cssdatatable.h @@ -0,0 +1,56 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSDATATABLE_H_ +#define CORE_FXCRT_CSS_CFX_CSSDATATABLE_H_ + +#include <memory> +#include <vector> + +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/css/cfx_cssnumbervalue.h" +#include "core/fxcrt/css/cfx_cssvalue.h" +#include "core/fxcrt/fx_system.h" + +#define CFX_IsOnlyValue(type, enum) \ + (((type) & ~(enum)) == CFX_CSSVALUETYPE_Primitive) + +struct CFX_CSSPropertyTable { + CFX_CSSProperty eName; + const wchar_t* pszName; + uint32_t dwHash; + uint32_t dwType; +}; + +struct CFX_CSSPropertyValueTable { + CFX_CSSPropertyValue eName; + const wchar_t* pszName; + uint32_t dwHash; +}; + +struct CFX_CSSLengthUnitTable { + uint16_t wHash; + CFX_CSSNumberType wValue; +}; + +struct CFX_CSSCOLORTABLE { + uint32_t dwHash; + FX_ARGB dwValue; +}; + +const CFX_CSSPropertyTable* CFX_GetCSSPropertyByName( + const CFX_WideStringC& wsName); +const CFX_CSSPropertyTable* CFX_GetCSSPropertyByEnum(CFX_CSSProperty eName); + +const CFX_CSSPropertyValueTable* CFX_GetCSSPropertyValueByName( + const CFX_WideStringC& wsName); + +const CFX_CSSLengthUnitTable* CFX_GetCSSLengthUnitByName( + const CFX_WideStringC& wsName); + +const CFX_CSSCOLORTABLE* CFX_GetCSSColorByName(const CFX_WideStringC& wsName); + +#endif // CORE_FXCRT_CSS_CFX_CSSDATATABLE_H_ diff --git a/core/fxcrt/css/cfx_cssdeclaration.cpp b/core/fxcrt/css/cfx_cssdeclaration.cpp new file mode 100644 index 0000000000..b65429edb7 --- /dev/null +++ b/core/fxcrt/css/cfx_cssdeclaration.cpp @@ -0,0 +1,634 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssdeclaration.h" + +#include "core/fxcrt/css/cfx_csscolorvalue.h" +#include "core/fxcrt/css/cfx_csscustomproperty.h" +#include "core/fxcrt/css/cfx_cssenumvalue.h" +#include "core/fxcrt/css/cfx_cssnumbervalue.h" +#include "core/fxcrt/css/cfx_csspropertyholder.h" +#include "core/fxcrt/css/cfx_cssstringvalue.h" +#include "core/fxcrt/css/cfx_cssvaluelist.h" +#include "core/fxcrt/css/cfx_cssvaluelistparser.h" +#include "core/fxcrt/fx_extension.h" +#include "third_party/base/logging.h" +#include "third_party/base/ptr_util.h" + +namespace { + +uint8_t Hex2Dec(uint8_t hexHigh, uint8_t hexLow) { + return (FXSYS_HexCharToInt(hexHigh) << 4) + FXSYS_HexCharToInt(hexLow); +} + +bool ParseCSSNumber(const wchar_t* pszValue, + int32_t iValueLen, + float& fValue, + CFX_CSSNumberType& eUnit) { + ASSERT(pszValue && iValueLen > 0); + int32_t iUsedLen = 0; + fValue = FXSYS_wcstof(pszValue, iValueLen, &iUsedLen); + if (iUsedLen <= 0) + return false; + + iValueLen -= iUsedLen; + pszValue += iUsedLen; + eUnit = CFX_CSSNumberType::Number; + if (iValueLen >= 1 && *pszValue == '%') { + eUnit = CFX_CSSNumberType::Percent; + } else if (iValueLen == 2) { + const CFX_CSSLengthUnitTable* pUnit = + CFX_GetCSSLengthUnitByName(CFX_WideStringC(pszValue, 2)); + if (pUnit) + eUnit = pUnit->wValue; + } + return true; +} + +} // namespace + +// static +bool CFX_CSSDeclaration::ParseCSSString(const wchar_t* pszValue, + int32_t iValueLen, + int32_t* iOffset, + int32_t* iLength) { + ASSERT(pszValue && iValueLen > 0); + *iOffset = 0; + *iLength = iValueLen; + if (iValueLen >= 2) { + wchar_t first = pszValue[0], last = pszValue[iValueLen - 1]; + if ((first == '\"' && last == '\"') || (first == '\'' && last == '\'')) { + *iOffset = 1; + *iLength -= 2; + } + } + return iValueLen > 0; +} + +// static. +bool CFX_CSSDeclaration::ParseCSSColor(const wchar_t* pszValue, + int32_t iValueLen, + FX_ARGB* dwColor) { + ASSERT(pszValue && iValueLen > 0); + ASSERT(dwColor); + + if (*pszValue == '#') { + switch (iValueLen) { + case 4: { + uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[1]); + uint8_t green = Hex2Dec((uint8_t)pszValue[2], (uint8_t)pszValue[2]); + uint8_t blue = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[3]); + *dwColor = ArgbEncode(255, red, green, blue); + return true; + } + case 7: { + uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[2]); + uint8_t green = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[4]); + uint8_t blue = Hex2Dec((uint8_t)pszValue[5], (uint8_t)pszValue[6]); + *dwColor = ArgbEncode(255, red, green, blue); + return true; + } + default: + return false; + } + } + + if (iValueLen >= 10) { + if (pszValue[iValueLen - 1] != ')' || FXSYS_wcsnicmp(L"rgb(", pszValue, 4)) + return false; + + uint8_t rgb[3] = {0}; + float fValue; + CFX_CSSPrimitiveType eType; + CFX_CSSValueListParser list(pszValue + 4, iValueLen - 5, ','); + for (int32_t i = 0; i < 3; ++i) { + if (!list.NextValue(eType, pszValue, iValueLen)) + return false; + if (eType != CFX_CSSPrimitiveType::Number) + return false; + CFX_CSSNumberType eNumType; + if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) + return false; + + rgb[i] = eNumType == CFX_CSSNumberType::Percent + ? FXSYS_round(fValue * 2.55f) + : FXSYS_round(fValue); + } + *dwColor = ArgbEncode(255, rgb[0], rgb[1], rgb[2]); + return true; + } + + const CFX_CSSCOLORTABLE* pColor = + CFX_GetCSSColorByName(CFX_WideStringC(pszValue, iValueLen)); + if (!pColor) + return false; + + *dwColor = pColor->dwValue; + return true; +} + +CFX_CSSDeclaration::CFX_CSSDeclaration() {} + +CFX_CSSDeclaration::~CFX_CSSDeclaration() {} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::GetProperty( + CFX_CSSProperty eProperty, + bool* bImportant) const { + for (const auto& p : properties_) { + if (p->eProperty == eProperty) { + *bImportant = p->bImportant; + return p->pValue; + } + } + return nullptr; +} + +void CFX_CSSDeclaration::AddPropertyHolder(CFX_CSSProperty eProperty, + CFX_RetainPtr<CFX_CSSValue> pValue, + bool bImportant) { + auto pHolder = pdfium::MakeUnique<CFX_CSSPropertyHolder>(); + pHolder->bImportant = bImportant; + pHolder->eProperty = eProperty; + pHolder->pValue = pValue; + properties_.push_back(std::move(pHolder)); +} + +void CFX_CSSDeclaration::AddProperty(const CFX_CSSPropertyTable* pTable, + const CFX_WideStringC& value) { + ASSERT(!value.IsEmpty()); + + const wchar_t* pszValue = value.unterminated_c_str(); + int32_t iValueLen = value.GetLength(); + bool bImportant = false; + if (iValueLen >= 10 && pszValue[iValueLen - 10] == '!' && + FXSYS_wcsnicmp(L"important", pszValue + iValueLen - 9, 9) == 0) { + if ((iValueLen -= 10) == 0) + return; + + bImportant = true; + } + const uint32_t dwType = pTable->dwType; + switch (dwType & 0x0F) { + case CFX_CSSVALUETYPE_Primitive: { + static const uint32_t g_ValueGuessOrder[] = { + CFX_CSSVALUETYPE_MaybeNumber, CFX_CSSVALUETYPE_MaybeEnum, + CFX_CSSVALUETYPE_MaybeColor, CFX_CSSVALUETYPE_MaybeString, + }; + static const int32_t g_ValueGuessCount = + sizeof(g_ValueGuessOrder) / sizeof(uint32_t); + for (int32_t i = 0; i < g_ValueGuessCount; ++i) { + const uint32_t dwMatch = dwType & g_ValueGuessOrder[i]; + if (dwMatch == 0) { + continue; + } + CFX_RetainPtr<CFX_CSSValue> pCSSValue; + switch (dwMatch) { + case CFX_CSSVALUETYPE_MaybeNumber: + pCSSValue = ParseNumber(pszValue, iValueLen); + break; + case CFX_CSSVALUETYPE_MaybeEnum: + pCSSValue = ParseEnum(pszValue, iValueLen); + break; + case CFX_CSSVALUETYPE_MaybeColor: + pCSSValue = ParseColor(pszValue, iValueLen); + break; + case CFX_CSSVALUETYPE_MaybeString: + pCSSValue = ParseString(pszValue, iValueLen); + break; + default: + break; + } + if (pCSSValue) { + AddPropertyHolder(pTable->eName, pCSSValue, bImportant); + return; + } + if (CFX_IsOnlyValue(dwType, g_ValueGuessOrder[i])) + return; + } + break; + } + case CFX_CSSVALUETYPE_Shorthand: { + CFX_RetainPtr<CFX_CSSValue> pWidth; + switch (pTable->eName) { + case CFX_CSSProperty::Font: + ParseFontProperty(pszValue, iValueLen, bImportant); + return; + case CFX_CSSProperty::Border: + if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { + AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth, + bImportant); + AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth, + bImportant); + AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth, + bImportant); + AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth, + bImportant); + return; + } + break; + case CFX_CSSProperty::BorderLeft: + if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { + AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth, + bImportant); + return; + } + break; + case CFX_CSSProperty::BorderTop: + if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { + AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth, + bImportant); + return; + } + break; + case CFX_CSSProperty::BorderRight: + if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { + AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth, + bImportant); + return; + } + break; + case CFX_CSSProperty::BorderBottom: + if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { + AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth, + bImportant); + return; + } + break; + default: + break; + } + } break; + case CFX_CSSVALUETYPE_List: + ParseValueListProperty(pTable, pszValue, iValueLen, bImportant); + return; + default: + NOTREACHED(); + break; + } +} + +void CFX_CSSDeclaration::AddProperty(const CFX_WideString& prop, + const CFX_WideString& value) { + custom_properties_.push_back( + pdfium::MakeUnique<CFX_CSSCustomProperty>(prop, value)); +} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber( + const wchar_t* pszValue, + int32_t iValueLen) { + float fValue; + CFX_CSSNumberType eUnit; + if (!ParseCSSNumber(pszValue, iValueLen, fValue, eUnit)) + return nullptr; + return pdfium::MakeRetain<CFX_CSSNumberValue>(eUnit, fValue); +} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum( + const wchar_t* pszValue, + int32_t iValueLen) { + const CFX_CSSPropertyValueTable* pValue = + CFX_GetCSSPropertyValueByName(CFX_WideStringC(pszValue, iValueLen)); + return pValue ? pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName) : nullptr; +} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor( + const wchar_t* pszValue, + int32_t iValueLen) { + FX_ARGB dwColor; + if (!ParseCSSColor(pszValue, iValueLen, &dwColor)) + return nullptr; + return pdfium::MakeRetain<CFX_CSSColorValue>(dwColor); +} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString( + const wchar_t* pszValue, + int32_t iValueLen) { + int32_t iOffset; + if (!ParseCSSString(pszValue, iValueLen, &iOffset, &iValueLen)) + return nullptr; + + if (iValueLen <= 0) + return nullptr; + + return pdfium::MakeRetain<CFX_CSSStringValue>( + CFX_WideString(pszValue + iOffset, iValueLen)); +} + +void CFX_CSSDeclaration::ParseValueListProperty( + const CFX_CSSPropertyTable* pTable, + const wchar_t* pszValue, + int32_t iValueLen, + bool bImportant) { + wchar_t separator = + (pTable->eName == CFX_CSSProperty::FontFamily) ? ',' : ' '; + CFX_CSSValueListParser parser(pszValue, iValueLen, separator); + + const uint32_t dwType = pTable->dwType; + CFX_CSSPrimitiveType eType; + std::vector<CFX_RetainPtr<CFX_CSSValue>> list; + while (parser.NextValue(eType, pszValue, iValueLen)) { + switch (eType) { + case CFX_CSSPrimitiveType::Number: + if (dwType & CFX_CSSVALUETYPE_MaybeNumber) { + float fValue; + CFX_CSSNumberType eNumType; + if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) + list.push_back( + pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue)); + } + break; + case CFX_CSSPrimitiveType::String: + if (dwType & CFX_CSSVALUETYPE_MaybeColor) { + FX_ARGB dwColor; + if (ParseCSSColor(pszValue, iValueLen, &dwColor)) { + list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor)); + continue; + } + } + if (dwType & CFX_CSSVALUETYPE_MaybeEnum) { + const CFX_CSSPropertyValueTable* pValue = + CFX_GetCSSPropertyValueByName( + CFX_WideStringC(pszValue, iValueLen)); + if (pValue) { + list.push_back(pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName)); + continue; + } + } + if (dwType & CFX_CSSVALUETYPE_MaybeString) { + list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>( + CFX_WideString(pszValue, iValueLen))); + } + break; + case CFX_CSSPrimitiveType::RGB: + if (dwType & CFX_CSSVALUETYPE_MaybeColor) { + FX_ARGB dwColor; + if (ParseCSSColor(pszValue, iValueLen, &dwColor)) { + list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor)); + } + } + break; + default: + break; + } + } + if (list.empty()) + return; + + switch (pTable->eName) { + case CFX_CSSProperty::BorderWidth: + Add4ValuesProperty(list, bImportant, CFX_CSSProperty::BorderLeftWidth, + CFX_CSSProperty::BorderTopWidth, + CFX_CSSProperty::BorderRightWidth, + CFX_CSSProperty::BorderBottomWidth); + return; + case CFX_CSSProperty::Margin: + Add4ValuesProperty(list, bImportant, CFX_CSSProperty::MarginLeft, + CFX_CSSProperty::MarginTop, + CFX_CSSProperty::MarginRight, + CFX_CSSProperty::MarginBottom); + return; + case CFX_CSSProperty::Padding: + Add4ValuesProperty(list, bImportant, CFX_CSSProperty::PaddingLeft, + CFX_CSSProperty::PaddingTop, + CFX_CSSProperty::PaddingRight, + CFX_CSSProperty::PaddingBottom); + return; + default: { + auto pList = pdfium::MakeRetain<CFX_CSSValueList>(list); + AddPropertyHolder(pTable->eName, pList, bImportant); + return; + } + } +} + +void CFX_CSSDeclaration::Add4ValuesProperty( + const std::vector<CFX_RetainPtr<CFX_CSSValue>>& list, + bool bImportant, + CFX_CSSProperty eLeft, + CFX_CSSProperty eTop, + CFX_CSSProperty eRight, + CFX_CSSProperty eBottom) { + switch (list.size()) { + case 1: + AddPropertyHolder(eLeft, list[0], bImportant); + AddPropertyHolder(eTop, list[0], bImportant); + AddPropertyHolder(eRight, list[0], bImportant); + AddPropertyHolder(eBottom, list[0], bImportant); + return; + case 2: + AddPropertyHolder(eLeft, list[1], bImportant); + AddPropertyHolder(eTop, list[0], bImportant); + AddPropertyHolder(eRight, list[1], bImportant); + AddPropertyHolder(eBottom, list[0], bImportant); + return; + case 3: + AddPropertyHolder(eLeft, list[1], bImportant); + AddPropertyHolder(eTop, list[0], bImportant); + AddPropertyHolder(eRight, list[1], bImportant); + AddPropertyHolder(eBottom, list[2], bImportant); + return; + case 4: + AddPropertyHolder(eLeft, list[3], bImportant); + AddPropertyHolder(eTop, list[0], bImportant); + AddPropertyHolder(eRight, list[1], bImportant); + AddPropertyHolder(eBottom, list[2], bImportant); + return; + default: + break; + } +} + +bool CFX_CSSDeclaration::ParseBorderProperty( + const wchar_t* pszValue, + int32_t iValueLen, + CFX_RetainPtr<CFX_CSSValue>& pWidth) const { + pWidth.Reset(nullptr); + + CFX_CSSValueListParser parser(pszValue, iValueLen, ' '); + CFX_CSSPrimitiveType eType; + while (parser.NextValue(eType, pszValue, iValueLen)) { + switch (eType) { + case CFX_CSSPrimitiveType::Number: { + if (pWidth) + continue; + + float fValue; + CFX_CSSNumberType eNumType; + if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) + pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); + break; + } + case CFX_CSSPrimitiveType::String: { + const CFX_CSSCOLORTABLE* pColorItem = + CFX_GetCSSColorByName(CFX_WideStringC(pszValue, iValueLen)); + if (pColorItem) + continue; + + const CFX_CSSPropertyValueTable* pValue = + CFX_GetCSSPropertyValueByName(CFX_WideStringC(pszValue, iValueLen)); + if (!pValue) + continue; + + switch (pValue->eName) { + case CFX_CSSPropertyValue::Thin: + case CFX_CSSPropertyValue::Thick: + case CFX_CSSPropertyValue::Medium: + if (!pWidth) + pWidth = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + break; + default: + break; + } + break; + } + default: + break; + } + } + if (!pWidth) + pWidth = + pdfium::MakeRetain<CFX_CSSNumberValue>(CFX_CSSNumberType::Number, 0.0f); + + return true; +} + +void CFX_CSSDeclaration::ParseFontProperty(const wchar_t* pszValue, + int32_t iValueLen, + bool bImportant) { + CFX_CSSValueListParser parser(pszValue, iValueLen, '/'); + CFX_RetainPtr<CFX_CSSValue> pStyle; + CFX_RetainPtr<CFX_CSSValue> pVariant; + CFX_RetainPtr<CFX_CSSValue> pWeight; + CFX_RetainPtr<CFX_CSSValue> pFontSize; + CFX_RetainPtr<CFX_CSSValue> pLineHeight; + std::vector<CFX_RetainPtr<CFX_CSSValue>> familyList; + CFX_CSSPrimitiveType eType; + while (parser.NextValue(eType, pszValue, iValueLen)) { + switch (eType) { + case CFX_CSSPrimitiveType::String: { + const CFX_CSSPropertyValueTable* pValue = + CFX_GetCSSPropertyValueByName(CFX_WideStringC(pszValue, iValueLen)); + if (pValue) { + switch (pValue->eName) { + case CFX_CSSPropertyValue::XxSmall: + case CFX_CSSPropertyValue::XSmall: + case CFX_CSSPropertyValue::Small: + case CFX_CSSPropertyValue::Medium: + case CFX_CSSPropertyValue::Large: + case CFX_CSSPropertyValue::XLarge: + case CFX_CSSPropertyValue::XxLarge: + case CFX_CSSPropertyValue::Smaller: + case CFX_CSSPropertyValue::Larger: + if (!pFontSize) + pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + continue; + case CFX_CSSPropertyValue::Bold: + case CFX_CSSPropertyValue::Bolder: + case CFX_CSSPropertyValue::Lighter: + if (!pWeight) + pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + continue; + case CFX_CSSPropertyValue::Italic: + case CFX_CSSPropertyValue::Oblique: + if (!pStyle) + pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + continue; + case CFX_CSSPropertyValue::SmallCaps: + if (!pVariant) + pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + continue; + case CFX_CSSPropertyValue::Normal: + if (!pStyle) + pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + else if (!pVariant) + pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + else if (!pWeight) + pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + else if (!pFontSize) + pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + else if (!pLineHeight) + pLineHeight = + pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); + continue; + default: + break; + } + } + if (pFontSize) { + familyList.push_back(pdfium::MakeRetain<CFX_CSSStringValue>( + CFX_WideString(pszValue, iValueLen))); + } + parser.m_Separator = ','; + break; + } + case CFX_CSSPrimitiveType::Number: { + float fValue; + CFX_CSSNumberType eNumType; + if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) + break; + if (eType == CFX_CSSPrimitiveType::Number) { + switch ((int32_t)fValue) { + case 100: + case 200: + case 300: + case 400: + case 500: + case 600: + case 700: + case 800: + case 900: + if (!pWeight) + pWeight = pdfium::MakeRetain<CFX_CSSNumberValue>( + CFX_CSSNumberType::Number, fValue); + continue; + } + } + if (!pFontSize) + pFontSize = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); + else if (!pLineHeight) + pLineHeight = + pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); + break; + } + default: + break; + } + } + + if (!pStyle) { + pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); + } + if (!pVariant) { + pVariant = + pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); + } + if (!pWeight) { + pWeight = + pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); + } + if (!pFontSize) { + pFontSize = + pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Medium); + } + if (!pLineHeight) { + pLineHeight = + pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); + } + + AddPropertyHolder(CFX_CSSProperty::FontStyle, pStyle, bImportant); + AddPropertyHolder(CFX_CSSProperty::FontVariant, pVariant, bImportant); + AddPropertyHolder(CFX_CSSProperty::FontWeight, pWeight, bImportant); + AddPropertyHolder(CFX_CSSProperty::FontSize, pFontSize, bImportant); + AddPropertyHolder(CFX_CSSProperty::LineHeight, pLineHeight, bImportant); + if (!familyList.empty()) { + auto pList = pdfium::MakeRetain<CFX_CSSValueList>(familyList); + AddPropertyHolder(CFX_CSSProperty::FontFamily, pList, bImportant); + } +} + +size_t CFX_CSSDeclaration::PropertyCountForTesting() const { + return properties_.size(); +} diff --git a/core/fxcrt/css/cfx_cssdeclaration.h b/core/fxcrt/css/cfx_cssdeclaration.h new file mode 100644 index 0000000000..7b39daef7e --- /dev/null +++ b/core/fxcrt/css/cfx_cssdeclaration.h @@ -0,0 +1,93 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSDECLARATION_H_ +#define CORE_FXCRT_CSS_CFX_CSSDECLARATION_H_ + +#include <memory> +#include <utility> +#include <vector> + +#include "core/fxcrt/css/cfx_cssdatatable.h" + +class CFX_CSSPropertyHolder; +class CFX_CSSCustomProperty; + +class CFX_CSSDeclaration { + public: + using const_prop_iterator = + std::vector<std::unique_ptr<CFX_CSSPropertyHolder>>::const_iterator; + using const_custom_iterator = + std::vector<std::unique_ptr<CFX_CSSCustomProperty>>::const_iterator; + + static bool ParseCSSString(const wchar_t* pszValue, + int32_t iValueLen, + int32_t* iOffset, + int32_t* iLength); + static bool ParseCSSColor(const wchar_t* pszValue, + int32_t iValueLen, + FX_ARGB* dwColor); + + CFX_CSSDeclaration(); + ~CFX_CSSDeclaration(); + + CFX_RetainPtr<CFX_CSSValue> GetProperty(CFX_CSSProperty eProperty, + bool* bImportant) const; + + const_prop_iterator begin() const { return properties_.begin(); } + const_prop_iterator end() const { return properties_.end(); } + + const_custom_iterator custom_begin() const { + return custom_properties_.begin(); + } + const_custom_iterator custom_end() const { return custom_properties_.end(); } + + bool empty() const { return properties_.empty(); } + + void AddProperty(const CFX_CSSPropertyTable* pTable, + const CFX_WideStringC& value); + void AddProperty(const CFX_WideString& prop, const CFX_WideString& value); + + size_t PropertyCountForTesting() const; + + FX_ARGB ParseColorForTest(const wchar_t* pszValue, + int32_t iValueLen, + FX_ARGB* dwColor) const; + + private: + void ParseFontProperty(const wchar_t* pszValue, + int32_t iValueLen, + bool bImportant); + bool ParseBorderProperty(const wchar_t* pszValue, + int32_t iValueLen, + CFX_RetainPtr<CFX_CSSValue>& pWidth) const; + void ParseValueListProperty(const CFX_CSSPropertyTable* pTable, + const wchar_t* pszValue, + int32_t iValueLen, + bool bImportant); + void Add4ValuesProperty(const std::vector<CFX_RetainPtr<CFX_CSSValue>>& list, + bool bImportant, + CFX_CSSProperty eLeft, + CFX_CSSProperty eTop, + CFX_CSSProperty eRight, + CFX_CSSProperty eBottom); + CFX_RetainPtr<CFX_CSSValue> ParseNumber(const wchar_t* pszValue, + int32_t iValueLen); + CFX_RetainPtr<CFX_CSSValue> ParseEnum(const wchar_t* pszValue, + int32_t iValueLen); + CFX_RetainPtr<CFX_CSSValue> ParseColor(const wchar_t* pszValue, + int32_t iValueLen); + CFX_RetainPtr<CFX_CSSValue> ParseString(const wchar_t* pszValue, + int32_t iValueLen); + void AddPropertyHolder(CFX_CSSProperty eProperty, + CFX_RetainPtr<CFX_CSSValue> pValue, + bool bImportant); + + std::vector<std::unique_ptr<CFX_CSSPropertyHolder>> properties_; + std::vector<std::unique_ptr<CFX_CSSCustomProperty>> custom_properties_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSDECLARATION_H_ diff --git a/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp b/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp new file mode 100644 index 0000000000..535e67da97 --- /dev/null +++ b/core/fxcrt/css/cfx_cssdeclaration_unittest.cpp @@ -0,0 +1,62 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fxcrt/css/cfx_cssdeclaration.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" + +TEST(CFX_CSSDeclarationTest, HexEncodingParsing) { + FX_ARGB color; + + // Length value invalid. + EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000", 3, &color)); + EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000000", 5, &color)); + EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"#000000", 8, &color)); + + // Invalid characters + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#zxytlm", 7, &color)); + EXPECT_EQ(0, FXARGB_R(color)); + EXPECT_EQ(0, FXARGB_G(color)); + EXPECT_EQ(0, FXARGB_B(color)); + + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#000", 4, &color)); + EXPECT_EQ(0, FXARGB_R(color)); + EXPECT_EQ(0, FXARGB_G(color)); + EXPECT_EQ(0, FXARGB_B(color)); + + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#FFF", 4, &color)); + EXPECT_EQ(255, FXARGB_R(color)); + EXPECT_EQ(255, FXARGB_G(color)); + EXPECT_EQ(255, FXARGB_B(color)); + + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#F0F0F0", 7, &color)); + EXPECT_EQ(240, FXARGB_R(color)); + EXPECT_EQ(240, FXARGB_G(color)); + EXPECT_EQ(240, FXARGB_B(color)); + + // Upper and lower case characters. + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"#1b2F3c", 7, &color)); + EXPECT_EQ(27, FXARGB_R(color)); + EXPECT_EQ(47, FXARGB_G(color)); + EXPECT_EQ(60, FXARGB_B(color)); +} + +TEST(CFX_CSSDeclarationTest, RGBEncodingParsing) { + FX_ARGB color; + + // Invalid input for rgb() syntax. + EXPECT_FALSE(CFX_CSSDeclaration::ParseCSSColor(L"blahblahblah", 11, &color)); + + EXPECT_TRUE(CFX_CSSDeclaration::ParseCSSColor(L"rgb(0, 0, 0)", 12, &color)); + EXPECT_EQ(0, FXARGB_R(color)); + EXPECT_EQ(0, FXARGB_G(color)); + EXPECT_EQ(0, FXARGB_B(color)); + + EXPECT_TRUE( + CFX_CSSDeclaration::ParseCSSColor(L"rgb(128,255,48)", 15, &color)); + EXPECT_EQ(128, FXARGB_R(color)); + EXPECT_EQ(255, FXARGB_G(color)); + EXPECT_EQ(48, FXARGB_B(color)); +} diff --git a/core/fxcrt/css/cfx_cssenumvalue.cpp b/core/fxcrt/css/cfx_cssenumvalue.cpp new file mode 100644 index 0000000000..c9b39beb34 --- /dev/null +++ b/core/fxcrt/css/cfx_cssenumvalue.cpp @@ -0,0 +1,12 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssenumvalue.h" + +CFX_CSSEnumValue::CFX_CSSEnumValue(CFX_CSSPropertyValue value) + : CFX_CSSValue(CFX_CSSPrimitiveType::Enum), value_(value) {} + +CFX_CSSEnumValue::~CFX_CSSEnumValue() {} diff --git a/core/fxcrt/css/cfx_cssenumvalue.h b/core/fxcrt/css/cfx_cssenumvalue.h new file mode 100644 index 0000000000..0d6b87e85d --- /dev/null +++ b/core/fxcrt/css/cfx_cssenumvalue.h @@ -0,0 +1,23 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSENUMVALUE_H_ +#define CORE_FXCRT_CSS_CFX_CSSENUMVALUE_H_ + +#include "core/fxcrt/css/cfx_cssvalue.h" + +class CFX_CSSEnumValue : public CFX_CSSValue { + public: + explicit CFX_CSSEnumValue(CFX_CSSPropertyValue value); + ~CFX_CSSEnumValue() override; + + CFX_CSSPropertyValue Value() const { return value_; } + + private: + CFX_CSSPropertyValue value_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSENUMVALUE_H_ diff --git a/core/fxcrt/css/cfx_cssexttextbuf.cpp b/core/fxcrt/css/cfx_cssexttextbuf.cpp new file mode 100644 index 0000000000..287dc2e954 --- /dev/null +++ b/core/fxcrt/css/cfx_cssexttextbuf.cpp @@ -0,0 +1,17 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssexttextbuf.h" + +CFX_CSSExtTextBuf::CFX_CSSExtTextBuf() + : m_pExtBuffer(nullptr), m_iDatLen(0), m_iDatPos(0) {} + +CFX_CSSExtTextBuf::~CFX_CSSExtTextBuf() {} + +void CFX_CSSExtTextBuf::AttachBuffer(const wchar_t* pBuffer, int32_t iBufLen) { + m_pExtBuffer = pBuffer; + m_iDatLen = iBufLen; +} diff --git a/core/fxcrt/css/cfx_cssexttextbuf.h b/core/fxcrt/css/cfx_cssexttextbuf.h new file mode 100644 index 0000000000..342b91e8aa --- /dev/null +++ b/core/fxcrt/css/cfx_cssexttextbuf.h @@ -0,0 +1,34 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSEXTTEXTBUF_H_ +#define CORE_FXCRT_CSS_CFX_CSSEXTTEXTBUF_H_ + +#include "core/fxcrt/fx_system.h" + +class CFX_CSSExtTextBuf { + public: + CFX_CSSExtTextBuf(); + ~CFX_CSSExtTextBuf(); + + void AttachBuffer(const wchar_t* pBuffer, int32_t iBufLen); + + bool IsEOF() const { return m_iDatPos >= m_iDatLen; } + + wchar_t GetChar() const { return m_pExtBuffer[m_iDatPos]; } + wchar_t GetNextChar() const { + return (m_iDatPos + 1 >= m_iDatLen) ? 0 : m_pExtBuffer[m_iDatPos + 1]; + } + + void MoveNext() { m_iDatPos++; } + + protected: + const wchar_t* m_pExtBuffer; + int32_t m_iDatLen; + int32_t m_iDatPos; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSEXTTEXTBUF_H_ diff --git a/core/fxcrt/css/cfx_cssnumbervalue.cpp b/core/fxcrt/css/cfx_cssnumbervalue.cpp new file mode 100644 index 0000000000..d8f72479d4 --- /dev/null +++ b/core/fxcrt/css/cfx_cssnumbervalue.cpp @@ -0,0 +1,39 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssnumbervalue.h" + +CFX_CSSNumberValue::CFX_CSSNumberValue(CFX_CSSNumberType type, float value) + : CFX_CSSValue(CFX_CSSPrimitiveType::Number), type_(type), value_(value) { + if (type_ == CFX_CSSNumberType::Number && fabs(value_) < 0.001f) + value_ = 0.0f; +} + +CFX_CSSNumberValue::~CFX_CSSNumberValue() {} + +float CFX_CSSNumberValue::Apply(float percentBase) const { + switch (type_) { + case CFX_CSSNumberType::Pixels: + case CFX_CSSNumberType::Number: + return value_ * 72 / 96; + case CFX_CSSNumberType::EMS: + case CFX_CSSNumberType::EXS: + return value_ * percentBase; + case CFX_CSSNumberType::Percent: + return value_ * percentBase / 100.0f; + case CFX_CSSNumberType::CentiMeters: + return value_ * 28.3464f; + case CFX_CSSNumberType::MilliMeters: + return value_ * 2.8346f; + case CFX_CSSNumberType::Inches: + return value_ * 72.0f; + case CFX_CSSNumberType::Picas: + return value_ / 12.0f; + case CFX_CSSNumberType::Points: + return value_; + } + return value_; +} diff --git a/core/fxcrt/css/cfx_cssnumbervalue.h b/core/fxcrt/css/cfx_cssnumbervalue.h new file mode 100644 index 0000000000..a49328d663 --- /dev/null +++ b/core/fxcrt/css/cfx_cssnumbervalue.h @@ -0,0 +1,41 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSNUMBERVALUE_H_ +#define CORE_FXCRT_CSS_CFX_CSSNUMBERVALUE_H_ + +#include "core/fxcrt/css/cfx_cssvalue.h" +#include "core/fxcrt/fx_system.h" + +enum class CFX_CSSNumberType { + Number, + Percent, + EMS, + EXS, + Pixels, + CentiMeters, + MilliMeters, + Inches, + Points, + Picas, +}; + +class CFX_CSSNumberValue : public CFX_CSSValue { + public: + CFX_CSSNumberValue(CFX_CSSNumberType type, float value); + ~CFX_CSSNumberValue() override; + + float Value() const { return value_; } + CFX_CSSNumberType Kind() const { return type_; } + + float Apply(float percentBase) const; + + private: + CFX_CSSNumberType type_; + float value_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSNUMBERVALUE_H_ diff --git a/core/fxcrt/css/cfx_csspropertyholder.cpp b/core/fxcrt/css/cfx_csspropertyholder.cpp new file mode 100644 index 0000000000..11e0d4b752 --- /dev/null +++ b/core/fxcrt/css/cfx_csspropertyholder.cpp @@ -0,0 +1,11 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_csspropertyholder.h" + +CFX_CSSPropertyHolder::CFX_CSSPropertyHolder() {} + +CFX_CSSPropertyHolder::~CFX_CSSPropertyHolder() {} diff --git a/core/fxcrt/css/cfx_csspropertyholder.h b/core/fxcrt/css/cfx_csspropertyholder.h new file mode 100644 index 0000000000..ab0e0ae1fb --- /dev/null +++ b/core/fxcrt/css/cfx_csspropertyholder.h @@ -0,0 +1,24 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSPROPERTYHOLDER_H_ +#define CORE_FXCRT_CSS_CFX_CSSPROPERTYHOLDER_H_ + +#include "core/fxcrt/cfx_retain_ptr.h" +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/css/cfx_cssvalue.h" + +class CFX_CSSPropertyHolder { + public: + CFX_CSSPropertyHolder(); + ~CFX_CSSPropertyHolder(); + + CFX_CSSProperty eProperty; + bool bImportant; + CFX_RetainPtr<CFX_CSSValue> pValue; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSPROPERTYHOLDER_H_ diff --git a/core/fxcrt/css/cfx_cssrulecollection.cpp b/core/fxcrt/css/cfx_cssrulecollection.cpp new file mode 100644 index 0000000000..635ca91c72 --- /dev/null +++ b/core/fxcrt/css/cfx_cssrulecollection.cpp @@ -0,0 +1,56 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssrulecollection.h" + +#include <algorithm> +#include <utility> + +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/css/cfx_cssselector.h" +#include "core/fxcrt/css/cfx_cssstylerule.h" +#include "core/fxcrt/css/cfx_cssstylesheet.h" +#include "core/fxcrt/css/cfx_csssyntaxparser.h" +#include "third_party/base/ptr_util.h" + +CFX_CSSRuleCollection::CFX_CSSRuleCollection() : m_iSelectors(0) {} + +CFX_CSSRuleCollection::~CFX_CSSRuleCollection() { + Clear(); +} + +void CFX_CSSRuleCollection::Clear() { + m_TagRules.clear(); + m_iSelectors = 0; +} + +const std::vector<std::unique_ptr<CFX_CSSRuleCollection::Data>>* +CFX_CSSRuleCollection::GetTagRuleData(const CFX_WideString& tagname) const { + auto it = m_TagRules.find(FX_HashCode_GetW(tagname.c_str(), true)); + return it != m_TagRules.end() ? &it->second : nullptr; +} + +void CFX_CSSRuleCollection::AddRulesFrom(const CFX_CSSStyleSheet* sheet) { + int32_t iRules = sheet->CountRules(); + for (int32_t j = 0; j < iRules; j++) + AddRulesFrom(sheet, sheet->GetRule(j)); +} + +void CFX_CSSRuleCollection::AddRulesFrom(const CFX_CSSStyleSheet* pStyleSheet, + CFX_CSSStyleRule* pStyleRule) { + CFX_CSSDeclaration* pDeclaration = pStyleRule->GetDeclaration(); + int32_t iSelectors = pStyleRule->CountSelectorLists(); + for (int32_t i = 0; i < iSelectors; ++i) { + CFX_CSSSelector* pSelector = pStyleRule->GetSelectorList(i); + m_TagRules[pSelector->GetNameHash()].push_back( + pdfium::MakeUnique<Data>(pSelector, pDeclaration)); + m_iSelectors++; + } +} + +CFX_CSSRuleCollection::Data::Data(CFX_CSSSelector* pSel, + CFX_CSSDeclaration* pDecl) + : pSelector(pSel), pDeclaration(pDecl) {} diff --git a/core/fxcrt/css/cfx_cssrulecollection.h b/core/fxcrt/css/cfx_cssrulecollection.h new file mode 100644 index 0000000000..6a509d49e7 --- /dev/null +++ b/core/fxcrt/css/cfx_cssrulecollection.h @@ -0,0 +1,49 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSRULECOLLECTION_H_ +#define CORE_FXCRT_CSS_CFX_CSSRULECOLLECTION_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "core/fxcrt/fx_basic.h" + +class CFX_CSSDeclaration; +class CFX_CSSSelector; +class CFX_CSSStyleRule; +class CFX_CSSStyleSheet; + +class CFX_CSSRuleCollection { + public: + class Data { + public: + Data(CFX_CSSSelector* pSel, CFX_CSSDeclaration* pDecl); + + CFX_CSSSelector* const pSelector; + CFX_CSSDeclaration* const pDeclaration; + }; + + CFX_CSSRuleCollection(); + ~CFX_CSSRuleCollection(); + + void AddRulesFrom(const CFX_CSSStyleSheet* sheet); + void Clear(); + int32_t CountSelectors() const { return m_iSelectors; } + + const std::vector<std::unique_ptr<Data>>* GetTagRuleData( + const CFX_WideString& tagname) const; + + private: + void AddRulesFrom(const CFX_CSSStyleSheet* pStyleSheet, + CFX_CSSStyleRule* pRule); + + std::map<uint32_t, std::vector<std::unique_ptr<Data>>> m_TagRules; + int32_t m_iSelectors; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSRULECOLLECTION_H_ diff --git a/core/fxcrt/css/cfx_cssselector.cpp b/core/fxcrt/css/cfx_cssselector.cpp new file mode 100644 index 0000000000..6ee81f5610 --- /dev/null +++ b/core/fxcrt/css/cfx_cssselector.cpp @@ -0,0 +1,87 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssselector.h" + +#include <utility> + +#include "core/fxcrt/fx_extension.h" +#include "third_party/base/ptr_util.h" + +namespace { + +int32_t GetCSSNameLen(const wchar_t* psz, const wchar_t* pEnd) { + const wchar_t* pStart = psz; + while (psz < pEnd) { + wchar_t wch = *psz; + if (!FXSYS_iswalnum(wch) && wch != '_' && wch != '-') + break; + ++psz; + } + return psz - pStart; +} + +} // namespace + +CFX_CSSSelector::CFX_CSSSelector(CFX_CSSSelectorType eType, + const wchar_t* psz, + int32_t iLen, + bool bIgnoreCase) + : m_eType(eType), + m_dwHash(FX_HashCode_GetW(CFX_WideStringC(psz, iLen), bIgnoreCase)) {} + +CFX_CSSSelector::~CFX_CSSSelector() {} + +CFX_CSSSelectorType CFX_CSSSelector::GetType() const { + return m_eType; +} + +uint32_t CFX_CSSSelector::GetNameHash() const { + return m_dwHash; +} + +CFX_CSSSelector* CFX_CSSSelector::GetNextSelector() const { + return m_pNext.get(); +} + +// static. +std::unique_ptr<CFX_CSSSelector> CFX_CSSSelector::FromString( + const CFX_WideStringC& str) { + ASSERT(!str.IsEmpty()); + + const wchar_t* psz = str.unterminated_c_str(); + const wchar_t* pStart = psz; + const wchar_t* pEnd = psz + str.GetLength(); + for (; psz < pEnd; ++psz) { + switch (*psz) { + case '>': + case '[': + case '+': + return nullptr; + } + } + + std::unique_ptr<CFX_CSSSelector> pFirst = nullptr; + for (psz = pStart; psz < pEnd;) { + wchar_t wch = *psz; + if (FXSYS_iswalpha(wch) || wch == '*') { + int32_t iNameLen = wch == '*' ? 1 : GetCSSNameLen(psz, pEnd); + auto p = pdfium::MakeUnique<CFX_CSSSelector>(CFX_CSSSelectorType::Element, + psz, iNameLen, true); + if (pFirst) { + pFirst->SetType(CFX_CSSSelectorType::Descendant); + p->SetNext(std::move(pFirst)); + } + pFirst = std::move(p); + psz += iNameLen; + } else if (wch == ' ') { + psz++; + } else { + return nullptr; + } + } + return pFirst; +} diff --git a/core/fxcrt/css/cfx_cssselector.h b/core/fxcrt/css/cfx_cssselector.h new file mode 100644 index 0000000000..9fff42a850 --- /dev/null +++ b/core/fxcrt/css/cfx_cssselector.h @@ -0,0 +1,43 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSELECTOR_H_ +#define CORE_FXCRT_CSS_CFX_CSSSELECTOR_H_ + +#include <memory> +#include <utility> + +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/fx_string.h" + +class CFX_CSSSelector { + public: + static std::unique_ptr<CFX_CSSSelector> FromString( + const CFX_WideStringC& str); + + CFX_CSSSelector(CFX_CSSSelectorType eType, + const wchar_t* psz, + int32_t iLen, + bool bIgnoreCase); + ~CFX_CSSSelector(); + + CFX_CSSSelectorType GetType() const; + uint32_t GetNameHash() const; + CFX_CSSSelector* GetNextSelector() const; + + void SetNext(std::unique_ptr<CFX_CSSSelector> pNext) { + m_pNext = std::move(pNext); + } + + private: + void SetType(CFX_CSSSelectorType eType) { m_eType = eType; } + + CFX_CSSSelectorType m_eType; + uint32_t m_dwHash; + std::unique_ptr<CFX_CSSSelector> m_pNext; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSELECTOR_H_ diff --git a/core/fxcrt/css/cfx_cssstringvalue.cpp b/core/fxcrt/css/cfx_cssstringvalue.cpp new file mode 100644 index 0000000000..b66c54505f --- /dev/null +++ b/core/fxcrt/css/cfx_cssstringvalue.cpp @@ -0,0 +1,12 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssstringvalue.h" + +CFX_CSSStringValue::CFX_CSSStringValue(const CFX_WideString& value) + : CFX_CSSValue(CFX_CSSPrimitiveType::String), value_(value) {} + +CFX_CSSStringValue::~CFX_CSSStringValue() {} diff --git a/core/fxcrt/css/cfx_cssstringvalue.h b/core/fxcrt/css/cfx_cssstringvalue.h new file mode 100644 index 0000000000..7680360973 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstringvalue.h @@ -0,0 +1,23 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSTRINGVALUE_H_ +#define CORE_FXCRT_CSS_CFX_CSSSTRINGVALUE_H_ + +#include "core/fxcrt/css/cfx_cssvalue.h" + +class CFX_CSSStringValue : public CFX_CSSValue { + public: + explicit CFX_CSSStringValue(const CFX_WideString& value); + ~CFX_CSSStringValue() override; + + const CFX_WideString Value() const { return value_; } + + private: + const CFX_WideString value_; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSTRINGVALUE_H_ diff --git a/core/fxcrt/css/cfx_cssstylerule.cpp b/core/fxcrt/css/cfx_cssstylerule.cpp new file mode 100644 index 0000000000..504771ed46 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstylerule.cpp @@ -0,0 +1,30 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssstylerule.h" + +CFX_CSSStyleRule::CFX_CSSStyleRule() {} + +CFX_CSSStyleRule::~CFX_CSSStyleRule() {} + +size_t CFX_CSSStyleRule::CountSelectorLists() const { + return m_ppSelector.size(); +} + +CFX_CSSSelector* CFX_CSSStyleRule::GetSelectorList(int32_t index) const { + return m_ppSelector[index].get(); +} + +CFX_CSSDeclaration* CFX_CSSStyleRule::GetDeclaration() { + return &m_Declaration; +} + +void CFX_CSSStyleRule::SetSelector( + std::vector<std::unique_ptr<CFX_CSSSelector>>* list) { + ASSERT(m_ppSelector.empty()); + + m_ppSelector.swap(*list); +} diff --git a/core/fxcrt/css/cfx_cssstylerule.h b/core/fxcrt/css/cfx_cssstylerule.h new file mode 100644 index 0000000000..bba1fc53c8 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstylerule.h @@ -0,0 +1,32 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSTYLERULE_H_ +#define CORE_FXCRT_CSS_CFX_CSSSTYLERULE_H_ + +#include <memory> +#include <vector> + +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/css/cfx_cssselector.h" + +class CFX_CSSStyleRule { + public: + CFX_CSSStyleRule(); + ~CFX_CSSStyleRule(); + + size_t CountSelectorLists() const; + CFX_CSSSelector* GetSelectorList(int32_t index) const; + CFX_CSSDeclaration* GetDeclaration(); + + void SetSelector(std::vector<std::unique_ptr<CFX_CSSSelector>>* list); + + private: + CFX_CSSDeclaration m_Declaration; + std::vector<std::unique_ptr<CFX_CSSSelector>> m_ppSelector; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSTYLERULE_H_ diff --git a/core/fxcrt/css/cfx_cssstyleselector.cpp b/core/fxcrt/css/cfx_cssstyleselector.cpp new file mode 100644 index 0000000000..9a2bc8c498 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstyleselector.cpp @@ -0,0 +1,598 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssstyleselector.h" + +#include <algorithm> +#include <utility> + +#include "core/fxcrt/css/cfx_csscolorvalue.h" +#include "core/fxcrt/css/cfx_csscomputedstyle.h" +#include "core/fxcrt/css/cfx_csscustomproperty.h" +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/css/cfx_cssenumvalue.h" +#include "core/fxcrt/css/cfx_csspropertyholder.h" +#include "core/fxcrt/css/cfx_cssselector.h" +#include "core/fxcrt/css/cfx_cssstylesheet.h" +#include "core/fxcrt/css/cfx_csssyntaxparser.h" +#include "core/fxcrt/css/cfx_cssvaluelist.h" +#include "third_party/base/logging.h" +#include "third_party/base/ptr_util.h" + +CFX_CSSStyleSelector::CFX_CSSStyleSelector() : m_fDefFontSize(12.0f) {} + +CFX_CSSStyleSelector::~CFX_CSSStyleSelector() {} + +void CFX_CSSStyleSelector::SetDefFontSize(float fFontSize) { + ASSERT(fFontSize > 0); + m_fDefFontSize = fFontSize; +} + +CFX_RetainPtr<CFX_CSSComputedStyle> CFX_CSSStyleSelector::CreateComputedStyle( + CFX_CSSComputedStyle* pParentStyle) { + auto pStyle = pdfium::MakeRetain<CFX_CSSComputedStyle>(); + if (pParentStyle) + pStyle->m_InheritedData = pParentStyle->m_InheritedData; + return pStyle; +} + +void CFX_CSSStyleSelector::SetUAStyleSheet( + std::unique_ptr<CFX_CSSStyleSheet> pSheet) { + m_UAStyles = std::move(pSheet); +} + +void CFX_CSSStyleSelector::UpdateStyleIndex() { + m_UARules.Clear(); + m_UARules.AddRulesFrom(m_UAStyles.get()); +} + +std::vector<const CFX_CSSDeclaration*> CFX_CSSStyleSelector::MatchDeclarations( + const CFX_WideString& tagname) { + std::vector<const CFX_CSSDeclaration*> matchedDecls; + if (m_UARules.CountSelectors() == 0 || tagname.IsEmpty()) + return matchedDecls; + + auto* rules = m_UARules.GetTagRuleData(tagname); + if (!rules) + return matchedDecls; + + for (const auto& d : *rules) { + if (MatchSelector(tagname, d->pSelector)) + matchedDecls.push_back(d->pDeclaration); + } + return matchedDecls; +} + +bool CFX_CSSStyleSelector::MatchSelector(const CFX_WideString& tagname, + CFX_CSSSelector* pSel) { + // TODO(dsinclair): The code only supports a single level of selector at this + // point. None of the code using selectors required the complexity so lets + // just say we don't support them to simplify the code for now. + if (!pSel || pSel->GetNextSelector() || + pSel->GetType() == CFX_CSSSelectorType::Descendant) { + return false; + } + return pSel->GetNameHash() == FX_HashCode_GetW(tagname.c_str(), true); +} + +void CFX_CSSStyleSelector::ComputeStyle( + const std::vector<const CFX_CSSDeclaration*>& declArray, + const CFX_WideString& styleString, + const CFX_WideString& alignString, + CFX_CSSComputedStyle* pDest) { + std::unique_ptr<CFX_CSSDeclaration> pDecl; + if (!styleString.IsEmpty() || !alignString.IsEmpty()) { + pDecl = pdfium::MakeUnique<CFX_CSSDeclaration>(); + + if (!styleString.IsEmpty()) + AppendInlineStyle(pDecl.get(), styleString); + if (!alignString.IsEmpty()) { + pDecl->AddProperty(CFX_GetCSSPropertyByEnum(CFX_CSSProperty::TextAlign), + alignString.AsStringC()); + } + } + ApplyDeclarations(declArray, pDecl.get(), pDest); +} + +void CFX_CSSStyleSelector::ApplyDeclarations( + const std::vector<const CFX_CSSDeclaration*>& declArray, + const CFX_CSSDeclaration* extraDecl, + CFX_CSSComputedStyle* pComputedStyle) { + std::vector<const CFX_CSSPropertyHolder*> importants; + std::vector<const CFX_CSSPropertyHolder*> normals; + std::vector<const CFX_CSSCustomProperty*> customs; + + for (auto* decl : declArray) + ExtractValues(decl, &importants, &normals, &customs); + + if (extraDecl) + ExtractValues(extraDecl, &importants, &normals, &customs); + + for (auto* prop : normals) + ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle); + + for (auto* prop : customs) + pComputedStyle->AddCustomStyle(*prop); + + for (auto* prop : importants) + ApplyProperty(prop->eProperty, prop->pValue, pComputedStyle); +} + +void CFX_CSSStyleSelector::ExtractValues( + const CFX_CSSDeclaration* decl, + std::vector<const CFX_CSSPropertyHolder*>* importants, + std::vector<const CFX_CSSPropertyHolder*>* normals, + std::vector<const CFX_CSSCustomProperty*>* custom) { + for (const auto& holder : *decl) { + if (holder->bImportant) + importants->push_back(holder.get()); + else + normals->push_back(holder.get()); + } + for (auto it = decl->custom_begin(); it != decl->custom_end(); it++) + custom->push_back(it->get()); +} + +void CFX_CSSStyleSelector::AppendInlineStyle(CFX_CSSDeclaration* pDecl, + const CFX_WideString& style) { + ASSERT(pDecl && !style.IsEmpty()); + + auto pSyntax = pdfium::MakeUnique<CFX_CSSSyntaxParser>( + style.c_str(), style.GetLength(), 32, true); + int32_t iLen2 = 0; + const CFX_CSSPropertyTable* table = nullptr; + CFX_WideString wsName; + while (1) { + CFX_CSSSyntaxStatus eStatus = pSyntax->DoSyntaxParse(); + if (eStatus == CFX_CSSSyntaxStatus::PropertyName) { + CFX_WideStringC strValue = pSyntax->GetCurrentString(); + table = CFX_GetCSSPropertyByName(strValue); + if (!table) + wsName = CFX_WideString(strValue); + } else if (eStatus == CFX_CSSSyntaxStatus::PropertyValue) { + if (table || iLen2 > 0) { + CFX_WideStringC strValue = pSyntax->GetCurrentString(); + if (!strValue.IsEmpty()) { + if (table) + pDecl->AddProperty(table, strValue); + else if (iLen2 > 0) + pDecl->AddProperty(wsName, CFX_WideString(strValue)); + } + } + } else { + break; + } + } +} + +void CFX_CSSStyleSelector::ApplyProperty( + CFX_CSSProperty eProperty, + const CFX_RetainPtr<CFX_CSSValue>& pValue, + CFX_CSSComputedStyle* pComputedStyle) { + if (pValue->GetType() != CFX_CSSPrimitiveType::List) { + CFX_CSSPrimitiveType eType = pValue->GetType(); + switch (eProperty) { + case CFX_CSSProperty::Display: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_NonInheritedData.m_eDisplay = + ToDisplay(pValue.As<CFX_CSSEnumValue>()->Value()); + } + break; + case CFX_CSSProperty::FontSize: { + float& fFontSize = pComputedStyle->m_InheritedData.m_fFontSize; + if (eType == CFX_CSSPrimitiveType::Number) { + fFontSize = pValue.As<CFX_CSSNumberValue>()->Apply(fFontSize); + } else if (eType == CFX_CSSPrimitiveType::Enum) { + fFontSize = + ToFontSize(pValue.As<CFX_CSSEnumValue>()->Value(), fFontSize); + } + } break; + case CFX_CSSProperty::LineHeight: + if (eType == CFX_CSSPrimitiveType::Number) { + CFX_RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>(); + if (v->Kind() == CFX_CSSNumberType::Number) { + pComputedStyle->m_InheritedData.m_fLineHeight = + v->Value() * pComputedStyle->m_InheritedData.m_fFontSize; + } else { + pComputedStyle->m_InheritedData.m_fLineHeight = + v->Apply(pComputedStyle->m_InheritedData.m_fFontSize); + } + } + break; + case CFX_CSSProperty::TextAlign: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_eTextAlign = + ToTextAlign(pValue.As<CFX_CSSEnumValue>()->Value()); + } + break; + case CFX_CSSProperty::TextIndent: + SetLengthWithPercent(pComputedStyle->m_InheritedData.m_TextIndent, + eType, pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + break; + case CFX_CSSProperty::FontWeight: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_wFontWeight = + ToFontWeight(pValue.As<CFX_CSSEnumValue>()->Value()); + } else if (eType == CFX_CSSPrimitiveType::Number) { + int32_t iValue = + (int32_t)pValue.As<CFX_CSSNumberValue>()->Value() / 100; + if (iValue >= 1 && iValue <= 9) { + pComputedStyle->m_InheritedData.m_wFontWeight = iValue * 100; + } + } + break; + case CFX_CSSProperty::FontStyle: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_eFontStyle = + ToFontStyle(pValue.As<CFX_CSSEnumValue>()->Value()); + } + break; + case CFX_CSSProperty::Color: + if (eType == CFX_CSSPrimitiveType::RGB) { + pComputedStyle->m_InheritedData.m_dwFontColor = + pValue.As<CFX_CSSColorValue>()->Value(); + } + break; + case CFX_CSSProperty::MarginLeft: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_MarginWidth.left, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasMargin = true; + } + break; + case CFX_CSSProperty::MarginTop: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_MarginWidth.top, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasMargin = true; + } + break; + case CFX_CSSProperty::MarginRight: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_MarginWidth.right, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasMargin = true; + } + break; + case CFX_CSSProperty::MarginBottom: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_MarginWidth.bottom, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasMargin = true; + } + break; + case CFX_CSSProperty::PaddingLeft: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_PaddingWidth.left, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasPadding = true; + } + break; + case CFX_CSSProperty::PaddingTop: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_PaddingWidth.top, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasPadding = true; + } + break; + case CFX_CSSProperty::PaddingRight: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_PaddingWidth.right, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasPadding = true; + } + break; + case CFX_CSSProperty::PaddingBottom: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_PaddingWidth.bottom, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasPadding = true; + } + break; + case CFX_CSSProperty::BorderLeftWidth: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_BorderWidth.left, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasBorder = true; + } + break; + case CFX_CSSProperty::BorderTopWidth: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_BorderWidth.top, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasBorder = true; + } + break; + case CFX_CSSProperty::BorderRightWidth: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_BorderWidth.right, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasBorder = true; + } + break; + case CFX_CSSProperty::BorderBottomWidth: + if (SetLengthWithPercent( + pComputedStyle->m_NonInheritedData.m_BorderWidth.bottom, eType, + pValue, pComputedStyle->m_InheritedData.m_fFontSize)) { + pComputedStyle->m_NonInheritedData.m_bHasBorder = true; + } + break; + case CFX_CSSProperty::VerticalAlign: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_NonInheritedData.m_eVerticalAlign = + ToVerticalAlign(pValue.As<CFX_CSSEnumValue>()->Value()); + } else if (eType == CFX_CSSPrimitiveType::Number) { + pComputedStyle->m_NonInheritedData.m_eVerticalAlign = + CFX_CSSVerticalAlign::Number; + pComputedStyle->m_NonInheritedData.m_fVerticalAlign = + pValue.As<CFX_CSSNumberValue>()->Apply( + pComputedStyle->m_InheritedData.m_fFontSize); + } + break; + case CFX_CSSProperty::FontVariant: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_eFontVariant = + ToFontVariant(pValue.As<CFX_CSSEnumValue>()->Value()); + } + break; + case CFX_CSSProperty::LetterSpacing: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_LetterSpacing.Set( + CFX_CSSLengthUnit::Normal); + } else if (eType == CFX_CSSPrimitiveType::Number) { + if (pValue.As<CFX_CSSNumberValue>()->Kind() == + CFX_CSSNumberType::Percent) { + break; + } + + SetLengthWithPercent(pComputedStyle->m_InheritedData.m_LetterSpacing, + eType, pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + } + break; + case CFX_CSSProperty::WordSpacing: + if (eType == CFX_CSSPrimitiveType::Enum) { + pComputedStyle->m_InheritedData.m_WordSpacing.Set( + CFX_CSSLengthUnit::Normal); + } else if (eType == CFX_CSSPrimitiveType::Number) { + if (pValue.As<CFX_CSSNumberValue>()->Kind() == + CFX_CSSNumberType::Percent) { + break; + } + SetLengthWithPercent(pComputedStyle->m_InheritedData.m_WordSpacing, + eType, pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + } + break; + case CFX_CSSProperty::Top: + SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Top, eType, + pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + break; + case CFX_CSSProperty::Bottom: + SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Bottom, eType, + pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + break; + case CFX_CSSProperty::Left: + SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Left, eType, + pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + break; + case CFX_CSSProperty::Right: + SetLengthWithPercent(pComputedStyle->m_NonInheritedData.m_Right, eType, + pValue, + pComputedStyle->m_InheritedData.m_fFontSize); + break; + default: + break; + } + } else if (pValue->GetType() == CFX_CSSPrimitiveType::List) { + CFX_RetainPtr<CFX_CSSValueList> pList = pValue.As<CFX_CSSValueList>(); + int32_t iCount = pList->CountValues(); + if (iCount > 0) { + switch (eProperty) { + case CFX_CSSProperty::FontFamily: + pComputedStyle->m_InheritedData.m_pFontFamily = pList; + break; + case CFX_CSSProperty::TextDecoration: + pComputedStyle->m_NonInheritedData.m_dwTextDecoration = + ToTextDecoration(pList); + break; + default: + break; + } + } + } else { + NOTREACHED(); + } +} + +CFX_CSSDisplay CFX_CSSStyleSelector::ToDisplay(CFX_CSSPropertyValue eValue) { + switch (eValue) { + case CFX_CSSPropertyValue::Block: + return CFX_CSSDisplay::Block; + case CFX_CSSPropertyValue::None: + return CFX_CSSDisplay::None; + case CFX_CSSPropertyValue::ListItem: + return CFX_CSSDisplay::ListItem; + case CFX_CSSPropertyValue::InlineTable: + return CFX_CSSDisplay::InlineTable; + case CFX_CSSPropertyValue::InlineBlock: + return CFX_CSSDisplay::InlineBlock; + case CFX_CSSPropertyValue::Inline: + default: + return CFX_CSSDisplay::Inline; + } +} + +CFX_CSSTextAlign CFX_CSSStyleSelector::ToTextAlign( + CFX_CSSPropertyValue eValue) { + switch (eValue) { + case CFX_CSSPropertyValue::Center: + return CFX_CSSTextAlign::Center; + case CFX_CSSPropertyValue::Right: + return CFX_CSSTextAlign::Right; + case CFX_CSSPropertyValue::Justify: + return CFX_CSSTextAlign::Justify; + case CFX_CSSPropertyValue::Left: + default: + return CFX_CSSTextAlign::Left; + } +} + +uint16_t CFX_CSSStyleSelector::ToFontWeight(CFX_CSSPropertyValue eValue) { + switch (eValue) { + case CFX_CSSPropertyValue::Bold: + return 700; + case CFX_CSSPropertyValue::Bolder: + return 900; + case CFX_CSSPropertyValue::Lighter: + return 200; + case CFX_CSSPropertyValue::Normal: + default: + return 400; + } +} + +CFX_CSSFontStyle CFX_CSSStyleSelector::ToFontStyle( + CFX_CSSPropertyValue eValue) { + switch (eValue) { + case CFX_CSSPropertyValue::Italic: + case CFX_CSSPropertyValue::Oblique: + return CFX_CSSFontStyle::Italic; + default: + return CFX_CSSFontStyle::Normal; + } +} + +bool CFX_CSSStyleSelector::SetLengthWithPercent( + CFX_CSSLength& width, + CFX_CSSPrimitiveType eType, + const CFX_RetainPtr<CFX_CSSValue>& pValue, + float fFontSize) { + if (eType == CFX_CSSPrimitiveType::Number) { + CFX_RetainPtr<CFX_CSSNumberValue> v = pValue.As<CFX_CSSNumberValue>(); + if (v->Kind() == CFX_CSSNumberType::Percent) { + width.Set(CFX_CSSLengthUnit::Percent, + pValue.As<CFX_CSSNumberValue>()->Value() / 100.0f); + return width.NonZero(); + } + + float fValue = v->Apply(fFontSize); + width.Set(CFX_CSSLengthUnit::Point, fValue); + return width.NonZero(); + } else if (eType == CFX_CSSPrimitiveType::Enum) { + switch (pValue.As<CFX_CSSEnumValue>()->Value()) { + case CFX_CSSPropertyValue::Auto: + width.Set(CFX_CSSLengthUnit::Auto); + return true; + case CFX_CSSPropertyValue::None: + width.Set(CFX_CSSLengthUnit::None); + return true; + case CFX_CSSPropertyValue::Thin: + width.Set(CFX_CSSLengthUnit::Point, 2); + return true; + case CFX_CSSPropertyValue::Medium: + width.Set(CFX_CSSLengthUnit::Point, 3); + return true; + case CFX_CSSPropertyValue::Thick: + width.Set(CFX_CSSLengthUnit::Point, 4); + return true; + default: + return false; + } + } + return false; +} + +float CFX_CSSStyleSelector::ToFontSize(CFX_CSSPropertyValue eValue, + float fCurFontSize) { + switch (eValue) { + case CFX_CSSPropertyValue::XxSmall: + return m_fDefFontSize / 1.2f / 1.2f / 1.2f; + case CFX_CSSPropertyValue::XSmall: + return m_fDefFontSize / 1.2f / 1.2f; + case CFX_CSSPropertyValue::Small: + return m_fDefFontSize / 1.2f; + case CFX_CSSPropertyValue::Medium: + return m_fDefFontSize; + case CFX_CSSPropertyValue::Large: + return m_fDefFontSize * 1.2f; + case CFX_CSSPropertyValue::XLarge: + return m_fDefFontSize * 1.2f * 1.2f; + case CFX_CSSPropertyValue::XxLarge: + return m_fDefFontSize * 1.2f * 1.2f * 1.2f; + case CFX_CSSPropertyValue::Larger: + return fCurFontSize * 1.2f; + case CFX_CSSPropertyValue::Smaller: + return fCurFontSize / 1.2f; + default: + return fCurFontSize; + } +} + +CFX_CSSVerticalAlign CFX_CSSStyleSelector::ToVerticalAlign( + CFX_CSSPropertyValue eValue) { + switch (eValue) { + case CFX_CSSPropertyValue::Middle: + return CFX_CSSVerticalAlign::Middle; + case CFX_CSSPropertyValue::Bottom: + return CFX_CSSVerticalAlign::Bottom; + case CFX_CSSPropertyValue::Super: + return CFX_CSSVerticalAlign::Super; + case CFX_CSSPropertyValue::Sub: + return CFX_CSSVerticalAlign::Sub; + case CFX_CSSPropertyValue::Top: + return CFX_CSSVerticalAlign::Top; + case CFX_CSSPropertyValue::TextTop: + return CFX_CSSVerticalAlign::TextTop; + case CFX_CSSPropertyValue::TextBottom: + return CFX_CSSVerticalAlign::TextBottom; + case CFX_CSSPropertyValue::Baseline: + default: + return CFX_CSSVerticalAlign::Baseline; + } +} + +uint32_t CFX_CSSStyleSelector::ToTextDecoration( + const CFX_RetainPtr<CFX_CSSValueList>& pValue) { + uint32_t dwDecoration = 0; + for (int32_t i = pValue->CountValues() - 1; i >= 0; --i) { + const CFX_RetainPtr<CFX_CSSValue> pVal = pValue->GetValue(i); + if (pVal->GetType() != CFX_CSSPrimitiveType::Enum) + continue; + + switch (pVal.As<CFX_CSSEnumValue>()->Value()) { + case CFX_CSSPropertyValue::Underline: + dwDecoration |= CFX_CSSTEXTDECORATION_Underline; + break; + case CFX_CSSPropertyValue::LineThrough: + dwDecoration |= CFX_CSSTEXTDECORATION_LineThrough; + break; + case CFX_CSSPropertyValue::Overline: + dwDecoration |= CFX_CSSTEXTDECORATION_Overline; + break; + case CFX_CSSPropertyValue::Blink: + dwDecoration |= CFX_CSSTEXTDECORATION_Blink; + break; + case CFX_CSSPropertyValue::Double: + dwDecoration |= CFX_CSSTEXTDECORATION_Double; + break; + default: + break; + } + } + return dwDecoration; +} + +CFX_CSSFontVariant CFX_CSSStyleSelector::ToFontVariant( + CFX_CSSPropertyValue eValue) { + return eValue == CFX_CSSPropertyValue::SmallCaps + ? CFX_CSSFontVariant::SmallCaps + : CFX_CSSFontVariant::Normal; +} diff --git a/core/fxcrt/css/cfx_cssstyleselector.h b/core/fxcrt/css/cfx_cssstyleselector.h new file mode 100644 index 0000000000..56d933b614 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstyleselector.h @@ -0,0 +1,85 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSTYLESELECTOR_H_ +#define CORE_FXCRT_CSS_CFX_CSSSTYLESELECTOR_H_ + +#include <memory> +#include <vector> + +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/css/cfx_cssrulecollection.h" +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_system.h" + +class CFX_CSSComputedStyle; +class CFX_CSSCustomProperty; +class CFX_CSSDeclaration; +class CFX_CSSPropertyHolder; +class CFX_CSSSelector; +class CFX_CSSStyleSheet; +class CFX_CSSValue; +class CFX_CSSValueList; + +class CFX_CSSStyleSelector { + public: + CFX_CSSStyleSelector(); + ~CFX_CSSStyleSelector(); + + void SetDefFontSize(float fFontSize); + void SetUAStyleSheet(std::unique_ptr<CFX_CSSStyleSheet> pSheet); + void UpdateStyleIndex(); + + CFX_RetainPtr<CFX_CSSComputedStyle> CreateComputedStyle( + CFX_CSSComputedStyle* pParentStyle); + + // Note, the dest style has to be an out param because the CXFA_TextParser + // adds non-inherited data from the parent style. Attempting to copy + // internally will fail as you'll lose the non-inherited data. + void ComputeStyle(const std::vector<const CFX_CSSDeclaration*>& declArray, + const CFX_WideString& styleString, + const CFX_WideString& alignString, + CFX_CSSComputedStyle* pDestStyle); + + std::vector<const CFX_CSSDeclaration*> MatchDeclarations( + const CFX_WideString& tagname); + + private: + bool MatchSelector(const CFX_WideString& tagname, CFX_CSSSelector* pSel); + + void AppendInlineStyle(CFX_CSSDeclaration* pDecl, + const CFX_WideString& style); + void ApplyDeclarations( + const std::vector<const CFX_CSSDeclaration*>& declArray, + const CFX_CSSDeclaration* extraDecl, + CFX_CSSComputedStyle* pDestStyle); + void ApplyProperty(CFX_CSSProperty eProperty, + const CFX_RetainPtr<CFX_CSSValue>& pValue, + CFX_CSSComputedStyle* pComputedStyle); + void ExtractValues(const CFX_CSSDeclaration* decl, + std::vector<const CFX_CSSPropertyHolder*>* importants, + std::vector<const CFX_CSSPropertyHolder*>* normals, + std::vector<const CFX_CSSCustomProperty*>* custom); + + bool SetLengthWithPercent(CFX_CSSLength& width, + CFX_CSSPrimitiveType eType, + const CFX_RetainPtr<CFX_CSSValue>& pValue, + float fFontSize); + float ToFontSize(CFX_CSSPropertyValue eValue, float fCurFontSize); + CFX_CSSDisplay ToDisplay(CFX_CSSPropertyValue eValue); + CFX_CSSTextAlign ToTextAlign(CFX_CSSPropertyValue eValue); + uint16_t ToFontWeight(CFX_CSSPropertyValue eValue); + CFX_CSSFontStyle ToFontStyle(CFX_CSSPropertyValue eValue); + CFX_CSSVerticalAlign ToVerticalAlign(CFX_CSSPropertyValue eValue); + uint32_t ToTextDecoration(const CFX_RetainPtr<CFX_CSSValueList>& pList); + CFX_CSSFontVariant ToFontVariant(CFX_CSSPropertyValue eValue); + + float m_fDefFontSize; + std::unique_ptr<CFX_CSSStyleSheet> m_UAStyles; + CFX_CSSRuleCollection m_UARules; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSTYLESELECTOR_H_ diff --git a/core/fxcrt/css/cfx_cssstylesheet.cpp b/core/fxcrt/css/cfx_cssstylesheet.cpp new file mode 100644 index 0000000000..9bd25c044f --- /dev/null +++ b/core/fxcrt/css/cfx_cssstylesheet.cpp @@ -0,0 +1,140 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssstylesheet.h" + +#include <utility> + +#include "core/fxcrt/css/cfx_cssdatatable.h" +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/css/cfx_cssstylerule.h" +#include "core/fxcrt/fx_codepage.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +CFX_CSSStyleSheet::CFX_CSSStyleSheet() {} + +CFX_CSSStyleSheet::~CFX_CSSStyleSheet() { + Reset(); +} + +void CFX_CSSStyleSheet::Reset() { + m_RuleArray.clear(); + m_StringCache.clear(); +} + +int32_t CFX_CSSStyleSheet::CountRules() const { + return pdfium::CollectionSize<int32_t>(m_RuleArray); +} + +CFX_CSSStyleRule* CFX_CSSStyleSheet::GetRule(int32_t index) const { + return m_RuleArray[index].get(); +} + +bool CFX_CSSStyleSheet::LoadBuffer(const wchar_t* pBuffer, int32_t iBufSize) { + ASSERT(pBuffer); + ASSERT(iBufSize > 0); + + auto pSyntax = pdfium::MakeUnique<CFX_CSSSyntaxParser>(pBuffer, iBufSize); + Reset(); + CFX_CSSSyntaxStatus eStatus; + do { + switch (eStatus = pSyntax->DoSyntaxParse()) { + case CFX_CSSSyntaxStatus::StyleRule: + eStatus = LoadStyleRule(pSyntax.get(), &m_RuleArray); + break; + default: + break; + } + } while (eStatus >= CFX_CSSSyntaxStatus::None); + + m_StringCache.clear(); + return eStatus != CFX_CSSSyntaxStatus::Error; +} + +CFX_CSSSyntaxStatus CFX_CSSStyleSheet::LoadStyleRule( + CFX_CSSSyntaxParser* pSyntax, + std::vector<std::unique_ptr<CFX_CSSStyleRule>>* ruleArray) { + std::vector<std::unique_ptr<CFX_CSSSelector>> selectors; + + CFX_CSSStyleRule* pStyleRule = nullptr; + int32_t iValueLen = 0; + const CFX_CSSPropertyTable* propertyTable = nullptr; + CFX_WideString wsName; + while (1) { + switch (pSyntax->DoSyntaxParse()) { + case CFX_CSSSyntaxStatus::Selector: { + CFX_WideStringC strValue = pSyntax->GetCurrentString(); + auto pSelector = CFX_CSSSelector::FromString(strValue); + if (pSelector) + selectors.push_back(std::move(pSelector)); + break; + } + case CFX_CSSSyntaxStatus::PropertyName: { + CFX_WideStringC strValue = pSyntax->GetCurrentString(); + propertyTable = CFX_GetCSSPropertyByName(strValue); + if (!propertyTable) + wsName = CFX_WideString(strValue); + break; + } + case CFX_CSSSyntaxStatus::PropertyValue: { + if (propertyTable || iValueLen > 0) { + CFX_WideStringC strValue = pSyntax->GetCurrentString(); + auto* decl = pStyleRule->GetDeclaration(); + if (!strValue.IsEmpty()) { + if (propertyTable) { + decl->AddProperty(propertyTable, strValue); + } else { + decl->AddProperty(wsName, CFX_WideString(strValue)); + } + } + } + break; + } + case CFX_CSSSyntaxStatus::DeclOpen: { + if (!pStyleRule && !selectors.empty()) { + auto rule = pdfium::MakeUnique<CFX_CSSStyleRule>(); + pStyleRule = rule.get(); + pStyleRule->SetSelector(&selectors); + ruleArray->push_back(std::move(rule)); + } else { + SkipRuleSet(pSyntax); + return CFX_CSSSyntaxStatus::None; + } + break; + } + case CFX_CSSSyntaxStatus::DeclClose: { + if (pStyleRule && pStyleRule->GetDeclaration()->empty()) { + ruleArray->pop_back(); + pStyleRule = nullptr; + } + return CFX_CSSSyntaxStatus::None; + } + case CFX_CSSSyntaxStatus::EOS: + return CFX_CSSSyntaxStatus::EOS; + case CFX_CSSSyntaxStatus::Error: + default: + return CFX_CSSSyntaxStatus::Error; + } + } +} + +void CFX_CSSStyleSheet::SkipRuleSet(CFX_CSSSyntaxParser* pSyntax) { + while (1) { + switch (pSyntax->DoSyntaxParse()) { + case CFX_CSSSyntaxStatus::Selector: + case CFX_CSSSyntaxStatus::DeclOpen: + case CFX_CSSSyntaxStatus::PropertyName: + case CFX_CSSSyntaxStatus::PropertyValue: + break; + case CFX_CSSSyntaxStatus::DeclClose: + case CFX_CSSSyntaxStatus::EOS: + case CFX_CSSSyntaxStatus::Error: + default: + return; + } + } +} diff --git a/core/fxcrt/css/cfx_cssstylesheet.h b/core/fxcrt/css/cfx_cssstylesheet.h new file mode 100644 index 0000000000..3f3a94a84b --- /dev/null +++ b/core/fxcrt/css/cfx_cssstylesheet.h @@ -0,0 +1,40 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSTYLESHEET_H_ +#define CORE_FXCRT_CSS_CFX_CSSSTYLESHEET_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "core/fxcrt/css/cfx_csssyntaxparser.h" +#include "core/fxcrt/fx_string.h" + +class CFX_CSSStyleRule; + +class CFX_CSSStyleSheet { + public: + CFX_CSSStyleSheet(); + ~CFX_CSSStyleSheet(); + + bool LoadBuffer(const wchar_t* pBuffer, int32_t iBufSize); + + int32_t CountRules() const; + CFX_CSSStyleRule* GetRule(int32_t index) const; + + private: + void Reset(); + CFX_CSSSyntaxStatus LoadStyleRule( + CFX_CSSSyntaxParser* pSyntax, + std::vector<std::unique_ptr<CFX_CSSStyleRule>>* ruleArray); + void SkipRuleSet(CFX_CSSSyntaxParser* pSyntax); + + std::vector<std::unique_ptr<CFX_CSSStyleRule>> m_RuleArray; + std::map<uint32_t, wchar_t*> m_StringCache; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSTYLESHEET_H_ diff --git a/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp b/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp new file mode 100644 index 0000000000..4194a70490 --- /dev/null +++ b/core/fxcrt/css/cfx_cssstylesheet_unittest.cpp @@ -0,0 +1,239 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssstylesheet.h" + +#include <memory> +#include <vector> + +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/css/cfx_cssenumvalue.h" +#include "core/fxcrt/css/cfx_cssnumbervalue.h" +#include "core/fxcrt/css/cfx_cssstylerule.h" +#include "core/fxcrt/css/cfx_cssvaluelist.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +class CFX_CSSStyleSheetTest : public testing::Test { + public: + void SetUp() override { + sheet_ = pdfium::MakeUnique<CFX_CSSStyleSheet>(); + decl_ = nullptr; + } + + void TearDown() override { decl_ = nullptr; } + + void LoadAndVerifyDecl(const wchar_t* buf, + const std::vector<CFX_WideString>& selectors, + size_t decl_count) { + ASSERT(sheet_); + + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(sheet_->CountRules(), 1); + + CFX_CSSStyleRule* style = sheet_->GetRule(0); + EXPECT_EQ(selectors.size(), style->CountSelectorLists()); + + for (size_t i = 0; i < selectors.size(); i++) { + uint32_t hash = FX_HashCode_GetW(selectors[i].AsStringC(), true); + EXPECT_EQ(hash, style->GetSelectorList(i)->GetNameHash()); + } + + decl_ = style->GetDeclaration(); + EXPECT_EQ(decl_->PropertyCountForTesting(), decl_count); + } + + void VerifyFloat(CFX_CSSProperty prop, float val, CFX_CSSNumberType type) { + ASSERT(decl_); + + bool important; + CFX_RetainPtr<CFX_CSSValue> v = decl_->GetProperty(prop, &important); + EXPECT_EQ(v->GetType(), CFX_CSSPrimitiveType::Number); + EXPECT_EQ(v.As<CFX_CSSNumberValue>()->Kind(), type); + EXPECT_EQ(v.As<CFX_CSSNumberValue>()->Value(), val); + } + + void VerifyEnum(CFX_CSSProperty prop, CFX_CSSPropertyValue val) { + ASSERT(decl_); + + bool important; + CFX_RetainPtr<CFX_CSSValue> v = decl_->GetProperty(prop, &important); + EXPECT_EQ(v->GetType(), CFX_CSSPrimitiveType::Enum); + EXPECT_EQ(v.As<CFX_CSSEnumValue>()->Value(), val); + } + + void VerifyList(CFX_CSSProperty prop, + std::vector<CFX_CSSPropertyValue> values) { + ASSERT(decl_); + + bool important; + CFX_RetainPtr<CFX_CSSValueList> list = + decl_->GetProperty(prop, &important).As<CFX_CSSValueList>(); + EXPECT_EQ(list->CountValues(), pdfium::CollectionSize<int32_t>(values)); + + for (size_t i = 0; i < values.size(); i++) { + CFX_RetainPtr<CFX_CSSValue> val = list->GetValue(i); + EXPECT_EQ(val->GetType(), CFX_CSSPrimitiveType::Enum); + EXPECT_EQ(val.As<CFX_CSSEnumValue>()->Value(), values[i]); + } + } + + std::unique_ptr<CFX_CSSStyleSheet> sheet_; + CFX_CSSDeclaration* decl_; +}; + +TEST_F(CFX_CSSStyleSheetTest, ParseMultipleSelectors) { + const wchar_t* buf = + L"a { border: 10px; }\nb { text-decoration: underline; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(2, sheet_->CountRules()); + + CFX_CSSStyleRule* style = sheet_->GetRule(0); + EXPECT_EQ(1UL, style->CountSelectorLists()); + + bool found_selector = false; + uint32_t hash = FX_HashCode_GetW(L"a", true); + for (size_t i = 0; i < style->CountSelectorLists(); i++) { + if (style->GetSelectorList(i)->GetNameHash() == hash) { + found_selector = true; + break; + } + } + EXPECT_TRUE(found_selector); + + decl_ = style->GetDeclaration(); + EXPECT_EQ(4UL, decl_->PropertyCountForTesting()); + + VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 10.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderRightWidth, 10.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderTopWidth, 10.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 10.0, + CFX_CSSNumberType::Pixels); + + style = sheet_->GetRule(1); + EXPECT_EQ(1UL, style->CountSelectorLists()); + + found_selector = false; + hash = FX_HashCode_GetW(L"b", true); + for (size_t i = 0; i < style->CountSelectorLists(); i++) { + if (style->GetSelectorList(i)->GetNameHash() == hash) { + found_selector = true; + break; + } + } + EXPECT_TRUE(found_selector); + + decl_ = style->GetDeclaration(); + EXPECT_EQ(1UL, decl_->PropertyCountForTesting()); + VerifyList(CFX_CSSProperty::TextDecoration, + {CFX_CSSPropertyValue::Underline}); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseChildSelectors) { + const wchar_t* buf = L"a b c { border: 10px; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(1, sheet_->CountRules()); + + CFX_CSSStyleRule* style = sheet_->GetRule(0); + EXPECT_EQ(1UL, style->CountSelectorLists()); + + auto* sel = style->GetSelectorList(0); + EXPECT_TRUE(sel != nullptr); + EXPECT_EQ(FX_HashCode_GetW(L"c", true), sel->GetNameHash()); + + sel = sel->GetNextSelector(); + EXPECT_TRUE(sel != nullptr); + EXPECT_EQ(FX_HashCode_GetW(L"b", true), sel->GetNameHash()); + + sel = sel->GetNextSelector(); + EXPECT_TRUE(sel != nullptr); + EXPECT_EQ(FX_HashCode_GetW(L"a", true), sel->GetNameHash()); + + sel = sel->GetNextSelector(); + EXPECT_TRUE(sel == nullptr); + + decl_ = style->GetDeclaration(); + EXPECT_EQ(4UL, decl_->PropertyCountForTesting()); + + VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 10.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderRightWidth, 10.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderTopWidth, 10.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 10.0, + CFX_CSSNumberType::Pixels); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseUnhandledSelectors) { + const wchar_t* buf = L"a > b { padding: 0; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(0, sheet_->CountRules()); + + buf = L"a[first] { padding: 0; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(0, sheet_->CountRules()); + + buf = L"a+b { padding: 0; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(0, sheet_->CountRules()); + + buf = L"a ^ b { padding: 0; }"; + EXPECT_TRUE(sheet_->LoadBuffer(buf, FXSYS_wcslen(buf))); + EXPECT_EQ(0, sheet_->CountRules()); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseMultipleSelectorsCombined) { + LoadAndVerifyDecl(L"a, b, c { border: 5px; }", {L"a", L"b", L"c"}, 4); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorder) { + LoadAndVerifyDecl(L"a { border: 5px; }", {L"a"}, 4); + VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 5.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderRightWidth, 5.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderTopWidth, 5.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 5.0, + CFX_CSSNumberType::Pixels); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderFull) { + LoadAndVerifyDecl(L"a { border: 5px solid red; }", {L"a"}, 4); + VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 5.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderRightWidth, 5.0, + CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderTopWidth, 5.0, CFX_CSSNumberType::Pixels); + VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 5.0, + CFX_CSSNumberType::Pixels); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderLeft) { + LoadAndVerifyDecl(L"a { border-left: 2.5pc; }", {L"a"}, 1); + VerifyFloat(CFX_CSSProperty::BorderLeftWidth, 2.5, CFX_CSSNumberType::Picas); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderLeftThick) { + LoadAndVerifyDecl(L"a { border-left: thick; }", {L"a"}, 1); + VerifyEnum(CFX_CSSProperty::BorderLeftWidth, CFX_CSSPropertyValue::Thick); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderRight) { + LoadAndVerifyDecl(L"a { border-right: 2.5pc; }", {L"a"}, 1); + VerifyFloat(CFX_CSSProperty::BorderRightWidth, 2.5, CFX_CSSNumberType::Picas); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderTop) { + LoadAndVerifyDecl(L"a { border-top: 2.5pc; }", {L"a"}, 1); + VerifyFloat(CFX_CSSProperty::BorderTopWidth, 2.5, CFX_CSSNumberType::Picas); +} + +TEST_F(CFX_CSSStyleSheetTest, ParseBorderBottom) { + LoadAndVerifyDecl(L"a { border-bottom: 2.5pc; }", {L"a"}, 1); + VerifyFloat(CFX_CSSProperty::BorderBottomWidth, 2.5, + CFX_CSSNumberType::Picas); +} diff --git a/core/fxcrt/css/cfx_csssyntaxparser.cpp b/core/fxcrt/css/cfx_csssyntaxparser.cpp new file mode 100644 index 0000000000..c8082e87fb --- /dev/null +++ b/core/fxcrt/css/cfx_csssyntaxparser.cpp @@ -0,0 +1,228 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_csssyntaxparser.h" + +#include <algorithm> + +#include "core/fxcrt/css/cfx_cssdatatable.h" +#include "core/fxcrt/css/cfx_cssdeclaration.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/fx_extension.h" +#include "third_party/base/logging.h" + +namespace { + +bool IsSelectorStart(wchar_t wch) { + return wch == '.' || wch == '#' || wch == '*' || FXSYS_iswalpha(wch); +} + +} // namespace + +CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer, + int32_t iBufferSize) + : CFX_CSSSyntaxParser(pBuffer, iBufferSize, 32, false) {} + +CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer, + int32_t iBufferSize, + int32_t iTextDatSize, + bool bOnlyDeclaration) + : m_iTextDataLen(0), + m_dwCheck(0xFFFFFFFF), + m_eStatus(CFX_CSSSyntaxStatus::None) { + ASSERT(pBuffer && iBufferSize > 0 && iTextDatSize > 0); + m_eMode = bOnlyDeclaration ? CFX_CSSSyntaxMode::PropertyName + : CFX_CSSSyntaxMode::RuleSet; + m_TextData.InitWithSize(iTextDatSize); + m_TextPlane.AttachBuffer(pBuffer, iBufferSize); +} + +CFX_CSSSyntaxParser::~CFX_CSSSyntaxParser() {} + +CFX_CSSSyntaxStatus CFX_CSSSyntaxParser::DoSyntaxParse() { + while (m_eStatus >= CFX_CSSSyntaxStatus::None) { + if (m_TextPlane.IsEOF()) { + if (m_eMode == CFX_CSSSyntaxMode::PropertyValue && + m_TextData.GetLength() > 0) { + SaveTextData(); + m_eStatus = CFX_CSSSyntaxStatus::PropertyValue; + return m_eStatus; + } + m_eStatus = CFX_CSSSyntaxStatus::EOS; + return m_eStatus; + } + wchar_t wch; + while (!m_TextPlane.IsEOF()) { + wch = m_TextPlane.GetChar(); + switch (m_eMode) { + case CFX_CSSSyntaxMode::RuleSet: + switch (wch) { + case '}': + m_TextPlane.MoveNext(); + if (RestoreMode()) + return CFX_CSSSyntaxStatus::DeclClose; + + m_eStatus = CFX_CSSSyntaxStatus::Error; + return m_eStatus; + case '/': + if (m_TextPlane.GetNextChar() == '*') { + m_ModeStack.push(m_eMode); + SwitchMode(CFX_CSSSyntaxMode::Comment); + break; + } + default: + if (wch <= ' ') { + m_TextPlane.MoveNext(); + } else if (IsSelectorStart(wch)) { + SwitchMode(CFX_CSSSyntaxMode::Selector); + return CFX_CSSSyntaxStatus::StyleRule; + } else { + m_eStatus = CFX_CSSSyntaxStatus::Error; + return m_eStatus; + } + break; + } + break; + case CFX_CSSSyntaxMode::Selector: + switch (wch) { + case ',': + m_TextPlane.MoveNext(); + SwitchMode(CFX_CSSSyntaxMode::Selector); + if (m_iTextDataLen > 0) + return CFX_CSSSyntaxStatus::Selector; + break; + case '{': + if (m_TextData.GetLength() > 0) { + SaveTextData(); + return CFX_CSSSyntaxStatus::Selector; + } + m_TextPlane.MoveNext(); + m_ModeStack.push(CFX_CSSSyntaxMode::RuleSet); + SwitchMode(CFX_CSSSyntaxMode::PropertyName); + return CFX_CSSSyntaxStatus::DeclOpen; + case '/': + if (m_TextPlane.GetNextChar() == '*') { + if (SwitchToComment() > 0) + return CFX_CSSSyntaxStatus::Selector; + break; + } + default: + AppendChar(wch); + break; + } + break; + case CFX_CSSSyntaxMode::PropertyName: + switch (wch) { + case ':': + m_TextPlane.MoveNext(); + SwitchMode(CFX_CSSSyntaxMode::PropertyValue); + return CFX_CSSSyntaxStatus::PropertyName; + case '}': + m_TextPlane.MoveNext(); + if (RestoreMode()) + return CFX_CSSSyntaxStatus::DeclClose; + + m_eStatus = CFX_CSSSyntaxStatus::Error; + return m_eStatus; + case '/': + if (m_TextPlane.GetNextChar() == '*') { + if (SwitchToComment() > 0) + return CFX_CSSSyntaxStatus::PropertyName; + break; + } + default: + AppendChar(wch); + break; + } + break; + case CFX_CSSSyntaxMode::PropertyValue: + switch (wch) { + case ';': + m_TextPlane.MoveNext(); + case '}': + SwitchMode(CFX_CSSSyntaxMode::PropertyName); + return CFX_CSSSyntaxStatus::PropertyValue; + case '/': + if (m_TextPlane.GetNextChar() == '*') { + if (SwitchToComment() > 0) + return CFX_CSSSyntaxStatus::PropertyValue; + break; + } + default: + AppendChar(wch); + break; + } + break; + case CFX_CSSSyntaxMode::Comment: + if (wch == '/' && m_TextData.GetLength() > 0 && + m_TextData.GetBuffer()[m_TextData.GetLength() - 1] == '*') { + RestoreMode(); + } else { + m_TextData.AppendChar(wch); + } + m_TextPlane.MoveNext(); + break; + case CFX_CSSSyntaxMode::UnknownRule: + if (wch == ';') + SwitchMode(CFX_CSSSyntaxMode::RuleSet); + m_TextPlane.MoveNext(); + break; + default: + NOTREACHED(); + break; + } + } + } + return m_eStatus; +} + +bool CFX_CSSSyntaxParser::IsImportEnabled() const { + if ((m_dwCheck & CFX_CSSSYNTAXCHECK_AllowImport) == 0) + return false; + if (m_ModeStack.size() > 1) + return false; + return true; +} + +bool CFX_CSSSyntaxParser::AppendChar(wchar_t wch) { + m_TextPlane.MoveNext(); + if (m_TextData.GetLength() > 0 || wch > ' ') { + m_TextData.AppendChar(wch); + return true; + } + return false; +} + +int32_t CFX_CSSSyntaxParser::SaveTextData() { + m_iTextDataLen = m_TextData.TrimEnd(); + m_TextData.Clear(); + return m_iTextDataLen; +} + +void CFX_CSSSyntaxParser::SwitchMode(CFX_CSSSyntaxMode eMode) { + m_eMode = eMode; + SaveTextData(); +} + +int32_t CFX_CSSSyntaxParser::SwitchToComment() { + int32_t iLength = m_TextData.GetLength(); + m_ModeStack.push(m_eMode); + SwitchMode(CFX_CSSSyntaxMode::Comment); + return iLength; +} + +bool CFX_CSSSyntaxParser::RestoreMode() { + if (m_ModeStack.empty()) + return false; + + SwitchMode(m_ModeStack.top()); + m_ModeStack.pop(); + return true; +} + +CFX_WideStringC CFX_CSSSyntaxParser::GetCurrentString() const { + return CFX_WideStringC(m_TextData.GetBuffer(), m_iTextDataLen); +} diff --git a/core/fxcrt/css/cfx_csssyntaxparser.h b/core/fxcrt/css/cfx_csssyntaxparser.h new file mode 100644 index 0000000000..9ddedfe4a7 --- /dev/null +++ b/core/fxcrt/css/cfx_csssyntaxparser.h @@ -0,0 +1,75 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSSYNTAXPARSER_H_ +#define CORE_FXCRT_CSS_CFX_CSSSYNTAXPARSER_H_ + +#include <stack> + +#include "core/fxcrt/css/cfx_cssexttextbuf.h" +#include "core/fxcrt/css/cfx_csstextbuf.h" +#include "core/fxcrt/fx_string.h" + +#define CFX_CSSSYNTAXCHECK_AllowCharset 1 +#define CFX_CSSSYNTAXCHECK_AllowImport 2 + +enum class CFX_CSSSyntaxMode { + RuleSet, + Comment, + UnknownRule, + Selector, + PropertyName, + PropertyValue, +}; + +enum class CFX_CSSSyntaxStatus : uint8_t { + Error, + EOS, + None, + StyleRule, + Selector, + DeclOpen, + DeclClose, + PropertyName, + PropertyValue, +}; + +class CFX_CSSSyntaxParser { + public: + CFX_CSSSyntaxParser(const wchar_t* pBuffer, int32_t iBufferSize); + CFX_CSSSyntaxParser(const wchar_t* pBuffer, + int32_t iBufferSize, + int32_t iTextDatSize, + bool bOnlyDeclaration); + ~CFX_CSSSyntaxParser(); + + CFX_CSSSyntaxStatus DoSyntaxParse(); + CFX_WideStringC GetCurrentString() const; + + protected: + void SwitchMode(CFX_CSSSyntaxMode eMode); + int32_t SwitchToComment(); + + bool RestoreMode(); + bool AppendChar(wchar_t wch); + int32_t SaveTextData(); + bool IsCharsetEnabled() const { + return (m_dwCheck & CFX_CSSSYNTAXCHECK_AllowCharset) != 0; + } + void DisableCharset() { m_dwCheck = CFX_CSSSYNTAXCHECK_AllowImport; } + bool IsImportEnabled() const; + void DisableImport() { m_dwCheck = 0; } + + CFX_CSSTextBuf m_TextData; + CFX_CSSExtTextBuf m_TextPlane; + int32_t m_iTextDataLen; + uint32_t m_dwCheck; + CFX_CSSSyntaxMode m_eMode; + CFX_CSSSyntaxStatus m_eStatus; + std::stack<CFX_CSSSyntaxMode> m_ModeStack; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSSYNTAXPARSER_H_ diff --git a/core/fxcrt/css/cfx_csstextbuf.cpp b/core/fxcrt/css/cfx_csstextbuf.cpp new file mode 100644 index 0000000000..f2f3b94419 --- /dev/null +++ b/core/fxcrt/css/cfx_csstextbuf.cpp @@ -0,0 +1,49 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_csstextbuf.h" + +#include "core/fxcrt/fx_memory.h" + +CFX_CSSTextBuf::CFX_CSSTextBuf() + : m_pBuffer(nullptr), m_iBufLen(0), m_iDatLen(0) {} + +CFX_CSSTextBuf::~CFX_CSSTextBuf() { + FX_Free(m_pBuffer); + m_pBuffer = nullptr; + m_iDatLen = m_iBufLen; +} + +void CFX_CSSTextBuf::InitWithSize(int32_t iAllocSize) { + ExpandBuf(iAllocSize); +} + +void CFX_CSSTextBuf::AppendChar(wchar_t wch) { + if (m_iDatLen >= m_iBufLen) + ExpandBuf(m_iBufLen * 2); + + m_pBuffer[m_iDatLen++] = wch; +} + +int32_t CFX_CSSTextBuf::TrimEnd() { + while (m_iDatLen > 0 && m_pBuffer[m_iDatLen - 1] <= ' ') + --m_iDatLen; + AppendChar(0); + return --m_iDatLen; +} + +void CFX_CSSTextBuf::ExpandBuf(int32_t iDesiredSize) { + ASSERT(iDesiredSize > 0); + if (m_pBuffer && m_iBufLen == iDesiredSize) + return; + + if (m_pBuffer) + m_pBuffer = FX_Realloc(wchar_t, m_pBuffer, iDesiredSize); + else + m_pBuffer = FX_Alloc(wchar_t, iDesiredSize); + + m_iBufLen = iDesiredSize; +} diff --git a/core/fxcrt/css/cfx_csstextbuf.h b/core/fxcrt/css/cfx_csstextbuf.h new file mode 100644 index 0000000000..e1b9c64e14 --- /dev/null +++ b/core/fxcrt/css/cfx_csstextbuf.h @@ -0,0 +1,35 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSTEXTBUF_H_ +#define CORE_FXCRT_CSS_CFX_CSSTEXTBUF_H_ + +#include "core/fxcrt/fx_system.h" + +class CFX_CSSTextBuf { + public: + CFX_CSSTextBuf(); + ~CFX_CSSTextBuf(); + + void InitWithSize(int32_t iAllocSize); + void AppendChar(wchar_t wch); + + void Clear() { m_iDatLen = 0; } + + int32_t TrimEnd(); + + int32_t GetLength() const { return m_iDatLen; } + const wchar_t* GetBuffer() const { return m_pBuffer; } + + protected: + void ExpandBuf(int32_t iDesiredSize); + + wchar_t* m_pBuffer; + int32_t m_iBufLen; + int32_t m_iDatLen; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSTEXTBUF_H_ diff --git a/core/fxcrt/css/cfx_cssvalue.cpp b/core/fxcrt/css/cfx_cssvalue.cpp new file mode 100644 index 0000000000..a55fc742b0 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvalue.cpp @@ -0,0 +1,9 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssvalue.h" + +CFX_CSSValue::CFX_CSSValue(CFX_CSSPrimitiveType type) : m_value(type) {} diff --git a/core/fxcrt/css/cfx_cssvalue.h b/core/fxcrt/css/cfx_cssvalue.h new file mode 100644 index 0000000000..4f11e4e0d7 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvalue.h @@ -0,0 +1,23 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSVALUE_H_ +#define CORE_FXCRT_CSS_CFX_CSSVALUE_H_ + +#include "core/fxcrt/css/cfx_css.h" + +class CFX_CSSValue : public CFX_Retainable { + public: + CFX_CSSPrimitiveType GetType() const { return m_value; } + + protected: + explicit CFX_CSSValue(CFX_CSSPrimitiveType type); + + private: + CFX_CSSPrimitiveType m_value; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSVALUE_H_ diff --git a/core/fxcrt/css/cfx_cssvaluelist.cpp b/core/fxcrt/css/cfx_cssvaluelist.cpp new file mode 100644 index 0000000000..18b5d82054 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvaluelist.cpp @@ -0,0 +1,25 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssvaluelist.h" + +#include <utility> + +#include "core/fxcrt/css/cfx_css.h" + +CFX_CSSValueList::CFX_CSSValueList( + std::vector<CFX_RetainPtr<CFX_CSSValue>>& list) + : CFX_CSSValue(CFX_CSSPrimitiveType::List), m_ppList(std::move(list)) {} + +CFX_CSSValueList::~CFX_CSSValueList() {} + +int32_t CFX_CSSValueList::CountValues() const { + return m_ppList.size(); +} + +CFX_RetainPtr<CFX_CSSValue> CFX_CSSValueList::GetValue(int32_t index) const { + return m_ppList[index]; +} diff --git a/core/fxcrt/css/cfx_cssvaluelist.h b/core/fxcrt/css/cfx_cssvaluelist.h new file mode 100644 index 0000000000..475abf4066 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvaluelist.h @@ -0,0 +1,26 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSVALUELIST_H_ +#define CORE_FXCRT_CSS_CFX_CSSVALUELIST_H_ + +#include <vector> + +#include "core/fxcrt/css/cfx_cssvalue.h" + +class CFX_CSSValueList : public CFX_CSSValue { + public: + explicit CFX_CSSValueList(std::vector<CFX_RetainPtr<CFX_CSSValue>>& list); + ~CFX_CSSValueList() override; + + int32_t CountValues() const; + CFX_RetainPtr<CFX_CSSValue> GetValue(int32_t index) const; + + protected: + std::vector<CFX_RetainPtr<CFX_CSSValue>> m_ppList; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSVALUELIST_H_ diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.cpp b/core/fxcrt/css/cfx_cssvaluelistparser.cpp new file mode 100644 index 0000000000..05204e5621 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvaluelistparser.cpp @@ -0,0 +1,87 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssvaluelistparser.h" + +#include "core/fxcrt/fx_extension.h" + +CFX_CSSValueListParser::CFX_CSSValueListParser(const wchar_t* psz, + int32_t iLen, + wchar_t separator) + : m_Separator(separator), m_pCur(psz), m_pEnd(psz + iLen) { + ASSERT(psz && iLen > 0); +} + +bool CFX_CSSValueListParser::NextValue(CFX_CSSPrimitiveType& eType, + const wchar_t*& pStart, + int32_t& iLength) { + while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator)) + ++m_pCur; + + if (m_pCur >= m_pEnd) + return false; + + eType = CFX_CSSPrimitiveType::Unknown; + pStart = m_pCur; + iLength = 0; + wchar_t wch = *m_pCur; + if (wch == '#') { + iLength = SkipTo(' ', false, false); + if (iLength == 4 || iLength == 7) + eType = CFX_CSSPrimitiveType::RGB; + } else if (std::iswdigit(wch) || wch == '.' || wch == '-' || wch == '+') { + while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator)) + ++m_pCur; + + iLength = m_pCur - pStart; + eType = CFX_CSSPrimitiveType::Number; + } else if (wch == '\"' || wch == '\'') { + pStart++; + m_pCur++; + iLength = SkipTo(wch, false, false); + m_pCur++; + eType = CFX_CSSPrimitiveType::String; + } else if (m_pEnd - m_pCur > 5 && m_pCur[3] == '(') { + if (FXSYS_wcsnicmp(L"rgb", m_pCur, 3) == 0) { + iLength = SkipTo(')', false, false) + 1; + m_pCur++; + eType = CFX_CSSPrimitiveType::RGB; + } + } else { + iLength = SkipTo(m_Separator, true, true); + eType = CFX_CSSPrimitiveType::String; + } + return m_pCur <= m_pEnd && iLength > 0; +} + +int32_t CFX_CSSValueListParser::SkipTo(wchar_t wch, + bool breakOnSpace, + bool matchBrackets) { + const wchar_t* pStart = m_pCur; + int32_t bracketCount = 0; + while (m_pCur < m_pEnd && *m_pCur != wch) { + if (breakOnSpace && *m_pCur <= ' ') + break; + if (!matchBrackets) { + m_pCur++; + continue; + } + + if (*m_pCur == '(') + bracketCount++; + else if (*m_pCur == ')') + bracketCount--; + + m_pCur++; + } + + while (bracketCount > 0 && m_pCur < m_pEnd) { + if (*m_pCur == ')') + bracketCount--; + m_pCur++; + } + return m_pCur - pStart; +} diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.h b/core/fxcrt/css/cfx_cssvaluelistparser.h new file mode 100644 index 0000000000..514db9e192 --- /dev/null +++ b/core/fxcrt/css/cfx_cssvaluelistparser.h @@ -0,0 +1,30 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_CSS_CFX_CSSVALUELISTPARSER_H_ +#define CORE_FXCRT_CSS_CFX_CSSVALUELISTPARSER_H_ + +#include "core/fxcrt/css/cfx_css.h" +#include "core/fxcrt/fx_system.h" + +class CFX_CSSValueListParser { + public: + CFX_CSSValueListParser(const wchar_t* psz, int32_t iLen, wchar_t separator); + + bool NextValue(CFX_CSSPrimitiveType& eType, + const wchar_t*& pStart, + int32_t& iLength); + + wchar_t m_Separator; + + private: + int32_t SkipTo(wchar_t wch, bool breakOnSpace, bool matchBrackets); + + const wchar_t* m_pCur; + const wchar_t* m_pEnd; +}; + +#endif // CORE_FXCRT_CSS_CFX_CSSVALUELISTPARSER_H_ diff --git a/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp b/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp new file mode 100644 index 0000000000..510c96251d --- /dev/null +++ b/core/fxcrt/css/cfx_cssvaluelistparser_unittest.cpp @@ -0,0 +1,141 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/css/cfx_cssvaluelistparser.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" +#include "third_party/base/ptr_util.h" + +TEST(CFX_CSSValueListParserTest, rgb_short) { + CFX_CSSPrimitiveType type; + const wchar_t* start; + int32_t len; + + auto parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"#abc", 4, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::RGB, type); + EXPECT_EQ(L"#abc", CFX_WideString(start, len)); + EXPECT_FALSE(parser->NextValue(type, start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"#abcdef", 7, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::RGB, type); + EXPECT_EQ(L"#abcdef", CFX_WideString(start, len)); + EXPECT_FALSE(parser->NextValue(type, start, len)); + + parser = + pdfium::MakeUnique<CFX_CSSValueListParser>(L"rgb(1, 255, 4)", 14, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::RGB, type); + EXPECT_EQ(L"rgb(1, 255, 4)", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"#abcdefghij", 11, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Unknown, type); + EXPECT_EQ(L"#abcdefghij", CFX_WideString(start, len)); + EXPECT_FALSE(parser->NextValue(type, start, len)); +} + +TEST(CFX_CSSValueListParserTest, number_parsing) { + CFX_CSSPrimitiveType type; + const wchar_t* start; + int32_t len; + + auto parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"1234", 4, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"1234", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"-1234", 5, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"-1234", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"+1234", 5, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"+1234", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L".1234", 5, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L".1234", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"4321.1234", 9, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"4321.1234", CFX_WideString(start, len)); + + // TODO(dsinclair): These should probably fail but currently don't. + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"4321.12.34", 10, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"4321.12.34", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"43a1.12.34", 10, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"43a1.12.34", CFX_WideString(start, len)); +} + +TEST(CFX_CSSValueListParserTest, string_parsing) { + CFX_CSSPrimitiveType type; + const wchar_t* start; + int32_t len; + + auto parser = + pdfium::MakeUnique<CFX_CSSValueListParser>(L"'string'", 8, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::String, type); + EXPECT_EQ(L"string", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"\"another string\"", 16, + L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::String, type); + EXPECT_EQ(L"another string", CFX_WideString(start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"standalone", 10, L' '); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::String, type); + EXPECT_EQ(L"standalone", CFX_WideString(start, len)); +} + +TEST(CFX_CSSValueListParserTest, multiparsing) { + CFX_CSSPrimitiveType type; + const wchar_t* start; + int32_t len; + + auto parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"1, 2, 3", 7, L','); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"1", CFX_WideString(start, len)); + + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"2", CFX_WideString(start, len)); + + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"3", CFX_WideString(start, len)); + + EXPECT_FALSE(parser->NextValue(type, start, len)); + + parser = pdfium::MakeUnique<CFX_CSSValueListParser>(L"'str', rgb(1, 2, 3), 4", + 22, L','); + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::String, type); + EXPECT_EQ(L"str", CFX_WideString(start, len)); + + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::RGB, type); + EXPECT_EQ(L"rgb(1, 2, 3)", CFX_WideString(start, len)); + + EXPECT_TRUE(parser->NextValue(type, start, len)); + EXPECT_EQ(CFX_CSSPrimitiveType::Number, type); + EXPECT_EQ(L"4", CFX_WideString(start, len)); +} |