| /* |
| * 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 "core/CSSPropertyNames.h" |
| #include "core/CSSValueKeywords.h" |
| #include "core/StyleBuilderFunctions.h" |
| #include "core/StylePropertyShorthand.h" |
| #include "core/css/BasicShapeFunctions.h" |
| #include "core/css/CSSBasicShapeValues.h" |
| #include "core/css/CSSCounterValue.h" |
| #include "core/css/CSSCursorImageValue.h" |
| #include "core/css/CSSCustomPropertyDeclaration.h" |
| #include "core/css/CSSFunctionValue.h" |
| #include "core/css/CSSGradientValue.h" |
| #include "core/css/CSSGridTemplateAreasValue.h" |
| #include "core/css/CSSHelper.h" |
| #include "core/css/CSSImageSetValue.h" |
| #include "core/css/CSSPathValue.h" |
| #include "core/css/CSSPrimitiveValueMappings.h" |
| #include "core/css/CSSPropertyMetadata.h" |
| #include "core/css/CSSURIValue.h" |
| #include "core/css/CSSValuePair.h" |
| #include "core/css/CSSVariableReferenceValue.h" |
| #include "core/css/StylePropertySet.h" |
| #include "core/css/StyleRule.h" |
| #include "core/css/resolver/CSSVariableResolver.h" |
| #include "core/css/resolver/ElementStyleResources.h" |
| #include "core/css/resolver/FilterOperationResolver.h" |
| #include "core/css/resolver/FontBuilder.h" |
| #include "core/css/resolver/StyleBuilder.h" |
| #include "core/css/resolver/TransformBuilder.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/Settings.h" |
| #include "core/style/CounterContent.h" |
| #include "core/style/ComputedStyle.h" |
| #include "core/style/ComputedStyleConstants.h" |
| #include "core/style/QuotesData.h" |
| #include "core/style/SVGComputedStyle.h" |
| #include "core/style/StyleGeneratedImage.h" |
| #include "core/style/StyleVariableData.h" |
| #include "platform/fonts/FontDescription.h" |
| #include "wtf/MathExtras.h" |
| #include "wtf/StdLibExtras.h" |
| #include "wtf/Vector.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| static inline bool isValidVisitedLinkProperty(CSSPropertyID id) |
| { |
| switch (id) { |
| case CSSPropertyBackgroundColor: |
| case CSSPropertyBorderLeftColor: |
| case CSSPropertyBorderRightColor: |
| case CSSPropertyBorderTopColor: |
| case CSSPropertyBorderBottomColor: |
| case CSSPropertyColor: |
| case CSSPropertyFill: |
| case CSSPropertyOutlineColor: |
| case CSSPropertyStroke: |
| case CSSPropertyTextDecorationColor: |
| case CSSPropertyColumnRuleColor: |
| case CSSPropertyWebkitTextEmphasisColor: |
| case CSSPropertyWebkitTextFillColor: |
| case CSSPropertyWebkitTextStrokeColor: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| } // namespace |
| |
| void StyleBuilder::applyProperty(CSSPropertyID id, StyleResolverState& state, CSSValue* value) |
| { |
| if (RuntimeEnabledFeatures::cssVariablesEnabled() && id != CSSPropertyVariable && value->isVariableReferenceValue()) { |
| CSSVariableResolver::resolveAndApplyVariableReferences(state, id, *toCSSVariableReferenceValue(value)); |
| if (!state.style()->hasVariableReferenceFromNonInheritedProperty() && !CSSPropertyMetadata::isInheritedProperty(id)) |
| state.style()->setHasVariableReferenceFromNonInheritedProperty(); |
| return; |
| } |
| |
| ASSERT_WITH_MESSAGE(!isShorthandProperty(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()) |
| |
| if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) { |
| // Limit the properties that can be applied to only the ones honored by :visited. |
| return; |
| } |
| |
| if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSPropertyMetadata::isInheritedProperty(id)) { |
| state.parentStyle()->setHasExplicitlyInheritedProperties(); |
| } else if (value->isUnsetValue()) { |
| ASSERT(!isInherit && !isInitial); |
| if (CSSPropertyMetadata::isInheritedProperty(id)) |
| isInherit = true; |
| else |
| isInitial = true; |
| } |
| |
| StyleBuilder::applyProperty(id, state, value, isInitial, isInherit); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyColor(StyleResolverState& state) |
| { |
| Color color = ComputedStyle::initialColor(); |
| if (state.applyPropertyToRegularStyle()) |
| state.style()->setColor(color); |
| if (state.applyPropertyToVisitedLinkStyle()) |
| state.style()->setVisitedLinkColor(color); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyColor(StyleResolverState& state) |
| { |
| Color color = state.parentStyle()->color(); |
| if (state.applyPropertyToRegularStyle()) |
| state.style()->setColor(color); |
| if (state.applyPropertyToVisitedLinkStyle()) |
| state.style()->setVisitedLinkColor(color); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyColor(StyleResolverState& state, CSSValue* value) |
| { |
| // As per the spec, 'color: currentColor' is treated as 'color: inherit' |
| if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueCurrentcolor) { |
| applyInheritCSSPropertyColor(state); |
| return; |
| } |
| |
| if (state.applyPropertyToRegularStyle()) |
| state.style()->setColor(StyleBuilderConverter::convertColor(state, *value)); |
| if (state.applyPropertyToVisitedLinkStyle()) |
| state.style()->setVisitedLinkColor(StyleBuilderConverter::convertColor(state, *value, true)); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyCursor(StyleResolverState& state) |
| { |
| state.style()->clearCursorList(); |
| state.style()->setCursor(ComputedStyle::initialCursor()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyCursor(StyleResolverState& state) |
| { |
| state.style()->setCursor(state.parentStyle()->cursor()); |
| state.style()->setCursorList(state.parentStyle()->cursors()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyCursor(StyleResolverState& state, 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); |
| if (image->updateIfSVGCursorIsUsed(state.element())) // Elements with SVG cursors are not allowed to share style. |
| state.style()->setUnique(); |
| state.style()->addCursor(state.styleImage(CSSPropertyCursor, *image), image->hotSpotSpecified(), image->hotSpot()); |
| } else { |
| state.style()->setCursor(toCSSPrimitiveValue(item)->convertTo<ECursor>()); |
| } |
| } |
| } else { |
| state.style()->setCursor(toCSSPrimitiveValue(value)->convertTo<ECursor>()); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyDirection(StyleResolverState& state, CSSValue* value) |
| { |
| state.style()->setDirection(toCSSPrimitiveValue(value)->convertTo<TextDirection>()); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyGridTemplateAreas(StyleResolverState& state) |
| { |
| state.style()->setNamedGridArea(ComputedStyle::initialNamedGridArea()); |
| state.style()->setNamedGridAreaRowCount(ComputedStyle::initialNamedGridAreaCount()); |
| state.style()->setNamedGridAreaColumnCount(ComputedStyle::initialNamedGridAreaCount()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyGridTemplateAreas(StyleResolverState& state) |
| { |
| state.style()->setNamedGridArea(state.parentStyle()->namedGridArea()); |
| state.style()->setNamedGridAreaRowCount(state.parentStyle()->namedGridAreaRowCount()); |
| state.style()->setNamedGridAreaColumnCount(state.parentStyle()->namedGridAreaColumnCount()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyGridTemplateAreas(StyleResolverState& state, CSSValue* value) |
| { |
| if (value->isPrimitiveValue()) { |
| // FIXME: Shouldn't we clear the grid-area values |
| ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone); |
| return; |
| } |
| |
| CSSGridTemplateAreasValue* gridTemplateAreasValue = toCSSGridTemplateAreasValue(value); |
| const NamedGridAreaMap& newNamedGridAreas = gridTemplateAreasValue->gridAreaMap(); |
| |
| NamedGridLinesMap namedGridColumnLines; |
| NamedGridLinesMap namedGridRowLines; |
| StyleBuilderConverter::convertOrderedNamedGridLinesMapToNamedGridLinesMap(state.style()->orderedNamedGridColumnLines(), namedGridColumnLines); |
| StyleBuilderConverter::convertOrderedNamedGridLinesMapToNamedGridLinesMap(state.style()->orderedNamedGridRowLines(), namedGridRowLines); |
| StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridColumnLines, ForColumns); |
| StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridRowLines, ForRows); |
| state.style()->setNamedGridColumnLines(namedGridColumnLines); |
| state.style()->setNamedGridRowLines(namedGridRowLines); |
| |
| state.style()->setNamedGridArea(newNamedGridAreas); |
| state.style()->setNamedGridAreaRowCount(gridTemplateAreasValue->rowCount()); |
| state.style()->setNamedGridAreaColumnCount(gridTemplateAreasValue->columnCount()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyListStyleImage(StyleResolverState& state, CSSValue* value) |
| { |
| state.style()->setListStyleImage(state.styleImage(CSSPropertyListStyleImage, *value)); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyOutlineStyle(StyleResolverState& state) |
| { |
| state.style()->setOutlineStyleIsAuto(ComputedStyle::initialOutlineStyleIsAuto()); |
| state.style()->setOutlineStyle(ComputedStyle::initialBorderStyle()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyOutlineStyle(StyleResolverState& state) |
| { |
| state.style()->setOutlineStyleIsAuto(state.parentStyle()->outlineStyleIsAuto()); |
| state.style()->setOutlineStyle(state.parentStyle()->outlineStyle()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyOutlineStyle(StyleResolverState& state, CSSValue* value) |
| { |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| state.style()->setOutlineStyleIsAuto(primitiveValue->convertTo<OutlineIsAuto>()); |
| state.style()->setOutlineStyle(primitiveValue->convertTo<EBorderStyle>()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyResize(StyleResolverState& state, CSSValue* value) |
| { |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| |
| EResize r = RESIZE_NONE; |
| if (primitiveValue->getValueID() == CSSValueAuto) { |
| if (Settings* settings = state.document().settings()) |
| r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE; |
| } else { |
| r = primitiveValue->convertTo<EResize>(); |
| } |
| state.style()->setResize(r); |
| } |
| |
| static float mmToPx(float mm) { return mm * cssPixelsPerMillimeter; } |
| static float inchToPx(float inch) { return inch * cssPixelsPerInch; } |
| static FloatSize getPageSizeFromName(CSSPrimitiveValue* pageSizeName) |
| { |
| switch (pageSizeName->getValueID()) { |
| case CSSValueA5: |
| return FloatSize(mmToPx(148), mmToPx(210)); |
| case CSSValueA4: |
| return FloatSize(mmToPx(210), mmToPx(297)); |
| case CSSValueA3: |
| return FloatSize(mmToPx(297), mmToPx(420)); |
| case CSSValueB5: |
| return FloatSize(mmToPx(176), mmToPx(250)); |
| case CSSValueB4: |
| return FloatSize(mmToPx(250), mmToPx(353)); |
| case CSSValueLetter: |
| return FloatSize(inchToPx(8.5), inchToPx(11)); |
| case CSSValueLegal: |
| return FloatSize(inchToPx(8.5), inchToPx(14)); |
| case CSSValueLedger: |
| return FloatSize(inchToPx(11), inchToPx(17)); |
| default: |
| ASSERT_NOT_REACHED(); |
| return FloatSize(0, 0); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertySize(StyleResolverState&) { } |
| void StyleBuilderFunctions::applyInheritCSSPropertySize(StyleResolverState&) { } |
| void StyleBuilderFunctions::applyValueCSSPropertySize(StyleResolverState& state, CSSValue* value) |
| { |
| state.style()->resetPageSizeType(); |
| FloatSize size; |
| PageSizeType pageSizeType = PAGE_SIZE_AUTO; |
| CSSValueList* list = toCSSValueList(value); |
| if (list->length() == 2) { |
| // <length>{2} | <page-size> <orientation> |
| CSSPrimitiveValue* first = toCSSPrimitiveValue(list->item(0)); |
| CSSPrimitiveValue* second = toCSSPrimitiveValue(list->item(1)); |
| if (first->isLength()) { |
| // <length>{2} |
| size = FloatSize(first->computeLength<float>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0)), |
| second->computeLength<float>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0))); |
| } else { |
| // <page-size> <orientation> |
| size = getPageSizeFromName(first); |
| |
| ASSERT(second->getValueID() == CSSValueLandscape || second->getValueID() == CSSValuePortrait); |
| if (second->getValueID() == CSSValueLandscape) |
| size = size.transposedSize(); |
| } |
| pageSizeType = PAGE_SIZE_RESOLVED; |
| } else { |
| ASSERT(list->length() == 1); |
| // <length> | auto | <page-size> | [ portrait | landscape] |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(list->item(0)); |
| if (primitiveValue->isLength()) { |
| // <length> |
| pageSizeType = PAGE_SIZE_RESOLVED; |
| float width = primitiveValue->computeLength<float>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0)); |
| size = FloatSize(width, width); |
| } else { |
| switch (primitiveValue->getValueID()) { |
| 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; |
| size = getPageSizeFromName(primitiveValue); |
| } |
| } |
| } |
| state.style()->setPageSizeType(pageSizeType); |
| state.style()->setPageSize(size); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertySnapHeight(StyleResolverState& state) |
| { |
| state.style()->setSnapHeightUnit(0); |
| state.style()->setSnapHeightPosition(0); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertySnapHeight(StyleResolverState& state) |
| { |
| state.style()->setSnapHeightUnit(state.parentStyle()->snapHeightUnit()); |
| state.style()->setSnapHeightPosition(state.parentStyle()->snapHeightPosition()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertySnapHeight(StyleResolverState& state, CSSValue* value) |
| { |
| CSSValueList* list = toCSSValueList(value); |
| CSSPrimitiveValue* first = toCSSPrimitiveValue(list->item(0)); |
| ASSERT(first->isLength()); |
| int unit = first->computeLength<int>(state.cssToLengthConversionData()); |
| ASSERT(unit >= 0); |
| state.style()->setSnapHeightUnit(clampTo<uint8_t>(unit)); |
| |
| if (list->length() == 1) { |
| state.style()->setSnapHeightPosition(0); |
| return; |
| } |
| |
| ASSERT(list->length() == 2); |
| CSSPrimitiveValue* second = toCSSPrimitiveValue(list->item(1)); |
| ASSERT(second->isNumber()); |
| int position = second->getIntValue(); |
| ASSERT(position > 0 && position <= 100); |
| state.style()->setSnapHeightPosition(position); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyTextAlign(StyleResolverState& state, CSSValue* value) |
| { |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| if (primitiveValue->isValueID() && primitiveValue->getValueID() != CSSValueWebkitMatchParent) |
| state.style()->setTextAlign(primitiveValue->convertTo<ETextAlign>()); |
| 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(ComputedStyle::initialTextIndent()); |
| state.style()->setTextIndentLine(ComputedStyle::initialTextIndentLine()); |
| state.style()->setTextIndentType(ComputedStyle::initialTextIndentType()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyTextIndent(StyleResolverState& state, CSSValue* value) |
| { |
| Length lengthOrPercentageValue; |
| TextIndentLine textIndentLineValue = ComputedStyle::initialTextIndentLine(); |
| TextIndentType textIndentTypeValue = ComputedStyle::initialTextIndentType(); |
| |
| for (auto& listValue : toCSSValueList(*value)) { |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(listValue.get()); |
| if (!primitiveValue->getValueID()) |
| lengthOrPercentageValue = primitiveValue->convertToLength(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) |
| { |
| // FIXME: We should just make this a converter |
| TransformOperations operations; |
| TransformBuilder::createTransformOperations(*value, state.cssToLengthConversionData(), operations); |
| state.style()->setTransform(operations); |
| } |
| |
| 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) |
| { |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| |
| if (primitiveValue->getValueID()) |
| state.style()->setVerticalAlign(primitiveValue->convertTo<EVerticalAlign>()); |
| else |
| state.style()->setVerticalAlignLength(primitiveValue->convertToLength(state.cssToLengthConversionData())); |
| } |
| |
| static void resetEffectiveZoom(StyleResolverState& state) |
| { |
| // Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect. |
| state.setEffectiveZoom(state.parentStyle() ? state.parentStyle()->effectiveZoom() : ComputedStyle::initialZoom()); |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyZoom(StyleResolverState& state) |
| { |
| resetEffectiveZoom(state); |
| state.setZoom(ComputedStyle::initialZoom()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyZoom(StyleResolverState& state) |
| { |
| resetEffectiveZoom(state); |
| state.setZoom(state.parentStyle()->zoom()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyZoom(StyleResolverState& state, CSSValue* value) |
| { |
| ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue()); |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| |
| if (primitiveValue->getValueID() == CSSValueNormal) { |
| resetEffectiveZoom(state); |
| state.setZoom(ComputedStyle::initialZoom()); |
| } else if (primitiveValue->getValueID() == CSSValueReset) { |
| state.setEffectiveZoom(ComputedStyle::initialZoom()); |
| state.setZoom(ComputedStyle::initialZoom()); |
| } else if (primitiveValue->getValueID() == CSSValueDocument) { |
| float docZoom = state.rootElementStyle() ? state.rootElementStyle()->zoom() : ComputedStyle::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::applyValueCSSPropertyWebkitBorderImage(StyleResolverState& state, CSSValue* value) |
| { |
| NinePieceImage image; |
| CSSToStyleMap::mapNinePieceImage(state, CSSPropertyWebkitBorderImage, *value, image); |
| state.style()->setBorderImage(image); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWebkitClipPath(StyleResolverState& state, CSSValue* value) |
| { |
| if (value->isBasicShapeValue()) { |
| state.style()->setClipPath(ShapeClipPathOperation::create(basicShapeForValue(state, *value))); |
| } |
| if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNone) { |
| state.style()->setClipPath(nullptr); |
| } |
| if (value->isURIValue()) { |
| String cssURLValue = toCSSURIValue(value)->value(); |
| KURL url = state.document().completeURL(cssURLValue); |
| // FIXME: It doesn't work with forward or external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=90405) |
| state.style()->setClipPath(ReferenceClipPathOperation::create(cssURLValue, AtomicString(url.fragmentIdentifier()))); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state) |
| { |
| state.style()->setTextEmphasisFill(ComputedStyle::initialTextEmphasisFill()); |
| state.style()->setTextEmphasisMark(ComputedStyle::initialTextEmphasisMark()); |
| state.style()->setTextEmphasisCustomMark(ComputedStyle::initialTextEmphasisCustomMark()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state) |
| { |
| state.style()->setTextEmphasisFill(state.parentStyle()->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); |
| for (unsigned i = 0; i < 2; ++i) { |
| CSSPrimitiveValue* value = toCSSPrimitiveValue(list->item(i)); |
| if (value->getValueID() == CSSValueFilled || value->getValueID() == CSSValueOpen) |
| state.style()->setTextEmphasisFill(value->convertTo<TextEmphasisFill>()); |
| else |
| state.style()->setTextEmphasisMark(value->convertTo<TextEmphasisMark>()); |
| } |
| state.style()->setTextEmphasisCustomMark(nullAtom); |
| return; |
| } |
| |
| if (value->isStringValue()) { |
| state.style()->setTextEmphasisFill(TextEmphasisFillFilled); |
| state.style()->setTextEmphasisMark(TextEmphasisMarkCustom); |
| state.style()->setTextEmphasisCustomMark(AtomicString(toCSSStringValue(value)->value())); |
| return; |
| } |
| |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| |
| state.style()->setTextEmphasisCustomMark(nullAtom); |
| |
| if (primitiveValue->getValueID() == CSSValueFilled || primitiveValue->getValueID() == CSSValueOpen) { |
| state.style()->setTextEmphasisFill(primitiveValue->convertTo<TextEmphasisFill>()); |
| state.style()->setTextEmphasisMark(TextEmphasisMarkAuto); |
| } else { |
| state.style()->setTextEmphasisFill(TextEmphasisFillFilled); |
| state.style()->setTextEmphasisMark(primitiveValue->convertTo<TextEmphasisMark>()); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyWillChange(StyleResolverState& state) |
| { |
| state.style()->setWillChangeContents(false); |
| state.style()->setWillChangeScrollPosition(false); |
| state.style()->setWillChangeProperties(Vector<CSSPropertyID>()); |
| state.style()->setSubtreeWillChangeContents(state.parentStyle()->subtreeWillChangeContents()); |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyWillChange(StyleResolverState& state) |
| { |
| state.style()->setWillChangeContents(state.parentStyle()->willChangeContents()); |
| state.style()->setWillChangeScrollPosition(state.parentStyle()->willChangeScrollPosition()); |
| state.style()->setWillChangeProperties(state.parentStyle()->willChangeProperties()); |
| state.style()->setSubtreeWillChangeContents(state.parentStyle()->subtreeWillChangeContents()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWillChange(StyleResolverState& state, CSSValue* value) |
| { |
| bool willChangeContents = false; |
| bool willChangeScrollPosition = false; |
| Vector<CSSPropertyID> willChangeProperties; |
| |
| if (value->isPrimitiveValue()) { |
| ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueAuto); |
| } else { |
| ASSERT(value->isValueList()); |
| for (auto& willChangeValue : toCSSValueList(*value)) { |
| if (willChangeValue->isCustomIdentValue()) |
| willChangeProperties.append(toCSSCustomIdentValue(*willChangeValue).valueAsPropertyID()); |
| else if (toCSSPrimitiveValue(*willChangeValue).getValueID() == CSSValueContents) |
| willChangeContents = true; |
| else if (toCSSPrimitiveValue(*willChangeValue).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 |
| |
| bool didSet = false; |
| for (auto& item : toCSSValueList(*value)) { |
| if (item->isImageGeneratorValue()) { |
| 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(CSSPropertyContent, toCSSImageValue(*item)), didSet); |
| didSet = true; |
| continue; |
| } |
| |
| if (item->isCounterValue()) { |
| CSSCounterValue* counterValue = toCSSCounterValue(item.get()); |
| EListStyleType listStyleType = NoneListStyle; |
| CSSValueID listStyleIdent = counterValue->listStyle(); |
| if (listStyleIdent != CSSValueNone) |
| listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc); |
| OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(AtomicString(counterValue->identifier()), listStyleType, AtomicString(counterValue->separator()))); |
| state.style()->setContent(counter.release(), didSet); |
| didSet = true; |
| } |
| |
| if (item->isFunctionValue()) { |
| CSSFunctionValue* functionValue = toCSSFunctionValue(item.get()); |
| ASSERT(functionValue->functionType() == CSSValueAttr); |
| // FIXME: Can a namespace be specified for an attr(foo)? |
| if (state.style()->styleType() == NOPSEUDO) |
| state.style()->setUnique(); |
| else |
| state.parentStyle()->setUnique(); |
| QualifiedName attr(nullAtom, AtomicString(toCSSCustomIdentValue(functionValue->item(0))->value()), nullAtom); |
| const AtomicString& value = state.element()->getAttribute(attr); |
| state.style()->setContent(value.isNull() ? emptyString() : value.string(), didSet); |
| didSet = true; |
| } |
| |
| if (!item->isPrimitiveValue() && !item->isStringValue()) |
| continue; |
| |
| if (item->isStringValue()) { |
| state.style()->setContent(toCSSStringValue(*item).value().impl(), didSet); |
| didSet = true; |
| } else { |
| switch (toCSSPrimitiveValue(*item).getValueID()) { |
| case CSSValueOpenQuote: |
| state.style()->setContent(OPEN_QUOTE, didSet); |
| didSet = true; |
| break; |
| case CSSValueCloseQuote: |
| state.style()->setContent(CLOSE_QUOTE, didSet); |
| didSet = true; |
| break; |
| case CSSValueNoOpenQuote: |
| state.style()->setContent(NO_OPEN_QUOTE, didSet); |
| didSet = true; |
| break; |
| case CSSValueNoCloseQuote: |
| state.style()->setContent(NO_CLOSE_QUOTE, didSet); |
| didSet = true; |
| break; |
| default: |
| // normal and none do not have any effect. |
| { } |
| } |
| } |
| } |
| if (!didSet) |
| state.style()->clearContent(); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWebkitLocale(StyleResolverState& state, CSSValue* value) |
| { |
| if (value->isPrimitiveValue()) { |
| ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueAuto); |
| state.fontBuilder().setLocale(nullAtom); |
| } else { |
| state.fontBuilder().setLocale(AtomicString(toCSSStringValue(value)->value())); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAppRegion(StyleResolverState&) |
| { |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyWebkitAppRegion(StyleResolverState&) |
| { |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWebkitAppRegion(StyleResolverState& state, CSSValue* value) |
| { |
| const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| state.style()->setDraggableRegionMode(primitiveValue->getValueID() == CSSValueDrag ? DraggableRegionDrag : DraggableRegionNoDrag); |
| state.document().setHasAnnotatedRegions(true); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWritingMode(StyleResolverState& state, CSSValue* value) |
| { |
| state.setWritingMode(toCSSPrimitiveValue(value)->convertTo<WritingMode>()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWebkitWritingMode(StyleResolverState& state, CSSValue* value) |
| { |
| state.setWritingMode(toCSSPrimitiveValue(value)->convertTo<WritingMode>()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyTextOrientation(StyleResolverState& state, CSSValue* value) |
| { |
| state.setTextOrientation(toCSSPrimitiveValue(value)->convertTo<TextOrientation>()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextOrientation(StyleResolverState& state, CSSValue* value) |
| { |
| state.setTextOrientation(toCSSPrimitiveValue(value)->convertTo<TextOrientation>()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyVariable(StyleResolverState& state, CSSValue* value) |
| { |
| CSSCustomPropertyDeclaration* declaration = toCSSCustomPropertyDeclaration(value); |
| switch (declaration->id()) { |
| case CSSValueInitial: |
| state.style()->removeVariable(declaration->name()); |
| break; |
| |
| case CSSValueUnset: |
| case CSSValueInherit: { |
| state.style()->removeVariable(declaration->name()); |
| StyleVariableData* parentVariables = state.parentStyle()->variables(); |
| if (!parentVariables) |
| return; |
| CSSVariableData* value = parentVariables->getVariable(declaration->name()); |
| if (!value) |
| return; |
| state.style()->setVariable(declaration->name(), value); |
| break; |
| } |
| case CSSValueInternalVariableValue: |
| state.style()->setVariable(declaration->name(), declaration->value()); |
| break; |
| default: |
| ASSERT_NOT_REACHED(); |
| } |
| } |
| |
| void StyleBuilderFunctions::applyInheritCSSPropertyBaselineShift(StyleResolverState& state) |
| { |
| const SVGComputedStyle& parentSvgStyle = state.parentStyle()->svgStyle(); |
| EBaselineShift baselineShift = parentSvgStyle.baselineShift(); |
| SVGComputedStyle& svgStyle = state.style()->accessSVGStyle(); |
| svgStyle.setBaselineShift(baselineShift); |
| if (baselineShift == BS_LENGTH) |
| svgStyle.setBaselineShiftValue(parentSvgStyle.baselineShiftValue()); |
| } |
| |
| void StyleBuilderFunctions::applyValueCSSPropertyBaselineShift(StyleResolverState& state, CSSValue* value) |
| { |
| SVGComputedStyle& svgStyle = state.style()->accessSVGStyle(); |
| CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); |
| if (!primitiveValue->isValueID()) { |
| svgStyle.setBaselineShift(BS_LENGTH); |
| svgStyle.setBaselineShiftValue(StyleBuilderConverter::convertLength(state, *primitiveValue)); |
| return; |
| } |
| switch (primitiveValue->getValueID()) { |
| case CSSValueBaseline: |
| svgStyle.setBaselineShift(BS_LENGTH); |
| svgStyle.setBaselineShiftValue(Length(Fixed)); |
| return; |
| case CSSValueSub: |
| svgStyle.setBaselineShift(BS_SUB); |
| return; |
| case CSSValueSuper: |
| svgStyle.setBaselineShift(BS_SUPER); |
| return; |
| default: |
| ASSERT_NOT_REACHED(); |
| } |
| } |
| |
| } // namespace blink |