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(); } }
FilterOperations FilterOperationResolver::createFilterOperations(StyleResolverState& state, const CSSValue& inValue) { FilterOperations operations; if (inValue.isPrimitiveValue()) { ASSERT(toCSSPrimitiveValue(inValue).getValueID() == CSSValueNone); return operations; } const CSSToLengthConversionData& conversionData = state.cssToLengthConversionData(); for (auto& currValue : toCSSValueList(inValue)) { CSSFunctionValue* filterValue = toCSSFunctionValue(currValue.get()); FilterOperation::OperationType operationType = filterOperationForType(filterValue->functionType()); countFilterUse(operationType, state.document()); ASSERT(filterValue->length() <= 1); if (operationType == FilterOperation::REFERENCE) { CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(filterValue->item(0)); KURL url = state.document().completeURL(svgDocumentValue->url()); RawPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier())); if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) { if (!svgDocumentValue->loadRequested()) state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue); else if (svgDocumentValue->cachedSVGDocument()) ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument()))); } operations.operations().append(operation); continue; } CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->item(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->item(0)) : nullptr; switch (filterValue->functionType()) { case CSSValueGrayscale: case CSSValueSepia: case CSSValueSaturate: { double amount = 1; if (filterValue->length() == 1) { amount = firstValue->getDoubleValue(); if (firstValue->isPercentage()) amount /= 100; } operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); break; } case CSSValueHueRotate: { double angle = 0; if (filterValue->length() == 1) angle = firstValue->computeDegrees(); operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType)); break; } case CSSValueInvert: case CSSValueBrightness: case CSSValueContrast: case CSSValueOpacity: { double amount = (filterValue->functionType() == CSSValueBrightness) ? 0 : 1; if (filterValue->length() == 1) { amount = firstValue->getDoubleValue(); if (firstValue->isPercentage()) amount /= 100; } operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); break; } case CSSValueBlur: { Length stdDeviation = Length(0, Fixed); if (filterValue->length() >= 1) stdDeviation = firstValue->convertToLength(conversionData); operations.operations().append(BlurFilterOperation::create(stdDeviation)); break; } case CSSValueDropShadow: { CSSShadowValue* item = toCSSShadowValue(filterValue->item(0)); IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData)); int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0; Color shadowColor = Color::black; if (item->color) shadowColor = state.document().textLinkColors().colorFromCSSValue(*item->color, state.style()->color()); operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor)); break; } default: ASSERT_NOT_REACHED(); break; } } return operations; }
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.get())), didSet); didSet = true; } else if (item->isImageSetValue()) { state.style()->setContent(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(item.get())), didSet); didSet = true; } if (item->isImageValue()) { state.style()->setContent(state.elementStyleResources().cachedOrPendingFromValue(state.document(), CSSPropertyContent, toCSSImageValue(item.get())), 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(toCSSPrimitiveValue(functionValue->item(0))->getStringValue()), nullAtom); const AtomicString& value = state.element()->getAttribute(attr); state.style()->setContent(value.isNull() ? emptyString() : value.string(), didSet); didSet = true; } if (!item->isPrimitiveValue()) continue; CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item.get()); if (contentValue->isString()) { state.style()->setContent(contentValue->getStringValue().impl(), didSet); didSet = true; } else { switch (contentValue->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(); }