static PassRefPtrWillBeRawPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string) { ASSERT(!string.isEmpty()); if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) { // All properties accept the values of "initial" and "inherit". String lowerCaseString = string.lower(); if (lowerCaseString != "initial" && lowerCaseString != "inherit") return nullptr; // Parse initial/inherit shorthands using the CSSPropertyParser. if (shorthandForProperty(propertyId).length()) return nullptr; } CSSParserString cssString; cssString.init(string); CSSValueID valueID = cssValueKeywordID(cssString); if (!valueID) return nullptr; if (valueID == CSSValueInherit) return cssValuePool().createInheritedValue(); if (valueID == CSSValueInitial) return cssValuePool().createExplicitInitialValue(); if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID)) return cssValuePool().createIdentifierValue(valueID); return nullptr; }
static CSSValue* parseKeywordValue(CSSPropertyID propertyId, const String& string, CSSParserMode parserMode) { ASSERT(!string.isEmpty()); if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) { // All properties accept the values of "initial" and "inherit". if (!equalIgnoringASCIICase(string, "initial") && !equalIgnoringASCIICase(string, "inherit")) return nullptr; // Parse initial/inherit shorthands using the CSSPropertyParser. if (shorthandForProperty(propertyId).length()) return nullptr; // Descriptors do not support css wide keywords. if (CSSPropertyMetadata::isDescriptorOnly(propertyId)) return nullptr; } CSSValueID valueID = cssValueKeywordID(string); if (!valueID) return nullptr; if (valueID == CSSValueInherit) return CSSInheritedValue::create(); if (valueID == CSSValueInitial) return CSSInitialValue::create(); if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode)) return CSSIdentifierValue::create(valueID); return nullptr; }
void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value) { CSSVariableResolver resolver(state.style()->variables()); Vector<CSSParserToken> tokens; if (resolver.resolveTokenRange(value.variableDataValue()->tokens(), tokens)) { CSSParserContext context(HTMLStandardMode, 0); HeapVector<CSSProperty, 256> parsedProperties; // TODO: Non-shorthands should just call CSSPropertyParser::parseSingleValue if (CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::RuleType::Style)) { unsigned parsedPropertiesCount = parsedProperties.size(); for (unsigned i = 0; i < parsedPropertiesCount; ++i) StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedProperties[i].value()); return; } } RawPtr<CSSUnsetValue> unset = cssValuePool().createUnsetValue(); if (isShorthandProperty(id)) { StylePropertyShorthand shorthand = shorthandForProperty(id); for (unsigned i = 0; i < shorthand.length(); i++) StyleBuilder::applyProperty(shorthand.properties()[i], state, unset.get()); return; } StyleBuilder::applyProperty(id, state, unset.get()); }
bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID) { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; return removePropertiesInSet(shorthand.properties(), shorthand.length()); }
bool isExpandedShorthand(CSSPropertyID id) { // The system fonts bypass the normal style resolution by using RenderTheme, // thus we need to special case it here. FIXME: This is a violation of CSS 3 Fonts // as we should still be able to change the longhands. // DON'T ADD ANY SHORTHAND HERE UNLESS IT ISN'T ALWAYS EXPANDED AT PARSE TIME (which is wrong). if (id == CSSPropertyFont) return false; return shorthandForProperty(id).length(); }
bool StylePropertySet::shorthandIsImportant(CSSPropertyID propertyID) const { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!propertyIsImportant(shorthand.properties()[i])) return false; } return true; }
void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important) { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) { setProperty(CSSProperty(propertyID, prpValue, important)); return; } removePropertiesInSet(shorthand.properties(), shorthand.length()); RefPtrWillBeRawPtr<CSSValue> value = prpValue; for (unsigned i = 0; i < shorthand.length(); ++i) m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important)); }
bool isExpandedShorthandForAll(CSSPropertyID propertyId) { // FIXME: isExpandedShorthand says "font" is not an expanded shorthand, // but font is expanded to font-family, font-size, and so on. // StylePropertySerializer::asText should not generate css text like // "font: initial; font-family: initial;...". To avoid this, we need to // treat "font" as an expanded shorthand. // And while applying "all" property, we cannot apply "font" property // directly. This causes ASSERT crash, because StyleBuilder assume that // all given properties are not expanded shorthands. // "marker" has the same issue. if (propertyId == CSSPropertyMarker || propertyId == CSSPropertyFont) return true; return shorthandForProperty(propertyId).length(); }
// Returns an empty list if the property is not a shorthand, otherwise the list of longhands for parsing. const StylePropertyShorthand& parsingShorthandForProperty(CSSPropertyID propertyID) { switch (propertyID) { case CSSPropertyAnimation: return animationShorthandForParsing(); case CSSPropertyBorder: return borderShorthandForParsing(); case CSSPropertyWebkitAnimation: return webkitAnimationShorthandForParsing(); case CSSPropertyTransition: return transitionShorthandForParsing(); case CSSPropertyWebkitTransition: return webkitTransitionShorthandForParsing(); default: return shorthandForProperty(propertyID); } }
void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate& update, const Element* animatingElement, const ComputedStyle& style) { if (!animatingElement) return; if (animatingElement->document().printing() || animatingElement->document().wasPrinting()) return; ElementAnimations* elementAnimations = animatingElement->elementAnimations(); const TransitionMap* activeTransitions = elementAnimations ? &elementAnimations->cssAnimations().m_transitions : nullptr; const CSSTransitionData* transitionData = style.transitions(); #if ENABLE(ASSERT) // In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation. const bool animationStyleRecalc = false; #else // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation. const bool animationStyleRecalc = elementAnimations && elementAnimations->isAnimationStyleChange(); #endif BitArray<numCSSProperties> listedProperties; bool anyTransitionHadTransitionAll = false; const LayoutObject* layoutObject = animatingElement->layoutObject(); if (!animationStyleRecalc && style.display() != NONE && layoutObject && layoutObject->style() && transitionData) { const ComputedStyle& oldStyle = *layoutObject->style(); for (size_t i = 0; i < transitionData->propertyList().size(); ++i) { const CSSTransitionData::TransitionProperty& transitionProperty = transitionData->propertyList()[i]; if (transitionProperty.propertyType != CSSTransitionData::TransitionKnownProperty) continue; CSSPropertyID property = resolveCSSPropertyID(transitionProperty.unresolvedProperty); bool animateAll = property == CSSPropertyAll; if (animateAll) anyTransitionHadTransitionAll = true; const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::propertiesForTransitionAll() : shorthandForProperty(property); // If not a shorthand we only execute one iteration of this loop, and refer to the property directly. for (unsigned j = 0; !j || j < propertyList.length(); ++j) { CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : property; ASSERT(id >= firstCSSProperty); if (!animateAll) { if (CSSPropertyMetadata::isInterpolableProperty(id)) listedProperties.set(id - firstCSSProperty); else continue; } // FIXME: We should transition if an !important property changes even when an animation is running, // but this is a bit hard to do with the current applyMatchedProperties system. PropertyHandle property = PropertyHandle(id); if (!update.activeInterpolationsForAnimations().contains(property) && (!elementAnimations || !elementAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(property))) { calculateTransitionUpdateForProperty(id, *transitionData, i, oldStyle, style, activeTransitions, update, animatingElement); } } } } if (activeTransitions) { for (const auto& entry : *activeTransitions) { CSSPropertyID id = entry.key; if (!anyTransitionHadTransitionAll && !animationStyleRecalc && !listedProperties.get(id - firstCSSProperty)) { // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507 // ASSERT(animation.playStateInternal() == Animation::Finished || !(elementAnimations && elementAnimations->isAnimationStyleChange())); update.cancelTransition(id); } else if (entry.value.animation->finishedInternal()) { update.finishTransition(id); } } } }
bool isShorthandProperty(CSSPropertyID id) { return shorthandForProperty(id).length(); }
void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const Element* element, const RenderStyle& style) { if (!element) return; ActiveAnimations* activeAnimations = element->activeAnimations(); const TransitionMap* activeTransitions = activeAnimations ? &activeAnimations->cssAnimations().m_transitions : 0; const CSSTransitionData* transitionData = style.transitions(); #if ENABLE(ASSERT) // In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation. const bool animationStyleRecalc = false; #else // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation. const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange(); #endif BitArray<numCSSProperties> listedProperties; bool anyTransitionHadTransitionAll = false; const RenderObject* renderer = element->renderer(); if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && transitionData) { const RenderStyle& oldStyle = *renderer->style(); for (size_t i = 0; i < transitionData->propertyList().size(); ++i) { const CSSTransitionData::TransitionProperty& transitionProperty = transitionData->propertyList()[i]; CSSTransitionData::TransitionPropertyType mode = transitionProperty.propertyType; CSSPropertyID property = transitionProperty.propertyId; if (mode == CSSTransitionData::TransitionNone || mode == CSSTransitionData::TransitionUnknown) continue; bool animateAll = mode == CSSTransitionData::TransitionAll; ASSERT(animateAll || mode == CSSTransitionData::TransitionSingleProperty); if (animateAll) anyTransitionHadTransitionAll = true; const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(property); // If not a shorthand we only execute one iteration of this loop, and refer to the property directly. for (unsigned j = 0; !j || j < propertyList.length(); ++j) { CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : property; CSSPropertyID eventId = id; if (!animateAll) { id = propertyForAnimation(id); if (CSSPropertyMetadata::isAnimatableProperty(id)) listedProperties.set(id); else continue; } if (!update->activeInterpolationsForAnimations().contains(id) && (!activeAnimations || !activeAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(id))) { calculateTransitionUpdateForProperty(id, eventId, *transitionData, i, oldStyle, style, activeTransitions, update, element); } } } } if (activeTransitions) { for (TransitionMap::const_iterator iter = activeTransitions->begin(); iter != activeTransitions->end(); ++iter) { const AnimationPlayer& player = *iter->value.player; CSSPropertyID id = iter->key; if (player.finishedInternal() || (!anyTransitionHadTransitionAll && !animationStyleRecalc && !listedProperties.get(id))) { // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507 // ASSERT(player.finishedInternal() || !(activeAnimations && activeAnimations->isAnimationStyleChange())); update->cancelTransition(id); } } } }
static void computeCandidateTransitions(const RenderStyle& oldStyle, const RenderStyle& newStyle, CandidateTransitionMap& candidateMap, HashSet<CSSPropertyID>& listedProperties) { if (!newStyle.transitions()) return; for (size_t i = 0; i < newStyle.transitions()->size(); ++i) { const CSSAnimationData* anim = newStyle.transitions()->animation(i); CSSAnimationData::AnimationMode mode = anim->animationMode(); if (anim->duration() + anim->delay() <= 0 || mode == CSSAnimationData::AnimateNone) continue; bool animateAll = mode == CSSAnimationData::AnimateAll; ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty); const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(anim->property()); if (!propertyList.length()) { if (!CSSAnimations::isAnimatableProperty(anim->property())) continue; listedProperties.add(anim->property()); calculateCandidateTransitionForProperty(anim, anim->property(), oldStyle, newStyle, candidateMap); } else { for (unsigned i = 0; i < propertyList.length(); ++i) { CSSPropertyID id = propertyList.properties()[i]; if (!animateAll && !CSSAnimations::isAnimatableProperty(id)) continue; listedProperties.add(id); calculateCandidateTransitionForProperty(anim, id, oldStyle, newStyle, candidateMap); } } } }