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();
}
Exemple #12
0
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);
            }
        }
    }
}