blob: 165275d7ec3760a72d17ce4c51afc0c4fda7136f [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/values_equivalent.h"
#include "third_party/blink/renderer/core/animation/timeline_offset.h"
#include "third_party/blink/renderer/core/css/css_content_distribution_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_initial_value.h"
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/css/css_pending_system_font_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
#include "third_party/blink/renderer/core/css/css_property_value.h"
#include "third_party/blink/renderer/core/css/css_value_pair.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_fast_paths.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
#include "third_party/blink/renderer/core/css/parser/font_variant_alternates_parser.h"
#include "third_party/blink/renderer/core/css/parser/font_variant_east_asian_parser.h"
#include "third_party/blink/renderer/core/css/parser/font_variant_ligatures_parser.h"
#include "third_party/blink/renderer/core/css/parser/font_variant_numeric_parser.h"
#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
#include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
#include "third_party/blink/renderer/core/css/properties/longhand.h"
#include "third_party/blink/renderer/core/css/properties/longhands.h"
#include "third_party/blink/renderer/core/css/properties/shorthands.h"
#include "third_party/blink/renderer/core/css/zoom_adjusted_pixel_value.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
// Implementations of methods in Shorthand subclasses that aren't generated.
namespace blink {
namespace css_shorthand {
namespace {
// New animation-* properties are "reset only":
// https://github.com/w3c/csswg-drafts/issues/6946#issuecomment-1233190360
bool IsResetOnlyAnimationProperty(CSSPropertyID property) {
switch (property) {
case CSSPropertyID::kAnimationDelayEnd:
case CSSPropertyID::kAnimationTimeline:
case CSSPropertyID::kAnimationRangeStart:
case CSSPropertyID::kAnimationRangeEnd:
return true;
default:
return false;
}
}
// Legacy parsing allows <string>s for animation-name.
CSSValue* ConsumeAnimationValue(CSSPropertyID property,
CSSParserTokenRange& range,
const CSSParserContext& context,
bool use_legacy_parsing) {
switch (property) {
case CSSPropertyID::kAnimationDelay:
DCHECK(!RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled());
return css_parsing_utils::ConsumeTime(
range, context, CSSPrimitiveValue::ValueRange::kAll);
case CSSPropertyID::kAnimationDelayStart:
DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled());
return css_parsing_utils::ConsumeAnimationDelay(range, context);
case CSSPropertyID::kAnimationDelayEnd:
// New animation-* properties are "reset only", see
// IsResetOnlyAnimationProperty.
//
// Returning nullptr here means that AnimationDelayEnd::InitialValue will
// be used.
DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled());
return nullptr;
case CSSPropertyID::kAnimationDirection:
return css_parsing_utils::ConsumeIdent<
CSSValueID::kNormal, CSSValueID::kAlternate, CSSValueID::kReverse,
CSSValueID::kAlternateReverse>(range);
case CSSPropertyID::kAnimationDuration:
return css_parsing_utils::ConsumeAnimationDuration(range, context);
case CSSPropertyID::kAnimationFillMode:
return css_parsing_utils::ConsumeIdent<
CSSValueID::kNone, CSSValueID::kForwards, CSSValueID::kBackwards,
CSSValueID::kBoth>(range);
case CSSPropertyID::kAnimationIterationCount:
return css_parsing_utils::ConsumeAnimationIterationCount(range, context);
case CSSPropertyID::kAnimationName:
return css_parsing_utils::ConsumeAnimationName(range, context,
use_legacy_parsing);
case CSSPropertyID::kAnimationPlayState:
return css_parsing_utils::ConsumeIdent<CSSValueID::kRunning,
CSSValueID::kPaused>(range);
case CSSPropertyID::kAnimationTimingFunction:
return css_parsing_utils::ConsumeAnimationTimingFunction(range, context);
case CSSPropertyID::kAnimationTimeline:
case CSSPropertyID::kAnimationRangeStart:
case CSSPropertyID::kAnimationRangeEnd:
// New animation-* properties are "reset only", see kAnimationDelayEnd.
DCHECK(RuntimeEnabledFeatures::ScrollTimelineEnabled());
return nullptr;
default:
NOTREACHED();
return nullptr;
}
}
bool ParseAnimationShorthand(const StylePropertyShorthand& shorthand,
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) {
const unsigned longhand_count = shorthand.length();
HeapVector<Member<CSSValueList>, css_parsing_utils::kMaxNumAnimationLonghands>
longhands(longhand_count);
if (!css_parsing_utils::ConsumeAnimationShorthand(
shorthand, longhands, ConsumeAnimationValue,
IsResetOnlyAnimationProperty, range, context,
local_context.UseAliasParsing())) {
return false;
}
for (unsigned i = 0; i < longhand_count; ++i) {
css_parsing_utils::AddProperty(
shorthand.properties()[i]->PropertyID(), shorthand.id(), *longhands[i],
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
}
return range.AtEnd();
}
const CSSValue* CSSValueFromComputedAnimation(
const StylePropertyShorthand& shorthand,
const CSSAnimationData* animation_data) {
if (animation_data) {
// The shorthand can not represent the following properties if they have
// non-initial values. This is because they are always reset to their
// initial value by the shorthand.
if (!animation_data->HasSingleInitialTimeline() ||
!animation_data->HasSingleInitialDelayEnd() ||
!animation_data->HasSingleInitialRangeStart() ||
!animation_data->HasSingleInitialRangeEnd()) {
return nullptr;
}
CSSValueList* animations_list = CSSValueList::CreateCommaSeparated();
for (wtf_size_t i = 0; i < animation_data->NameList().size(); ++i) {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*ComputedStyleUtils::ValueForAnimationDuration(
CSSTimingData::GetRepeated(animation_data->DurationList(), i),
/* resolve_auto_to_zero */ true));
list->Append(*ComputedStyleUtils::ValueForAnimationTimingFunction(
CSSTimingData::GetRepeated(animation_data->TimingFunctionList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationDelayStart(
CSSTimingData::GetRepeated(animation_data->DelayStartList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationIterationCount(
CSSTimingData::GetRepeated(animation_data->IterationCountList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationDirection(
CSSTimingData::GetRepeated(animation_data->DirectionList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationFillMode(
CSSTimingData::GetRepeated(animation_data->FillModeList(), i)));
list->Append(*ComputedStyleUtils::ValueForAnimationPlayState(
CSSTimingData::GetRepeated(animation_data->PlayStateList(), i)));
list->Append(*MakeGarbageCollected<CSSCustomIdentValue>(
animation_data->NameList()[i]));
animations_list->Append(*list);
}
return animations_list;
}
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
// animation-name default value.
list->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
list->Append(*ComputedStyleUtils::ValueForAnimationDuration(
CSSAnimationData::InitialDuration(),
/* resolve_auto_to_zero */ true));
list->Append(*ComputedStyleUtils::ValueForAnimationTimingFunction(
CSSAnimationData::InitialTimingFunction()));
list->Append(*ComputedStyleUtils::ValueForAnimationDelayStart(
CSSAnimationData::InitialDelayStart()));
list->Append(*ComputedStyleUtils::ValueForAnimationIterationCount(
CSSAnimationData::InitialIterationCount()));
list->Append(*ComputedStyleUtils::ValueForAnimationDirection(
CSSAnimationData::InitialDirection()));
list->Append(*ComputedStyleUtils::ValueForAnimationFillMode(
CSSAnimationData::InitialFillMode()));
list->Append(*ComputedStyleUtils::ValueForAnimationPlayState(
CSSAnimationData::InitialPlayState()));
return list;
}
bool ParseBackgroundOrMaskPosition(
const StylePropertyShorthand& shorthand,
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
std::optional<WebFeature> three_value_position,
HeapVector<CSSPropertyValue, 64>& properties) {
const CSSValue* result_x = nullptr;
const CSSValue* result_y = nullptr;
if (!css_parsing_utils::ConsumeBackgroundPosition(
range, context, css_parsing_utils::UnitlessQuirk::kAllow,
three_value_position, result_x, result_y) ||
!range.AtEnd()) {
return false;
}
const CSSProperty** longhands = shorthand.properties();
DCHECK_EQ(2u, shorthand.length());
css_parsing_utils::AddProperty(
longhands[0]->PropertyID(), shorthand.id(), *result_x, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
longhands[1]->PropertyID(), shorthand.id(), *result_y, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
} // namespace
bool Animation::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseAnimationShorthand(animationShorthand(), important, range,
context, local_context, properties);
}
const CSSValue* Animation::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return CSSValueFromComputedAnimation(animationShorthand(),
style.Animations());
}
bool AlternativeAnimationWithTimeline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseAnimationShorthand(alternativeAnimationWithTimelineShorthand(),
important, range, context, local_context,
properties);
}
const CSSValue*
AlternativeAnimationWithTimeline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return CSSValueFromComputedAnimation(
alternativeAnimationWithTimelineShorthand(), style.Animations());
}
bool AlternativeAnimationWithDelayStartEnd::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseAnimationShorthand(
alternativeAnimationWithDelayStartEndShorthand(), important, range,
context, local_context, properties);
}
const CSSValue*
AlternativeAnimationWithDelayStartEnd::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return CSSValueFromComputedAnimation(
alternativeAnimationWithDelayStartEndShorthand(), style.Animations());
}
namespace {
// Consume a single <animation-delay-start> and a single
// <animation-delay-end>, and append the result to `start_list` and
// `end_list` respectively.
bool ConsumeAnimationDelayItemInto(CSSParserTokenRange& range,
const CSSParserContext& context,
CSSValueList* start_list,
CSSValueList* end_list) {
using css_parsing_utils::ConsumeAnimationDelay;
const CSSValue* start_delay = ConsumeAnimationDelay(range, context);
const CSSValue* end_delay = ConsumeAnimationDelay(range, context);
if (!start_delay) {
return false;
}
// If the <animation-delay-end> value is omitted, it is set to zero.
//
// https://drafts.csswg.org/scroll-animations-1/#propdef-animation-delay
if (!end_delay) {
end_delay = CSSNumericLiteralValue::Create(
0, CSSPrimitiveValue::UnitType::kSeconds);
}
DCHECK(start_delay);
DCHECK(end_delay);
start_list->Append(*start_delay);
end_list->Append(*end_delay);
return true;
}
// Consume a single <animation-range-start> and a single
// <animation-range-end>, and append the result to `start_list` and
// `end_list` respectively.
bool ConsumeAnimationRangeItemInto(CSSParserTokenRange& range,
const CSSParserContext& context,
CSSValueList* start_list,
CSSValueList* end_list) {
using css_parsing_utils::ConsumeAnimationRange;
using css_parsing_utils::ConsumeTimelineRangeName;
const CSSValue* start_range =
ConsumeAnimationRange(range, context, /* default_offset_percent */ 0.0);
const CSSValue* end_range =
ConsumeAnimationRange(range, context, /* default_offset_percent */ 100.0);
// The form 'name X' must expand to 'name X name 100%'.
//
// https://github.com/w3c/csswg-drafts/issues/8438
if (start_range && start_range->IsValueList() && !end_range) {
CSSValueList* implied_end = CSSValueList::CreateSpaceSeparated();
const CSSValue& name = To<CSSValueList>(start_range)->First();
if (name.IsIdentifierValue()) {
implied_end->Append(name);
end_range = implied_end;
}
}
if (!start_range) {
return false;
}
if (!end_range) {
end_range = CSSIdentifierValue::Create(CSSValueID::kNormal);
}
DCHECK(start_range);
DCHECK(end_range);
start_list->Append(*start_range);
end_list->Append(*end_range);
return true;
}
} // namespace
bool AlternativeAnimationDelay::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled());
using css_parsing_utils::AddProperty;
using css_parsing_utils::ConsumeCommaIncludingWhitespace;
using css_parsing_utils::IsImplicitProperty;
const StylePropertyShorthand shorthand = alternativeAnimationDelayShorthand();
DCHECK_EQ(2u, shorthand.length());
DCHECK_EQ(&GetCSSPropertyAnimationDelayStart(), shorthand.properties()[0]);
DCHECK_EQ(&GetCSSPropertyAnimationDelayEnd(), shorthand.properties()[1]);
CSSValueList* start_list = CSSValueList::CreateCommaSeparated();
CSSValueList* end_list = CSSValueList::CreateCommaSeparated();
do {
if (!ConsumeAnimationDelayItemInto(range, context, start_list, end_list)) {
return false;
}
} while (ConsumeCommaIncludingWhitespace(range));
DCHECK(start_list->length());
DCHECK(end_list->length());
DCHECK_EQ(start_list->length(), end_list->length());
AddProperty(CSSPropertyID::kAnimationDelayStart,
CSSPropertyID::kAlternativeAnimationDelay, *start_list, important,
IsImplicitProperty::kNotImplicit, properties);
AddProperty(CSSPropertyID::kAnimationDelayEnd,
CSSPropertyID::kAlternativeAnimationDelay, *end_list, important,
IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
const CSSValue* AlternativeAnimationDelay::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const Vector<Timing::Delay>& delay_start_list =
style.Animations()
? style.Animations()->DelayStartList()
: Vector<Timing::Delay>{CSSAnimationData::InitialDelayStart()};
const Vector<Timing::Delay>& delay_end_list =
style.Animations()
? style.Animations()->DelayEndList()
: Vector<Timing::Delay>{CSSAnimationData::InitialDelayEnd()};
if (delay_start_list.size() != delay_end_list.size()) {
return nullptr;
}
auto* outer_list = CSSValueList::CreateCommaSeparated();
for (wtf_size_t i = 0; i < delay_start_list.size(); ++i) {
const Timing::Delay& end = delay_end_list[i];
auto* inner_list = CSSValueList::CreateSpaceSeparated();
inner_list->Append(
*ComputedStyleUtils::ValueForAnimationDelayStart(delay_start_list[i]));
if (end != CSSTimingData::InitialDelayEnd()) {
inner_list->Append(
*ComputedStyleUtils::ValueForAnimationDelayEnd(delay_end_list[i]));
}
outer_list->Append(*inner_list);
}
return outer_list;
}
bool AnimationRange::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK(RuntimeEnabledFeatures::ScrollTimelineEnabled());
using css_parsing_utils::AddProperty;
using css_parsing_utils::ConsumeCommaIncludingWhitespace;
using css_parsing_utils::IsImplicitProperty;
const StylePropertyShorthand shorthand = animationRangeShorthand();
DCHECK_EQ(2u, shorthand.length());
DCHECK_EQ(&GetCSSPropertyAnimationRangeStart(), shorthand.properties()[0]);
DCHECK_EQ(&GetCSSPropertyAnimationRangeEnd(), shorthand.properties()[1]);
CSSValueList* start_list = CSSValueList::CreateCommaSeparated();
CSSValueList* end_list = CSSValueList::CreateCommaSeparated();
do {
if (!ConsumeAnimationRangeItemInto(range, context, start_list, end_list)) {
return false;
}
} while (ConsumeCommaIncludingWhitespace(range));
DCHECK(start_list->length());
DCHECK(end_list->length());
DCHECK_EQ(start_list->length(), end_list->length());
AddProperty(CSSPropertyID::kAnimationRangeStart,
CSSPropertyID::kAnimationRange, *start_list, important,
IsImplicitProperty::kNotImplicit, properties);
AddProperty(CSSPropertyID::kAnimationRangeEnd, CSSPropertyID::kAnimationRange,
*end_list, important, IsImplicitProperty::kNotImplicit,
properties);
return range.AtEnd();
}
const CSSValue* AnimationRange::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const Vector<std::optional<TimelineOffset>>& range_start_list =
style.Animations() ? style.Animations()->RangeStartList()
: Vector<std::optional<TimelineOffset>>{
CSSAnimationData::InitialRangeStart()};
const Vector<std::optional<TimelineOffset>>& range_end_list =
style.Animations() ? style.Animations()->RangeEndList()
: Vector<std::optional<TimelineOffset>>{
CSSAnimationData::InitialRangeEnd()};
if (range_start_list.size() != range_end_list.size()) {
return nullptr;
}
TimelineOffset default_start(TimelineOffset::NamedRange::kNone,
Length::Percent(0));
TimelineOffset default_end(TimelineOffset::NamedRange::kNone,
Length::Percent(100));
auto* outer_list = CSSValueList::CreateCommaSeparated();
for (wtf_size_t i = 0; i < range_start_list.size(); ++i) {
const std::optional<TimelineOffset>& start = range_start_list[i];
const std::optional<TimelineOffset>& end = range_end_list[i];
auto* inner_list = CSSValueList::CreateSpaceSeparated();
inner_list->Append(
*ComputedStyleUtils::ValueForAnimationRangeStart(start, style));
// The form "name X name 100%" must contract to "name X".
//
// https://github.com/w3c/csswg-drafts/issues/8438
TimelineOffset omittable_end(start.value_or(default_start).name,
Length::Percent(100));
if (end.value_or(default_end) != omittable_end) {
inner_list->Append(
*ComputedStyleUtils::ValueForAnimationRangeEnd(end, style));
}
outer_list->Append(*inner_list);
}
return outer_list;
}
bool Background::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ParseBackgroundOrMask(important, range, context,
local_context, properties);
}
const CSSValue* Background::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForBackgroundShorthand(
style, layout_object, allow_visited_style, value_phase);
}
bool BackgroundPosition::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseBackgroundOrMaskPosition(
backgroundPositionShorthand(), important, range, context,
WebFeature::kThreeValuedPositionBackground, properties);
}
const CSSValue* BackgroundPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::BackgroundPositionOrMaskPosition(
*this, style, &style.BackgroundLayers());
}
bool BorderBlockColor::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderBlockColorShorthand(), important, context, range, properties);
}
const CSSValue* BorderBlockColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderBlockColorShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* width = nullptr;
const CSSValue* style = nullptr;
const CSSValue* color = nullptr;
if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
color)) {
return false;
};
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderBlockWidth, *width, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderBlockStyle, *style, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderBlockColor, *color, important, properties);
return range.AtEnd();
}
const CSSValue* BorderBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* value_start =
GetCSSPropertyBorderBlockStart().CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
const CSSValue* value_end =
GetCSSPropertyBorderBlockEnd().CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
if (!base::ValuesEquivalent(value_start, value_end)) {
return nullptr;
}
return value_start;
}
bool BorderBlockEnd::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderBlockEndShorthand(), important, context, range, properties);
}
bool BorderBlockStart::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderBlockStartShorthand(), important, context, range, properties);
}
bool BorderBlockStyle::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderBlockStyleShorthand(), important, context, range, properties);
}
const CSSValue* BorderBlockStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderBlockStyleShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderBlockWidth::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderBlockWidthShorthand(), important, context, range, properties);
}
const CSSValue* BorderBlockWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderBlockWidthShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderBottom::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderBottomShorthand(), important, context, range, properties);
}
const CSSValue* BorderBottom::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
borderBottomShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderColor::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
borderColorShorthand(), important, context, range, properties);
}
const CSSValue* BorderColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
borderColorShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Border::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* width = nullptr;
const CSSValue* style = nullptr;
const CSSValue* color = nullptr;
if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
color)) {
return false;
};
css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderWidth,
*width, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderStyle,
*style, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderColor,
*color, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(CSSPropertyID::kBorderImage,
*CSSInitialValue::Create(),
important, properties);
return range.AtEnd();
}
const CSSValue* Border::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* value = GetCSSPropertyBorderTop().CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
static const CSSProperty* kProperties[3] = {&GetCSSPropertyBorderRight(),
&GetCSSPropertyBorderBottom(),
&GetCSSPropertyBorderLeft()};
for (size_t i = 0; i < std::size(kProperties); ++i) {
const CSSValue* value_for_side = kProperties[i]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
if (!base::ValuesEquivalent(value, value_for_side)) {
return nullptr;
}
}
return value;
}
bool BorderImage::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* source = nullptr;
CSSValue* slice = nullptr;
CSSValue* width = nullptr;
CSSValue* outset = nullptr;
CSSValue* repeat = nullptr;
if (!css_parsing_utils::ConsumeBorderImageComponents(
range, context, source, slice, width, outset, repeat,
css_parsing_utils::DefaultFill::kNoFill)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderImageSource, CSSPropertyID::kBorderImage,
source
? *source
: *To<Longhand>(&GetCSSPropertyBorderImageSource())->InitialValue(),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderImageSlice, CSSPropertyID::kBorderImage,
slice ? *slice
: *To<Longhand>(&GetCSSPropertyBorderImageSlice())->InitialValue(),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderImageWidth, CSSPropertyID::kBorderImage,
width ? *width
: *To<Longhand>(&GetCSSPropertyBorderImageWidth())->InitialValue(),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderImageOutset, CSSPropertyID::kBorderImage,
outset
? *outset
: *To<Longhand>(&GetCSSPropertyBorderImageOutset())->InitialValue(),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderImageRepeat, CSSPropertyID::kBorderImage,
repeat
? *repeat
: *To<Longhand>(&GetCSSPropertyBorderImageRepeat())->InitialValue(),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* BorderImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForNinePieceImage(
style.BorderImage(), style, allow_visited_style, value_phase);
}
bool BorderInlineColor::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderInlineColorShorthand(), important, context, range, properties);
}
const CSSValue* BorderInlineColor::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderInlineColorShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* width = nullptr;
const CSSValue* style = nullptr;
const CSSValue* color = nullptr;
if (!css_parsing_utils::ConsumeBorderShorthand(range, context, width, style,
color)) {
return false;
};
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderInlineWidth, *width, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderInlineStyle, *style, important, properties);
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kBorderInlineColor, *color, important, properties);
return range.AtEnd();
}
const CSSValue* BorderInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* value_start =
GetCSSPropertyBorderInlineStart().CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
const CSSValue* value_end =
GetCSSPropertyBorderInlineEnd().CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
if (!base::ValuesEquivalent(value_start, value_end)) {
return nullptr;
}
return value_start;
}
bool BorderInlineEnd::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderInlineEndShorthand(), important, context, range, properties);
}
bool BorderInlineStart::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderInlineStartShorthand(), important, context, range, properties);
}
bool BorderInlineStyle::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderInlineStyleShorthand(), important, context, range, properties);
}
const CSSValue* BorderInlineStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderInlineStyleShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderInlineWidth::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
borderInlineWidthShorthand(), important, context, range, properties);
}
const CSSValue* BorderInlineWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
borderInlineWidthShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderLeft::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderLeftShorthand(), important, context, range, properties);
}
const CSSValue* BorderLeft::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
borderLeftShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderRadius::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* horizontal_radii[4] = {nullptr};
CSSValue* vertical_radii[4] = {nullptr};
if (!css_parsing_utils::ConsumeRadii(horizontal_radii, vertical_radii, range,
context,
local_context.UseAliasParsing())) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderTopLeftRadius, CSSPropertyID::kBorderRadius,
*MakeGarbageCollected<CSSValuePair>(horizontal_radii[0],
vertical_radii[0],
CSSValuePair::kDropIdenticalValues),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderTopRightRadius, CSSPropertyID::kBorderRadius,
*MakeGarbageCollected<CSSValuePair>(horizontal_radii[1],
vertical_radii[1],
CSSValuePair::kDropIdenticalValues),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderBottomRightRadius, CSSPropertyID::kBorderRadius,
*MakeGarbageCollected<CSSValuePair>(horizontal_radii[2],
vertical_radii[2],
CSSValuePair::kDropIdenticalValues),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kBorderBottomLeftRadius, CSSPropertyID::kBorderRadius,
*MakeGarbageCollected<CSSValuePair>(horizontal_radii[3],
vertical_radii[3],
CSSValuePair::kDropIdenticalValues),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* BorderRadius::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForBorderRadiusShorthand(style);
}
bool BorderRight::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderRightShorthand(), important, context, range, properties);
}
const CSSValue* BorderRight::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
borderRightShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderSpacing::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* horizontal_spacing =
ConsumeLength(range, context, CSSPrimitiveValue::ValueRange::kNonNegative,
css_parsing_utils::UnitlessQuirk::kAllow);
if (!horizontal_spacing) {
return false;
}
CSSValue* vertical_spacing = horizontal_spacing;
if (!range.AtEnd()) {
vertical_spacing = ConsumeLength(
range, context, CSSPrimitiveValue::ValueRange::kNonNegative,
css_parsing_utils::UnitlessQuirk::kAllow);
}
if (!vertical_spacing || !range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitBorderHorizontalSpacing,
CSSPropertyID::kBorderSpacing, *horizontal_spacing, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitBorderVerticalSpacing,
CSSPropertyID::kBorderSpacing, *vertical_spacing, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* BorderSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*ZoomAdjustedPixelValue(style.HorizontalBorderSpacing(), style));
list->Append(*ZoomAdjustedPixelValue(style.VerticalBorderSpacing(), style));
return list;
}
bool BorderStyle::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
borderStyleShorthand(), important, context, range, properties);
}
const CSSValue* BorderStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
borderStyleShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderTop::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
borderTopShorthand(), important, context, range, properties);
}
const CSSValue* BorderTop::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
borderTopShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool BorderWidth::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
borderWidthShorthand(), important, context, range, properties);
}
const CSSValue* BorderWidth::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
borderWidthShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ColumnRule::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
columnRuleShorthand(), important, context, range, properties);
}
const CSSValue* ColumnRule::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
columnRuleShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Columns::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* column_width = nullptr;
CSSValue* column_count = nullptr;
if (!css_parsing_utils::ConsumeColumnWidthOrCount(
range, context, column_width, column_count)) {
return false;
}
css_parsing_utils::ConsumeColumnWidthOrCount(range, context, column_width,
column_count);
if (!range.AtEnd()) {
return false;
}
if (!column_width) {
column_width = CSSIdentifierValue::Create(CSSValueID::kAuto);
}
if (!column_count) {
column_count = CSSIdentifierValue::Create(CSSValueID::kAuto);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kColumnWidth, CSSPropertyID::kInvalid, *column_width,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kColumnCount, CSSPropertyID::kInvalid, *column_count,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* Columns::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
columnsShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ContainIntrinsicSize::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
containIntrinsicSizeShorthand(), important, context, range, properties);
}
const CSSValue* ContainIntrinsicSize::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const StylePropertyShorthand& shorthand = containIntrinsicSizeShorthand();
const auto& width = style.ContainIntrinsicWidth();
const auto& height = style.ContainIntrinsicHeight();
if (width != height) {
return ComputedStyleUtils::ValuesForShorthandProperty(
shorthand, style, layout_object, allow_visited_style, value_phase);
}
return shorthand.properties()[0]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
}
bool Container::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* name =
css_parsing_utils::ConsumeContainerName(range, context);
if (!name) {
return false;
}
const CSSValue* type = CSSIdentifierValue::Create(CSSValueID::kNormal);
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
if (!(type = css_parsing_utils::ConsumeContainerType(range))) {
return false;
}
}
if (!range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kContainerName, CSSPropertyID::kContainer, *name,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kContainerType, CSSPropertyID::kContainer, *type,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* Container::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForContainerShorthand(
style, layout_object, allow_visited_style, value_phase);
}
bool Flex::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
static const double kUnsetValue = -1;
double flex_grow = kUnsetValue;
double flex_shrink = kUnsetValue;
CSSValue* flex_basis = nullptr;
if (range.Peek().Id() == CSSValueID::kNone) {
flex_grow = 0;
flex_shrink = 0;
flex_basis = CSSIdentifierValue::Create(CSSValueID::kAuto);
range.ConsumeIncludingWhitespace();
} else {
unsigned index = 0;
while (!range.AtEnd() && index++ < 3) {
double num;
if (css_parsing_utils::ConsumeNumberRaw(range, context, num)) {
if (num < 0) {
return false;
}
if (flex_grow == kUnsetValue) {
flex_grow = num;
} else if (flex_shrink == kUnsetValue) {
flex_shrink = num;
} else if (!num) {
// flex only allows a basis of 0 (sans units) if
// flex-grow and flex-shrink values have already been
// set.
flex_basis = CSSNumericLiteralValue::Create(
0, CSSPrimitiveValue::UnitType::kPixels);
} else {
return false;
}
} else if (!flex_basis) {
if (css_parsing_utils::IdentMatches<
CSSValueID::kAuto, CSSValueID::kContent,
CSSValueID::kMinContent, CSSValueID::kMaxContent,
CSSValueID::kFitContent>(range.Peek().Id())) {
flex_basis = css_parsing_utils::ConsumeIdent(range);
}
if (!flex_basis) {
flex_basis = css_parsing_utils::ConsumeLengthOrPercent(
range, context, CSSPrimitiveValue::ValueRange::kNonNegative);
}
if (index == 2 && !range.AtEnd()) {
return false;
}
}
}
if (index == 0) {
return false;
}
if (flex_grow == kUnsetValue) {
flex_grow = 1;
}
if (flex_shrink == kUnsetValue) {
flex_shrink = 1;
}
if (!flex_basis) {
flex_basis = CSSNumericLiteralValue::Create(
0, CSSPrimitiveValue::UnitType::kPercentage);
}
}
if (!range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kFlexGrow, CSSPropertyID::kFlex,
*CSSNumericLiteralValue::Create(ClampTo<float>(flex_grow),
CSSPrimitiveValue::UnitType::kNumber),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFlexShrink, CSSPropertyID::kFlex,
*CSSNumericLiteralValue::Create(ClampTo<float>(flex_shrink),
CSSPrimitiveValue::UnitType::kNumber),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFlexBasis, CSSPropertyID::kFlex, *flex_basis, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* Flex::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
flexShorthand(), style, layout_object, allow_visited_style, value_phase);
}
bool FlexFlow::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
flexFlowShorthand(), important, context, range, properties,
/* use_initial_value_function */ true);
}
const CSSValue* FlexFlow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
flexFlowShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
namespace {
bool ConsumeSystemFont(bool important,
CSSParserTokenRange& range,
HeapVector<CSSPropertyValue, 64>& properties) {
CSSValueID system_font_id = range.ConsumeIncludingWhitespace().Id();
DCHECK(CSSParserFastPaths::IsValidSystemFont(system_font_id));
if (!range.AtEnd()) {
return false;
}
css_parsing_utils::AddExpandedPropertyForValue(
CSSPropertyID::kFont,
*cssvalue::CSSPendingSystemFontValue::Create(system_font_id), important,
properties);
return true;
}
bool ConsumeFont(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
HeapVector<CSSPropertyValue, 64>& properties) {
// Optional font-style, font-variant, font-stretch and font-weight.
// Each may be normal.
CSSValue* font_style = nullptr;
CSSIdentifierValue* font_variant_caps = nullptr;
CSSValue* font_weight = nullptr;
CSSValue* font_stretch = nullptr;
const int kNumReorderableFontProperties = 4;
for (int i = 0; i < kNumReorderableFontProperties && !range.AtEnd(); ++i) {
CSSValueID id = range.Peek().Id();
if (id == CSSValueID::kNormal) {
css_parsing_utils::ConsumeIdent(range);
continue;
}
if (!font_style &&
(id == CSSValueID::kItalic || id == CSSValueID::kOblique)) {
font_style = css_parsing_utils::ConsumeFontStyle(range, context);
if (!font_style) {
return false;
}
continue;
}
if (!font_variant_caps && id == CSSValueID::kSmallCaps) {
// Font variant in the shorthand is particular, it only accepts normal or
// small-caps.
// See https://drafts.csswg.org/css-fonts/#propdef-font
font_variant_caps = css_parsing_utils::ConsumeFontVariantCSS21(range);
if (font_variant_caps) {
continue;
}
}
if (!font_weight) {
font_weight = css_parsing_utils::ConsumeFontWeight(range, context);
if (font_weight) {
continue;
}
}
// Stretch in the font shorthand can only take the CSS Fonts Level 3
// keywords, not arbitrary values, compare
// https://drafts.csswg.org/css-fonts-4/#font-prop
// Bail out if the last possible property of the set in this loop could not
// be parsed, this closes the first block of optional values of the font
// shorthand, compare: [ [ <‘font-style’> || <font-variant-css21> ||
// <‘font-weight’> || <font-stretch-css3> ]?
if (font_stretch ||
!(font_stretch = css_parsing_utils::ConsumeFontStretchKeywordOnly(
range, context))) {
break;
}
}
if (range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kFontStyle, CSSPropertyID::kFont,
font_style ? *font_style
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFont,
font_variant_caps ? *font_variant_caps
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
// All subproperties of the font, i.e. font-size-adjust, font-kerning, all
// subproperties of font-variant, font-feature-settings,
// font-language-override, font-optical-sizing and font-variation-settings
// property should be reset to their initial values, compare
// https://drafts.csswg.org/css-fonts-4/#font-prop
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantAlternates, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
if (RuntimeEnabledFeatures::CSSFontSizeAdjustEnabled()) {
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSizeAdjust, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNone), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kFontKerning, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kAuto), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontOpticalSizing, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kAuto), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontFeatureSettings, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariationSettings, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantPosition, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontWeight, CSSPropertyID::kFont,
font_weight ? *font_weight
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontStretch, CSSPropertyID::kFont,
font_stretch ? *font_stretch
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
// Now a font size _must_ come.
CSSValue* font_size = css_parsing_utils::ConsumeFontSize(range, context);
if (!font_size || range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSize, CSSPropertyID::kFont, *font_size, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
CSSValue* line_height =
css_parsing_utils::ConsumeLineHeight(range, context);
if (!line_height) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kLineHeight, CSSPropertyID::kFont, *line_height,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
} else {
css_parsing_utils::AddProperty(
CSSPropertyID::kLineHeight, CSSPropertyID::kFont,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
}
// Font family must come now.
CSSValue* parsed_family_value = css_parsing_utils::ConsumeFontFamily(range);
if (!parsed_family_value) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kFontFamily, CSSPropertyID::kFont, *parsed_family_value,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return range.AtEnd();
}
} // namespace
bool Font::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSParserToken& token = range.Peek();
if (CSSParserFastPaths::IsValidSystemFont(token.Id())) {
return ConsumeSystemFont(important, range, properties);
}
return ConsumeFont(important, range, context, properties);
}
const CSSValue* Font::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForFont(style);
}
bool FontVariant::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
if (css_parsing_utils::IdentMatches<CSSValueID::kNormal, CSSValueID::kNone>(
range.Peek().Id())) {
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFontVariant,
*css_parsing_utils::ConsumeIdent(range), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFontVariant,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFontVariant,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFontVariant,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantAlternates, CSSPropertyID::kFontVariant,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantPosition, CSSPropertyID::kFontVariant,
*CSSIdentifierValue::Create(CSSValueID::kNormal), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
CSSIdentifierValue* caps_value = nullptr;
FontVariantLigaturesParser ligatures_parser;
FontVariantNumericParser numeric_parser;
FontVariantEastAsianParser east_asian_parser;
FontVariantAlternatesParser alternates_parser;
CSSIdentifierValue* position_value = nullptr;
do {
FontVariantLigaturesParser::ParseResult ligatures_parse_result =
ligatures_parser.ConsumeLigature(range);
FontVariantNumericParser::ParseResult numeric_parse_result =
numeric_parser.ConsumeNumeric(range);
FontVariantEastAsianParser::ParseResult east_asian_parse_result =
east_asian_parser.ConsumeEastAsian(range);
FontVariantAlternatesParser::ParseResult alternates_parse_result =
alternates_parser.ConsumeAlternates(range, context);
if (ligatures_parse_result ==
FontVariantLigaturesParser::ParseResult::kConsumedValue ||
numeric_parse_result ==
FontVariantNumericParser::ParseResult::kConsumedValue ||
east_asian_parse_result ==
FontVariantEastAsianParser::ParseResult::kConsumedValue ||
alternates_parse_result ==
FontVariantAlternatesParser::ParseResult::kConsumedValue) {
continue;
}
if (ligatures_parse_result ==
FontVariantLigaturesParser::ParseResult::kDisallowedValue ||
numeric_parse_result ==
FontVariantNumericParser::ParseResult::kDisallowedValue ||
east_asian_parse_result ==
FontVariantEastAsianParser::ParseResult::kDisallowedValue ||
alternates_parse_result ==
FontVariantAlternatesParser::ParseResult::kDisallowedValue) {
return false;
}
CSSValueID id = range.Peek().Id();
switch (id) {
case CSSValueID::kSmallCaps:
case CSSValueID::kAllSmallCaps:
case CSSValueID::kPetiteCaps:
case CSSValueID::kAllPetiteCaps:
case CSSValueID::kUnicase:
case CSSValueID::kTitlingCaps:
// Only one caps value permitted in font-variant grammar.
if (caps_value) {
return false;
}
caps_value = css_parsing_utils::ConsumeIdent(range);
break;
case CSSValueID::kSub:
case CSSValueID::kSuper:
// Only one position value permitted in font-variant grammar.
if (position_value) {
return false;
}
position_value = css_parsing_utils::ConsumeIdent(range);
break;
default:
return false;
}
} while (!range.AtEnd());
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantLigatures, CSSPropertyID::kFontVariant,
*ligatures_parser.FinalizeValue(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantNumeric, CSSPropertyID::kFontVariant,
*numeric_parser.FinalizeValue(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantEastAsian, CSSPropertyID::kFontVariant,
*east_asian_parser.FinalizeValue(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantCaps, CSSPropertyID::kFontVariant,
caps_value ? *caps_value
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantAlternates, CSSPropertyID::kFontVariant,
*alternates_parser.FinalizeValue(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontVariantPosition, CSSPropertyID::kFontVariant,
position_value ? *position_value
: *CSSIdentifierValue::Create(CSSValueID::kNormal),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* FontVariant::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForFontVariantProperty(
style, layout_object, allow_visited_style, value_phase);
}
bool FontSynthesis::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
if (range.Peek().Id() == CSSValueID::kNone) {
range.ConsumeIncludingWhitespace();
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisWeight, CSSPropertyID::kFontSynthesis,
*CSSIdentifierValue::Create(CSSValueID::kNone), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisStyle, CSSPropertyID::kFontSynthesis,
*CSSIdentifierValue::Create(CSSValueID::kNone), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisSmallCaps, CSSPropertyID::kFontSynthesis,
*CSSIdentifierValue::Create(CSSValueID::kNone), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
CSSValue* font_synthesis_weight = nullptr;
CSSValue* font_synthesis_style = nullptr;
CSSValue* font_synthesis_small_caps = nullptr;
do {
CSSValueID id = range.ConsumeIncludingWhitespace().Id();
switch (id) {
case CSSValueID::kWeight:
if (font_synthesis_weight) {
return false;
}
font_synthesis_weight = CSSIdentifierValue::Create(CSSValueID::kAuto);
break;
case CSSValueID::kStyle:
if (font_synthesis_style) {
return false;
}
font_synthesis_style = CSSIdentifierValue::Create(CSSValueID::kAuto);
break;
case CSSValueID::kSmallCaps:
if (font_synthesis_small_caps) {
return false;
}
font_synthesis_small_caps =
CSSIdentifierValue::Create(CSSValueID::kAuto);
break;
default:
return false;
}
} while (!range.AtEnd());
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisWeight, CSSPropertyID::kFontSynthesis,
font_synthesis_weight ? *font_synthesis_weight
: *CSSIdentifierValue::Create(CSSValueID::kNone),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisStyle, CSSPropertyID::kFontSynthesis,
font_synthesis_style ? *font_synthesis_style
: *CSSIdentifierValue::Create(CSSValueID::kNone),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kFontSynthesisSmallCaps, CSSPropertyID::kFontSynthesis,
font_synthesis_small_caps
? *font_synthesis_small_caps
: *CSSIdentifierValue::Create(CSSValueID::kNone),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* FontSynthesis::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForFontSynthesisProperty(
style, layout_object, allow_visited_style, value_phase);
}
bool Gap::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kGap).length(), 2u);
CSSValue* row_gap = css_parsing_utils::ConsumeGapLength(range, context);
CSSValue* column_gap = css_parsing_utils::ConsumeGapLength(range, context);
if (!row_gap || !range.AtEnd()) {
return false;
}
if (!column_gap) {
column_gap = row_gap;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kRowGap, CSSPropertyID::kGap, *row_gap, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kColumnGap, CSSPropertyID::kGap, *column_gap, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* Gap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGapShorthand(
gapShorthand(), style, layout_object, allow_visited_style, value_phase);
}
bool GridArea::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(gridAreaShorthand().length(), 4u);
CSSValue* row_start_value =
css_parsing_utils::ConsumeGridLine(range, context);
if (!row_start_value) {
return false;
}
CSSValue* column_start_value = nullptr;
CSSValue* row_end_value = nullptr;
CSSValue* column_end_value = nullptr;
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
column_start_value = css_parsing_utils::ConsumeGridLine(range, context);
if (!column_start_value) {
return false;
}
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
row_end_value = css_parsing_utils::ConsumeGridLine(range, context);
if (!row_end_value) {
return false;
}
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
column_end_value = css_parsing_utils::ConsumeGridLine(range, context);
if (!column_end_value) {
return false;
}
}
}
}
if (!range.AtEnd()) {
return false;
}
if (!column_start_value) {
column_start_value = row_start_value->IsCustomIdentValue()
? row_start_value
: CSSIdentifierValue::Create(CSSValueID::kAuto);
}
if (!row_end_value) {
row_end_value = row_start_value->IsCustomIdentValue()
? row_start_value
: CSSIdentifierValue::Create(CSSValueID::kAuto);
}
if (!column_end_value) {
column_end_value = column_start_value->IsCustomIdentValue()
? column_start_value
: CSSIdentifierValue::Create(CSSValueID::kAuto);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kGridRowStart, CSSPropertyID::kGridArea, *row_start_value,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridColumnStart, CSSPropertyID::kGridArea,
*column_start_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridRowEnd, CSSPropertyID::kGridArea, *row_end_value,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridColumnEnd, CSSPropertyID::kGridArea,
*column_end_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* GridArea::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGridAreaShorthand(
gridAreaShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool GridColumn::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const StylePropertyShorthand& shorthand =
shorthandForProperty(CSSPropertyID::kGridColumn);
DCHECK_EQ(shorthand.length(), 2u);
CSSValue* start_value = nullptr;
CSSValue* end_value = nullptr;
if (!css_parsing_utils::ConsumeGridItemPositionShorthand(
important, range, context, start_value, end_value)) {
return false;
}
css_parsing_utils::AddProperty(
shorthand.properties()[0]->PropertyID(), CSSPropertyID::kGridColumn,
*start_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
shorthand.properties()[1]->PropertyID(), CSSPropertyID::kGridColumn,
*end_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* GridColumn::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGridLineShorthand(
gridColumnShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool GridColumnGap::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* gap_length = css_parsing_utils::ConsumeGapLength(range, context);
if (!gap_length || !range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kColumnGap, CSSPropertyID::kGridColumnGap, *gap_length,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* GridColumnGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
gridColumnGapShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
namespace {
CSSValueList* ConsumeImplicitAutoFlow(
CSSParserTokenRange& range,
const CSSIdentifierValue& flow_direction) {
// [ auto-flow && dense? ]
CSSValue* dense_algorithm = nullptr;
if (css_parsing_utils::ConsumeIdent<CSSValueID::kAutoFlow>(range)) {
dense_algorithm =
css_parsing_utils::ConsumeIdent<CSSValueID::kDense>(range);
} else {
dense_algorithm =
css_parsing_utils::ConsumeIdent<CSSValueID::kDense>(range);
if (!dense_algorithm) {
return nullptr;
}
if (!css_parsing_utils::ConsumeIdent<CSSValueID::kAutoFlow>(range)) {
return nullptr;
}
}
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
if (flow_direction.GetValueID() == CSSValueID::kColumn || !dense_algorithm) {
list->Append(flow_direction);
}
if (dense_algorithm) {
list->Append(*dense_algorithm);
}
return list;
}
} // namespace
bool Grid::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kGrid).length(), 6u);
CSSParserTokenRange range_copy = range;
const CSSValue* template_rows = nullptr;
const CSSValue* template_columns = nullptr;
const CSSValue* template_areas = nullptr;
if (css_parsing_utils::ConsumeGridTemplateShorthand(
important, range, context, template_rows, template_columns,
template_areas)) {
DCHECK(template_rows);
DCHECK(template_columns);
DCHECK(template_areas);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGrid, *template_rows,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGrid,
*template_columns, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGrid,
*template_areas, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
// It can only be specified the explicit or the implicit grid properties in
// a single grid declaration. The sub-properties not specified are set to
// their initial value, as normal for shorthands.
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoFlow, CSSPropertyID::kGrid,
*(To<Longhand>(GetCSSPropertyGridAutoFlow()).InitialValue()), important,
css_parsing_utils::IsImplicitProperty::kImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoColumns, CSSPropertyID::kGrid,
*(To<Longhand>(GetCSSPropertyGridAutoColumns()).InitialValue()),
important, css_parsing_utils::IsImplicitProperty::kImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoRows, CSSPropertyID::kGrid,
*(To<Longhand>(GetCSSPropertyGridAutoRows()).InitialValue()), important,
css_parsing_utils::IsImplicitProperty::kImplicit, properties);
return true;
}
range = range_copy;
const CSSValue* auto_columns_value = nullptr;
const CSSValue* auto_rows_value = nullptr;
const CSSValueList* grid_auto_flow = nullptr;
template_rows = nullptr;
template_columns = nullptr;
if (css_parsing_utils::IdentMatches<CSSValueID::kDense,
CSSValueID::kAutoFlow>(
range.Peek().Id())) {
// 2- [ auto-flow && dense? ] <grid-auto-rows>? / <grid-template-columns>
grid_auto_flow = ConsumeImplicitAutoFlow(
range, *CSSIdentifierValue::Create(CSSValueID::kRow));
if (!grid_auto_flow) {
return false;
}
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
auto_rows_value =
To<Longhand>(GetCSSPropertyGridAutoRows()).InitialValue();
} else {
auto_rows_value = css_parsing_utils::ConsumeGridTrackList(
range, context, css_parsing_utils::TrackListType::kGridAuto);
if (!auto_rows_value) {
return false;
}
if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
return false;
}
}
if (!(template_columns =
css_parsing_utils::ConsumeGridTemplatesRowsOrColumns(range,
context))) {
return false;
}
template_rows =
To<Longhand>(GetCSSPropertyGridTemplateRows()).InitialValue();
auto_columns_value =
To<Longhand>(GetCSSPropertyGridAutoColumns()).InitialValue();
} else {
// 3- <grid-template-rows> / [ auto-flow && dense? ] <grid-auto-columns>?
template_rows =
css_parsing_utils::ConsumeGridTemplatesRowsOrColumns(range, context);
if (!template_rows) {
return false;
}
if (!css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
return false;
}
grid_auto_flow = ConsumeImplicitAutoFlow(
range, *CSSIdentifierValue::Create(CSSValueID::kColumn));
if (!grid_auto_flow) {
return false;
}
if (range.AtEnd()) {
auto_columns_value =
To<Longhand>(GetCSSPropertyGridAutoColumns()).InitialValue();
} else {
auto_columns_value = css_parsing_utils::ConsumeGridTrackList(
range, context, css_parsing_utils::TrackListType::kGridAuto);
if (!auto_columns_value) {
return false;
}
}
template_columns =
To<Longhand>(GetCSSPropertyGridTemplateColumns()).InitialValue();
auto_rows_value = To<Longhand>(GetCSSPropertyGridAutoRows()).InitialValue();
}
if (!range.AtEnd()) {
return false;
}
// It can only be specified the explicit or the implicit grid properties in a
// single grid declaration. The sub-properties not specified are set to their
// initial value, as normal for shorthands.
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGrid,
*template_columns, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGrid, *template_rows,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGrid,
*(To<Longhand>(GetCSSPropertyGridTemplateAreas()).InitialValue()),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoFlow, CSSPropertyID::kGrid, *grid_auto_flow,
important, css_parsing_utils::IsImplicitProperty::kImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoColumns, CSSPropertyID::kGrid,
*auto_columns_value, important,
css_parsing_utils::IsImplicitProperty::kImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridAutoRows, CSSPropertyID::kGrid, *auto_rows_value,
important, css_parsing_utils::IsImplicitProperty::kImplicit, properties);
return true;
}
bool Grid::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsLayoutGrid();
}
const CSSValue* Grid::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGridShorthand(
gridShorthand(), style, layout_object, allow_visited_style, value_phase);
}
bool GridGap::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kGridGap).length(), 2u);
CSSValue* row_gap = css_parsing_utils::ConsumeGapLength(range, context);
CSSValue* column_gap = css_parsing_utils::ConsumeGapLength(range, context);
if (!row_gap || !range.AtEnd()) {
return false;
}
if (!column_gap) {
column_gap = row_gap;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kRowGap, CSSPropertyID::kGap, *row_gap, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kColumnGap, CSSPropertyID::kGap, *column_gap, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* GridGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
gridGapShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool GridRow::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const StylePropertyShorthand& shorthand =
shorthandForProperty(CSSPropertyID::kGridRow);
DCHECK_EQ(shorthand.length(), 2u);
CSSValue* start_value = nullptr;
CSSValue* end_value = nullptr;
if (!css_parsing_utils::ConsumeGridItemPositionShorthand(
important, range, context, start_value, end_value)) {
return false;
}
css_parsing_utils::AddProperty(
shorthand.properties()[0]->PropertyID(), CSSPropertyID::kGridRow,
*start_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
shorthand.properties()[1]->PropertyID(), CSSPropertyID::kGridRow,
*end_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* GridRow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGridLineShorthand(
gridRowShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool GridRowGap::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* gap_length = css_parsing_utils::ConsumeGapLength(range, context);
if (!gap_length || !range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kRowGap, CSSPropertyID::kGridRowGap, *gap_length,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* GridRowGap::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
gridRowGapShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool GridTemplate::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* template_rows = nullptr;
const CSSValue* template_columns = nullptr;
const CSSValue* template_areas = nullptr;
if (!css_parsing_utils::ConsumeGridTemplateShorthand(
important, range, context, template_rows, template_columns,
template_areas)) {
return false;
}
DCHECK(template_rows);
DCHECK(template_columns);
DCHECK(template_areas);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateRows, CSSPropertyID::kGridTemplate,
*template_rows, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateColumns, CSSPropertyID::kGridTemplate,
*template_columns, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kGridTemplateAreas, CSSPropertyID::kGridTemplate,
*template_areas, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
bool GridTemplate::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsLayoutGrid();
}
const CSSValue* GridTemplate::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForGridTemplateShorthand(
gridTemplateShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool InsetBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
insetBlockShorthand(), important, context, range, properties);
}
const CSSValue* InsetBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
insetBlockShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool InsetBlock::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox();
}
bool Inset::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
insetShorthand(), important, context, range, properties);
}
const CSSValue* Inset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
insetShorthand(), style, layout_object, allow_visited_style, value_phase);
}
bool Inset::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox();
}
bool InsetInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
insetInlineShorthand(), important, context, range, properties);
}
const CSSValue* InsetInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
insetInlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool InsetInline::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox();
}
bool ListStyle::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* none = nullptr;
const CSSValue* list_style_position = nullptr;
const CSSValue* list_style_image = nullptr;
const CSSValue* list_style_type = nullptr;
do {
if (!none) {
none = css_parsing_utils::ConsumeIdent<CSSValueID::kNone>(range);
if (none) {
continue;
}
}
if (!list_style_position) {
list_style_position = css_parsing_utils::ParseLonghand(
CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle, context,
range);
if (list_style_position) {
continue;
}
}
if (!list_style_image) {
list_style_image = css_parsing_utils::ParseLonghand(
CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle, context,
range);
if (list_style_image) {
continue;
}
}
if (!list_style_type) {
list_style_type = css_parsing_utils::ParseLonghand(
CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle, context,
range);
if (list_style_type) {
continue;
}
}
return false;
} while (!range.AtEnd());
if (none) {
if (!list_style_type) {
list_style_type = none;
} else if (!list_style_image) {
list_style_image = none;
} else {
return false;
}
}
if (list_style_position) {
AddProperty(CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle,
*list_style_position, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
} else {
AddProperty(CSSPropertyID::kListStylePosition, CSSPropertyID::kListStyle,
*CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
}
if (list_style_image) {
AddProperty(CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle,
*list_style_image, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
} else {
AddProperty(CSSPropertyID::kListStyleImage, CSSPropertyID::kListStyle,
*CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
}
if (list_style_type) {
AddProperty(CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle,
*list_style_type, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
} else {
AddProperty(CSSPropertyID::kListStyleType, CSSPropertyID::kListStyle,
*CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
}
return true;
}
const CSSValue* ListStyle::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
listStyleShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool MarginBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
marginBlockShorthand(), important, context, range, properties);
}
bool MarginBlock::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox();
}
const CSSValue* MarginBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
marginBlockShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Margin::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
marginShorthand(), important, context, range, properties);
}
bool Margin::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox() &&
(!style || !style->MarginBottom().IsFixed() ||
!style->MarginTop().IsFixed() || !style->MarginLeft().IsFixed() ||
!style->MarginRight().IsFixed() ||
style->MayHavePositionFallbackList());
}
const CSSValue* Margin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
marginShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool MarginInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
marginInlineShorthand(), important, context, range, properties);
}
bool MarginInline::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox();
}
const CSSValue* MarginInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
marginInlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Marker::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* marker = css_parsing_utils::ParseLonghand(
CSSPropertyID::kMarkerStart, CSSPropertyID::kMarker, context, range);
if (!marker || !range.AtEnd()) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kMarkerStart, CSSPropertyID::kMarker, *marker, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kMarkerMid, CSSPropertyID::kMarker, *marker, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kMarkerEnd, CSSPropertyID::kMarker, *marker, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* Marker::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* marker_start =
ComputedStyleUtils::ValueForSVGResource(style.MarkerStartResource());
if (*marker_start ==
*ComputedStyleUtils::ValueForSVGResource(style.MarkerMidResource()) &&
*marker_start ==
*ComputedStyleUtils::ValueForSVGResource(style.MarkerEndResource())) {
return marker_start;
}
return nullptr;
}
bool Offset::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
// TODO(meade): The propertyID parameter isn't used - it can be removed
// once all of the ParseSingleValue implementations have been moved to the
// CSSPropertys, and the base CSSProperty::ParseSingleValue contains
// no functionality.
const CSSValue* offset_position =
To<Longhand>(GetCSSPropertyOffsetPosition())
.ParseSingleValue(range, context, CSSParserLocalContext());
const CSSValue* offset_path =
css_parsing_utils::ConsumeOffsetPath(range, context);
const CSSValue* offset_distance = nullptr;
const CSSValue* offset_rotate = nullptr;
if (offset_path) {
offset_distance = css_parsing_utils::ConsumeLengthOrPercent(
range, context, CSSPrimitiveValue::ValueRange::kAll);
offset_rotate = css_parsing_utils::ConsumeOffsetRotate(range, context);
if (offset_rotate && !offset_distance) {
offset_distance = css_parsing_utils::ConsumeLengthOrPercent(
range, context, CSSPrimitiveValue::ValueRange::kAll);
}
}
const CSSValue* offset_anchor = nullptr;
if (css_parsing_utils::ConsumeSlashIncludingWhitespace(range)) {
offset_anchor =
To<Longhand>(GetCSSPropertyOffsetAnchor())
.ParseSingleValue(range, context, CSSParserLocalContext());
if (!offset_anchor) {
return false;
}
}
if ((!offset_position && !offset_path) || !range.AtEnd()) {
return false;
}
if (!offset_position) {
offset_position = CSSIdentifierValue::Create(CSSValueID::kNormal);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kOffsetPosition, CSSPropertyID::kOffset, *offset_position,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
if (!offset_path) {
offset_path = CSSIdentifierValue::Create(CSSValueID::kNone);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kOffsetPath, CSSPropertyID::kOffset, *offset_path,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
if (!offset_distance) {
offset_distance =
CSSNumericLiteralValue::Create(0, CSSPrimitiveValue::UnitType::kPixels);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kOffsetDistance, CSSPropertyID::kOffset, *offset_distance,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
if (!offset_rotate) {
offset_rotate = CSSIdentifierValue::Create(CSSValueID::kAuto);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kOffsetRotate, CSSPropertyID::kOffset, *offset_rotate,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
if (!offset_anchor) {
offset_anchor = CSSIdentifierValue::Create(CSSValueID::kAuto);
}
css_parsing_utils::AddProperty(
CSSPropertyID::kOffsetAnchor, CSSPropertyID::kOffset, *offset_anchor,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
return true;
}
const CSSValue* Offset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForOffset(style, layout_object,
allow_visited_style, value_phase);
}
bool Outline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
outlineShorthand(), important, context, range, properties);
}
const CSSValue* Outline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
outlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Overflow::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
overflowShorthand(), important, context, range, properties);
}
const CSSValue* Overflow::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*CSSIdentifierValue::Create(style.OverflowX()));
if (style.OverflowX() != style.OverflowY()) {
list->Append(*CSSIdentifierValue::Create(style.OverflowY()));
}
return list;
}
bool OverscrollBehavior::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
overscrollBehaviorShorthand(), important, context, range, properties);
}
const CSSValue* OverscrollBehavior::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*CSSIdentifierValue::Create(style.OverscrollBehaviorX()));
if (style.OverscrollBehaviorX() != style.OverscrollBehaviorY()) {
list->Append(*CSSIdentifierValue::Create(style.OverscrollBehaviorY()));
}
return list;
}
bool PaddingBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
paddingBlockShorthand(), important, context, range, properties);
}
const CSSValue* PaddingBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
paddingBlockShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool Padding::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
paddingShorthand(), important, context, range, properties);
}
bool Padding::IsLayoutDependent(const ComputedStyle* style,
LayoutObject* layout_object) const {
return layout_object && layout_object->IsBox() &&
(!style || !style->PaddingBottom().IsFixed() ||
!style->PaddingTop().IsFixed() || !style->PaddingLeft().IsFixed() ||
!style->PaddingRight().IsFixed());
}
const CSSValue* Padding::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
paddingShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool PaddingInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
paddingInlineShorthand(), important, context, range, properties);
}
const CSSValue* PaddingInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
paddingInlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool PageBreakAfter::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromPageBreakBetween(range, value)) {
return false;
}
DCHECK(IsValidCSSValueID(value));
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakAfter, CSSPropertyID::kPageBreakAfter,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PageBreakAfter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForPageBreakBetween(style.BreakAfter());
}
bool PageBreakBefore::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromPageBreakBetween(range, value)) {
return false;
}
DCHECK(IsValidCSSValueID(value));
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakBefore, CSSPropertyID::kPageBreakBefore,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PageBreakBefore::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForPageBreakBetween(style.BreakBefore());
}
bool PageBreakInside::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromColumnOrPageBreakInside(range, value)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakInside, CSSPropertyID::kPageBreakInside,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PageBreakInside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForPageBreakInside(style.BreakInside());
}
bool PlaceContent::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kPlaceContent).length(), 2u);
CSSParserTokenRange range_copy = range;
bool is_baseline = css_parsing_utils::IsBaselineKeyword(range.Peek().Id());
const CSSValue* align_content_value =
To<Longhand>(GetCSSPropertyAlignContent())
.ParseSingleValue(range, context, local_context);
if (!align_content_value) {
return false;
}
const CSSValue* justify_content_value = nullptr;
if (range.AtEnd()) {
if (is_baseline) {
justify_content_value =
MakeGarbageCollected<cssvalue::CSSContentDistributionValue>(
CSSValueID::kInvalid, CSSValueID::kStart, CSSValueID::kInvalid);
} else {
range = range_copy;
}
}
if (!justify_content_value) {
justify_content_value =
To<Longhand>(GetCSSPropertyJustifyContent())
.ParseSingleValue(range, context, local_context);
}
if (!justify_content_value || !range.AtEnd()) {
return false;
}
DCHECK(align_content_value);
DCHECK(justify_content_value);
css_parsing_utils::AddProperty(
CSSPropertyID::kAlignContent, CSSPropertyID::kPlaceContent,
*align_content_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kJustifyContent, CSSPropertyID::kPlaceContent,
*justify_content_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PlaceContent::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
placeContentShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool PlaceItems::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kPlaceItems).length(), 2u);
CSSParserTokenRange range_copy = range;
const CSSValue* align_items_value =
To<Longhand>(GetCSSPropertyAlignItems())
.ParseSingleValue(range, context, local_context);
if (!align_items_value) {
return false;
}
if (range.AtEnd()) {
range = range_copy;
}
const CSSValue* justify_items_value =
To<Longhand>(GetCSSPropertyJustifyItems())
.ParseSingleValue(range, context, local_context);
if (!justify_items_value || !range.AtEnd()) {
return false;
}
DCHECK(align_items_value);
DCHECK(justify_items_value);
css_parsing_utils::AddProperty(
CSSPropertyID::kAlignItems, CSSPropertyID::kPlaceItems,
*align_items_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kJustifyItems, CSSPropertyID::kPlaceItems,
*justify_items_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PlaceItems::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
placeItemsShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool PlaceSelf::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
DCHECK_EQ(shorthandForProperty(CSSPropertyID::kPlaceSelf).length(), 2u);
CSSParserTokenRange range_copy = range;
const CSSValue* align_self_value =
To<Longhand>(GetCSSPropertyAlignSelf())
.ParseSingleValue(range, context, local_context);
if (!align_self_value) {
return false;
}
if (range.AtEnd()) {
range = range_copy;
}
const CSSValue* justify_self_value =
To<Longhand>(GetCSSPropertyJustifySelf())
.ParseSingleValue(range, context, local_context);
if (!justify_self_value || !range.AtEnd()) {
return false;
}
DCHECK(align_self_value);
DCHECK(justify_self_value);
css_parsing_utils::AddProperty(
CSSPropertyID::kAlignSelf, CSSPropertyID::kPlaceSelf, *align_self_value,
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kJustifySelf, CSSPropertyID::kPlaceSelf,
*justify_self_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* PlaceSelf::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForPlaceShorthand(
placeSelfShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool PositionTry::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSValue* order = css_parsing_utils::ParseLonghand(
CSSPropertyID::kPositionTryOrder, CSSPropertyID::kPositionTry, context,
range);
if (!order) {
order = To<Longhand>(&GetCSSPropertyPositionTryOrder())->InitialValue();
}
AddProperty(CSSPropertyID::kPositionTryOrder, CSSPropertyID::kPositionTry,
*order, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
if (const CSSValue* options = css_parsing_utils::ParseLonghand(
CSSPropertyID::kPositionTryOptions, CSSPropertyID::kPositionTry,
context, range)) {
css_parsing_utils::AddProperty(
CSSPropertyID::kPositionTryOptions, CSSPropertyID::kPositionTry,
*options, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
return false;
}
const CSSValue* PositionTry::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
if (EPositionTryOrder order = style.PositionTryOrder();
order != ComputedStyleInitialValues::InitialPositionTryOrder()) {
list->Append(*CSSIdentifierValue::Create(order));
}
list->Append(*CSSIdentifierValue::Create(style.PositionTryOrder()));
return list;
}
bool ScrollMarginBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
scrollMarginBlockShorthand(), important, context, range, properties);
}
const CSSValue* ScrollMarginBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
scrollMarginBlockShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ScrollMargin::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
scrollMarginShorthand(), important, context, range, properties);
}
const CSSValue* ScrollMargin::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
scrollMarginShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ScrollMarginInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
scrollMarginInlineShorthand(), important, context, range, properties);
}
const CSSValue* ScrollMarginInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
scrollMarginInlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ScrollPaddingBlock::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
scrollPaddingBlockShorthand(), important, context, range, properties);
}
const CSSValue* ScrollPaddingBlock::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
scrollPaddingBlockShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ScrollPadding::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia4Longhands(
scrollPaddingShorthand(), important, context, range, properties);
}
const CSSValue* ScrollPadding::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForSidesShorthand(
scrollPaddingShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool ScrollPaddingInline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandVia2Longhands(
scrollPaddingInlineShorthand(), important, context, range, properties);
}
const CSSValue* ScrollPaddingInline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForInlineBlockShorthand(
scrollPaddingInlineShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
namespace {
// Consume a single name, axis, and optionally inset, then append the result to
// `name_list`, `axis_list`, and `inset_list` respectively.
//
// Insets are only relevant for the view-timeline shorthand, and not for
// the scroll-timeline shorthand, hence `inset_list` may be nullptr.
//
// https://drafts.csswg.org/scroll-animations-1/#view-timeline-shorthand
// https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-shorthand
bool ConsumeTimelineItemInto(CSSParserTokenRange& range,
const CSSParserContext& context,
CSSValueList* name_list,
CSSValueList* axis_list,
CSSValueList* inset_list) {
using css_parsing_utils::ConsumeSingleTimelineAxis;
using css_parsing_utils::ConsumeSingleTimelineInset;
using css_parsing_utils::ConsumeSingleTimelineName;
CSSValue* name = ConsumeSingleTimelineName(range, context);
if (!name) {
return false;
}
CSSValue* axis = nullptr;
CSSValue* inset = nullptr;
// [ <'view-timeline-axis'> || <'view-timeline-inset'> ]
while (true) {
if (!axis && (axis = ConsumeSingleTimelineAxis(range))) {
continue;
}
if (inset_list && !inset &&
(inset = ConsumeSingleTimelineInset(range, context))) {
continue;
}
break;
}
if (!axis) {
axis = CSSIdentifierValue::Create(CSSValueID::kBlock);
}
if (inset_list && !inset) {
inset = MakeGarbageCollected<CSSValuePair>(
CSSIdentifierValue::Create(CSSValueID::kAuto),
CSSIdentifierValue::Create(CSSValueID::kAuto),
CSSValuePair::kDropIdenticalValues);
}
DCHECK(name_list);
DCHECK(axis_list);
name_list->Append(*name);
axis_list->Append(*axis);
if (inset) {
DCHECK(inset_list);
inset_list->Append(*inset);
}
return true;
}
bool ParseTimelineShorthand(CSSPropertyID shorthand_id,
const StylePropertyShorthand& shorthand,
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) {
using css_parsing_utils::AddProperty;
using css_parsing_utils::ConsumeCommaIncludingWhitespace;
using css_parsing_utils::IsImplicitProperty;
CSSValueList* name_list = CSSValueList::CreateCommaSeparated();
CSSValueList* axis_list = CSSValueList::CreateCommaSeparated();
CSSValueList* inset_list =
shorthand.length() == 3u ? CSSValueList::CreateCommaSeparated() : nullptr;
do {
if (!ConsumeTimelineItemInto(range, context, name_list, axis_list,
inset_list)) {
return false;
}
} while (ConsumeCommaIncludingWhitespace(range));
DCHECK(name_list->length());
DCHECK(axis_list->length());
DCHECK(!inset_list || inset_list->length());
DCHECK_EQ(name_list->length(), axis_list->length());
DCHECK_EQ(inset_list ? name_list->length() : 0,
inset_list ? inset_list->length() : 0);
DCHECK_GE(shorthand.length(), 2u);
DCHECK_LE(shorthand.length(), 3u);
AddProperty(shorthand.properties()[0]->PropertyID(), shorthand_id, *name_list,
important, IsImplicitProperty::kNotImplicit, properties);
AddProperty(shorthand.properties()[1]->PropertyID(), shorthand_id, *axis_list,
important, IsImplicitProperty::kNotImplicit, properties);
if (inset_list) {
DCHECK_EQ(shorthand.length(), 3u);
AddProperty(shorthand.properties()[2]->PropertyID(), shorthand_id,
*inset_list, important, IsImplicitProperty::kNotImplicit,
properties);
}
return range.AtEnd();
}
static CSSValue* CSSValueForTimelineShorthand(
const HeapVector<Member<const ScopedCSSName>>& name_vector,
const Vector<TimelineAxis>& axis_vector,
const Vector<TimelineInset>* inset_vector,
const ComputedStyle& style) {
CSSValueList* list = CSSValueList::CreateCommaSeparated();
if (name_vector.size() != axis_vector.size()) {
return list;
}
if (inset_vector && name_vector.size() != inset_vector->size()) {
return list;
}
if (name_vector.empty()) {
list->Append(*ComputedStyleUtils::SingleValueForTimelineShorthand(
/* name */ nullptr, TimelineAxis::kBlock, /* inset */ std::nullopt,
style));
return list;
}
for (wtf_size_t i = 0; i < name_vector.size(); ++i) {
list->Append(*ComputedStyleUtils::SingleValueForTimelineShorthand(
name_vector[i].Get(), axis_vector[i],
inset_vector ? std::optional<TimelineInset>((*inset_vector)[i])
: std::optional<TimelineInset>(),
style));
}
return list;
}
} // namespace
bool ScrollStart::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* block_value = css_parsing_utils::ConsumeScrollStart(range, context);
if (!block_value) {
return false;
}
CSSValue* inline_value =
css_parsing_utils::ConsumeScrollStart(range, context);
if (!inline_value) {
inline_value = CSSIdentifierValue::Create(CSSValueID::kStart);
}
AddProperty(scrollStartShorthand().properties()[0]->PropertyID(),
scrollStartShorthand().id(), *block_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
AddProperty(scrollStartShorthand().properties()[1]->PropertyID(),
scrollStartShorthand().id(), *inline_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
const CSSValue* ScrollStart::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* block_value =
scrollStartShorthand().properties()[0]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
const CSSValue* inline_value =
scrollStartShorthand().properties()[1]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
if (const auto* ident_value = DynamicTo<CSSIdentifierValue>(inline_value);
!ident_value || ident_value->GetValueID() != CSSValueID::kStart) {
return MakeGarbageCollected<CSSValuePair>(
block_value, inline_value, CSSValuePair::kDropIdenticalValues);
}
return block_value;
}
bool ScrollStartTarget::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* block_value = css_parsing_utils::ConsumeScrollStartTarget(range);
if (!block_value) {
return false;
}
CSSValue* inline_value = css_parsing_utils::ConsumeScrollStartTarget(range);
if (!inline_value) {
inline_value = CSSIdentifierValue::Create(CSSValueID::kNone);
}
AddProperty(scrollStartTargetShorthand().properties()[0]->PropertyID(),
scrollStartTargetShorthand().id(), *block_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
AddProperty(scrollStartTargetShorthand().properties()[1]->PropertyID(),
scrollStartTargetShorthand().id(), *inline_value, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return range.AtEnd();
}
const CSSValue* ScrollStartTarget::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSValue* block_value =
scrollStartTargetShorthand().properties()[0]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
const CSSValue* inline_value =
scrollStartTargetShorthand().properties()[1]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
if (To<CSSIdentifierValue>(*inline_value).GetValueID() != CSSValueID::kNone) {
return MakeGarbageCollected<CSSValuePair>(
block_value, inline_value, CSSValuePair::kDropIdenticalValues);
}
return block_value;
}
bool ScrollTimeline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseTimelineShorthand(CSSPropertyID::kScrollTimeline,
scrollTimelineShorthand(), important, range,
context, local_context, properties);
}
const CSSValue* ScrollTimeline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const HeapVector<Member<const ScopedCSSName>>& name_vector =
style.ScrollTimelineName() ? style.ScrollTimelineName()->GetNames()
: HeapVector<Member<const ScopedCSSName>>{};
const Vector<TimelineAxis>& axis_vector = style.ScrollTimelineAxis();
return CSSValueForTimelineShorthand(name_vector, axis_vector,
/* inset_vector */ nullptr, style);
}
bool TextDecoration::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
// Use RuntimeEnabledFeature-aware shorthandForProperty() method until
// text-decoration-thickness ships, see style_property_shorthand.cc.tmpl.
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
shorthandForProperty(CSSPropertyID::kTextDecoration), important, context,
range, properties);
}
const CSSValue* TextDecoration::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
// Use RuntimeEnabledFeature-aware shorthandForProperty() method until
// text-decoration-thickness ships, see style_property_shorthand.cc.tmpl.
const StylePropertyShorthand& shorthand =
shorthandForProperty(CSSPropertyID::kTextDecoration);
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
for (unsigned i = 0; i < shorthand.length(); ++i) {
const CSSValue* value =
shorthand.properties()[i]->CSSValueFromComputedStyle(
style, layout_object, allow_visited_style, value_phase);
// Do not include initial value 'auto' for thickness.
// TODO(https://crbug.com/1093826): general shorthand serialization issues
// remain, in particular for text-decoration.
if (shorthand.properties()[i]->PropertyID() ==
CSSPropertyID::kTextDecorationThickness) {
if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
CSSValueID value_id = identifier_value->GetValueID();
if (value_id == CSSValueID::kAuto) {
continue;
}
}
}
DCHECK(value);
list->Append(*value);
}
return list;
}
namespace {
CSSValue* ConsumeTransitionValue(CSSPropertyID property,
CSSParserTokenRange& range,
const CSSParserContext& context,
bool use_legacy_parsing) {
switch (property) {
case CSSPropertyID::kTransitionDelay:
return css_parsing_utils::ConsumeTime(
range, context, CSSPrimitiveValue::ValueRange::kAll);
case CSSPropertyID::kTransitionDuration:
return css_parsing_utils::ConsumeTime(
range, context, CSSPrimitiveValue::ValueRange::kNonNegative);
case CSSPropertyID::kTransitionProperty:
return css_parsing_utils::ConsumeTransitionProperty(range, context);
case CSSPropertyID::kTransitionTimingFunction:
return css_parsing_utils::ConsumeAnimationTimingFunction(range, context);
case CSSPropertyID::kTransitionBehavior:
if (css_parsing_utils::IsValidTransitionBehavior(range.Peek().Id())) {
return CSSIdentifierValue::Create(
range.ConsumeIncludingWhitespace().Id());
}
return nullptr;
default:
NOTREACHED();
return nullptr;
}
}
} // namespace
bool Transition::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
const StylePropertyShorthand shorthand = transitionShorthandForParsing();
const unsigned longhand_count = shorthand.length();
// Only relevant for 'animation'.
auto is_reset_only_function = [](CSSPropertyID) { return false; };
HeapVector<Member<CSSValueList>, css_parsing_utils::kMaxNumAnimationLonghands>
longhands(longhand_count);
if (!css_parsing_utils::ConsumeAnimationShorthand(
shorthand, longhands, ConsumeTransitionValue, is_reset_only_function,
range, context, local_context.UseAliasParsing())) {
return false;
}
for (unsigned i = 0; i < longhand_count; ++i) {
if (shorthand.properties()[i]->IDEquals(
CSSPropertyID::kTransitionProperty) &&
!css_parsing_utils::IsValidPropertyList(*longhands[i])) {
return false;
}
}
for (unsigned i = 0; i < longhand_count; ++i) {
css_parsing_utils::AddProperty(
shorthand.properties()[i]->PropertyID(), shorthand.id(), *longhands[i],
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
}
return range.AtEnd();
}
const CSSValue* Transition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const CSSTransitionData* transition_data = style.Transitions();
if (transition_data) {
CSSValueList* transitions_list = CSSValueList::CreateCommaSeparated();
for (wtf_size_t i = 0; i < transition_data->PropertyList().size(); ++i) {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*ComputedStyleUtils::CreateTransitionPropertyValue(
transition_data->PropertyList()[i]));
list->Append(*CSSNumericLiteralValue::Create(
CSSTimingData::GetRepeated(transition_data->DurationList(), i)
.value(),
CSSPrimitiveValue::UnitType::kSeconds));
list->Append(*ComputedStyleUtils::ValueForAnimationTimingFunction(
CSSTimingData::GetRepeated(transition_data->TimingFunctionList(),
i)));
list->Append(*ComputedStyleUtils::ValueForAnimationDelayStart(
CSSTimingData::GetRepeated(transition_data->DelayStartList(), i)));
if (CSSTimingData::GetRepeated(transition_data->BehaviorList(), i) !=
CSSTransitionData::InitialBehavior()) {
list->Append(*ComputedStyleUtils::CreateTransitionBehaviorValue(
transition_data->BehaviorList()[i]));
}
transitions_list->Append(*list);
}
return transitions_list;
}
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
// transition-property default value.
list->Append(*CSSIdentifierValue::Create(CSSValueID::kAll));
list->Append(*CSSNumericLiteralValue::Create(
CSSTransitionData::InitialDuration().value(),
CSSPrimitiveValue::UnitType::kSeconds));
list->Append(*ComputedStyleUtils::ValueForAnimationTimingFunction(
CSSTransitionData::InitialTimingFunction()));
list->Append(*ComputedStyleUtils::ValueForAnimationDelayStart(
CSSTransitionData::InitialDelayStart()));
return list;
}
bool ViewTimeline::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseTimelineShorthand(CSSPropertyID::kViewTimeline,
viewTimelineShorthand(), important, range,
context, local_context, properties);
}
const CSSValue* ViewTimeline::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const HeapVector<Member<const ScopedCSSName>>& name_vector =
style.ViewTimelineName() ? style.ViewTimelineName()->GetNames()
: HeapVector<Member<const ScopedCSSName>>{};
const Vector<TimelineAxis>& axis_vector = style.ViewTimelineAxis();
return CSSValueForTimelineShorthand(name_vector, axis_vector,
/* inset_vector */ nullptr, style);
}
bool AlternativeViewTimelineWithInset::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseTimelineShorthand(
CSSPropertyID::kAlternativeViewTimelineWithInset,
alternativeViewTimelineWithInsetShorthand(), important, range, context,
local_context, properties);
}
const CSSValue*
AlternativeViewTimelineWithInset::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const HeapVector<Member<const ScopedCSSName>>& name_vector =
style.ViewTimelineName() ? style.ViewTimelineName()->GetNames()
: HeapVector<Member<const ScopedCSSName>>{};
const Vector<TimelineAxis>& axis_vector = style.ViewTimelineAxis();
const Vector<TimelineInset>& inset_vector = style.ViewTimelineInset();
return CSSValueForTimelineShorthand(name_vector, axis_vector, &inset_vector,
style);
}
bool WebkitColumnBreakAfter::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromColumnBreakBetween(range, value)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakAfter, CSSPropertyID::kWebkitColumnBreakAfter,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* WebkitColumnBreakAfter::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakBetween(
style.BreakAfter());
}
bool WebkitColumnBreakBefore::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromColumnBreakBetween(range, value)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakBefore, CSSPropertyID::kWebkitColumnBreakBefore,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* WebkitColumnBreakBefore::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakBetween(
style.BreakBefore());
}
bool WebkitColumnBreakInside::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext&,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValueID value;
if (!css_parsing_utils::ConsumeFromColumnOrPageBreakInside(range, value)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kBreakInside, CSSPropertyID::kWebkitColumnBreakInside,
*CSSIdentifierValue::Create(value), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* WebkitColumnBreakInside::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForWebkitColumnBreakInside(
style.BreakInside());
}
bool WebkitMaskBoxImage::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
CSSValue* source = nullptr;
CSSValue* slice = nullptr;
CSSValue* width = nullptr;
CSSValue* outset = nullptr;
CSSValue* repeat = nullptr;
if (!css_parsing_utils::ConsumeBorderImageComponents(
range, context, source, slice, width, outset, repeat,
css_parsing_utils::DefaultFill::kFill)) {
return false;
}
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitMaskBoxImageSource,
CSSPropertyID::kWebkitMaskBoxImage,
source ? *source : *CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitMaskBoxImageSlice,
CSSPropertyID::kWebkitMaskBoxImage,
slice ? *slice : *CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitMaskBoxImageWidth,
CSSPropertyID::kWebkitMaskBoxImage,
width ? *width : *CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitMaskBoxImageOutset,
CSSPropertyID::kWebkitMaskBoxImage,
outset ? *outset : *CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
css_parsing_utils::AddProperty(
CSSPropertyID::kWebkitMaskBoxImageRepeat,
CSSPropertyID::kWebkitMaskBoxImage,
repeat ? *repeat : *CSSInitialValue::Create(), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* WebkitMaskBoxImage::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValueForNinePieceImage(
style.MaskBoxImage(), style, allow_visited_style, value_phase);
}
bool Mask::ParseShorthand(bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ParseBackgroundOrMask(important, range, context,
local_context, properties);
}
const CSSValue* Mask::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForMaskShorthand(
maskShorthand(), style, layout_object, allow_visited_style, value_phase);
}
bool MaskPosition::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context,
HeapVector<CSSPropertyValue, 64>& properties) const {
return ParseBackgroundOrMaskPosition(
maskPositionShorthand(), important, range, context,
local_context.UseAliasParsing()
? WebFeature::kThreeValuedPositionBackground
: std::optional<WebFeature>(),
properties);
}
const CSSValue* MaskPosition::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject*,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::BackgroundPositionOrMaskPosition(
*this, style, &style.MaskLayers());
}
bool TextEmphasis::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
textEmphasisShorthand(), important, context, range, properties);
}
const CSSValue* TextEmphasis::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
textEmphasisShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool TextSpacing::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSParserTokenRange original_range = range;
CSSValue* autospace = nullptr;
CSSValue* spacing_trim = nullptr;
// The `text-spacing` shorthand doesn't lean directly on the longhand's
// grammar, instead uses the `autospace` and `spacing-trim` productions.
// https://drafts.csswg.org/css-text-4/#text-spacing-property
//
// Try `none` first.
if (const CSSIdentifierValue* ident =
css_parsing_utils::ConsumeIdent<CSSValueID::kNone>(range);
ident && range.AtEnd()) {
autospace = CSSIdentifierValue::Create(CSSValueID::kNoAutospace);
spacing_trim = CSSIdentifierValue::Create(CSSValueID::kSpaceAll);
}
// Try `<autospace> || <spacing-trim>`.
if (!autospace) {
range = original_range;
wtf_size_t num_values = 0;
while (!range.AtEnd()) {
if (++num_values > 2) {
return false;
}
if (css_parsing_utils::ConsumeIdent<CSSValueID::kNormal>(range)) {
// `normal` can be either `text-autospace`, `text-spacing-trim`, or
// both. Keep parsing without setting the value.
continue;
}
if (!autospace &&
(autospace = css_parsing_utils::ConsumeAutospace(range))) {
continue;
}
if (!spacing_trim &&
(spacing_trim = css_parsing_utils::ConsumeSpacingTrim(range))) {
continue;
}
return false;
}
if (!num_values) {
return false;
}
if (!autospace) {
autospace = CSSIdentifierValue::Create(CSSValueID::kNormal);
}
if (!spacing_trim) {
spacing_trim = CSSIdentifierValue::Create(CSSValueID::kNormal);
}
}
CHECK(autospace);
AddProperty(CSSPropertyID::kTextAutospace, CSSPropertyID::kTextSpacing,
*autospace, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
CHECK(spacing_trim);
AddProperty(CSSPropertyID::kTextSpacingTrim, CSSPropertyID::kTextSpacing,
*spacing_trim, important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
const CSSValue* TextSpacing::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const ETextAutospace autospace = style.TextAutospace();
const TextSpacingTrim spacing_trim =
style.GetFontDescription().GetTextSpacingTrim();
if (autospace == ComputedStyleInitialValues::InitialTextAutospace() &&
spacing_trim == FontBuilder::InitialTextSpacingTrim()) {
return CSSIdentifierValue::Create(CSSValueID::kNormal);
}
if (autospace == ETextAutospace::kNoAutospace &&
spacing_trim == TextSpacingTrim::kSpaceAll) {
return CSSIdentifierValue::Create(CSSValueID::kNone);
}
const CSSValue* autospace_value =
autospace == ComputedStyleInitialValues::InitialTextAutospace()
? nullptr
: CSSIdentifierValue::Create(autospace);
const CSSValue* spacing_trim_value =
spacing_trim == FontBuilder::InitialTextSpacingTrim()
? nullptr
: CSSIdentifierValue::Create(spacing_trim);
if (!autospace_value) {
CHECK(spacing_trim_value);
return spacing_trim_value;
}
if (!spacing_trim_value) {
return autospace_value;
}
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
list->Append(*spacing_trim_value);
list->Append(*autospace_value);
return list;
}
bool WebkitTextStroke::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
webkitTextStrokeShorthand(), important, context, range, properties);
}
const CSSValue* WebkitTextStroke::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
return ComputedStyleUtils::ValuesForShorthandProperty(
webkitTextStrokeShorthand(), style, layout_object, allow_visited_style,
value_phase);
}
bool WhiteSpace::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&,
HeapVector<CSSPropertyValue, 64>& properties) const {
const CSSParserTokenRange original_range = range;
// Try to parse as a pre-defined keyword. The `white-space` has pre-defined
// keywords in addition to the multi-values shorthand, for the backward
// compatibility with when it was a longhand.
if (const CSSIdentifierValue* value = css_parsing_utils::ConsumeIdent<
CSSValueID::kBreakSpaces, CSSValueID::kNormal, CSSValueID::kNowrap,
CSSValueID::kPre, CSSValueID::kPreLine, CSSValueID::kPreWrap>(
range)) {
// Parse as a pre-defined keyword only if it is at the end. Some keywords
// can be both a pre-defined keyword or a longhand value.
if (range.AtEnd()) {
const EWhiteSpace whitespace =
CssValueIDToPlatformEnum<EWhiteSpace>(value->GetValueID());
DCHECK(IsValidWhiteSpace(whitespace));
AddProperty(
CSSPropertyID::kWhiteSpaceCollapse, CSSPropertyID::kWhiteSpace,
*CSSIdentifierValue::Create(ToWhiteSpaceCollapse(whitespace)),
important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
properties);
AddProperty(
CSSPropertyID::kTextWrap, CSSPropertyID::kWhiteSpace,
*CSSIdentifierValue::Create(ToTextWrap(whitespace)), important,
css_parsing_utils::IsImplicitProperty::kNotImplicit, properties);
return true;
}
// If `range` is not at end, the keyword is for longhands. Restore `range`.
range = original_range;
}
// Consume multi-value syntax if the first identifier is not pre-defined.
return css_parsing_utils::ConsumeShorthandGreedilyViaLonghands(
whiteSpaceShorthand(), important, context, range, properties);
}
const CSSValue* WhiteSpace::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style,
CSSValuePhase value_phase) const {
const EWhiteSpace whitespace = style.WhiteSpace();
if (IsValidWhiteSpace(whitespace)) {
const CSSValueID value = PlatformEnumToCSSValueID(whitespace);
DCHECK_NE(value, CSSValueID::kNone);
return CSSIdentifierValue::Create(value);
}
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
const WhiteSpaceCollapse collapse = style.GetWhiteSpaceCollapse();
if (collapse != ComputedStyleInitialValues::InitialWhiteSpaceCollapse()) {
list->Append(*CSSIdentifierValue::Create(collapse));
}
const TextWrap wrap = style.GetTextWrap();
if (wrap != ComputedStyleInitialValues::InitialTextWrap()) {
list->Append(*CSSIdentifierValue::Create(wrap));
}
// When all longhands are initial values, it should be `normal`, covered by
// `IsValidWhiteSpace()` above.
DCHECK(list->length());
return list;
}
} // namespace css_shorthand
} // namespace blink