flutter_flutter/engine/core/css/resolver/StyleBuilderCustom.cpp
Ojan Vafai 2793661b5a Remove scroll corners and resizers.
We never paint scroll corners. The only thing we need them
for is so that the vertical and horizontal scrollbars don't
overlap each other. So, that's the only place left that
still computes a scroll corner rect.

We don't support resizers. Remove the code for them as well
as the CSS resize property.

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/689283003
2014-11-07 09:46:16 -08:00

962 lines
38 KiB
C++

/*
* 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 "config.h"
#include "core/CSSPropertyNames.h"
#include "core/CSSValueKeywords.h"
#include "core/StyleBuilderFunctions.h"
#include "core/StylePropertyShorthand.h"
#include "core/css/BasicShapeFunctions.h"
#include "core/css/CSSAspectRatioValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSFontValue.h"
#include "core/css/CSSGradientValue.h"
#include "core/css/CSSHelper.h"
#include "core/css/CSSImageSetValue.h"
#include "core/css/CSSLineBoxContainValue.h"
#include "core/css/parser/BisonCSSParser.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/css/CSSPropertyMetadata.h"
#include "core/css/Pair.h"
#include "core/css/StylePropertySet.h"
#include "core/css/StyleRule.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/css/resolver/TransformBuilder.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/rendering/style/QuotesData.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/rendering/style/RenderStyleConstants.h"
#include "core/rendering/style/StyleGeneratedImage.h"
#include "platform/fonts/FontDescription.h"
#include "wtf/MathExtras.h"
#include "wtf/StdLibExtras.h"
#include "wtf/Vector.h"
namespace blink {
void StyleBuilder::applyProperty(CSSPropertyID id, StyleResolverState& state, CSSValue* value)
{
ASSERT_WITH_MESSAGE(!isExpandedShorthand(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
bool isInherit = state.parentNode() && value->isInheritedValue();
bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle())
CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value) : 0;
if (primitiveValue && primitiveValue->getValueID() == CSSValueCurrentcolor)
state.style()->setHasCurrentColor();
if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSPropertyMetadata::isInheritedProperty(id))
state.parentStyle()->setHasExplicitlyInheritedProperties();
StyleBuilder::applyProperty(id, state, value, isInitial, isInherit);
}
void StyleBuilderFunctions::applyInitialCSSPropertyColor(StyleResolverState& state)
{
Color color = RenderStyle::initialColor();
state.style()->setColor(color);
}
void StyleBuilderFunctions::applyInheritCSSPropertyColor(StyleResolverState& state)
{
Color color = state.parentStyle()->color();
state.style()->setColor(color);
}
void StyleBuilderFunctions::applyValueCSSPropertyColor(StyleResolverState& state, CSSValue* value)
{
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
// As per the spec, 'color: currentColor' is treated as 'color: inherit'
if (primitiveValue->getValueID() == CSSValueCurrentcolor) {
applyInheritCSSPropertyColor(state);
return;
}
state.style()->setColor(StyleBuilderConverter::convertColor(state, value));
}
void StyleBuilderFunctions::applyInitialCSSPropertyCursor(StyleResolverState& state)
{
state.style()->clearCursorList();
state.style()->setCursor(RenderStyle::initialCursor());
}
void StyleBuilderFunctions::applyInheritCSSPropertyCursor(StyleResolverState& state)
{
state.style()->setCursor(state.parentStyle()->cursor());
state.style()->setCursorList(state.parentStyle()->cursors());
}
void StyleBuilderFunctions::applyValueCSSPropertyCursor(StyleResolverState& state, CSSValue* value)
{
state.style()->clearCursorList();
if (value->isValueList()) {
CSSValueList* list = toCSSValueList(value);
int len = list->length();
state.style()->setCursor(CURSOR_AUTO);
for (int i = 0; i < len; i++) {
CSSValue* item = list->item(i);
if (item->isCursorImageValue()) {
CSSCursorImageValue* image = toCSSCursorImageValue(item);
state.style()->addCursor(state.styleImage(CSSPropertyCursor, image), image->hotSpot());
} else {
state.style()->setCursor(*toCSSPrimitiveValue(item));
}
}
} else {
state.style()->setCursor(*toCSSPrimitiveValue(value));
}
}
void StyleBuilderFunctions::applyValueCSSPropertyDirection(StyleResolverState& state, CSSValue* value)
{
state.style()->setDirection(*toCSSPrimitiveValue(value));
Element* element = state.element();
if (element && element == element->document().documentElement())
element->document().setDirectionSetOnDocumentElement(true);
}
void StyleBuilderFunctions::applyInitialCSSPropertyFontFamily(StyleResolverState& state)
{
state.fontBuilder().setFontFamilyInitial();
}
void StyleBuilderFunctions::applyInheritCSSPropertyFontFamily(StyleResolverState& state)
{
state.fontBuilder().setFontFamilyInherit(state.parentFontDescription());
}
void StyleBuilderFunctions::applyValueCSSPropertyFontFamily(StyleResolverState& state, CSSValue* value)
{
state.fontBuilder().setFontFamilyValue(value);
}
void StyleBuilderFunctions::applyInitialCSSPropertyFontSize(StyleResolverState& state)
{
state.fontBuilder().setFontSizeInitial();
}
void StyleBuilderFunctions::applyInheritCSSPropertyFontSize(StyleResolverState& state)
{
state.fontBuilder().setFontSizeInherit(state.parentFontDescription());
}
void StyleBuilderFunctions::applyValueCSSPropertyFontSize(StyleResolverState& state, CSSValue* value)
{
state.fontBuilder().setFontSizeValue(value, state.parentStyle(), state.rootElementStyle());
}
void StyleBuilderFunctions::applyValueCSSPropertyLineHeight(StyleResolverState& state, CSSValue* value)
{
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
Length lineHeight;
if (primitiveValue->getValueID() == CSSValueNormal) {
lineHeight = RenderStyle::initialLineHeight();
} else if (primitiveValue->isLength()) {
float multiplier = state.style()->effectiveZoom();
if (LocalFrame* frame = state.document().frame())
multiplier *= frame->textZoomFactor();
lineHeight = primitiveValue->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(multiplier));
} else if (primitiveValue->isPercentage()) {
lineHeight = Length((state.style()->computedFontSize() * primitiveValue->getIntValue()) / 100.0, Fixed);
} else if (primitiveValue->isNumber()) {
lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
} else if (primitiveValue->isCalculated()) {
double multiplier = state.style()->effectiveZoom();
if (LocalFrame* frame = state.document().frame())
multiplier *= frame->textZoomFactor();
Length zoomedLength = Length(primitiveValue->cssCalcValue()->toCalcValue(state.cssToLengthConversionData().copyWithAdjustedZoom(multiplier)));
lineHeight = Length(valueForLength(zoomedLength, state.style()->fontSize()), Fixed);
} else {
return;
}
state.style()->setLineHeight(lineHeight);
}
void StyleBuilderFunctions::applyValueCSSPropertyListStyleImage(StyleResolverState& state, CSSValue* value)
{
state.style()->setListStyleImage(state.styleImage(CSSPropertyListStyleImage, value));
}
void StyleBuilderFunctions::applyInitialCSSPropertyOutlineStyle(StyleResolverState& state)
{
state.style()->setOutlineStyleIsAuto(RenderStyle::initialOutlineStyleIsAuto());
state.style()->setOutlineStyle(RenderStyle::initialBorderStyle());
}
void StyleBuilderFunctions::applyInheritCSSPropertyOutlineStyle(StyleResolverState& state)
{
state.style()->setOutlineStyleIsAuto(state.parentStyle()->outlineStyleIsAuto());
state.style()->setOutlineStyle(state.parentStyle()->outlineStyle());
}
void StyleBuilderFunctions::applyValueCSSPropertyOutlineStyle(StyleResolverState& state, CSSValue* value)
{
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
state.style()->setOutlineStyleIsAuto(*primitiveValue);
state.style()->setOutlineStyle(*primitiveValue);
}
static Length mmLength(double mm) { return Length(mm * cssPixelsPerMillimeter, Fixed); }
static Length inchLength(double inch) { return Length(inch * cssPixelsPerInch, Fixed); }
static bool getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height)
{
DEFINE_STATIC_LOCAL(Length, a5Width, (mmLength(148)));
DEFINE_STATIC_LOCAL(Length, a5Height, (mmLength(210)));
DEFINE_STATIC_LOCAL(Length, a4Width, (mmLength(210)));
DEFINE_STATIC_LOCAL(Length, a4Height, (mmLength(297)));
DEFINE_STATIC_LOCAL(Length, a3Width, (mmLength(297)));
DEFINE_STATIC_LOCAL(Length, a3Height, (mmLength(420)));
DEFINE_STATIC_LOCAL(Length, b5Width, (mmLength(176)));
DEFINE_STATIC_LOCAL(Length, b5Height, (mmLength(250)));
DEFINE_STATIC_LOCAL(Length, b4Width, (mmLength(250)));
DEFINE_STATIC_LOCAL(Length, b4Height, (mmLength(353)));
DEFINE_STATIC_LOCAL(Length, letterWidth, (inchLength(8.5)));
DEFINE_STATIC_LOCAL(Length, letterHeight, (inchLength(11)));
DEFINE_STATIC_LOCAL(Length, legalWidth, (inchLength(8.5)));
DEFINE_STATIC_LOCAL(Length, legalHeight, (inchLength(14)));
DEFINE_STATIC_LOCAL(Length, ledgerWidth, (inchLength(11)));
DEFINE_STATIC_LOCAL(Length, ledgerHeight, (inchLength(17)));
if (!pageSizeName)
return false;
switch (pageSizeName->getValueID()) {
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->getValueID()) {
case CSSValueLandscape:
std::swap(width, height);
break;
case CSSValuePortrait:
// Nothing to do.
break;
default:
return false;
}
}
return true;
}
void StyleBuilderFunctions::applyInitialCSSPropertySize(StyleResolverState&) { }
void StyleBuilderFunctions::applyInheritCSSPropertySize(StyleResolverState&) { }
void StyleBuilderFunctions::applyValueCSSPropertySize(StyleResolverState& state, CSSValue* value)
{
state.style()->resetPageSizeType();
Length width;
Length height;
PageSizeType pageSizeType = PAGE_SIZE_AUTO;
CSSValueListInspector inspector(value);
switch (inspector.length()) {
case 2: {
// <length>{2} | <page-size> <orientation>
if (!inspector.first()->isPrimitiveValue() || !inspector.second()->isPrimitiveValue())
return;
CSSPrimitiveValue* first = toCSSPrimitiveValue(inspector.first());
CSSPrimitiveValue* second = toCSSPrimitiveValue(inspector.second());
if (first->isLength()) {
// <length>{2}
if (!second->isLength())
return;
width = first->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
height = second->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
} else {
// <page-size> <orientation>
// The value order is guaranteed. See BisonCSSParser::parseSizeParameter.
if (!getPageSizeFromName(first, second, width, height))
return;
}
pageSizeType = PAGE_SIZE_RESOLVED;
break;
}
case 1: {
// <length> | auto | <page-size> | [ portrait | landscape]
if (!inspector.first()->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inspector.first());
if (primitiveValue->isLength()) {
// <length>
pageSizeType = PAGE_SIZE_RESOLVED;
width = height = primitiveValue->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
} else {
switch (primitiveValue->getValueID()) {
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, 0, width, height))
return;
}
}
break;
}
default:
return;
}
state.style()->setPageSizeType(pageSizeType);
state.style()->setPageSize(LengthSize(width, height));
}
void StyleBuilderFunctions::applyValueCSSPropertyTextAlign(StyleResolverState& state, CSSValue* value)
{
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
// FIXME : Per http://www.w3.org/TR/css3-text/#text-align0 can now take <string> but this is not implemented in the
// rendering code.
if (primitiveValue->isString())
return;
if (primitiveValue->isValueID() && primitiveValue->getValueID() != CSSValueWebkitMatchParent)
state.style()->setTextAlign(*primitiveValue);
else if (state.parentStyle()->textAlign() == TASTART)
state.style()->setTextAlign(state.parentStyle()->isLeftToRightDirection() ? LEFT : RIGHT);
else if (state.parentStyle()->textAlign() == TAEND)
state.style()->setTextAlign(state.parentStyle()->isLeftToRightDirection() ? RIGHT : LEFT);
else
state.style()->setTextAlign(state.parentStyle()->textAlign());
}
void StyleBuilderFunctions::applyInheritCSSPropertyTextIndent(StyleResolverState& state)
{
state.style()->setTextIndent(state.parentStyle()->textIndent());
state.style()->setTextIndentLine(state.parentStyle()->textIndentLine());
state.style()->setTextIndentType(state.parentStyle()->textIndentType());
}
void StyleBuilderFunctions::applyInitialCSSPropertyTextIndent(StyleResolverState& state)
{
state.style()->setTextIndent(RenderStyle::initialTextIndent());
state.style()->setTextIndentLine(RenderStyle::initialTextIndentLine());
state.style()->setTextIndentType(RenderStyle::initialTextIndentType());
}
void StyleBuilderFunctions::applyValueCSSPropertyTextIndent(StyleResolverState& state, CSSValue* value)
{
if (!value->isValueList())
return;
Length lengthOrPercentageValue;
TextIndentLine textIndentLineValue = RenderStyle::initialTextIndentLine();
TextIndentType textIndentTypeValue = RenderStyle::initialTextIndentType();
for (CSSValueListIterator i(value); i.hasMore(); i.advance()) {
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
if (!primitiveValue->getValueID())
lengthOrPercentageValue = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
else if (primitiveValue->getValueID() == CSSValueEachLine)
textIndentLineValue = TextIndentEachLine;
else if (primitiveValue->getValueID() == CSSValueHanging)
textIndentTypeValue = TextIndentHanging;
else
ASSERT_NOT_REACHED();
}
state.style()->setTextIndent(lengthOrPercentageValue);
state.style()->setTextIndentLine(textIndentLineValue);
state.style()->setTextIndentType(textIndentTypeValue);
}
void StyleBuilderFunctions::applyValueCSSPropertyTransform(StyleResolverState& state, CSSValue* value)
{
TransformOperations operations;
TransformBuilder::createTransformOperations(value, state.cssToLengthConversionData(), operations);
state.style()->setTransform(operations);
}
void StyleBuilderFunctions::applyInitialCSSPropertyTransformOrigin(StyleResolverState& state)
{
applyInitialCSSPropertyWebkitTransformOriginX(state);
applyInitialCSSPropertyWebkitTransformOriginY(state);
applyInitialCSSPropertyWebkitTransformOriginZ(state);
}
void StyleBuilderFunctions::applyInheritCSSPropertyTransformOrigin(StyleResolverState& state)
{
applyInheritCSSPropertyWebkitTransformOriginX(state);
applyInheritCSSPropertyWebkitTransformOriginY(state);
applyInheritCSSPropertyWebkitTransformOriginZ(state);
}
void StyleBuilderFunctions::applyValueCSSPropertyTransformOrigin(StyleResolverState& state, CSSValue* value)
{
CSSValueList* list = toCSSValueList(value);
ASSERT(list->length() == 3);
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(list->item(0));
if (primitiveValue->isValueID()) {
switch (primitiveValue->getValueID()) {
case CSSValueLeft:
state.style()->setTransformOriginX(Length(0, Percent));
break;
case CSSValueRight:
state.style()->setTransformOriginX(Length(100, Percent));
break;
case CSSValueCenter:
state.style()->setTransformOriginX(Length(50, Percent));
break;
default:
ASSERT_NOT_REACHED();
}
} else {
state.style()->setTransformOriginX(StyleBuilderConverter::convertLength(state, primitiveValue));
}
primitiveValue = toCSSPrimitiveValue(list->item(1));
if (primitiveValue->isValueID()) {
switch (primitiveValue->getValueID()) {
case CSSValueTop:
state.style()->setTransformOriginY(Length(0, Percent));
break;
case CSSValueBottom:
state.style()->setTransformOriginY(Length(100, Percent));
break;
case CSSValueCenter:
state.style()->setTransformOriginY(Length(50, Percent));
break;
default:
ASSERT_NOT_REACHED();
}
} else {
state.style()->setTransformOriginY(StyleBuilderConverter::convertLength(state, primitiveValue));
}
primitiveValue = toCSSPrimitiveValue(list->item(2));
state.style()->setTransformOriginZ(StyleBuilderConverter::convertComputedLength<float>(state, primitiveValue));
}
void StyleBuilderFunctions::applyInitialCSSPropertyPerspectiveOrigin(StyleResolverState& state)
{
applyInitialCSSPropertyWebkitPerspectiveOriginX(state);
applyInitialCSSPropertyWebkitPerspectiveOriginY(state);
}
void StyleBuilderFunctions::applyInheritCSSPropertyPerspectiveOrigin(StyleResolverState& state)
{
applyInheritCSSPropertyWebkitPerspectiveOriginX(state);
applyInheritCSSPropertyWebkitPerspectiveOriginY(state);
}
void StyleBuilderFunctions::applyValueCSSPropertyPerspectiveOrigin(StyleResolverState& state, CSSValue* value)
{
CSSValueList* list = toCSSValueList(value);
ASSERT(list->length() == 2);
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(list->item(0));
if (primitiveValue->isValueID()) {
switch (primitiveValue->getValueID()) {
case CSSValueLeft:
state.style()->setPerspectiveOriginX(Length(0, Percent));
break;
case CSSValueRight:
state.style()->setPerspectiveOriginX(Length(100, Percent));
break;
case CSSValueCenter:
state.style()->setPerspectiveOriginX(Length(50, Percent));
break;
default:
ASSERT_NOT_REACHED();
}
} else {
state.style()->setPerspectiveOriginX(StyleBuilderConverter::convertLength(state, primitiveValue));
}
primitiveValue = toCSSPrimitiveValue(list->item(1));
if (primitiveValue->isValueID()) {
switch (primitiveValue->getValueID()) {
case CSSValueTop:
state.style()->setPerspectiveOriginY(Length(0, Percent));
break;
case CSSValueBottom:
state.style()->setPerspectiveOriginY(Length(100, Percent));
break;
case CSSValueCenter:
state.style()->setPerspectiveOriginY(Length(50, Percent));
break;
default:
ASSERT_NOT_REACHED();
}
} else {
state.style()->setPerspectiveOriginY(StyleBuilderConverter::convertLength(state, primitiveValue));
}
}
void StyleBuilderFunctions::applyInheritCSSPropertyVerticalAlign(StyleResolverState& state)
{
EVerticalAlign verticalAlign = state.parentStyle()->verticalAlign();
state.style()->setVerticalAlign(verticalAlign);
if (verticalAlign == LENGTH)
state.style()->setVerticalAlignLength(state.parentStyle()->verticalAlignLength());
}
void StyleBuilderFunctions::applyValueCSSPropertyVerticalAlign(StyleResolverState& state, CSSValue* value)
{
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->getValueID()) {
state.style()->setVerticalAlign(*primitiveValue);
return;
}
state.style()->setVerticalAlignLength(primitiveValue->convertToLength<FixedConversion | PercentConversion>(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() : RenderStyle::initialZoom());
}
void StyleBuilderFunctions::applyInitialCSSPropertyZoom(StyleResolverState& state)
{
resetEffectiveZoom(state);
state.setZoom(RenderStyle::initialZoom());
}
void StyleBuilderFunctions::applyInheritCSSPropertyZoom(StyleResolverState& state)
{
resetEffectiveZoom(state);
state.setZoom(state.parentStyle()->zoom());
}
void StyleBuilderFunctions::applyValueCSSPropertyZoom(StyleResolverState& state, CSSValue* value)
{
ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->getValueID() == CSSValueNormal) {
resetEffectiveZoom(state);
state.setZoom(RenderStyle::initialZoom());
} else if (primitiveValue->getValueID() == CSSValueReset) {
state.setEffectiveZoom(RenderStyle::initialZoom());
state.setZoom(RenderStyle::initialZoom());
} else if (primitiveValue->getValueID() == CSSValueDocument) {
float docZoom = state.rootElementStyle() ? state.rootElementStyle()->zoom() : RenderStyle::initialZoom();
state.setEffectiveZoom(docZoom);
state.setZoom(docZoom);
} else if (primitiveValue->isPercentage()) {
resetEffectiveZoom(state);
if (float percent = primitiveValue->getFloatValue())
state.setZoom(percent / 100.0f);
} else if (primitiveValue->isNumber()) {
resetEffectiveZoom(state);
if (float number = primitiveValue->getFloatValue())
state.setZoom(number);
}
}
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAspectRatio(StyleResolverState& state)
{
state.style()->setHasAspectRatio(RenderStyle::initialHasAspectRatio());
state.style()->setAspectRatioDenominator(RenderStyle::initialAspectRatioDenominator());
state.style()->setAspectRatioNumerator(RenderStyle::initialAspectRatioNumerator());
}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitAspectRatio(StyleResolverState& state)
{
if (!state.parentStyle()->hasAspectRatio())
return;
state.style()->setHasAspectRatio(true);
state.style()->setAspectRatioDenominator(state.parentStyle()->aspectRatioDenominator());
state.style()->setAspectRatioNumerator(state.parentStyle()->aspectRatioNumerator());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitAspectRatio(StyleResolverState& state, CSSValue* value)
{
if (!value->isAspectRatioValue()) {
state.style()->setHasAspectRatio(false);
return;
}
CSSAspectRatioValue* aspectRatioValue = toCSSAspectRatioValue(value);
state.style()->setHasAspectRatio(true);
state.style()->setAspectRatioDenominator(aspectRatioValue->denominatorValue());
state.style()->setAspectRatioNumerator(aspectRatioValue->numeratorValue());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitBorderImage(StyleResolverState& state, CSSValue* value)
{
NinePieceImage image;
state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBorderImage, value, image);
state.style()->setBorderImage(image);
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitClipPath(StyleResolverState& state, CSSValue* value)
{
if (value->isPrimitiveValue()) {
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->getValueID() == CSSValueNone) {
state.style()->setClipPath(nullptr);
} else if (primitiveValue->isShape()) {
state.style()->setClipPath(ShapeClipPathOperation::create(basicShapeForValue(state, primitiveValue->getShapeValue())));
}
}
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitFilter(StyleResolverState& state, CSSValue* value)
{
FilterOperations operations;
if (FilterOperationResolver::createFilterOperations(value, state.cssToLengthConversionData(), operations, state))
state.style()->setFilter(operations);
}
// FIXME: We should use the same system for this as the rest of the pseudo-shorthands (e.g. background-position)
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitPerspectiveOrigin(StyleResolverState& state)
{
applyInitialCSSPropertyWebkitPerspectiveOriginX(state);
applyInitialCSSPropertyWebkitPerspectiveOriginY(state);
}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitPerspectiveOrigin(StyleResolverState& state)
{
applyInheritCSSPropertyWebkitPerspectiveOriginX(state);
applyInheritCSSPropertyWebkitPerspectiveOriginY(state);
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitPerspectiveOrigin(StyleResolverState&, CSSValue* value)
{
// This is expanded in the parser
ASSERT_NOT_REACHED();
}
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state)
{
state.style()->setTextEmphasisFill(RenderStyle::initialTextEmphasisFill());
state.style()->setTextEmphasisMark(RenderStyle::initialTextEmphasisMark());
state.style()->setTextEmphasisCustomMark(RenderStyle::initialTextEmphasisCustomMark());
}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state)
{
state.style()->setTextEmphasisFill(state.parentStyle()->textEmphasisFill());
state.style()->setTextEmphasisMark(state.parentStyle()->textEmphasisMark());
state.style()->setTextEmphasisCustomMark(state.parentStyle()->textEmphasisCustomMark());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state, CSSValue* value)
{
if (value->isValueList()) {
CSSValueList* list = toCSSValueList(value);
ASSERT(list->length() == 2);
if (list->length() != 2)
return;
for (unsigned i = 0; i < 2; ++i) {
CSSValue* item = list->item(i);
if (!item->isPrimitiveValue())
continue;
CSSPrimitiveValue* value = toCSSPrimitiveValue(item);
if (value->getValueID() == CSSValueFilled || value->getValueID() == CSSValueOpen)
state.style()->setTextEmphasisFill(*value);
else
state.style()->setTextEmphasisMark(*value);
}
state.style()->setTextEmphasisCustomMark(nullAtom);
return;
}
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->isString()) {
state.style()->setTextEmphasisFill(TextEmphasisFillFilled);
state.style()->setTextEmphasisMark(TextEmphasisMarkCustom);
state.style()->setTextEmphasisCustomMark(AtomicString(primitiveValue->getStringValue()));
return;
}
state.style()->setTextEmphasisCustomMark(nullAtom);
if (primitiveValue->getValueID() == CSSValueFilled || primitiveValue->getValueID() == CSSValueOpen) {
state.style()->setTextEmphasisFill(*primitiveValue);
state.style()->setTextEmphasisMark(TextEmphasisMarkAuto);
} else {
state.style()->setTextEmphasisFill(TextEmphasisFillFilled);
state.style()->setTextEmphasisMark(*primitiveValue);
}
}
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, CSSValue* value)
{
ASSERT(value->isValueList());
bool willChangeContents = false;
bool willChangeScrollPosition = false;
Vector<CSSPropertyID> willChangeProperties;
for (CSSValueListIterator i(value); i.hasMore(); i.advance()) {
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
if (CSSPropertyID propertyID = primitiveValue->getPropertyID())
willChangeProperties.append(propertyID);
else if (primitiveValue->getValueID() == CSSValueContents)
willChangeContents = true;
else if (primitiveValue->getValueID() == CSSValueScrollPosition)
willChangeScrollPosition = true;
else
ASSERT_NOT_REACHED();
}
state.style()->setWillChangeContents(willChangeContents);
state.style()->setWillChangeScrollPosition(willChangeScrollPosition);
state.style()->setWillChangeProperties(willChangeProperties);
state.style()->setSubtreeWillChangeContents(willChangeContents || state.parentStyle()->subtreeWillChangeContents());
}
void StyleBuilderFunctions::applyInitialCSSPropertyContent(StyleResolverState& state)
{
state.style()->clearContent();
}
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, CSSValue* value)
{
// list of string, uri, counter, attr, i
if (!value->isValueList())
return;
bool didSet = false;
for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
CSSValue* item = i.value();
if (item->isImageGeneratorValue()) {
if (item->isGradientValue())
state.style()->setContent(StyleGeneratedImage::create(toCSSGradientValue(item)->gradientWithStylesResolved(state.document().textLinkColors(), state.style()->color()).get()), didSet);
else
state.style()->setContent(StyleGeneratedImage::create(toCSSImageGeneratorValue(item)), didSet);
didSet = true;
} else if (item->isImageSetValue()) {
state.style()->setContent(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(item)), didSet);
didSet = true;
}
if (item->isImageValue()) {
state.style()->setContent(state.elementStyleResources().cachedOrPendingFromValue(state.document(), CSSPropertyContent, toCSSImageValue(item)), didSet);
didSet = true;
continue;
}
if (!item->isPrimitiveValue())
continue;
CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
if (contentValue->isString()) {
state.style()->setContent(contentValue->getStringValue().impl(), didSet);
didSet = true;
} else if (contentValue->isAttr()) {
// FIXME: Can a namespace be specified for an attr(foo)?
if (state.style()->styleType() == NOPSEUDO)
state.style()->setUnique();
else
state.parentStyle()->setUnique();
QualifiedName attr(AtomicString(contentValue->getStringValue()));
const AtomicString& value = state.element()->getAttribute(attr);
state.style()->setContent(value.isNull() ? emptyString() : value.string(), didSet);
didSet = true;
// register the fact that the attribute value affects the style
state.contentAttrValues().append(attr.localName());
} else {
switch (contentValue->getValueID()) {
default:
// normal and none do not have any effect.
{ }
}
}
}
if (!didSet)
state.style()->clearContent();
}
void StyleBuilderFunctions::applyInitialCSSPropertyFont(StyleResolverState&)
{
ASSERT_NOT_REACHED();
}
void StyleBuilderFunctions::applyInheritCSSPropertyFont(StyleResolverState&)
{
ASSERT_NOT_REACHED();
}
void StyleBuilderFunctions::applyValueCSSPropertyFont(StyleResolverState& state, CSSValue* value)
{
// Only System Font identifiers should come through this method
// all other values should have been handled when the shorthand
// was expanded by the parser.
// FIXME: System Font identifiers should not hijack this
// short-hand CSSProperty like this (crbug.com/353932)
state.style()->setLineHeight(RenderStyle::initialLineHeight());
state.setLineHeightValue(0);
state.fontBuilder().fromSystemFont(toCSSPrimitiveValue(value)->getValueID(), state.style()->effectiveZoom());
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitLocale(StyleResolverState& state, CSSValue* value)
{
if (!value->isPrimitiveValue())
return;
const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->getValueID() == CSSValueAuto)
state.style()->setLocale(nullAtom);
else
state.style()->setLocale(AtomicString(primitiveValue->getStringValue()));
state.fontBuilder().setScript(state.style()->locale());
}
void StyleBuilderFunctions::applyInitialCSSPropertyWebkitPerspective(StyleResolverState& state)
{
applyInitialCSSPropertyPerspective(state);
}
void StyleBuilderFunctions::applyInheritCSSPropertyWebkitPerspective(StyleResolverState& state)
{
applyInheritCSSPropertyPerspective(state);
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitPerspective(StyleResolverState& state, CSSValue* value)
{
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->isNumber()) {
float perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLength<float>(state.cssToLengthConversionData());
if (perspectiveValue >= 0.0f)
state.style()->setPerspective(perspectiveValue);
} else {
applyValueCSSPropertyPerspective(state, value);
}
}
void StyleBuilderFunctions::applyValueCSSPropertyPerspective(StyleResolverState& state, CSSValue* value)
{
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->getValueID() == CSSValueNone) {
state.style()->setPerspective(0);
return;
}
if (!primitiveValue->isLength())
return;
float perspectiveValue = primitiveValue->computeLength<float>(state.cssToLengthConversionData());
if (perspectiveValue >= 0.0f)
state.style()->setPerspective(perspectiveValue);
}
void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextOrientation(StyleResolverState& state, CSSValue* value)
{
if (value->isPrimitiveValue())
state.setTextOrientation(*toCSSPrimitiveValue(value));
}
} // namespace blink