bool ShadowStyleInterpolation::usesDefaultStyleInterpolation(const CSSValue& start, const CSSValue& end) { if (start.isValueList() && end.isValueList() && toCSSValueList(start).length() == toCSSValueList(end).length()) { const CSSValueList* startList = toCSSValueList(&start); const CSSValueList* endList = toCSSValueList(&end); for (size_t i = 0; i < toCSSValueList(start).length(); i++) { if (startList->item(i)->isShadowValue() && endList->item(i)->isShadowValue() && toCSSShadowValue(startList->item(i))->style != toCSSShadowValue(endList->item(i))->style) return true; } } return false; }
bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSValue& value) { // FIXME: should not require resolving styles for inherit/initial/unset. if (value.isCSSWideKeyword()) return true; if (value.isBasicShapeCircleValue()) return interpolationRequiresStyleResolve(toCSSBasicShapeCircleValue(value)); if (value.isBasicShapeEllipseValue()) return interpolationRequiresStyleResolve(toCSSBasicShapeEllipseValue(value)); if (value.isBasicShapePolygonValue()) return interpolationRequiresStyleResolve(toCSSBasicShapePolygonValue(value)); if (value.isBasicShapeInsetValue()) return interpolationRequiresStyleResolve(toCSSBasicShapeInsetValue(value)); if (value.isPrimitiveValue()) return interpolationRequiresStyleResolve(toCSSPrimitiveValue(value)); if (value.isQuadValue()) return interpolationRequiresStyleResolve(toCSSQuadValue(value)); if (value.isValueList()) return interpolationRequiresStyleResolve(toCSSValueList(value)); if (value.isValuePair()) return interpolationRequiresStyleResolve(toCSSValuePair(value)); if (value.isImageValue()) return interpolationRequiresStyleResolve(toCSSImageValue(value)); if (value.isShadowValue()) return interpolationRequiresStyleResolve(toCSSShadowValue(value)); if (value.isSVGDocumentValue()) return interpolationRequiresStyleResolve(toCSSSVGDocumentValue(value)); // FIXME: consider other custom types. return true; }
CSSValueList* CSSVariablesDeclaration::getParsedVariable(const String& variableName) { CSSValue* result = m_variablesMap.get(variableName).get(); if (result->isValueList()) return static_cast<CSSValueList*>(result); return 0; }
FontFace* FontFace::create(Document* document, const StyleRuleFontFace* fontFaceRule) { const StylePropertySet& properties = fontFaceRule->properties(); // Obtain the font-family property and the src property. Both must be defined. CSSValue* family = properties.getPropertyCSSValue(CSSPropertyFontFamily); if (!family || (!family->isFontFamilyValue() && !family->isPrimitiveValue())) return nullptr; CSSValue* src = properties.getPropertyCSSValue(CSSPropertySrc); if (!src || !src->isValueList()) return nullptr; FontFace* fontFace = new FontFace(document); if (fontFace->setFamilyValue(*family) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontStyle) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontWeight) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontStretch) && fontFace->setPropertyFromStyle(properties, CSSPropertyUnicodeRange) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontVariant) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontFeatureSettings) && fontFace->setPropertyFromStyle(properties, CSSPropertyFontDisplay) && !fontFace->family().isEmpty() && fontFace->traits().bitfield()) { fontFace->initCSSFontFace(document, src); return fontFace; } return nullptr; }
InterpolationValue CSSTransformInterpolationType::maybeConvertValue( const CSSValue& value, const StyleResolverState& state, ConversionCheckers& conversionCheckers) const { if (value.isValueList()) { CSSLengthArray lengthArray; for (const CSSValue* item : toCSSValueList(value)) { const CSSFunctionValue& transformFunction = toCSSFunctionValue(*item); if (transformFunction.functionType() == CSSValueMatrix || transformFunction.functionType() == CSSValueMatrix3d) { lengthArray.typeFlags.set(CSSPrimitiveValue::UnitTypePixels); continue; } for (const CSSValue* argument : transformFunction) { const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(*argument); if (!primitiveValue.isLength()) continue; primitiveValue.accumulateLengthArray(lengthArray); } } std::unique_ptr<InterpolationType::ConversionChecker> lengthUnitsChecker = LengthUnitsChecker::maybeCreate(std::move(lengthArray), state); if (lengthUnitsChecker) conversionCheckers.append(std::move(lengthUnitsChecker)); } TransformOperations transform; TransformBuilder::createTransformOperations( value, state.cssToLengthConversionData(), transform); return convertTransform(std::move(transform)); }
void CSSToStyleMap::mapNinePieceImage(StyleResolverState& state, CSSPropertyID property, CSSValue* value, NinePieceImage& image) { // If we're not a value list, then we are "none" and don't need to alter the empty image at all. if (!value || !value->isValueList()) return; // Retrieve the border image value. CSSValueList* borderImage = toCSSValueList(value); // Set the image (this kicks off the load). CSSPropertyID imageProperty; if (property == CSSPropertyWebkitBorderImage) imageProperty = CSSPropertyBorderImageSource; else if (property == CSSPropertyWebkitMaskBoxImage) imageProperty = CSSPropertyWebkitMaskBoxImageSource; else imageProperty = property; for (unsigned i = 0 ; i < borderImage->length() ; ++i) { CSSValue* current = borderImage->item(i); if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue()) image.setImage(state.styleImage(imageProperty, current)); else if (current->isBorderImageSliceValue()) mapNinePieceImageSlice(state, current, image); else if (current->isValueList()) { CSSValueList* slashList = toCSSValueList(current); size_t length = slashList->length(); // Map in the image slices. if (length && slashList->item(0)->isBorderImageSliceValue()) mapNinePieceImageSlice(state, slashList->item(0), image); // Map in the border slices. if (length > 1) image.setBorderSlices(mapNinePieceImageQuad(state, slashList->item(1))); // Map in the outset. if (length > 2) image.setOutset(mapNinePieceImageQuad(state, slashList->item(2))); } else if (current->isPrimitiveValue()) { // Set the appropriate rules for stretch/round/repeat of the slices. mapNinePieceImageRepeat(state, current, image); } } if (property == CSSPropertyWebkitBorderImage) { // We have to preserve the legacy behavior of -webkit-border-image and make the border slices // also set the border widths. We don't need to worry about percentages, since we don't even support // those on real borders yet. if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed()) state.style()->setBorderTopWidth(image.borderSlices().top().length().value()); if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed()) state.style()->setBorderRightWidth(image.borderSlices().right().length().value()); if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed()) state.style()->setBorderBottomWidth(image.borderSlices().bottom().length().value()); if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed()) state.style()->setBorderLeftWidth(image.borderSlices().left().length().value()); } }
FontFace* FontFace::create(ExecutionContext* context, const AtomicString& family, const String& source, const FontFaceDescriptors& descriptors) { FontFace* fontFace = new FontFace(context, family, descriptors); CSSValue* src = parseCSSValue(toDocument(context), source, CSSPropertySrc); if (!src || !src->isValueList()) fontFace->setError(DOMException::create(SyntaxError, "The source provided ('" + source + "') could not be parsed as a value list.")); fontFace->initCSSFontFace(toDocument(context), src); return fontFace; }
PassRefPtr<FilterStyleInterpolation::FilterListStyleInterpolation> FilterStyleInterpolation::maybeCreateList(const CSSValue& start, const CSSValue& end, CSSPropertyID property) { if (start.isCSSWideKeyword() || end.isCSSWideKeyword()) return nullptr; ASSERT(start.isValueList() || toCSSPrimitiveValue(start).getValueID() == CSSValueNone); ASSERT(end.isValueList() || toCSSPrimitiveValue(end).getValueID() == CSSValueNone); if (!start.isValueList() && !end.isValueList()) return nullptr; return maybeCreateFromList( start.isValueList() ? toCSSValueList(start) : *CSSValueList::createSpaceSeparated(), end.isValueList() ? toCSSValueList(end) : *CSSValueList::createSpaceSeparated(), property); }
static bool computationallyIndependent(const CSSValue& value) { DCHECK(!value.isCSSWideKeyword()); if (value.isVariableReferenceValue()) return !toCSSVariableReferenceValue(value) .variableDataValue() ->needsVariableResolution(); if (value.isValueList()) { for (const CSSValue* innerValue : toCSSValueList(value)) { if (!computationallyIndependent(*innerValue)) return false; } return true; } if (value.isPrimitiveValue()) { const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); if (!primitiveValue.isLength() && !primitiveValue.isCalculatedPercentageWithLength()) return true; CSSPrimitiveValue::CSSLengthArray lengthArray; primitiveValue.accumulateLengthArray(lengthArray); for (size_t i = 0; i < lengthArray.values.size(); i++) { if (lengthArray.typeFlags.get(i) && i != CSSPrimitiveValue::UnitTypePixels && i != CSSPrimitiveValue::UnitTypePercentage) return false; } return true; } // TODO(timloh): Images and transform-function values can also contain // lengths. return true; }
void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& ruleData) { const StylePropertySet& propertySet = ruleData.rule()->properties(); int propertyIndex = propertySet.findPropertyIndex(CSSPropertyContent); if (propertyIndex == -1) return; StylePropertySet::PropertyReference contentProperty = propertySet.propertyAt(propertyIndex); CSSValue* contentValue = contentProperty.value(); if (!contentValue->isValueList()) return; for (auto& item : toCSSValueList(*contentValue)) { if (!item->isFunctionValue()) continue; CSSFunctionValue* functionValue = toCSSFunctionValue(item.get()); if (functionValue->functionType() != CSSValueAttr) continue; ensureAttributeInvalidationSet(AtomicString(toCSSPrimitiveValue(functionValue->item(0))->getStringValue())).setInvalidatesSelf(); } }
TransformOperations TransformBuilder::createTransformOperations( const CSSValue& inValue, const CSSToLengthConversionData& conversionData) { TransformOperations operations; if (!inValue.isValueList()) { DCHECK_EQ(toCSSIdentifierValue(inValue).getValueID(), CSSValueNone); return operations; } float zoomFactor = conversionData.zoom(); for (auto& value : toCSSValueList(inValue)) { const CSSFunctionValue* transformValue = toCSSFunctionValue(value.get()); TransformOperation::OperationType transformType = getTransformOperationType(transformValue->functionType()); const CSSPrimitiveValue& firstValue = toCSSPrimitiveValue(transformValue->item(0)); switch (transformType) { case TransformOperation::Scale: case TransformOperation::ScaleX: case TransformOperation::ScaleY: { double sx = 1.0; double sy = 1.0; if (transformType == TransformOperation::ScaleY) { sy = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); if (transformType != TransformOperation::ScaleX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); sy = secondValue.getDoubleValue(); } else { sy = sx; } } } operations.operations().append( ScaleTransformOperation::create(sx, sy, 1.0, transformType)); break; } case TransformOperation::ScaleZ: case TransformOperation::Scale3D: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transformType == TransformOperation::ScaleZ) { sz = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); sy = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); sz = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); } operations.operations().append( ScaleTransformOperation::create(sx, sy, sz, transformType)); break; } case TransformOperation::Translate: case TransformOperation::TranslateX: case TransformOperation::TranslateY: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); if (transformType == TransformOperation::TranslateY) ty = convertToFloatLength(firstValue, conversionData); else { tx = convertToFloatLength(firstValue, conversionData); if (transformType != TransformOperation::TranslateX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); ty = convertToFloatLength(secondValue, conversionData); } } } operations.operations().append( TranslateTransformOperation::create(tx, ty, 0, transformType)); break; } case TransformOperation::TranslateZ: case TransformOperation::Translate3D: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); double tz = 0; if (transformType == TransformOperation::TranslateZ) { tz = firstValue.computeLength<double>(conversionData); } else { tx = convertToFloatLength(firstValue, conversionData); ty = convertToFloatLength( toCSSPrimitiveValue(transformValue->item(1)), conversionData); tz = toCSSPrimitiveValue(transformValue->item(2)) .computeLength<double>(conversionData); } operations.operations().append( TranslateTransformOperation::create(tx, ty, tz, transformType)); break; } case TransformOperation::RotateX: case TransformOperation::RotateY: case TransformOperation::RotateZ: { double angle = firstValue.computeDegrees(); if (transformValue->length() == 1) { double x = transformType == TransformOperation::RotateX; double y = transformType == TransformOperation::RotateY; double z = transformType == TransformOperation::RotateZ; operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); } else { // For SVG 'transform' attributes we generate 3-argument rotate() // functions. DCHECK_EQ(transformValue->length(), 3u); const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); operations.operations().append( RotateAroundOriginTransformOperation::create( angle, secondValue.computeLength<double>(conversionData), thirdValue.computeLength<double>(conversionData))); } break; } case TransformOperation::Rotate3D: { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); const CSSPrimitiveValue& fourthValue = toCSSPrimitiveValue(transformValue->item(3)); double x = firstValue.getDoubleValue(); double y = secondValue.getDoubleValue(); double z = thirdValue.getDoubleValue(); double angle = fourthValue.computeDegrees(); operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); break; } case TransformOperation::Skew: case TransformOperation::SkewX: case TransformOperation::SkewY: { double angleX = 0; double angleY = 0; double angle = firstValue.computeDegrees(); if (transformType == TransformOperation::SkewY) angleY = angle; else { angleX = angle; if (transformType == TransformOperation::Skew) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); angleY = secondValue.computeDegrees(); } } } operations.operations().append( SkewTransformOperation::create(angleX, angleY, transformType)); break; } case TransformOperation::Matrix: { double a = firstValue.getDoubleValue(); double b = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); double c = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); double d = toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(); double e = zoomFactor * toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(); double f = zoomFactor * toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(); operations.operations().append( MatrixTransformOperation::create(a, b, c, d, e, f)); break; } case TransformOperation::Matrix3D: { TransformationMatrix matrix( toCSSPrimitiveValue(transformValue->item(0)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(6)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(7)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(8)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(9)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(10)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(11)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(12)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(13)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(14)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(15)).getDoubleValue()); matrix.zoom(zoomFactor); operations.operations().append( Matrix3DTransformOperation::create(matrix)); break; } case TransformOperation::Perspective: { double p = firstValue.computeLength<double>(conversionData); ASSERT(p >= 0); operations.operations().append( PerspectiveTransformOperation::create(p)); break; } default: ASSERT_NOT_REACHED(); break; } } return operations; }
static PassRefPtr<CustomFilterOperation> createCustomFilterOperationWithInlineSyntax(CSSFilterValue* filterValue, StyleResolverState& state) { CSSValue* shadersValue = filterValue->itemWithoutBoundsCheck(0); ASSERT_WITH_SECURITY_IMPLICATION(shadersValue->isValueList()); CSSValueList* shadersList = toCSSValueList(shadersValue); unsigned shadersListLength = shadersList->length(); ASSERT(shadersListLength); CSSShaderValue* vertexShader = 0; CSSShaderValue* fragmentShader = 0; if (shadersList->itemWithoutBoundsCheck(0)->isShaderValue()) vertexShader = toCSSShaderValue(shadersList->itemWithoutBoundsCheck(0)); CustomFilterProgramType programType = ProgramTypeBlendsElementTexture; CustomFilterProgramMixSettings mixSettings; if (shadersListLength > 1) { CSSValue* fragmentShaderOrMixFunction = shadersList->itemWithoutBoundsCheck(1); if (fragmentShaderOrMixFunction->isMixFunctionValue()) { CSSMixFunctionValue* mixFunction = toCSSMixFunctionValue(fragmentShaderOrMixFunction); CSSValueListIterator iterator(mixFunction); ASSERT(mixFunction->length()); if (iterator.value()->isShaderValue()) fragmentShader = toCSSShaderValue(iterator.value()); iterator.advance(); ASSERT(mixFunction->length() <= 3); while (iterator.hasMore()) { CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(iterator.value()); if (CSSParser::isBlendMode(primitiveValue->getValueID())) mixSettings.blendMode = *primitiveValue; else if (CSSParser::isCompositeOperator(primitiveValue->getValueID())) mixSettings.compositeOperator = *primitiveValue; else ASSERT_NOT_REACHED(); iterator.advance(); } } else { programType = ProgramTypeNoElementTexture; if (fragmentShaderOrMixFunction->isShaderValue()) fragmentShader = toCSSShaderValue(fragmentShaderOrMixFunction); } } if (!vertexShader && !fragmentShader) return 0; unsigned meshRows = 1; unsigned meshColumns = 1; CustomFilterMeshType meshType = MeshTypeAttached; CSSValue* parametersValue = 0; if (filterValue->length() > 1) { CSSValueListIterator iterator(filterValue->itemWithoutBoundsCheck(1)); // The second value might be the mesh box or the list of parameters: // If it starts with a number or any of the mesh-box identifiers it is // the mesh-box list, if not it means it is the parameters list. if (iterator.hasMore() && iterator.isPrimitiveValue()) { CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(iterator.value()); if (primitiveValue->isNumber()) { // If only one integer value is specified, it will set both // the rows and the columns. meshColumns = meshRows = primitiveValue->getIntValue(); iterator.advance(); // Try to match another number for the rows. if (iterator.hasMore() && iterator.isPrimitiveValue()) { CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(iterator.value()); if (primitiveValue->isNumber()) { meshRows = primitiveValue->getIntValue(); iterator.advance(); } } } } if (iterator.hasMore() && iterator.isPrimitiveValue()) { CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(iterator.value()); if (primitiveValue->getValueID() == CSSValueDetached) { meshType = MeshTypeDetached; iterator.advance(); } } if (!iterator.index()) { // If no value was consumed from the mesh value, then it is just a parameter list, meaning that we end up // having just two CSSListValues: list of shaders and list of parameters. ASSERT(filterValue->length() == 2); parametersValue = filterValue->itemWithoutBoundsCheck(1); } } if (filterValue->length() > 2 && !parametersValue) parametersValue = filterValue->itemWithoutBoundsCheck(2); CustomFilterParameterList parameterList; if (parametersValue && !parseCustomFilterParameterList(parametersValue, parameterList, state)) return 0; RefPtr<CustomFilterProgram> program = createCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType, state); return CustomFilterOperation::create(program.release(), parameterList, meshRows, meshColumns, meshType); }