blob: 28de116c9251d4128953c49287e18a17365b8d45 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
* Copyright (C) 2014-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
*/
#pragma once
#include "CSSAspectRatioValue.h"
#include "CSSCursorImageValue.h"
#include "CSSFontFamily.h"
#include "CSSFontValue.h"
#include "CSSGradientValue.h"
#include "CSSGridTemplateAreasValue.h"
#include "CSSRegisteredCustomProperty.h"
#include "CSSShadowValue.h"
#include "Counter.h"
#include "CounterContent.h"
#include "CursorList.h"
#include "ElementAncestorIterator.h"
#include "FontVariantBuilder.h"
#include "Frame.h"
#include "HTMLElement.h"
#include "Rect.h"
#include "SVGElement.h"
#include "SVGRenderStyle.h"
#include "StyleBuilderConverter.h"
#include "StyleCachedImage.h"
#include "StyleFontSizeFunctions.h"
#include "StyleGeneratedImage.h"
#include "StyleResolver.h"
#include "WillChangeData.h"
namespace WebCore {
#define DECLARE_PROPERTY_CUSTOM_HANDLERS(property) \
static void applyInherit##property(StyleResolver&); \
static void applyInitial##property(StyleResolver&); \
static void applyValue##property(StyleResolver&, CSSValue&)
template<typename T> inline T forwardInheritedValue(T&& value) { return std::forward<T>(value); }
inline Length forwardInheritedValue(const Length& value) { auto copy = value; return copy; }
inline LengthSize forwardInheritedValue(const LengthSize& value) { auto copy = value; return copy; }
inline LengthBox forwardInheritedValue(const LengthBox& value) { auto copy = value; return copy; }
inline GapLength forwardInheritedValue(const GapLength& value) { auto copy = value; return copy; }
// Note that we assume the CSS parser only allows valid CSSValue types.
class StyleBuilderCustom {
public:
// Custom handling of inherit, initial and value setting.
DECLARE_PROPERTY_CUSTOM_HANDLERS(BorderImageOutset);
DECLARE_PROPERTY_CUSTOM_HANDLERS(BorderImageRepeat);
DECLARE_PROPERTY_CUSTOM_HANDLERS(BorderImageSlice);
DECLARE_PROPERTY_CUSTOM_HANDLERS(BorderImageWidth);
DECLARE_PROPERTY_CUSTOM_HANDLERS(BoxShadow);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Clip);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Content);
DECLARE_PROPERTY_CUSTOM_HANDLERS(CounterIncrement);
DECLARE_PROPERTY_CUSTOM_HANDLERS(CounterReset);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Cursor);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Fill);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontFamily);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontSize);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontStyle);
#if ENABLE(CSS_IMAGE_RESOLUTION)
DECLARE_PROPERTY_CUSTOM_HANDLERS(ImageResolution);
#endif
#if ENABLE(TEXT_AUTOSIZING)
DECLARE_PROPERTY_CUSTOM_HANDLERS(LineHeight);
#endif
DECLARE_PROPERTY_CUSTOM_HANDLERS(OutlineStyle);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Size);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Stroke);
DECLARE_PROPERTY_CUSTOM_HANDLERS(TextIndent);
DECLARE_PROPERTY_CUSTOM_HANDLERS(TextShadow);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitAspectRatio);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitBoxShadow);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantLigatures);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantNumeric);
DECLARE_PROPERTY_CUSTOM_HANDLERS(FontVariantEastAsian);
DECLARE_PROPERTY_CUSTOM_HANDLERS(GridTemplateAreas);
DECLARE_PROPERTY_CUSTOM_HANDLERS(GridTemplateColumns);
DECLARE_PROPERTY_CUSTOM_HANDLERS(GridTemplateRows);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitMaskBoxImageOutset);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitMaskBoxImageRepeat);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitMaskBoxImageSlice);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitMaskBoxImageWidth);
DECLARE_PROPERTY_CUSTOM_HANDLERS(WebkitTextEmphasisStyle);
DECLARE_PROPERTY_CUSTOM_HANDLERS(Zoom);
// Custom handling of initial + inherit value setting only.
static void applyInitialWebkitMaskImage(StyleResolver&) { }
static void applyInheritWebkitMaskImage(StyleResolver&) { }
static void applyInitialFontFeatureSettings(StyleResolver&) { }
static void applyInheritFontFeatureSettings(StyleResolver&) { }
#if ENABLE(VARIATION_FONTS)
static void applyInitialFontVariationSettings(StyleResolver&) { }
static void applyInheritFontVariationSettings(StyleResolver&) { }
#endif
// Custom handling of inherit + value setting only.
static void applyInheritDisplay(StyleResolver&);
static void applyValueDisplay(StyleResolver&, CSSValue&);
// Custom handling of value setting only.
static void applyValueBaselineShift(StyleResolver&, CSSValue&);
static void applyValueDirection(StyleResolver&, CSSValue&);
static void applyValueVerticalAlign(StyleResolver&, CSSValue&);
static void applyInitialTextAlign(StyleResolver&);
static void applyValueTextAlign(StyleResolver&, CSSValue&);
static void applyValueWebkitLocale(StyleResolver&, CSSValue&);
static void applyValueWebkitTextOrientation(StyleResolver&, CSSValue&);
#if ENABLE(TEXT_AUTOSIZING)
static void applyValueWebkitTextSizeAdjust(StyleResolver&, CSSValue&);
#endif
static void applyValueWebkitTextZoom(StyleResolver&, CSSValue&);
static void applyValueWritingMode(StyleResolver&, CSSValue&);
static void applyValueAlt(StyleResolver&, CSSValue&);
static void applyValueWillChange(StyleResolver&, CSSValue&);
#if ENABLE(DARK_MODE_CSS)
static void applyValueColorScheme(StyleResolver&, CSSValue&);
#endif
static void applyValueStrokeWidth(StyleResolver&, CSSValue&);
static void applyValueStrokeColor(StyleResolver&, CSSValue&);
static void applyInitialCustomProperty(StyleResolver&, const CSSRegisteredCustomProperty*, const AtomString& name);
static void applyInheritCustomProperty(StyleResolver&, const CSSRegisteredCustomProperty*, const AtomString& name);
static void applyValueCustomProperty(StyleResolver&, const CSSRegisteredCustomProperty*, CSSCustomPropertyValue&);
private:
static void resetEffectiveZoom(StyleResolver&);
static Length mmLength(double mm);
static Length inchLength(double inch);
static bool getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height);
template <CSSPropertyID id>
static void applyTextOrBoxShadowValue(StyleResolver&, CSSValue&);
static bool isValidDisplayValue(StyleResolver&, DisplayType);
enum CounterBehavior {Increment = 0, Reset};
template <CounterBehavior counterBehavior>
static void applyInheritCounter(StyleResolver&);
template <CounterBehavior counterBehavior>
static void applyValueCounter(StyleResolver&, CSSValue&);
static float largerFontSize(float size);
static float smallerFontSize(float size);
static float determineRubyTextSizeMultiplier(StyleResolver&);
};
inline void StyleBuilderCustom::applyValueDirection(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->setDirection(downcast<CSSPrimitiveValue>(value));
styleResolver.style()->setHasExplicitlySetDirection(true);
}
inline void StyleBuilderCustom::applyInitialTextAlign(StyleResolver& styleResolver)
{
styleResolver.style()->setTextAlign(RenderStyle::initialTextAlign());
styleResolver.style()->setHasExplicitlySetTextAlign(true);
}
inline void StyleBuilderCustom::applyValueTextAlign(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->setTextAlign(StyleBuilderConverter::convertTextAlign(styleResolver, value));
styleResolver.style()->setHasExplicitlySetTextAlign(true);
}
inline void StyleBuilderCustom::resetEffectiveZoom(StyleResolver& styleResolver)
{
// Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect.
styleResolver.setEffectiveZoom(styleResolver.parentStyle() ? styleResolver.parentStyle()->effectiveZoom() : RenderStyle::initialZoom());
}
inline void StyleBuilderCustom::applyInitialZoom(StyleResolver& styleResolver)
{
resetEffectiveZoom(styleResolver);
styleResolver.setZoom(RenderStyle::initialZoom());
}
inline void StyleBuilderCustom::applyInheritZoom(StyleResolver& styleResolver)
{
resetEffectiveZoom(styleResolver);
styleResolver.setZoom(styleResolver.parentStyle()->zoom());
}
inline void StyleBuilderCustom::applyValueZoom(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.valueID() == CSSValueNormal) {
resetEffectiveZoom(styleResolver);
styleResolver.setZoom(RenderStyle::initialZoom());
} else if (primitiveValue.valueID() == CSSValueReset) {
styleResolver.setEffectiveZoom(RenderStyle::initialZoom());
styleResolver.setZoom(RenderStyle::initialZoom());
} else if (primitiveValue.valueID() == CSSValueDocument) {
float docZoom = styleResolver.rootElementStyle() ? styleResolver.rootElementStyle()->zoom() : RenderStyle::initialZoom();
styleResolver.setEffectiveZoom(docZoom);
styleResolver.setZoom(docZoom);
} else if (primitiveValue.isPercentage()) {
resetEffectiveZoom(styleResolver);
if (float percent = primitiveValue.floatValue())
styleResolver.setZoom(percent / 100.0f);
} else if (primitiveValue.isNumber()) {
resetEffectiveZoom(styleResolver);
if (float number = primitiveValue.floatValue())
styleResolver.setZoom(number);
}
}
inline Length StyleBuilderCustom::mmLength(double mm)
{
Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM));
return value.get().computeLength<Length>(CSSToLengthConversionData());
}
inline Length StyleBuilderCustom::inchLength(double inch)
{
Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN));
return value.get().computeLength<Length>(CSSToLengthConversionData());
}
bool StyleBuilderCustom::getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height)
{
static NeverDestroyed<Length> a5Width(mmLength(148));
static NeverDestroyed<Length> a5Height(mmLength(210));
static NeverDestroyed<Length> a4Width(mmLength(210));
static NeverDestroyed<Length> a4Height(mmLength(297));
static NeverDestroyed<Length> a3Width(mmLength(297));
static NeverDestroyed<Length> a3Height(mmLength(420));
static NeverDestroyed<Length> b5Width(mmLength(176));
static NeverDestroyed<Length> b5Height(mmLength(250));
static NeverDestroyed<Length> b4Width(mmLength(250));
static NeverDestroyed<Length> b4Height(mmLength(353));
static NeverDestroyed<Length> letterWidth(inchLength(8.5));
static NeverDestroyed<Length> letterHeight(inchLength(11));
static NeverDestroyed<Length> legalWidth(inchLength(8.5));
static NeverDestroyed<Length> legalHeight(inchLength(14));
static NeverDestroyed<Length> ledgerWidth(inchLength(11));
static NeverDestroyed<Length> ledgerHeight(inchLength(17));
if (!pageSizeName)
return false;
switch (pageSizeName->valueID()) {
case CSSValueA5:
width = a5Width;
height = a5Height;
break;
case CSSValueA4:
width = a4Width;
height = a4Height;
break;
case CSSValueA3:
width = a3Width;
height = a3Height;
break;
case CSSValueB5:
width = b5Width;
height = b5Height;
break;
case CSSValueB4:
width = b4Width;
height = b4Height;
break;
case CSSValueLetter:
width = letterWidth;
height = letterHeight;
break;
case CSSValueLegal:
width = legalWidth;
height = legalHeight;
break;
case CSSValueLedger:
width = ledgerWidth;
height = ledgerHeight;
break;
default:
return false;
}
if (pageOrientation) {
switch (pageOrientation->valueID()) {
case CSSValueLandscape:
std::swap(width, height);
break;
case CSSValuePortrait:
// Nothing to do.
break;
default:
return false;
}
}
return true;
}
inline void StyleBuilderCustom::applyValueVerticalAlign(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.valueID())
styleResolver.style()->setVerticalAlign(primitiveValue);
else
styleResolver.style()->setVerticalAlignLength(primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData()));
}
#if ENABLE(CSS_IMAGE_RESOLUTION)
inline void StyleBuilderCustom::applyInheritImageResolution(StyleResolver& styleResolver)
{
styleResolver.style()->setImageResolutionSource(styleResolver.parentStyle()->imageResolutionSource());
styleResolver.style()->setImageResolutionSnap(styleResolver.parentStyle()->imageResolutionSnap());
styleResolver.style()->setImageResolution(styleResolver.parentStyle()->imageResolution());
}
inline void StyleBuilderCustom::applyInitialImageResolution(StyleResolver& styleResolver)
{
styleResolver.style()->setImageResolutionSource(RenderStyle::initialImageResolutionSource());
styleResolver.style()->setImageResolutionSnap(RenderStyle::initialImageResolutionSnap());
styleResolver.style()->setImageResolution(RenderStyle::initialImageResolution());
}
inline void StyleBuilderCustom::applyValueImageResolution(StyleResolver& styleResolver, CSSValue& value)
{
ImageResolutionSource source = RenderStyle::initialImageResolutionSource();
ImageResolutionSnap snap = RenderStyle::initialImageResolutionSnap();
double resolution = RenderStyle::initialImageResolution();
for (auto& item : downcast<CSSValueList>(value)) {
CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
if (primitiveValue.valueID() == CSSValueFromImage)
source = ImageResolutionSource::FromImage;
else if (primitiveValue.valueID() == CSSValueSnap)
snap = ImageResolutionSnap::Pixels;
else
resolution = primitiveValue.doubleValue(CSSPrimitiveValue::CSS_DPPX);
}
styleResolver.style()->setImageResolutionSource(source);
styleResolver.style()->setImageResolutionSnap(snap);
styleResolver.style()->setImageResolution(resolution);
}
#endif // ENABLE(CSS_IMAGE_RESOLUTION)
inline void StyleBuilderCustom::applyInheritSize(StyleResolver&) { }
inline void StyleBuilderCustom::applyInitialSize(StyleResolver&) { }
inline void StyleBuilderCustom::applyValueSize(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->resetPageSizeType();
if (!is<CSSValueList>(value))
return;
Length width;
Length height;
PageSizeType pageSizeType = PAGE_SIZE_AUTO;
auto& valueList = downcast<CSSValueList>(value);
switch (valueList.length()) {
case 2: {
auto firstValue = valueList.itemWithoutBoundsCheck(0);
auto secondValue = valueList.itemWithoutBoundsCheck(1);
// <length>{2} | <page-size> <orientation>
if (!is<CSSPrimitiveValue>(*firstValue) || !is<CSSPrimitiveValue>(*secondValue))
return;
auto& firstPrimitiveValue = downcast<CSSPrimitiveValue>(*firstValue);
auto& secondPrimitiveValue = downcast<CSSPrimitiveValue>(*secondValue);
if (firstPrimitiveValue.isLength()) {
// <length>{2}
if (!secondPrimitiveValue.isLength())
return;
CSSToLengthConversionData conversionData = styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f);
width = firstPrimitiveValue.computeLength<Length>(conversionData);
height = secondPrimitiveValue.computeLength<Length>(conversionData);
} else {
// <page-size> <orientation>
// The value order is guaranteed. See CSSParser::parseSizeParameter.
if (!getPageSizeFromName(&firstPrimitiveValue, &secondPrimitiveValue, width, height))
return;
}
pageSizeType = PAGE_SIZE_RESOLVED;
break;
}
case 1: {
auto value = valueList.itemWithoutBoundsCheck(0);
// <length> | auto | <page-size> | [ portrait | landscape]
if (!is<CSSPrimitiveValue>(*value))
return;
auto& primitiveValue = downcast<CSSPrimitiveValue>(*value);
if (primitiveValue.isLength()) {
// <length>
pageSizeType = PAGE_SIZE_RESOLVED;
width = height = primitiveValue.computeLength<Length>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
} else {
switch (primitiveValue.valueID()) {
case 0:
return;
case CSSValueAuto:
pageSizeType = PAGE_SIZE_AUTO;
break;
case CSSValuePortrait:
pageSizeType = PAGE_SIZE_AUTO_PORTRAIT;
break;
case CSSValueLandscape:
pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE;
break;
default:
// <page-size>
pageSizeType = PAGE_SIZE_RESOLVED;
if (!getPageSizeFromName(&primitiveValue, nullptr, width, height))
return;
}
}
break;
}
default:
return;
}
styleResolver.style()->setPageSizeType(pageSizeType);
styleResolver.style()->setPageSize({ WTFMove(width), WTFMove(height) });
}
inline void StyleBuilderCustom::applyInheritTextIndent(StyleResolver& styleResolver)
{
styleResolver.style()->setTextIndent(Length { styleResolver.parentStyle()->textIndent() });
#if ENABLE(CSS3_TEXT)
styleResolver.style()->setTextIndentLine(styleResolver.parentStyle()->textIndentLine());
styleResolver.style()->setTextIndentType(styleResolver.parentStyle()->textIndentType());
#endif
}
inline void StyleBuilderCustom::applyInitialTextIndent(StyleResolver& styleResolver)
{
styleResolver.style()->setTextIndent(RenderStyle::initialTextIndent());
#if ENABLE(CSS3_TEXT)
styleResolver.style()->setTextIndentLine(RenderStyle::initialTextIndentLine());
styleResolver.style()->setTextIndentType(RenderStyle::initialTextIndentType());
#endif
}
inline void StyleBuilderCustom::applyValueTextIndent(StyleResolver& styleResolver, CSSValue& value)
{
Length lengthOrPercentageValue;
#if ENABLE(CSS3_TEXT)
TextIndentLine textIndentLineValue = RenderStyle::initialTextIndentLine();
TextIndentType textIndentTypeValue = RenderStyle::initialTextIndentType();
#endif
for (auto& item : downcast<CSSValueList>(value)) {
auto& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
if (!primitiveValue.valueID())
lengthOrPercentageValue = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData());
#if ENABLE(CSS3_TEXT)
else if (primitiveValue.valueID() == CSSValueWebkitEachLine)
textIndentLineValue = TextIndentLine::EachLine;
else if (primitiveValue.valueID() == CSSValueWebkitHanging)
textIndentTypeValue = TextIndentType::Hanging;
#endif
}
if (lengthOrPercentageValue.isUndefined())
return;
styleResolver.style()->setTextIndent(WTFMove(lengthOrPercentageValue));
#if ENABLE(CSS3_TEXT)
styleResolver.style()->setTextIndentLine(textIndentLineValue);
styleResolver.style()->setTextIndentType(textIndentTypeValue);
#endif
}
enum BorderImageType { BorderImage, WebkitMaskBoxImage };
enum BorderImageModifierType { Outset, Repeat, Slice, Width };
template <BorderImageType type, BorderImageModifierType modifier>
class ApplyPropertyBorderImageModifier {
public:
static void applyInheritValue(StyleResolver& styleResolver)
{
NinePieceImage image(getValue(styleResolver.style()));
switch (modifier) {
case Outset:
image.copyOutsetFrom(getValue(styleResolver.parentStyle()));
break;
case Repeat:
image.copyRepeatFrom(getValue(styleResolver.parentStyle()));
break;
case Slice:
image.copyImageSlicesFrom(getValue(styleResolver.parentStyle()));
break;
case Width:
image.copyBorderSlicesFrom(getValue(styleResolver.parentStyle()));
break;
}
setValue(styleResolver.style(), image);
}
static void applyInitialValue(StyleResolver& styleResolver)
{
NinePieceImage image(getValue(styleResolver.style()));
switch (modifier) {
case Outset:
image.setOutset(LengthBox(0));
break;
case Repeat:
image.setHorizontalRule(NinePieceImageRule::Stretch);
image.setVerticalRule(NinePieceImageRule::Stretch);
break;
case Slice:
// Masks have a different initial value for slices. Preserve the value of 0 for backwards compatibility.
image.setImageSlices(type == BorderImage ? LengthBox(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent)) : LengthBox());
image.setFill(false);
break;
case Width:
// FIXME: This is a local variable to work around a bug in the GCC 8.1 Address Sanitizer.
// Might be slightly less efficient when the type is not BorderImage since this is unused in that case.
// Should be switched back to a temporary when possible. See https://webkit.org/b/186980
LengthBox lengthBox(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative));
// Masks have a different initial value for widths. They use an 'auto' value rather than trying to fit to the border.
image.setBorderSlices(type == BorderImage ? lengthBox : LengthBox());
break;
}
setValue(styleResolver.style(), image);
}
static void applyValue(StyleResolver& styleResolver, CSSValue& value)
{
NinePieceImage image(getValue(styleResolver.style()));
switch (modifier) {
case Outset:
image.setOutset(styleResolver.styleMap()->mapNinePieceImageQuad(value));
break;
case Repeat:
styleResolver.styleMap()->mapNinePieceImageRepeat(value, image);
break;
case Slice:
styleResolver.styleMap()->mapNinePieceImageSlice(value, image);
break;
case Width:
image.setBorderSlices(styleResolver.styleMap()->mapNinePieceImageQuad(value));
break;
}
setValue(styleResolver.style(), image);
}
private:
static const NinePieceImage& getValue(const RenderStyle* style)
{
return type == BorderImage ? style->borderImage() : style->maskBoxImage();
}
static void setValue(RenderStyle* style, const NinePieceImage& value)
{
return type == BorderImage ? style->setBorderImage(value) : style->setMaskBoxImage(value);
}
};
#define DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(type, modifier) \
inline void StyleBuilderCustom::applyInherit##type##modifier(StyleResolver& styleResolver) \
{ \
ApplyPropertyBorderImageModifier<type, modifier>::applyInheritValue(styleResolver); \
} \
inline void StyleBuilderCustom::applyInitial##type##modifier(StyleResolver& styleResolver) \
{ \
ApplyPropertyBorderImageModifier<type, modifier>::applyInitialValue(styleResolver); \
} \
inline void StyleBuilderCustom::applyValue##type##modifier(StyleResolver& styleResolver, CSSValue& value) \
{ \
ApplyPropertyBorderImageModifier<type, modifier>::applyValue(styleResolver, value); \
}
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Outset)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Repeat)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Slice)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Width)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Outset)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Repeat)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Slice)
DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Width)
#if ENABLE(TEXT_AUTOSIZING)
inline void StyleBuilderCustom::applyInheritLineHeight(StyleResolver& styleResolver)
{
styleResolver.style()->setLineHeight(Length { styleResolver.parentStyle()->lineHeight() });
styleResolver.style()->setSpecifiedLineHeight(Length { styleResolver.parentStyle()->specifiedLineHeight() });
}
inline void StyleBuilderCustom::applyInitialLineHeight(StyleResolver& styleResolver)
{
styleResolver.style()->setLineHeight(RenderStyle::initialLineHeight());
styleResolver.style()->setSpecifiedLineHeight(RenderStyle::initialSpecifiedLineHeight());
}
static inline float computeBaseSpecifiedFontSize(const Document& document, const RenderStyle& style, bool percentageAutosizingEnabled)
{
float result = style.specifiedFontSize();
auto* frame = document.frame();
if (frame && style.textZoom() != TextZoom::Reset)
result *= frame->textZoomFactor();
result *= style.effectiveZoom();
if (percentageAutosizingEnabled && !document.settings().textAutosizingUsesIdempotentMode())
result *= style.textSizeAdjust().multiplier();
return result;
}
static inline float computeLineHeightMultiplierDueToFontSize(const Document& document, const RenderStyle& style, const CSSPrimitiveValue& value)
{
bool percentageAutosizingEnabled = document.settings().textAutosizingEnabled() && style.textSizeAdjust().isPercentage();
if (value.isLength()) {
auto minimumFontSize = document.settings().minimumFontSize();
if (minimumFontSize > 0) {
auto specifiedFontSize = computeBaseSpecifiedFontSize(document, style, percentageAutosizingEnabled);
// Small font sizes cause a preposterously large (near infinity) line-height. Add a fuzz-factor of 1px which opts out of
// boosted line-height.
if (specifiedFontSize < minimumFontSize && specifiedFontSize >= 1) {
// FIXME: There are two settings which are relevant here: minimum font size, and minimum logical font size (as
// well as things like the zoom property, text zoom on the page, and text autosizing). The minimum logical font
// size is nonzero by default, and already incorporated into the computed font size, so if we just use the ratio
// of the computed : specified font size, it will be > 1 in the cases where the minimum logical font size kicks
// in. In general, this is the right thing to do, however, this kind of blanket change is too risky to perform
// right now. https://bugs.webkit.org/show_bug.cgi?id=174570 tracks turning this on. For now, we can just pretend
// that the minimum font size is the only thing affecting the computed font size.
// This calculation matches the line-height computed size calculation in
// TextAutoSizing::Value::adjustTextNodeSizes().
auto scaleChange = minimumFontSize / specifiedFontSize;
return scaleChange;
}
}
}
if (percentageAutosizingEnabled && !document.settings().textAutosizingUsesIdempotentMode())
return style.textSizeAdjust().multiplier();
return 1;
}
inline void StyleBuilderCustom::applyValueLineHeight(StyleResolver& styleResolver, CSSValue& value)
{
Optional<Length> lineHeight = StyleBuilderConverter::convertLineHeight(styleResolver, value, 1);
if (!lineHeight)
return;
Length computedLineHeight;
if (lineHeight.value().isNegative())
computedLineHeight = lineHeight.value();
else {
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
auto multiplier = computeLineHeightMultiplierDueToFontSize(styleResolver.document(), *styleResolver.style(), primitiveValue);
if (multiplier == 1)
computedLineHeight = lineHeight.value();
else
computedLineHeight = StyleBuilderConverter::convertLineHeight(styleResolver, value, multiplier).value();
}
styleResolver.style()->setLineHeight(WTFMove(computedLineHeight));
styleResolver.style()->setSpecifiedLineHeight(WTFMove(lineHeight.value()));
}
#endif
inline void StyleBuilderCustom::applyInheritOutlineStyle(StyleResolver& styleResolver)
{
styleResolver.style()->setOutlineStyleIsAuto(styleResolver.parentStyle()->outlineStyleIsAuto());
styleResolver.style()->setOutlineStyle(styleResolver.parentStyle()->outlineStyle());
}
inline void StyleBuilderCustom::applyInitialOutlineStyle(StyleResolver& styleResolver)
{
styleResolver.style()->setOutlineStyleIsAuto(RenderStyle::initialOutlineStyleIsAuto());
styleResolver.style()->setOutlineStyle(RenderStyle::initialBorderStyle());
}
inline void StyleBuilderCustom::applyValueOutlineStyle(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
styleResolver.style()->setOutlineStyleIsAuto(primitiveValue);
styleResolver.style()->setOutlineStyle(primitiveValue);
}
inline void StyleBuilderCustom::applyInitialClip(StyleResolver& styleResolver)
{
styleResolver.style()->setClip(Length(), Length(), Length(), Length());
styleResolver.style()->setHasClip(false);
}
inline void StyleBuilderCustom::applyInheritClip(StyleResolver& styleResolver)
{
auto* parentStyle = styleResolver.parentStyle();
if (!parentStyle->hasClip())
return applyInitialClip(styleResolver);
styleResolver.style()->setClip(Length { parentStyle->clipTop() }, Length { parentStyle->clipRight() },
Length { parentStyle->clipBottom() }, Length { parentStyle->clipLeft() });
styleResolver.style()->setHasClip(true);
}
inline void StyleBuilderCustom::applyValueClip(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (auto* rect = primitiveValue.rectValue()) {
auto conversionData = styleResolver.state().cssToLengthConversionData();
auto top = rect->top()->convertToLength<FixedIntegerConversion | PercentConversion | AutoConversion>(conversionData);
auto right = rect->right()->convertToLength<FixedIntegerConversion | PercentConversion | AutoConversion>(conversionData);
auto bottom = rect->bottom()->convertToLength<FixedIntegerConversion | PercentConversion | AutoConversion>(conversionData);
auto left = rect->left()->convertToLength<FixedIntegerConversion | PercentConversion | AutoConversion>(conversionData);
styleResolver.style()->setClip(WTFMove(top), WTFMove(right), WTFMove(bottom), WTFMove(left));
styleResolver.style()->setHasClip(true);
} else {
ASSERT(primitiveValue.valueID() == CSSValueAuto);
applyInitialClip(styleResolver);
}
}
inline void StyleBuilderCustom::applyValueWebkitLocale(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
FontCascadeDescription fontDescription = styleResolver.style()->fontDescription();
if (primitiveValue.valueID() == CSSValueAuto)
fontDescription.setLocale(nullAtom());
else
fontDescription.setLocale(primitiveValue.stringValue());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueWritingMode(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.setWritingMode(downcast<CSSPrimitiveValue>(value));
styleResolver.style()->setHasExplicitlySetWritingMode(true);
}
inline void StyleBuilderCustom::applyValueWebkitTextOrientation(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.setTextOrientation(downcast<CSSPrimitiveValue>(value));
}
#if ENABLE(TEXT_AUTOSIZING)
inline void StyleBuilderCustom::applyValueWebkitTextSizeAdjust(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.valueID() == CSSValueAuto)
styleResolver.style()->setTextSizeAdjust(TextSizeAdjustment(AutoTextSizeAdjustment));
else if (primitiveValue.valueID() == CSSValueNone)
styleResolver.style()->setTextSizeAdjust(TextSizeAdjustment(NoTextSizeAdjustment));
else
styleResolver.style()->setTextSizeAdjust(TextSizeAdjustment(primitiveValue.floatValue()));
styleResolver.state().setFontDirty(true);
}
#endif
inline void StyleBuilderCustom::applyValueWebkitTextZoom(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.valueID() == CSSValueNormal)
styleResolver.style()->setTextZoom(TextZoom::Normal);
else if (primitiveValue.valueID() == CSSValueReset)
styleResolver.style()->setTextZoom(TextZoom::Reset);
styleResolver.state().setFontDirty(true);
}
#if ENABLE(DARK_MODE_CSS)
inline void StyleBuilderCustom::applyValueColorScheme(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->setColorScheme(StyleBuilderConverter::convertColorScheme(styleResolver, value));
styleResolver.style()->setHasExplicitlySetColorScheme(true);
}
#endif
template<CSSPropertyID property>
inline void StyleBuilderCustom::applyTextOrBoxShadowValue(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSPrimitiveValue>(value)) {
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
if (property == CSSPropertyTextShadow)
styleResolver.style()->setTextShadow(nullptr);
else
styleResolver.style()->setBoxShadow(nullptr);
return;
}
bool isFirstEntry = true;
for (auto& item : downcast<CSSValueList>(value)) {
auto& shadowValue = downcast<CSSShadowValue>(item.get());
auto conversionData = styleResolver.state().cssToLengthConversionData();
int x = shadowValue.x->computeLength<int>(conversionData);
int y = shadowValue.y->computeLength<int>(conversionData);
int blur = shadowValue.blur ? shadowValue.blur->computeLength<int>(conversionData) : 0;
int spread = shadowValue.spread ? shadowValue.spread->computeLength<int>(conversionData) : 0;
ShadowStyle shadowStyle = shadowValue.style && shadowValue.style->valueID() == CSSValueInset ? Inset : Normal;
Color color;
if (shadowValue.color)
color = styleResolver.colorFromPrimitiveValue(*shadowValue.color);
else
color = styleResolver.style()->color();
auto shadowData = makeUnique<ShadowData>(IntPoint(x, y), blur, spread, shadowStyle, property == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent);
if (property == CSSPropertyTextShadow)
styleResolver.style()->setTextShadow(WTFMove(shadowData), !isFirstEntry); // add to the list if this is not the first entry
else
styleResolver.style()->setBoxShadow(WTFMove(shadowData), !isFirstEntry); // add to the list if this is not the first entry
isFirstEntry = false;
}
}
inline void StyleBuilderCustom::applyInitialTextShadow(StyleResolver& styleResolver)
{
styleResolver.style()->setTextShadow(nullptr);
}
inline void StyleBuilderCustom::applyInheritTextShadow(StyleResolver& styleResolver)
{
styleResolver.style()->setTextShadow(styleResolver.parentStyle()->textShadow() ? makeUnique<ShadowData>(*styleResolver.parentStyle()->textShadow()) : nullptr);
}
inline void StyleBuilderCustom::applyValueTextShadow(StyleResolver& styleResolver, CSSValue& value)
{
applyTextOrBoxShadowValue<CSSPropertyTextShadow>(styleResolver, value);
}
inline void StyleBuilderCustom::applyInitialBoxShadow(StyleResolver& styleResolver)
{
styleResolver.style()->setBoxShadow(nullptr);
}
inline void StyleBuilderCustom::applyInheritBoxShadow(StyleResolver& styleResolver)
{
styleResolver.style()->setBoxShadow(styleResolver.parentStyle()->boxShadow() ? makeUnique<ShadowData>(*styleResolver.parentStyle()->boxShadow()) : nullptr);
}
inline void StyleBuilderCustom::applyValueBoxShadow(StyleResolver& styleResolver, CSSValue& value)
{
applyTextOrBoxShadowValue<CSSPropertyBoxShadow>(styleResolver, value);
}
inline void StyleBuilderCustom::applyInitialWebkitBoxShadow(StyleResolver& styleResolver)
{
applyInitialBoxShadow(styleResolver);
}
inline void StyleBuilderCustom::applyInheritWebkitBoxShadow(StyleResolver& styleResolver)
{
applyInheritBoxShadow(styleResolver);
}
inline void StyleBuilderCustom::applyValueWebkitBoxShadow(StyleResolver& styleResolver, CSSValue& value)
{
applyTextOrBoxShadowValue<CSSPropertyWebkitBoxShadow>(styleResolver, value);
}
inline void StyleBuilderCustom::applyInitialFontFamily(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.style()->fontDescription();
auto initialDesc = FontCascadeDescription();
// We need to adjust the size to account for the generic family change from monospace to non-monospace.
if (fontDescription.useFixedDefaultSize()) {
if (CSSValueID sizeIdentifier = fontDescription.keywordSizeAsIdentifier())
styleResolver.setFontSize(fontDescription, Style::fontSizeForKeyword(sizeIdentifier, false, styleResolver.document()));
}
if (!initialDesc.firstFamily().isEmpty())
fontDescription.setFamilies(initialDesc.families());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInheritFontFamily(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.style()->fontDescription();
auto parentFontDescription = styleResolver.parentStyle()->fontDescription();
fontDescription.setFamilies(parentFontDescription.families());
fontDescription.setIsSpecifiedFont(parentFontDescription.isSpecifiedFont());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontFamily(StyleResolver& styleResolver, CSSValue& value)
{
auto& valueList = downcast<CSSValueList>(value);
auto fontDescription = styleResolver.style()->fontDescription();
// Before mapping in a new font-family property, we should reset the generic family.
bool oldFamilyUsedFixedDefaultSize = fontDescription.useFixedDefaultSize();
Vector<AtomString> families;
families.reserveInitialCapacity(valueList.length());
for (auto& item : valueList) {
auto& contentValue = downcast<CSSPrimitiveValue>(item.get());
AtomString family;
bool isGenericFamily = false;
if (contentValue.isFontFamily()) {
const CSSFontFamily& fontFamily = contentValue.fontFamily();
family = fontFamily.familyName;
// If the family name was resolved by the CSS parser from a system font ID, then it is generic.
isGenericFamily = fontFamily.fromSystemFontID;
} else {
switch (contentValue.valueID()) {
case CSSValueWebkitBody:
family = styleResolver.settings().standardFontFamily();
break;
case CSSValueSerif:
family = serifFamily;
isGenericFamily = true;
break;
case CSSValueSansSerif:
family = sansSerifFamily;
isGenericFamily = true;
break;
case CSSValueCursive:
family = cursiveFamily;
isGenericFamily = true;
break;
case CSSValueFantasy:
family = fantasyFamily;
isGenericFamily = true;
break;
case CSSValueMonospace:
family = monospaceFamily;
isGenericFamily = true;
break;
case CSSValueWebkitPictograph:
family = pictographFamily;
isGenericFamily = true;
break;
case CSSValueSystemUi:
family = systemUiFamily;
isGenericFamily = true;
break;
default:
break;
}
}
if (family.isEmpty())
continue;
if (families.isEmpty())
fontDescription.setIsSpecifiedFont(!isGenericFamily);
families.uncheckedAppend(family);
}
if (families.isEmpty())
return;
fontDescription.setFamilies(families);
if (fontDescription.useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize) {
if (CSSValueID sizeIdentifier = fontDescription.keywordSizeAsIdentifier())
styleResolver.setFontSize(fontDescription, Style::fontSizeForKeyword(sizeIdentifier, !oldFamilyUsedFixedDefaultSize, styleResolver.document()));
}
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline bool StyleBuilderCustom::isValidDisplayValue(StyleResolver& styleResolver, DisplayType display)
{
if (is<SVGElement>(styleResolver.element()) && styleResolver.style()->styleType() == PseudoId::None)
return display == DisplayType::Inline || display == DisplayType::Block || display == DisplayType::None;
return true;
}
inline void StyleBuilderCustom::applyInheritDisplay(StyleResolver& styleResolver)
{
DisplayType display = styleResolver.parentStyle()->display();
if (isValidDisplayValue(styleResolver, display))
styleResolver.style()->setDisplay(display);
}
inline void StyleBuilderCustom::applyValueDisplay(StyleResolver& styleResolver, CSSValue& value)
{
DisplayType display = downcast<CSSPrimitiveValue>(value);
if (isValidDisplayValue(styleResolver, display))
styleResolver.style()->setDisplay(display);
}
inline void StyleBuilderCustom::applyValueBaselineShift(StyleResolver& styleResolver, CSSValue& value)
{
SVGRenderStyle& svgStyle = styleResolver.style()->accessSVGStyle();
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.isValueID()) {
switch (primitiveValue.valueID()) {
case CSSValueBaseline:
svgStyle.setBaselineShift(BaselineShift::Baseline);
break;
case CSSValueSub:
svgStyle.setBaselineShift(BaselineShift::Sub);
break;
case CSSValueSuper:
svgStyle.setBaselineShift(BaselineShift::Super);
break;
default:
break;
}
} else {
svgStyle.setBaselineShift(BaselineShift::Length);
svgStyle.setBaselineShiftValue(SVGLengthValue::fromCSSPrimitiveValue(primitiveValue));
}
}
inline void StyleBuilderCustom::applyInitialWebkitAspectRatio(StyleResolver& styleResolver)
{
styleResolver.style()->setAspectRatioType(RenderStyle::initialAspectRatioType());
styleResolver.style()->setAspectRatioDenominator(RenderStyle::initialAspectRatioDenominator());
styleResolver.style()->setAspectRatioNumerator(RenderStyle::initialAspectRatioNumerator());
}
inline void StyleBuilderCustom::applyInheritWebkitAspectRatio(StyleResolver& styleResolver)
{
if (styleResolver.parentStyle()->aspectRatioType() == AspectRatioType::Auto)
return;
styleResolver.style()->setAspectRatioType(styleResolver.parentStyle()->aspectRatioType());
styleResolver.style()->setAspectRatioDenominator(styleResolver.parentStyle()->aspectRatioDenominator());
styleResolver.style()->setAspectRatioNumerator(styleResolver.parentStyle()->aspectRatioNumerator());
}
inline void StyleBuilderCustom::applyValueWebkitAspectRatio(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSPrimitiveValue>(value)) {
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.valueID() == CSSValueFromDimensions)
return styleResolver.style()->setAspectRatioType(AspectRatioType::FromDimensions);
if (primitiveValue.valueID() == CSSValueFromIntrinsic)
return styleResolver.style()->setAspectRatioType(AspectRatioType::FromIntrinsic);
ASSERT(primitiveValue.valueID() == CSSValueAuto);
return styleResolver.style()->setAspectRatioType(AspectRatioType::Auto);
}
auto& aspectRatioValue = downcast<CSSAspectRatioValue>(value);
styleResolver.style()->setAspectRatioType(AspectRatioType::Specified);
styleResolver.style()->setAspectRatioDenominator(aspectRatioValue.denominatorValue());
styleResolver.style()->setAspectRatioNumerator(aspectRatioValue.numeratorValue());
}
inline void StyleBuilderCustom::applyInitialWebkitTextEmphasisStyle(StyleResolver& styleResolver)
{
styleResolver.style()->setTextEmphasisFill(RenderStyle::initialTextEmphasisFill());
styleResolver.style()->setTextEmphasisMark(RenderStyle::initialTextEmphasisMark());
styleResolver.style()->setTextEmphasisCustomMark(RenderStyle::initialTextEmphasisCustomMark());
}
inline void StyleBuilderCustom::applyInheritWebkitTextEmphasisStyle(StyleResolver& styleResolver)
{
styleResolver.style()->setTextEmphasisFill(styleResolver.parentStyle()->textEmphasisFill());
styleResolver.style()->setTextEmphasisMark(styleResolver.parentStyle()->textEmphasisMark());
styleResolver.style()->setTextEmphasisCustomMark(styleResolver.parentStyle()->textEmphasisCustomMark());
}
inline void StyleBuilderCustom::applyValueWebkitTextEmphasisStyle(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSValueList>(value)) {
auto& list = downcast<CSSValueList>(value);
ASSERT(list.length() == 2);
for (auto& item : list) {
CSSPrimitiveValue& value = downcast<CSSPrimitiveValue>(item.get());
if (value.valueID() == CSSValueFilled || value.valueID() == CSSValueOpen)
styleResolver.style()->setTextEmphasisFill(value);
else
styleResolver.style()->setTextEmphasisMark(value);
}
styleResolver.style()->setTextEmphasisCustomMark(nullAtom());
return;
}
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.isString()) {
styleResolver.style()->setTextEmphasisFill(TextEmphasisFill::Filled);
styleResolver.style()->setTextEmphasisMark(TextEmphasisMark::Custom);
styleResolver.style()->setTextEmphasisCustomMark(primitiveValue.stringValue());
return;
}
styleResolver.style()->setTextEmphasisCustomMark(nullAtom());
if (primitiveValue.valueID() == CSSValueFilled || primitiveValue.valueID() == CSSValueOpen) {
styleResolver.style()->setTextEmphasisFill(primitiveValue);
styleResolver.style()->setTextEmphasisMark(TextEmphasisMark::Auto);
} else {
styleResolver.style()->setTextEmphasisFill(TextEmphasisFill::Filled);
styleResolver.style()->setTextEmphasisMark(primitiveValue);
}
}
template <StyleBuilderCustom::CounterBehavior counterBehavior>
inline void StyleBuilderCustom::applyInheritCounter(StyleResolver& styleResolver)
{
auto& map = styleResolver.style()->accessCounterDirectives();
for (auto& keyValue : const_cast<RenderStyle*>(styleResolver.parentStyle())->accessCounterDirectives()) {
auto& directives = map.add(keyValue.key, CounterDirectives { }).iterator->value;
if (counterBehavior == Reset)
directives.resetValue = keyValue.value.resetValue;
else
directives.incrementValue = keyValue.value.incrementValue;
}
}
template <StyleBuilderCustom::CounterBehavior counterBehavior>
inline void StyleBuilderCustom::applyValueCounter(StyleResolver& styleResolver, CSSValue& value)
{
bool setCounterIncrementToNone = counterBehavior == Increment && is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone;
if (!is<CSSValueList>(value) && !setCounterIncrementToNone)
return;
CounterDirectiveMap& map = styleResolver.style()->accessCounterDirectives();
for (auto& keyValue : map) {
if (counterBehavior == Reset)
keyValue.value.resetValue = WTF::nullopt;
else
keyValue.value.incrementValue = WTF::nullopt;
}
if (setCounterIncrementToNone)
return;
for (auto& item : downcast<CSSValueList>(value)) {
Pair* pair = downcast<CSSPrimitiveValue>(item.get()).pairValue();
AtomString identifier = pair->first()->stringValue();
int value = pair->second()->intValue();
auto& directives = map.add(identifier, CounterDirectives { }).iterator->value;
if (counterBehavior == Reset)
directives.resetValue = value;
else
directives.incrementValue = saturatedAddition(directives.incrementValue.valueOr(0), value);
}
}
inline void StyleBuilderCustom::applyInitialCounterIncrement(StyleResolver&) { }
inline void StyleBuilderCustom::applyInheritCounterIncrement(StyleResolver& styleResolver)
{
applyInheritCounter<Increment>(styleResolver);
}
inline void StyleBuilderCustom::applyValueCounterIncrement(StyleResolver& styleResolver, CSSValue& value)
{
applyValueCounter<Increment>(styleResolver, value);
}
inline void StyleBuilderCustom::applyInitialCounterReset(StyleResolver&) { }
inline void StyleBuilderCustom::applyInheritCounterReset(StyleResolver& styleResolver)
{
applyInheritCounter<Reset>(styleResolver);
}
inline void StyleBuilderCustom::applyValueCounterReset(StyleResolver& styleResolver, CSSValue& value)
{
applyValueCounter<Reset>(styleResolver, value);
}
inline void StyleBuilderCustom::applyInitialCursor(StyleResolver& styleResolver)
{
styleResolver.style()->clearCursorList();
styleResolver.style()->setCursor(RenderStyle::initialCursor());
}
inline void StyleBuilderCustom::applyInheritCursor(StyleResolver& styleResolver)
{
styleResolver.style()->setCursor(styleResolver.parentStyle()->cursor());
styleResolver.style()->setCursorList(styleResolver.parentStyle()->cursors());
}
inline void StyleBuilderCustom::applyValueCursor(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->clearCursorList();
if (is<CSSPrimitiveValue>(value)) {
CursorType cursor = downcast<CSSPrimitiveValue>(value);
if (styleResolver.style()->cursor() != cursor)
styleResolver.style()->setCursor(cursor);
return;
}
styleResolver.style()->setCursor(CursorType::Auto);
auto& list = downcast<CSSValueList>(value);
for (auto& item : list) {
if (is<CSSCursorImageValue>(item)) {
auto& image = downcast<CSSCursorImageValue>(item.get());
styleResolver.style()->addCursor(styleResolver.styleImage(image), image.hotSpot());
continue;
}
styleResolver.style()->setCursor(downcast<CSSPrimitiveValue>(item.get()));
ASSERT_WITH_MESSAGE(item.ptr() == list.item(list.length() - 1), "Cursor ID fallback should always be last in the list");
return;
}
}
inline void StyleBuilderCustom::applyInitialFill(StyleResolver& styleResolver)
{
auto& svgStyle = styleResolver.style()->accessSVGStyle();
svgStyle.setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri(), styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyInheritFill(StyleResolver& styleResolver)
{
auto& svgStyle = styleResolver.style()->accessSVGStyle();
auto& svgParentStyle = styleResolver.parentStyle()->svgStyle();
svgStyle.setFillPaint(svgParentStyle.fillPaintType(), svgParentStyle.fillPaintColor(), svgParentStyle.fillPaintUri(), styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyValueFill(StyleResolver& styleResolver, CSSValue& value)
{
auto& svgStyle = styleResolver.style()->accessSVGStyle();
const auto* localValue = value.isPrimitiveValue() ? &downcast<CSSPrimitiveValue>(value) : nullptr;
String url;
if (value.isValueList()) {
const CSSValueList& list = downcast<CSSValueList>(value);
url = downcast<CSSPrimitiveValue>(list.item(0))->stringValue();
localValue = downcast<CSSPrimitiveValue>(list.item(1));
}
if (!localValue)
return;
Color color;
auto paintType = SVGPaintType::RGBColor;
if (localValue->isURI()) {
paintType = SVGPaintType::URI;
url = localValue->stringValue();
} else if (localValue->isValueID() && localValue->valueID() == CSSValueNone)
paintType = url.isEmpty() ? SVGPaintType::None : SVGPaintType::URINone;
else if (localValue->isValueID() && localValue->valueID() == CSSValueCurrentcolor) {
color = styleResolver.style()->color();
paintType = url.isEmpty() ? SVGPaintType::CurrentColor : SVGPaintType::URICurrentColor;
} else {
color = styleResolver.colorFromPrimitiveValue(*localValue);
paintType = url.isEmpty() ? SVGPaintType::RGBColor : SVGPaintType::URIRGBColor;
}
svgStyle.setFillPaint(paintType, color, url, styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyInitialStroke(StyleResolver& styleResolver)
{
SVGRenderStyle& svgStyle = styleResolver.style()->accessSVGStyle();
svgStyle.setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri(), styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyInheritStroke(StyleResolver& styleResolver)
{
auto& svgStyle = styleResolver.style()->accessSVGStyle();
auto& svgParentStyle = styleResolver.parentStyle()->svgStyle();
svgStyle.setStrokePaint(svgParentStyle.strokePaintType(), svgParentStyle.strokePaintColor(), svgParentStyle.strokePaintUri(), styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyValueStroke(StyleResolver& styleResolver, CSSValue& value)
{
auto& svgStyle = styleResolver.style()->accessSVGStyle();
const auto* localValue = value.isPrimitiveValue() ? &downcast<CSSPrimitiveValue>(value) : nullptr;
String url;
if (value.isValueList()) {
const CSSValueList& list = downcast<CSSValueList>(value);
url = downcast<CSSPrimitiveValue>(list.item(0))->stringValue();
localValue = downcast<CSSPrimitiveValue>(list.item(1));
}
if (!localValue)
return;
Color color;
auto paintType = SVGPaintType::RGBColor;
if (localValue->isURI()) {
paintType = SVGPaintType::URI;
url = downcast<CSSPrimitiveValue>(localValue)->stringValue();
} else if (localValue->isValueID() && localValue->valueID() == CSSValueNone)
paintType = url.isEmpty() ? SVGPaintType::None : SVGPaintType::URINone;
else if (localValue->isValueID() && localValue->valueID() == CSSValueCurrentcolor) {
color = styleResolver.style()->color();
paintType = url.isEmpty() ? SVGPaintType::CurrentColor : SVGPaintType::URICurrentColor;
} else {
color = styleResolver.colorFromPrimitiveValue(*localValue);
paintType = url.isEmpty() ? SVGPaintType::RGBColor : SVGPaintType::URIRGBColor;
}
svgStyle.setStrokePaint(paintType, color, url, styleResolver.applyPropertyToRegularStyle(), styleResolver.applyPropertyToVisitedLinkStyle());
}
inline void StyleBuilderCustom::applyInitialContent(StyleResolver& styleResolver)
{
styleResolver.style()->clearContent();
}
inline void StyleBuilderCustom::applyInheritContent(StyleResolver&)
{
// 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.
}
inline void StyleBuilderCustom::applyValueContent(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSPrimitiveValue>(value)) {
const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
ASSERT_UNUSED(primitiveValue, primitiveValue.valueID() == CSSValueNormal || primitiveValue.valueID() == CSSValueNone);
styleResolver.style()->clearContent();
return;
}
bool didSet = false;
for (auto& item : downcast<CSSValueList>(value)) {
if (is<CSSImageGeneratorValue>(item)) {
if (is<CSSGradientValue>(item))
styleResolver.style()->setContent(StyleGeneratedImage::create(downcast<CSSGradientValue>(item.get()).gradientWithStylesResolved(styleResolver)), didSet);
else
styleResolver.style()->setContent(StyleGeneratedImage::create(downcast<CSSImageGeneratorValue>(item.get())), didSet);
didSet = true;
} else if (is<CSSImageSetValue>(item)) {
styleResolver.style()->setContent(StyleCachedImage::create(item), didSet);
didSet = true;
}
if (is<CSSImageValue>(item)) {
styleResolver.style()->setContent(StyleCachedImage::create(item), didSet);
didSet = true;
continue;
}
if (!is<CSSPrimitiveValue>(item))
continue;
auto& contentValue = downcast<CSSPrimitiveValue>(item.get());
if (contentValue.isString()) {
styleResolver.style()->setContent(contentValue.stringValue().impl(), didSet);
didSet = true;
} else if (contentValue.isAttr()) {
// FIXME: Can a namespace be specified for an attr(foo)?
if (styleResolver.style()->styleType() == PseudoId::None)
styleResolver.style()->setHasAttrContent();
else
const_cast<RenderStyle*>(styleResolver.parentStyle())->setHasAttrContent();
QualifiedName attr(nullAtom(), contentValue.stringValue().impl(), nullAtom());
const AtomString& value = styleResolver.element()->getAttribute(attr);
styleResolver.style()->setContent(value.isNull() ? emptyAtom() : value.impl(), didSet);
didSet = true;
// Register the fact that the attribute value affects the style.
styleResolver.ruleSets().mutableFeatures().registerContentAttribute(attr.localName());
} else if (contentValue.isCounter()) {
auto* counterValue = contentValue.counterValue();
ListStyleType listStyleType = ListStyleType::None;
CSSValueID listStyleIdent = counterValue->listStyleIdent();
if (listStyleIdent != CSSValueNone)
listStyleType = static_cast<ListStyleType>(listStyleIdent - CSSValueDisc);
auto counter = makeUnique<CounterContent>(counterValue->identifier(), listStyleType, counterValue->separator());
styleResolver.style()->setContent(WTFMove(counter), didSet);
didSet = true;
} else {
switch (contentValue.valueID()) {
case CSSValueOpenQuote:
styleResolver.style()->setContent(QuoteType::OpenQuote, didSet);
didSet = true;
break;
case CSSValueCloseQuote:
styleResolver.style()->setContent(QuoteType::CloseQuote, didSet);
didSet = true;
break;
case CSSValueNoOpenQuote:
styleResolver.style()->setContent(QuoteType::NoOpenQuote, didSet);
didSet = true;
break;
case CSSValueNoCloseQuote:
styleResolver.style()->setContent(QuoteType::NoCloseQuote, didSet);
didSet = true;
break;
default:
// normal and none do not have any effect.
break;
}
}
}
if (!didSet)
styleResolver.style()->clearContent();
}
inline void StyleBuilderCustom::applyInheritFontVariantLigatures(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantCommonLigatures(styleResolver.parentFontDescription().variantCommonLigatures());
fontDescription.setVariantDiscretionaryLigatures(styleResolver.parentFontDescription().variantDiscretionaryLigatures());
fontDescription.setVariantHistoricalLigatures(styleResolver.parentFontDescription().variantHistoricalLigatures());
fontDescription.setVariantContextualAlternates(styleResolver.parentFontDescription().variantContextualAlternates());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInitialFontVariantLigatures(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantCommonLigatures(FontVariantLigatures::Normal);
fontDescription.setVariantDiscretionaryLigatures(FontVariantLigatures::Normal);
fontDescription.setVariantHistoricalLigatures(FontVariantLigatures::Normal);
fontDescription.setVariantContextualAlternates(FontVariantLigatures::Normal);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontVariantLigatures(StyleResolver& styleResolver, CSSValue& value)
{
auto fontDescription = styleResolver.fontDescription();
auto variantLigatures = extractFontVariantLigatures(value);
fontDescription.setVariantCommonLigatures(variantLigatures.commonLigatures);
fontDescription.setVariantDiscretionaryLigatures(variantLigatures.discretionaryLigatures);
fontDescription.setVariantHistoricalLigatures(variantLigatures.historicalLigatures);
fontDescription.setVariantContextualAlternates(variantLigatures.contextualAlternates);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInheritFontVariantNumeric(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantNumericFigure(styleResolver.parentFontDescription().variantNumericFigure());
fontDescription.setVariantNumericSpacing(styleResolver.parentFontDescription().variantNumericSpacing());
fontDescription.setVariantNumericFraction(styleResolver.parentFontDescription().variantNumericFraction());
fontDescription.setVariantNumericOrdinal(styleResolver.parentFontDescription().variantNumericOrdinal());
fontDescription.setVariantNumericSlashedZero(styleResolver.parentFontDescription().variantNumericSlashedZero());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInitialFontVariantNumeric(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantNumericFigure(FontVariantNumericFigure::Normal);
fontDescription.setVariantNumericSpacing(FontVariantNumericSpacing::Normal);
fontDescription.setVariantNumericFraction(FontVariantNumericFraction::Normal);
fontDescription.setVariantNumericOrdinal(FontVariantNumericOrdinal::Normal);
fontDescription.setVariantNumericSlashedZero(FontVariantNumericSlashedZero::Normal);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontVariantNumeric(StyleResolver& styleResolver, CSSValue& value)
{
auto fontDescription = styleResolver.fontDescription();
auto variantNumeric = extractFontVariantNumeric(value);
fontDescription.setVariantNumericFigure(variantNumeric.figure);
fontDescription.setVariantNumericSpacing(variantNumeric.spacing);
fontDescription.setVariantNumericFraction(variantNumeric.fraction);
fontDescription.setVariantNumericOrdinal(variantNumeric.ordinal);
fontDescription.setVariantNumericSlashedZero(variantNumeric.slashedZero);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInheritFontVariantEastAsian(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantEastAsianVariant(styleResolver.parentFontDescription().variantEastAsianVariant());
fontDescription.setVariantEastAsianWidth(styleResolver.parentFontDescription().variantEastAsianWidth());
fontDescription.setVariantEastAsianRuby(styleResolver.parentFontDescription().variantEastAsianRuby());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInitialFontVariantEastAsian(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setVariantEastAsianVariant(FontVariantEastAsianVariant::Normal);
fontDescription.setVariantEastAsianWidth(FontVariantEastAsianWidth::Normal);
fontDescription.setVariantEastAsianRuby(FontVariantEastAsianRuby::Normal);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontVariantEastAsian(StyleResolver& styleResolver, CSSValue& value)
{
auto fontDescription = styleResolver.fontDescription();
auto variantEastAsian = extractFontVariantEastAsian(value);
fontDescription.setVariantEastAsianVariant(variantEastAsian.variant);
fontDescription.setVariantEastAsianWidth(variantEastAsian.width);
fontDescription.setVariantEastAsianRuby(variantEastAsian.ruby);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInitialFontSize(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.style()->fontDescription();
float size = Style::fontSizeForKeyword(CSSValueMedium, fontDescription.useFixedDefaultSize(), styleResolver.document());
if (size < 0)
return;
fontDescription.setKeywordSizeFromIdentifier(CSSValueMedium);
styleResolver.setFontSize(fontDescription, size);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInheritFontSize(StyleResolver& styleResolver)
{
const auto& parentFontDescription = styleResolver.parentStyle()->fontDescription();
float size = parentFontDescription.specifiedSize();
if (size < 0)
return;
auto fontDescription = styleResolver.style()->fontDescription();
fontDescription.setKeywordSize(parentFontDescription.keywordSize());
styleResolver.setFontSize(fontDescription, size);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
// When the CSS keyword "larger" is used, this function will attempt to match within the keyword
// table, and failing that, will simply multiply by 1.2.
inline float StyleBuilderCustom::largerFontSize(float size)
{
// FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale up to
// the next size level.
return size * 1.2f;
}
// Like the previous function, but for the keyword "smaller".
inline float StyleBuilderCustom::smallerFontSize(float size)
{
// FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale down to
// the next size level.
return size / 1.2f;
}
inline float StyleBuilderCustom::determineRubyTextSizeMultiplier(StyleResolver& styleResolver)
{
if (styleResolver.style()->rubyPosition() != RubyPosition::InterCharacter)
return 0.5f;
// FIXME: This hack is to ensure tone marks are the same size as
// the bopomofo. This code will go away if we make a special renderer
// for the tone marks eventually.
if (auto* element = styleResolver.state().element()) {
for (auto& ancestor : ancestorsOfType<HTMLElement>(*element)) {
if (ancestor.hasTagName(HTMLNames::rtTag))
return 1.0f;
}
}
return 0.25f;
}
inline void StyleBuilderCustom::applyInitialFontStyle(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setItalic(FontCascadeDescription::initialItalic());
fontDescription.setFontStyleAxis(FontCascadeDescription::initialFontStyleAxis());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInheritFontStyle(StyleResolver& styleResolver)
{
auto fontDescription = styleResolver.fontDescription();
fontDescription.setItalic(styleResolver.parentFontDescription().italic());
fontDescription.setFontStyleAxis(styleResolver.parentFontDescription().fontStyleAxis());
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontStyle(StyleResolver& styleResolver, CSSValue& value)
{
auto& fontStyleValue = downcast<CSSFontStyleValue>(value);
auto fontDescription = styleResolver.fontDescription();
fontDescription.setItalic(StyleBuilderConverter::convertFontStyleFromValue(fontStyleValue));
fontDescription.setFontStyleAxis(fontStyleValue.fontStyleValue->valueID() == CSSValueItalic ? FontStyleAxis::ital : FontStyleAxis::slnt);
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyValueFontSize(StyleResolver& styleResolver, CSSValue& value)
{
auto fontDescription = styleResolver.style()->fontDescription();
fontDescription.setKeywordSizeFromIdentifier(CSSValueInvalid);
float parentSize = 0;
bool parentIsAbsoluteSize = false;
if (auto* parentStyle = styleResolver.parentStyle()) {
parentSize = parentStyle->fontDescription().specifiedSize();
parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
}
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
float size;
if (CSSValueID ident = primitiveValue.valueID()) {
fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && (ident == CSSValueLarger || ident == CSSValueSmaller || ident == CSSValueWebkitRubyText));
// Keywords are being used.
switch (ident) {
case CSSValueXxSmall:
case CSSValueXSmall:
case CSSValueSmall:
case CSSValueMedium:
case CSSValueLarge:
case CSSValueXLarge:
case CSSValueXxLarge:
case CSSValueWebkitXxxLarge:
size = Style::fontSizeForKeyword(ident, fontDescription.useFixedDefaultSize(), styleResolver.document());
fontDescription.setKeywordSizeFromIdentifier(ident);
break;
case CSSValueLarger:
size = largerFontSize(parentSize);
break;
case CSSValueSmaller:
size = smallerFontSize(parentSize);
break;
case CSSValueWebkitRubyText:
size = determineRubyTextSizeMultiplier(styleResolver) * parentSize;
break;
default:
return;
}
} else {
fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize || !(primitiveValue.isPercentage() || primitiveValue.isFontRelativeLength()));
if (primitiveValue.isLength()) {
size = primitiveValue.computeLength<float>(CSSToLengthConversionData(styleResolver.parentStyle(), styleResolver.rootElementStyle(), styleResolver.document().renderView(), 1.0f, true));
styleResolver.state().setFontSizeHasViewportUnits(primitiveValue.isViewportPercentageLength());
} else if (primitiveValue.isPercentage())
size = (primitiveValue.floatValue() * parentSize) / 100.0f;
else if (primitiveValue.isCalculatedPercentageWithLength()) {
const auto& conversionData = styleResolver.state().cssToLengthConversionData();
CSSToLengthConversionData parentConversionData { styleResolver.parentStyle(), conversionData.rootStyle(), styleResolver.document().renderView(), 1.0f, true };
size = primitiveValue.cssCalcValue()->createCalculationValue(parentConversionData)->evaluate(parentSize);
} else
return;
}
if (size < 0)
return;
styleResolver.setFontSize(fontDescription, std::min(maximumAllowedFontSize, size));
styleResolver.setFontDescription(WTFMove(fontDescription));
}
inline void StyleBuilderCustom::applyInitialGridTemplateAreas(StyleResolver& styleResolver)
{
styleResolver.style()->setNamedGridArea(RenderStyle::initialNamedGridArea());
styleResolver.style()->setNamedGridAreaRowCount(RenderStyle::initialNamedGridAreaCount());
styleResolver.style()->setNamedGridAreaColumnCount(RenderStyle::initialNamedGridAreaCount());
}
inline void StyleBuilderCustom::applyInheritGridTemplateAreas(StyleResolver& styleResolver)
{
styleResolver.style()->setNamedGridArea(styleResolver.parentStyle()->namedGridArea());
styleResolver.style()->setNamedGridAreaRowCount(styleResolver.parentStyle()->namedGridAreaRowCount());
styleResolver.style()->setNamedGridAreaColumnCount(styleResolver.parentStyle()->namedGridAreaColumnCount());
}
inline void StyleBuilderCustom::applyValueGridTemplateAreas(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSPrimitiveValue>(value)) {
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
return;
}
auto& gridTemplateAreasValue = downcast<CSSGridTemplateAreasValue>(value);
const NamedGridAreaMap& newNamedGridAreas = gridTemplateAreasValue.gridAreaMap();
NamedGridLinesMap namedGridColumnLines = styleResolver.style()->namedGridColumnLines();
NamedGridLinesMap namedGridRowLines = styleResolver.style()->namedGridRowLines();
StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridColumnLines, ForColumns);
StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridRowLines, ForRows);
styleResolver.style()->setNamedGridColumnLines(namedGridColumnLines);
styleResolver.style()->setNamedGridRowLines(namedGridRowLines);
styleResolver.style()->setNamedGridArea(gridTemplateAreasValue.gridAreaMap());
styleResolver.style()->setNamedGridAreaRowCount(gridTemplateAreasValue.rowCount());
styleResolver.style()->setNamedGridAreaColumnCount(gridTemplateAreasValue.columnCount());
}
inline void StyleBuilderCustom::applyInitialGridTemplateColumns(StyleResolver& styleResolver)
{
styleResolver.style()->setGridColumns(RenderStyle::initialGridColumns());
styleResolver.style()->setNamedGridColumnLines(RenderStyle::initialNamedGridColumnLines());
styleResolver.style()->setOrderedNamedGridColumnLines(RenderStyle::initialOrderedNamedGridColumnLines());
}
inline void StyleBuilderCustom::applyInheritGridTemplateColumns(StyleResolver& styleResolver)
{
styleResolver.style()->setGridColumns(styleResolver.parentStyle()->gridColumns());
styleResolver.style()->setNamedGridColumnLines(styleResolver.parentStyle()->namedGridColumnLines());
styleResolver.style()->setOrderedNamedGridColumnLines(styleResolver.parentStyle()->orderedNamedGridColumnLines());
}
#define SET_TRACKS_DATA(tracksData, style, TrackType) \
style->setGrid##TrackType##s(tracksData.m_trackSizes); \
style->setNamedGrid##TrackType##Lines(tracksData.m_namedGridLines); \
style->setOrderedNamedGrid##TrackType##Lines(tracksData.m_orderedNamedGridLines); \
style->setGridAutoRepeat##TrackType##s(tracksData.m_autoRepeatTrackSizes); \
style->setGridAutoRepeat##TrackType##sInsertionPoint(tracksData.m_autoRepeatInsertionPoint); \
style->setAutoRepeatNamedGrid##TrackType##Lines(tracksData.m_autoRepeatNamedGridLines); \
style->setAutoRepeatOrderedNamedGrid##TrackType##Lines(tracksData.m_autoRepeatOrderedNamedGridLines); \
style->setGridAutoRepeat##TrackType##sType(tracksData.m_autoRepeatType); \
style->setGridAutoRepeat##TrackType##sInsertionPoint(tracksData.m_autoRepeatInsertionPoint);
inline void StyleBuilderCustom::applyValueGridTemplateColumns(StyleResolver& styleResolver, CSSValue& value)
{
StyleBuilderConverter::TracksData tracksData;
if (!StyleBuilderConverter::createGridTrackList(value, tracksData, styleResolver))
return;
const NamedGridAreaMap& namedGridAreas = styleResolver.style()->namedGridArea();
if (!namedGridAreas.isEmpty())
StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(namedGridAreas, tracksData.m_namedGridLines, ForColumns);
SET_TRACKS_DATA(tracksData, styleResolver.style(), Column);
}
inline void StyleBuilderCustom::applyInitialGridTemplateRows(StyleResolver& styleResolver)
{
styleResolver.style()->setGridRows(RenderStyle::initialGridRows());
styleResolver.style()->setNamedGridRowLines(RenderStyle::initialNamedGridRowLines());
styleResolver.style()->setOrderedNamedGridRowLines(RenderStyle::initialOrderedNamedGridRowLines());
}
inline void StyleBuilderCustom::applyInheritGridTemplateRows(StyleResolver& styleResolver)
{
styleResolver.style()->setGridRows(styleResolver.parentStyle()->gridRows());
styleResolver.style()->setNamedGridRowLines(styleResolver.parentStyle()->namedGridRowLines());
styleResolver.style()->setOrderedNamedGridRowLines(styleResolver.parentStyle()->orderedNamedGridRowLines());
}
inline void StyleBuilderCustom::applyValueGridTemplateRows(StyleResolver& styleResolver, CSSValue& value)
{
StyleBuilderConverter::TracksData tracksData;
if (!StyleBuilderConverter::createGridTrackList(value, tracksData, styleResolver))
return;
const NamedGridAreaMap& namedGridAreas = styleResolver.style()->namedGridArea();
if (!namedGridAreas.isEmpty())
StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(namedGridAreas, tracksData.m_namedGridLines, ForRows);
SET_TRACKS_DATA(tracksData, styleResolver.style(), Row);
}
void StyleBuilderCustom::applyValueAlt(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (primitiveValue.isString())
styleResolver.style()->setContentAltText(primitiveValue.stringValue());
else if (primitiveValue.isAttr()) {
// FIXME: Can a namespace be specified for an attr(foo)?
if (styleResolver.style()->styleType() == PseudoId::None)
styleResolver.style()->setUnique();
else
const_cast<RenderStyle*>(styleResolver.parentStyle())->setUnique();
QualifiedName attr(nullAtom(), primitiveValue.stringValue(), nullAtom());
const AtomString& value = styleResolver.element()->getAttribute(attr);
styleResolver.style()->setContentAltText(value.isNull() ? emptyAtom() : value);
// Register the fact that the attribute value affects the style.
styleResolver.ruleSets().mutableFeatures().registerContentAttribute(attr.localName());
} else
styleResolver.style()->setContentAltText(emptyAtom());
}
inline void StyleBuilderCustom::applyValueWillChange(StyleResolver& styleResolver, CSSValue& value)
{
if (is<CSSPrimitiveValue>(value)) {
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto);
styleResolver.style()->setWillChange(nullptr);
return;
}
auto willChange = WillChangeData::create();
for (auto& item : downcast<CSSValueList>(value)) {
if (!is<CSSPrimitiveValue>(item))
continue;
auto& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
switch (primitiveValue.valueID()) {
case CSSValueScrollPosition:
willChange->addFeature(WillChangeData::Feature::ScrollPosition);
break;
case CSSValueContents:
willChange->addFeature(WillChangeData::Feature::Contents);
break;
default:
if (primitiveValue.isPropertyID())
willChange->addFeature(WillChangeData::Feature::Property, primitiveValue.propertyID());
break;
}
}
styleResolver.style()->setWillChange(WTFMove(willChange));
}
inline void StyleBuilderCustom::applyValueStrokeWidth(StyleResolver& styleResolver, CSSValue& value)
{
styleResolver.style()->setStrokeWidth(StyleBuilderConverter::convertLength(styleResolver, value));
styleResolver.style()->setHasExplicitlySetStrokeWidth(true);
}
inline void StyleBuilderCustom::applyValueStrokeColor(StyleResolver& styleResolver, CSSValue& value)
{
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
if (styleResolver.applyPropertyToRegularStyle())
styleResolver.style()->setStrokeColor(styleResolver.colorFromPrimitiveValue(primitiveValue, /* forVisitedLink */ false));
if (styleResolver.applyPropertyToVisitedLinkStyle())
styleResolver.style()->setVisitedLinkStrokeColor(styleResolver.colorFromPrimitiveValue(primitiveValue, /* forVisitedLink */ true));
styleResolver.style()->setHasExplicitlySetStrokeColor(true);
}
inline void StyleBuilderCustom::applyInitialCustomProperty(StyleResolver& styleResolver, const CSSRegisteredCustomProperty* registered, const AtomString& name)
{
if (registered && registered->initialValue()) {
auto initialValue = registered->initialValueCopy();
applyValueCustomProperty(styleResolver, registered, *initialValue);
return;
}
auto invalid = CSSCustomPropertyValue::createUnresolved(name, CSSValueInvalid);
applyValueCustomProperty(styleResolver, registered, invalid.get());
}
inline void StyleBuilderCustom::applyInheritCustomProperty(StyleResolver& styleResolver, const CSSRegisteredCustomProperty* registered, const AtomString& name)
{
auto* parentValue = styleResolver.parentStyle() ? styleResolver.parentStyle()->inheritedCustomProperties().get(name) : nullptr;
if (parentValue && !(registered && !registered->inherits))
applyValueCustomProperty(styleResolver, registered, *parentValue);
else
applyInitialCustomProperty(styleResolver, registered, name);
}
inline void StyleBuilderCustom::applyValueCustomProperty(StyleResolver& styleResolver, const CSSRegisteredCustomProperty* registered, CSSCustomPropertyValue& value)
{
ASSERT(value.isResolved());
const auto& name = value.name();
if (!registered || registered->inherits)
styleResolver.style()->setInheritedCustomPropertyValue(name, makeRef(value));
else
styleResolver.style()->setNonInheritedCustomPropertyValue(name, makeRef(value));
}
} // namespace WebCore