blob: d9a49cbf41c5da51936754072342c503d0f29c72 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
* All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <memory>
#include "core/CSSPropertyNames.h"
#include "core/CSSValueKeywords.h"
#include "core/StyleBuilderFunctions.h"
#include "core/StylePropertyShorthand.h"
#include "core/animation/css/CSSAnimations.h"
#include "core/css/CSSCounterValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSCustomPropertyDeclaration.h"
#include "core/css/CSSFunctionValue.h"
#include "core/css/CSSGridTemplateAreasValue.h"
#include "core/css/CSSHelper.h"
#include "core/css/CSSImageSetValue.h"
#include "core/css/CSSPendingSubstitutionValue.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/css/CSSPropertyMetadata.h"
#include "core/css/CSSValueIDMappings.h"
#include "core/css/CSSVariableReferenceValue.h"
#include "core/css/PropertyRegistration.h"
#include "core/css/PropertyRegistry.h"
#include "core/css/StylePropertySet.h"
#include "core/css/StyleRule.h"
#include "core/css/resolver/CSSVariableResolver.h"
#include "core/css/resolver/ElementStyleResources.h"
#include "core/css/resolver/FilterOperationResolver.h"
#include "core/css/resolver/FontBuilder.h"
#include "core/css/resolver/StyleBuilder.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/style/ComputedStyle.h"
#include "core/style/ComputedStyleConstants.h"
#include "core/style/ContentData.h"
#include "core/style/CounterContent.h"
#include "core/style/QuotesData.h"
#include "core/style/SVGComputedStyle.h"
#include "core/style/StyleGeneratedImage.h"
#include "core/style/StyleInheritedVariables.h"
#include "core/style/StyleNonInheritedVariables.h"
#include "platform/fonts/FontDescription.h"
#include "platform/wtf/MathExtras.h"
#include "platform/wtf/PtrUtil.h"
#include "platform/wtf/StdLibExtras.h"
#include "platform/wtf/Vector.h"
namespace blink {
namespace {
static inline bool IsValidVisitedLinkProperty(CSSPropertyID id) {
switch (id) {
case CSSPropertyBackgroundColor:
case CSSPropertyBorderLeftColor:
case CSSPropertyBorderRightColor:
case CSSPropertyBorderTopColor:
case CSSPropertyBorderBottomColor:
case CSSPropertyCaretColor:
case CSSPropertyColor:
case CSSPropertyFill:
case CSSPropertyOutlineColor:
case CSSPropertyStroke:
case CSSPropertyTextDecorationColor:
case CSSPropertyColumnRuleColor:
case CSSPropertyWebkitTextEmphasisColor:
case CSSPropertyWebkitTextFillColor:
case CSSPropertyWebkitTextStrokeColor:
return true;
default:
return false;
}
}
} // namespace
void StyleBuilder::ApplyProperty(CSSPropertyID id,
StyleResolverState& state,
const CSSValue& value) {
if (id != CSSPropertyVariable && (value.IsVariableReferenceValue() ||
value.IsPendingSubstitutionValue())) {
bool omit_animation_tainted =
CSSAnimations::IsAnimationAffectingProperty(id);
const CSSValue* resolved_value =
CSSVariableResolver::ResolveVariableReferences(state, id, value,
omit_animation_tainted);
ApplyProperty(id, state, *resolved_value);
if (!state.Style()->HasVariableReferenceFromNonInheritedProperty() &&
!CSSPropertyMetadata::IsInheritedProperty(id))
state.Style()->SetHasVariableReferenceFromNonInheritedProperty();
return;
}
DCHECK(!isShorthandProperty(id)) << "Shorthand property id = " << id
<< " wasn't expanded at parsing time";
bool is_inherit = state.ParentNode() && value.IsInheritedValue();
bool is_initial = value.IsInitialValue() ||
(!state.ParentNode() && value.IsInheritedValue());
// isInherit => !isInitial && isInitial => !isInherit
DCHECK(!is_inherit || !is_initial);
// isInherit => (state.parentNode() && state.parentStyle())
DCHECK(!is_inherit || (state.ParentNode() && state.ParentStyle()));
if (!state.ApplyPropertyToRegularStyle() &&
(!state.ApplyPropertyToVisitedLinkStyle() ||
!IsValidVisitedLinkProperty(id))) {
// Limit the properties that can be applied to only the ones honored by
// :visited.
return;
}
if (is_inherit && !state.ParentStyle()->HasExplicitlyInheritedProperties() &&
!CSSPropertyMetadata::IsInheritedProperty(id)) {
state.ParentStyle()->SetHasExplicitlyInheritedProperties();
} else if (value.IsUnsetValue()) {
DCHECK(!is_inherit && !is_initial);
if (CSSPropertyMetadata::IsInheritedProperty(id))
is_inherit = true;
else
is_initial = true;
}
StyleBuilder::ApplyProperty(id, state, value, is_initial, is_inherit);
}
void StyleBuilderFunctions::applyInitialCSSPropertyColor(
StyleResolverState& state) {
Color color = ComputedStyle::InitialColor();
if (state.ApplyPropertyToRegularStyle())
state.Style()->SetColor(color);
if (state.ApplyPropertyToVisitedLinkStyle())
state.Style()->SetVisitedLinkColor(color);
}
void StyleBuilderFunctions::applyInheritCSSPropertyColor(
StyleResolverState& state) {
Color color = state.ParentStyle()->GetColor();
if (state.ApplyPropertyToRegularStyle())
state.Style()->SetColor(color);
if (state.ApplyPropertyToVisitedLinkStyle())
state.Style()->SetVisitedLinkColor(color);
}
void StyleBuilderFunctions::applyValueCSSPropertyColor(
StyleResolverState& state,
const CSSValue& value) {
// As per the spec, 'color: currentColor' is treated as 'color: inherit'
if (value.IsIdentifierValue() &&
ToCSSIdentifierValue(value).GetValueID() == CSSValueCurrentcolor) {
applyInheritCSSPropertyColor(state);
return;
}
if (state.ApplyPropertyToRegularStyle())
state.Style()->SetColor(StyleBuilderConverter::ConvertColor(state, value));
if (state.ApplyPropertyToVisitedLinkStyle())
state.Style()->SetVisitedLinkColor(
StyleBuilderConverter::ConvertColor(state, value, true));
}
void StyleBuilderFunctions::applyInitialCSSPropertyCursor(
StyleResolverState& state) {
state.Style()->ClearCursorList();
state.Style()->SetCursor(ComputedStyle::InitialCursor());
}
void StyleBuilderFunctions::applyInheritCSSPropertyCursor(
StyleResolverState& state) {
state.Style()->SetCursor(state.ParentStyle()->Cursor());
state.Style()->SetCursorList(state.ParentStyle()->Cursors());
}
void StyleBuilderFunctions::applyValueCSSPropertyCursor(
StyleResolverState& state,
const CSSValue& value) {
state.Style()->ClearCursorList();
if (value.IsValueList()) {
state.Style()->SetCursor(ECursor::kAuto);
for (const auto& item : ToCSSValueList(value)) {
if (item->IsCursorImageValue()) {
const cssvalue::CSSCursorImageValue& cursor =
cssvalue::ToCSSCursorImageValue(*item);
const CSSValue& image = cursor.ImageValue();
state.Style()->AddCursor(state.GetStyleImage(CSSPropertyCursor, image),
cursor.HotSpotSpecified(), cursor.HotSpot());
} else {
state.Style()->SetCursor(
ToCSSIdentifierValue(*item).ConvertTo<ECursor>());
}
}
} else {
state.Style()->SetCursor(ToCSSIdentifierValue(value).ConvertTo<ECursor>());
}
}
void StyleBuilderFunctions::applyValueCSSPropertyDirection(
StyleResolverState& state,
const CSSValue& value) {
state.Style()->SetDirection(
ToCSSIdentifierValue(value).ConvertTo<TextDirection>());
}
void StyleBuilderFunctions::applyInitialCSSPropertyGridTemplateAreas(
StyleResolverState& state) {
state.Style()->SetNamedGridArea(ComputedStyle::InitialNamedGridArea());
state.Style()->SetNamedGridAreaRowCount(
ComputedStyle::InitialNamedGridAreaCount());
state.Style()->SetNamedGridAreaColumnCount(
ComputedStyle::InitialNamedGridAreaCount());
}
void StyleBuilderFunctions::applyInheritCSSPropertyGridTemplateAreas(
StyleResolverState& state) {
state.Style()->SetNamedGridArea(state.ParentStyle()->NamedGridArea());
state.Style()->SetNamedGridAreaRowCount(
state.ParentStyle()->NamedGridAreaRowCount());
state.Style()->SetNamedGridAreaColumnCount(
state.ParentStyle()->NamedGridAreaColumnCount());
}
void StyleBuilderFunctions::applyValueCSSPropertyGridTemplateAreas(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsIdentifierValue()) {
// FIXME: Shouldn't we clear the grid-area values
DCHECK_EQ(ToCSSIdentifierValue(value).GetValueID(), CSSValueNone);
return;
}
const CSSGridTemplateAreasValue& grid_template_areas_value =
ToCSSGridTemplateAreasValue(value);
const NamedGridAreaMap& new_named_grid_areas =
grid_template_areas_value.GridAreaMap();
NamedGridLinesMap named_grid_column_lines;
NamedGridLinesMap named_grid_row_lines;
StyleBuilderConverter::ConvertOrderedNamedGridLinesMapToNamedGridLinesMap(
state.Style()->OrderedNamedGridColumnLines(), named_grid_column_lines);
StyleBuilderConverter::ConvertOrderedNamedGridLinesMapToNamedGridLinesMap(
state.Style()->OrderedNamedGridRowLines(), named_grid_row_lines);
StyleBuilderConverter::CreateImplicitNamedGridLinesFromGridArea(
new_named_grid_areas, named_grid_column_lines, kForColumns);
StyleBuilderConverter::CreateImplicitNamedGridLinesFromGridArea(
new_named_grid_areas, named_grid_row_lines, kForRows);
state.Style()->SetNamedGridColumnLines(named_grid_column_lines);
state.Style()->SetNamedGridRowLines(named_grid_row_lines);
state.Style()->SetNamedGridArea(new_named_grid_areas);
state.Style()->SetNamedGridAreaRowCount(grid_template_areas_value.RowCount());
state.Style()->SetNamedGridAreaColumnCount(
grid_template_areas_value.ColumnCount());
}
void StyleBuilderFunctions::applyValueCSSPropertyListStyleImage(
StyleResolverState& state,
const CSSValue& value) {
state.Style()->SetListStyleImage(
state.GetStyleImage(CSSPropertyListStyleImage, value));
}
void StyleBuilderFunctions::applyInitialCSSPropertyOutlineStyle(
StyleResolverState& state) {
state.Style()->SetOutlineStyleIsAuto(
ComputedStyle::InitialOutlineStyleIsAuto());
state.Style()->SetOutlineStyle(ComputedStyle::InitialBorderStyle());
}
void StyleBuilderFunctions::applyInheritCSSPropertyOutlineStyle(
StyleResolverState& state) {
state.Style()->SetOutlineStyleIsAuto(
state.ParentStyle()->OutlineStyleIsAuto());
state.Style()->SetOutlineStyle(state.ParentStyle()->OutlineStyle());
}
void StyleBuilderFunctions::applyValueCSSPropertyOutlineStyle(
StyleResolverState& state,
const CSSValue& value) {
const CSSIdentifierValue& identifier_value = ToCSSIdentifierValue(value);
state.Style()->SetOutlineStyleIsAuto(
identifier_value.ConvertTo<OutlineIsAuto>());
state.Style()->SetOutlineStyle(identifier_value.ConvertTo<EBorderStyle>());
}
void StyleBuilderFunctions::applyValueCSSPropertyResize(
StyleResolverState& state,
const CSSValue& value) {
const CSSIdentifierValue& identifier_value = ToCSSIdentifierValue(value);
EResize r = RESIZE_NONE;
if (identifier_value.GetValueID() == CSSValueAuto) {
if (Settings* settings = state.GetDocument().GetSettings())
r = settings->GetTextAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
} else {
r = identifier_value.ConvertTo<EResize>();
}
state.Style()->SetResize(r);
}
static float MmToPx(float mm) {
return mm * kCssPixelsPerMillimeter;
}
static float InchToPx(float inch) {
return inch * kCssPixelsPerInch;
}
static FloatSize GetPageSizeFromName(const CSSIdentifierValue& page_size_name) {
switch (page_size_name.GetValueID()) {
case CSSValueA5:
return FloatSize(MmToPx(148), MmToPx(210));
case CSSValueA4:
return FloatSize(MmToPx(210), MmToPx(297));
case CSSValueA3:
return FloatSize(MmToPx(297), MmToPx(420));
case CSSValueB5:
return FloatSize(MmToPx(176), MmToPx(250));
case CSSValueB4:
return FloatSize(MmToPx(250), MmToPx(353));
case CSSValueLetter:
return FloatSize(InchToPx(8.5), InchToPx(11));
case CSSValueLegal:
return FloatSize(InchToPx(8.5), InchToPx(14));
case CSSValueLedger:
return FloatSize(InchToPx(11), InchToPx(17));
default:
NOTREACHED();
return FloatSize(0, 0);
}
}
void StyleBuilderFunctions::applyInitialCSSPropertySize(StyleResolverState&) {}
void StyleBuilderFunctions::applyInheritCSSPropertySize(StyleResolverState&) {}
void StyleBuilderFunctions::applyValueCSSPropertySize(StyleResolverState& state,
const CSSValue& value) {
state.Style()->ResetPageSizeType();
FloatSize size;
PageSizeType page_size_type = PAGE_SIZE_AUTO;
const CSSValueList& list = ToCSSValueList(value);
if (list.length() == 2) {
// <length>{2} | <page-size> <orientation>
const CSSValue& first = list.Item(0);
const CSSValue& second = list.Item(1);
if (first.IsPrimitiveValue() && ToCSSPrimitiveValue(first).IsLength()) {
// <length>{2}
size = FloatSize(
ToCSSPrimitiveValue(first).ComputeLength<float>(
state.CssToLengthConversionData().CopyWithAdjustedZoom(1.0)),
ToCSSPrimitiveValue(second).ComputeLength<float>(
state.CssToLengthConversionData().CopyWithAdjustedZoom(1.0)));
} else {
// <page-size> <orientation>
size = GetPageSizeFromName(ToCSSIdentifierValue(first));
DCHECK(ToCSSIdentifierValue(second).GetValueID() == CSSValueLandscape ||
ToCSSIdentifierValue(second).GetValueID() == CSSValuePortrait);
if (ToCSSIdentifierValue(second).GetValueID() == CSSValueLandscape)
size = size.TransposedSize();
}
page_size_type = PAGE_SIZE_RESOLVED;
} else {
DCHECK_EQ(list.length(), 1U);
// <length> | auto | <page-size> | [ portrait | landscape]
const CSSValue& first = list.Item(0);
if (first.IsPrimitiveValue() && ToCSSPrimitiveValue(first).IsLength()) {
// <length>
page_size_type = PAGE_SIZE_RESOLVED;
float width = ToCSSPrimitiveValue(first).ComputeLength<float>(
state.CssToLengthConversionData().CopyWithAdjustedZoom(1.0));
size = FloatSize(width, width);
} else {
const CSSIdentifierValue& ident = ToCSSIdentifierValue(first);
switch (ident.GetValueID()) {
case CSSValueAuto:
page_size_type = PAGE_SIZE_AUTO;
break;
case CSSValuePortrait:
page_size_type = PAGE_SIZE_AUTO_PORTRAIT;
break;
case CSSValueLandscape:
page_size_type = PAGE_SIZE_AUTO_LANDSCAPE;
break;
default:
// <page-size>
page_size_type = PAGE_SIZE_RESOLVED;
size = GetPageSizeFromName(ident);
}
}
}
state.Style()->SetPageSizeType(page_size_type);
state.Style()->SetPageSize(size);
}
void StyleBuilderFunctions::applyValueCSSPropertyTextAlign(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsIdentifierValue() &&
ToCSSIdentifierValue(value).GetValueID() != CSSValueWebkitMatchParent) {
// Special case for th elements - UA stylesheet text-align does not apply if
// parent's computed value for text-align is not its initial value
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2
const CSSIdentifierValue& ident_value = ToCSSIdentifierValue(value);
if (ident_value.GetValueID() == CSSValueInternalCenter &&
state.ParentStyle()->GetTextAlign() !=
ComputedStyle::InitialTextAlign())
state.Style()->SetTextAlign(state.ParentStyle()->GetTextAlign());
else
state.Style()->SetTextAlign(ident_value.ConvertTo<ETextAlign>());
} else if (state.ParentStyle()->GetTextAlign() == ETextAlign::kStart) {
state.Style()->SetTextAlign(state.ParentStyle()->IsLeftToRightDirection()
? ETextAlign::kLeft
: ETextAlign::kRight);
} else if (state.ParentStyle()->GetTextAlign() == ETextAlign::kEnd) {
state.Style()->SetTextAlign(state.ParentStyle()->IsLeftToRightDirection()
? ETextAlign::kRight
: ETextAlign::kLeft);
} else {
state.Style()->SetTextAlign(state.ParentStyle()->GetTextAlign());
}
state.Style()->SetTextAlignIsInherited(false);
}
void StyleBuilderFunctions::applyInheritCSSPropertyTextIndent(
StyleResolverState& state) {
state.Style()->SetTextIndent(state.ParentStyle()->TextIndent());
state.Style()->SetTextIndentLine(state.ParentStyle()->GetTextIndentLine());
state.Style()->SetTextIndentType(state.ParentStyle()->GetTextIndentType());
}
void StyleBuilderFunctions::applyInitialCSSPropertyTextIndent(
StyleResolverState& state) {
state.Style()->SetTextIndent(ComputedStyle::InitialTextIndent());
state.Style()->SetTextIndentLine(ComputedStyle::InitialTextIndentLine());
state.Style()->SetTextIndentType(ComputedStyle::InitialTextIndentType());
}
void StyleBuilderFunctions::applyValueCSSPropertyTextIndent(
StyleResolverState& state,
const CSSValue& value) {
Length length_or_percentage_value;
TextIndentLine text_indent_line_value =
ComputedStyle::InitialTextIndentLine();
TextIndentType text_indent_type_value =
ComputedStyle::InitialTextIndentType();
for (auto& list_value : ToCSSValueList(value)) {
if (list_value->IsPrimitiveValue()) {
length_or_percentage_value =
ToCSSPrimitiveValue(*list_value)
.ConvertToLength(state.CssToLengthConversionData());
} else if (ToCSSIdentifierValue(*list_value).GetValueID() ==
CSSValueEachLine) {
text_indent_line_value = kTextIndentEachLine;
} else if (ToCSSIdentifierValue(*list_value).GetValueID() ==
CSSValueHanging) {
text_indent_type_value = kTextIndentHanging;
} else {
NOTREACHED();
}
}
state.Style()->SetTextIndent(length_or_percentage_value);
state.Style()->SetTextIndentLine(text_indent_line_value);
state.Style()->SetTextIndentType(text_indent_type_value);
}
void StyleBuilderFunctions::applyInheritCSSPropertyVerticalAlign(
StyleResolverState& state) {
EVerticalAlign vertical_align = state.ParentStyle()->VerticalAlign();
state.Style()->SetVerticalAlign(vertical_align);
if (vertical_align == EVerticalAlign::kLength)
state.Style()->SetVerticalAlignLength(
state.ParentStyle()->GetVerticalAlignLength());
}
void StyleBuilderFunctions::applyValueCSSPropertyVerticalAlign(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsIdentifierValue()) {
state.Style()->SetVerticalAlign(
ToCSSIdentifierValue(value).ConvertTo<EVerticalAlign>());
} else {
state.Style()->SetVerticalAlignLength(
ToCSSPrimitiveValue(value).ConvertToLength(
state.CssToLengthConversionData()));
}
}
static void ResetEffectiveZoom(StyleResolverState& state) {
// Reset the zoom in effect. This allows the setZoom method to accurately
// compute a new zoom in effect.
state.SetEffectiveZoom(state.ParentStyle()
? state.ParentStyle()->EffectiveZoom()
: ComputedStyle::InitialZoom());
}
void StyleBuilderFunctions::applyInitialCSSPropertyZoom(
StyleResolverState& state) {
ResetEffectiveZoom(state);
state.SetZoom(ComputedStyle::InitialZoom());
}
void StyleBuilderFunctions::applyInheritCSSPropertyZoom(
StyleResolverState& state) {
ResetEffectiveZoom(state);
state.SetZoom(state.ParentStyle()->Zoom());
}
void StyleBuilderFunctions::applyValueCSSPropertyZoom(StyleResolverState& state,
const CSSValue& value) {
SECURITY_DCHECK(value.IsPrimitiveValue() || value.IsIdentifierValue());
if (value.IsIdentifierValue()) {
const CSSIdentifierValue& identifier_value = ToCSSIdentifierValue(value);
if (identifier_value.GetValueID() == CSSValueNormal) {
ResetEffectiveZoom(state);
state.SetZoom(ComputedStyle::InitialZoom());
}
} else if (value.IsPrimitiveValue()) {
const CSSPrimitiveValue& primitive_value = ToCSSPrimitiveValue(value);
if (primitive_value.IsPercentage()) {
ResetEffectiveZoom(state);
if (float percent = primitive_value.GetFloatValue())
state.SetZoom(percent / 100.0f);
} else if (primitive_value.IsNumber()) {
ResetEffectiveZoom(state);
if (float number = primitive_value.GetFloatValue())
state.SetZoom(number);
}
}
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitBorderImage(
StyleResolverState& state,
const CSSValue& value) {
NinePieceImage image;
CSSToStyleMap::MapNinePieceImage(state, CSSPropertyWebkitBorderImage, value,
image);
state.Style()->SetBorderImage(image);
}
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitTextEmphasisStyle(
StyleResolverState& state) {
state.Style()->SetTextEmphasisFill(ComputedStyle::InitialTextEmphasisFill());
state.Style()->SetTextEmphasisMark(ComputedStyle::InitialTextEmphasisMark());
state.Style()->SetTextEmphasisCustomMark(
ComputedStyle::InitialTextEmphasisCustomMark());
}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitTextEmphasisStyle(
StyleResolverState& state) {
state.Style()->SetTextEmphasisFill(
state.ParentStyle()->GetTextEmphasisFill());
state.Style()->SetTextEmphasisMark(
state.ParentStyle()->GetTextEmphasisMark());
state.Style()->SetTextEmphasisCustomMark(
state.ParentStyle()->TextEmphasisCustomMark());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextEmphasisStyle(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsValueList()) {
const CSSValueList& list = ToCSSValueList(value);
DCHECK_EQ(list.length(), 2U);
for (unsigned i = 0; i < 2; ++i) {
const CSSIdentifierValue& value = ToCSSIdentifierValue(list.Item(i));
if (value.GetValueID() == CSSValueFilled ||
value.GetValueID() == CSSValueOpen)
state.Style()->SetTextEmphasisFill(value.ConvertTo<TextEmphasisFill>());
else
state.Style()->SetTextEmphasisMark(value.ConvertTo<TextEmphasisMark>());
}
state.Style()->SetTextEmphasisCustomMark(g_null_atom);
return;
}
if (value.IsStringValue()) {
state.Style()->SetTextEmphasisFill(kTextEmphasisFillFilled);
state.Style()->SetTextEmphasisMark(kTextEmphasisMarkCustom);
state.Style()->SetTextEmphasisCustomMark(
AtomicString(ToCSSStringValue(value).Value()));
return;
}
const CSSIdentifierValue& identifier_value = ToCSSIdentifierValue(value);
state.Style()->SetTextEmphasisCustomMark(g_null_atom);
if (identifier_value.GetValueID() == CSSValueFilled ||
identifier_value.GetValueID() == CSSValueOpen) {
state.Style()->SetTextEmphasisFill(
identifier_value.ConvertTo<TextEmphasisFill>());
state.Style()->SetTextEmphasisMark(kTextEmphasisMarkAuto);
} else {
state.Style()->SetTextEmphasisFill(kTextEmphasisFillFilled);
state.Style()->SetTextEmphasisMark(
identifier_value.ConvertTo<TextEmphasisMark>());
}
}
void StyleBuilderFunctions::applyInitialCSSPropertyWillChange(
StyleResolverState& state) {
state.Style()->SetWillChangeContents(false);
state.Style()->SetWillChangeScrollPosition(false);
state.Style()->SetWillChangeProperties(Vector<CSSPropertyID>());
state.Style()->SetSubtreeWillChangeContents(
state.ParentStyle()->SubtreeWillChangeContents());
}
void StyleBuilderFunctions::applyInheritCSSPropertyWillChange(
StyleResolverState& state) {
state.Style()->SetWillChangeContents(
state.ParentStyle()->WillChangeContents());
state.Style()->SetWillChangeScrollPosition(
state.ParentStyle()->WillChangeScrollPosition());
state.Style()->SetWillChangeProperties(
state.ParentStyle()->WillChangeProperties());
state.Style()->SetSubtreeWillChangeContents(
state.ParentStyle()->SubtreeWillChangeContents());
}
void StyleBuilderFunctions::applyValueCSSPropertyWillChange(
StyleResolverState& state,
const CSSValue& value) {
bool will_change_contents = false;
bool will_change_scroll_position = false;
Vector<CSSPropertyID> will_change_properties;
if (value.IsIdentifierValue()) {
DCHECK_EQ(ToCSSIdentifierValue(value).GetValueID(), CSSValueAuto);
} else {
DCHECK(value.IsValueList());
for (auto& will_change_value : ToCSSValueList(value)) {
if (will_change_value->IsCustomIdentValue())
will_change_properties.push_back(
ToCSSCustomIdentValue(*will_change_value).ValueAsPropertyID());
else if (ToCSSIdentifierValue(*will_change_value).GetValueID() ==
CSSValueContents)
will_change_contents = true;
else if (ToCSSIdentifierValue(*will_change_value).GetValueID() ==
CSSValueScrollPosition)
will_change_scroll_position = true;
else
NOTREACHED();
}
}
state.Style()->SetWillChangeContents(will_change_contents);
state.Style()->SetWillChangeScrollPosition(will_change_scroll_position);
state.Style()->SetWillChangeProperties(will_change_properties);
state.Style()->SetSubtreeWillChangeContents(
will_change_contents || state.ParentStyle()->SubtreeWillChangeContents());
}
void StyleBuilderFunctions::applyInitialCSSPropertyContent(
StyleResolverState& state) {
state.Style()->SetContent(nullptr);
}
void StyleBuilderFunctions::applyInheritCSSPropertyContent(
StyleResolverState&) {
// FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not.
// This note is a reminder that eventually "inherit" needs to be supported.
}
void StyleBuilderFunctions::applyValueCSSPropertyContent(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsIdentifierValue()) {
DCHECK(ToCSSIdentifierValue(value).GetValueID() == CSSValueNormal ||
ToCSSIdentifierValue(value).GetValueID() == CSSValueNone);
state.Style()->SetContent(nullptr);
return;
}
ContentData* first_content = nullptr;
ContentData* prev_content = nullptr;
for (auto& item : ToCSSValueList(value)) {
ContentData* next_content = nullptr;
if (item->IsImageGeneratorValue() || item->IsImageSetValue() ||
item->IsImageValue()) {
next_content =
ContentData::Create(state.GetStyleImage(CSSPropertyContent, *item));
} else if (item->IsCounterValue()) {
const cssvalue::CSSCounterValue* counter_value =
cssvalue::ToCSSCounterValue(item.Get());
const auto list_style_type =
CssValueIDToPlatformEnum<EListStyleType>(counter_value->ListStyle());
std::unique_ptr<CounterContent> counter =
WTF::WrapUnique(new CounterContent(
AtomicString(counter_value->Identifier()), list_style_type,
AtomicString(counter_value->Separator())));
next_content = ContentData::Create(std::move(counter));
} else if (item->IsIdentifierValue()) {
QuoteType quote_type;
switch (ToCSSIdentifierValue(*item).GetValueID()) {
default:
NOTREACHED();
case CSSValueOpenQuote:
quote_type = OPEN_QUOTE;
break;
case CSSValueCloseQuote:
quote_type = CLOSE_QUOTE;
break;
case CSSValueNoOpenQuote:
quote_type = NO_OPEN_QUOTE;
break;
case CSSValueNoCloseQuote:
quote_type = NO_CLOSE_QUOTE;
break;
}
next_content = ContentData::Create(quote_type);
} else {
String string;
if (item->IsFunctionValue()) {
const CSSFunctionValue* function_value = ToCSSFunctionValue(item.Get());
DCHECK_EQ(function_value->FunctionType(), CSSValueAttr);
// FIXME: Can a namespace be specified for an attr(foo)?
if (state.Style()->StyleType() == kPseudoIdNone)
state.Style()->SetUnique();
else
state.ParentStyle()->SetUnique();
QualifiedName attr(
g_null_atom, ToCSSCustomIdentValue(function_value->Item(0)).Value(),
g_null_atom);
const AtomicString& value = state.GetElement()->getAttribute(attr);
string = value.IsNull() ? g_empty_string : value.GetString();
} else {
string = ToCSSStringValue(*item).Value();
}
if (prev_content && prev_content->IsText()) {
TextContentData* text_content = ToTextContentData(prev_content);
text_content->SetText(text_content->GetText() + string);
continue;
}
next_content = ContentData::Create(string);
}
if (!first_content)
first_content = next_content;
else
prev_content->SetNext(next_content);
prev_content = next_content;
}
DCHECK(first_content);
state.Style()->SetContent(first_content);
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitLocale(
StyleResolverState& state,
const CSSValue& value) {
if (value.IsIdentifierValue()) {
DCHECK_EQ(ToCSSIdentifierValue(value).GetValueID(), CSSValueAuto);
state.GetFontBuilder().SetLocale(nullptr);
} else {
state.GetFontBuilder().SetLocale(
LayoutLocale::Get(AtomicString(ToCSSStringValue(value).Value())));
}
}
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAppRegion(
StyleResolverState&) {}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitAppRegion(
StyleResolverState&) {}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitAppRegion(
StyleResolverState& state,
const CSSValue& value) {
const CSSIdentifierValue& identifier_value = ToCSSIdentifierValue(value);
state.Style()->SetDraggableRegionMode(
identifier_value.GetValueID() == CSSValueDrag ? kDraggableRegionDrag
: kDraggableRegionNoDrag);
state.GetDocument().SetHasAnnotatedRegions(true);
}
void StyleBuilderFunctions::applyValueCSSPropertyWritingMode(
StyleResolverState& state,
const CSSValue& value) {
state.SetWritingMode(ToCSSIdentifierValue(value).ConvertTo<WritingMode>());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitWritingMode(
StyleResolverState& state,
const CSSValue& value) {
state.SetWritingMode(ToCSSIdentifierValue(value).ConvertTo<WritingMode>());
}
void StyleBuilderFunctions::applyValueCSSPropertyTextOrientation(
StyleResolverState& state,
const CSSValue& value) {
state.SetTextOrientation(
ToCSSIdentifierValue(value).ConvertTo<TextOrientation>());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextOrientation(
StyleResolverState& state,
const CSSValue& value) {
state.SetTextOrientation(
ToCSSIdentifierValue(value).ConvertTo<TextOrientation>());
}
void StyleBuilderFunctions::applyValueCSSPropertyVariable(
StyleResolverState& state,
const CSSValue& value) {
const CSSCustomPropertyDeclaration& declaration =
ToCSSCustomPropertyDeclaration(value);
const AtomicString& name = declaration.GetName();
const PropertyRegistration* registration = nullptr;
const PropertyRegistry* registry = state.GetDocument().GetPropertyRegistry();
if (registry)
registration = registry->Registration(name);
bool is_inherited_property = !registration || registration->Inherits();
bool initial = declaration.IsInitial(is_inherited_property);
bool inherit = declaration.IsInherit(is_inherited_property);
DCHECK(!(initial && inherit));
if (!initial && !inherit) {
if (declaration.Value()->NeedsVariableResolution()) {
if (is_inherited_property)
state.Style()->SetUnresolvedInheritedVariable(name,
declaration.Value());
else
state.Style()->SetUnresolvedNonInheritedVariable(name,
declaration.Value());
return;
}
if (!registration) {
state.Style()->SetResolvedUnregisteredVariable(name, declaration.Value());
return;
}
const CSSValue* parsed_value =
declaration.Value()->ParseForSyntax(registration->Syntax());
if (parsed_value) {
DCHECK(parsed_value);
if (is_inherited_property)
state.Style()->SetResolvedInheritedVariable(name, declaration.Value(),
parsed_value);
else
state.Style()->SetResolvedNonInheritedVariable(
name, declaration.Value(), parsed_value);
return;
}
if (is_inherited_property)
inherit = true;
else
initial = true;
}
DCHECK(initial ^ inherit);
state.Style()->RemoveVariable(name, is_inherited_property);
if (initial) {
return;
}
DCHECK(inherit);
CSSVariableData* parent_value =
state.ParentStyle()->GetVariable(name, is_inherited_property);
const CSSValue* parent_css_value =
registration && parent_value ? state.ParentStyle()->GetRegisteredVariable(
name, is_inherited_property)
: nullptr;
if (!is_inherited_property) {
DCHECK(registration);
if (parent_value) {
state.Style()->SetResolvedNonInheritedVariable(name, parent_value,
parent_css_value);
}
return;
}
if (parent_value) {
if (!registration) {
state.Style()->SetResolvedUnregisteredVariable(name, parent_value);
} else {
state.Style()->SetResolvedInheritedVariable(name, parent_value,
parent_css_value);
}
}
}
void StyleBuilderFunctions::applyInheritCSSPropertyBaselineShift(
StyleResolverState& state) {
const SVGComputedStyle& parent_svg_style = state.ParentStyle()->SvgStyle();
EBaselineShift baseline_shift = parent_svg_style.BaselineShift();
SVGComputedStyle& svg_style = state.Style()->AccessSVGStyle();
svg_style.SetBaselineShift(baseline_shift);
if (baseline_shift == BS_LENGTH)
svg_style.SetBaselineShiftValue(parent_svg_style.BaselineShiftValue());
}
void StyleBuilderFunctions::applyValueCSSPropertyBaselineShift(
StyleResolverState& state,
const CSSValue& value) {
SVGComputedStyle& svg_style = state.Style()->AccessSVGStyle();
if (!value.IsIdentifierValue()) {
svg_style.SetBaselineShift(BS_LENGTH);
svg_style.SetBaselineShiftValue(StyleBuilderConverter::ConvertLength(
state, ToCSSPrimitiveValue(value)));
return;
}
switch (ToCSSIdentifierValue(value).GetValueID()) {
case CSSValueBaseline:
svg_style.SetBaselineShift(BS_LENGTH);
svg_style.SetBaselineShiftValue(Length(kFixed));
return;
case CSSValueSub:
svg_style.SetBaselineShift(BS_SUB);
return;
case CSSValueSuper:
svg_style.SetBaselineShift(BS_SUPER);
return;
default:
NOTREACHED();
}
}
void StyleBuilderFunctions::applyInheritCSSPropertyPosition(
StyleResolverState& state) {
if (!state.ParentNode()->IsDocumentNode())
state.Style()->SetPosition(state.ParentStyle()->GetPosition());
}
void StyleBuilderFunctions::applyInitialCSSPropertyCaretColor(
StyleResolverState& state) {
StyleAutoColor color = StyleAutoColor::AutoColor();
if (state.ApplyPropertyToRegularStyle())
state.Style()->SetCaretColor(color);
if (state.ApplyPropertyToVisitedLinkStyle())
state.Style()->SetVisitedLinkCaretColor(color);
}
void StyleBuilderFunctions::applyInheritCSSPropertyCaretColor(
StyleResolverState& state) {
StyleAutoColor color = state.ParentStyle()->CaretColor();
if (state.ApplyPropertyToRegularStyle())
state.Style()->SetCaretColor(color);
if (state.ApplyPropertyToVisitedLinkStyle())
state.Style()->SetVisitedLinkCaretColor(color);
}
void StyleBuilderFunctions::applyValueCSSPropertyCaretColor(
StyleResolverState& state,
const CSSValue& value) {
if (state.ApplyPropertyToRegularStyle()) {
state.Style()->SetCaretColor(
StyleBuilderConverter::ConvertStyleAutoColor(state, value));
}
if (state.ApplyPropertyToVisitedLinkStyle()) {
state.Style()->SetVisitedLinkCaretColor(
StyleBuilderConverter::ConvertStyleAutoColor(state, value, true));
}
}
} // namespace blink