blob: e4191a0aac1d6d8e8089284cb6192316c6d9c102 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/css/properties/CSSPropertyTransformUtils.h"
#include "core/css/CSSFunctionValue.h"
#include "core/css/CSSValueList.h"
#include "core/css/parser/CSSParserContext.h"
#include "core/css/parser/CSSParserLocalContext.h"
#include "core/css/parser/CSSPropertyParserHelpers.h"
#include "platform/Length.h"
namespace blink {
namespace {
bool ConsumeNumbers(CSSParserTokenRange& args,
CSSFunctionValue*& transform_value,
unsigned number_of_arguments) {
do {
CSSValue* parsed_value =
CSSPropertyParserHelpers::ConsumeNumber(args, kValueRangeAll);
if (!parsed_value)
return false;
transform_value->Append(*parsed_value);
if (--number_of_arguments &&
!CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args)) {
return false;
}
} while (number_of_arguments);
return true;
}
bool ConsumePerspective(CSSParserTokenRange& args,
const CSSParserContext* context,
CSSFunctionValue*& transform_value,
bool use_legacy_parsing) {
CSSPrimitiveValue* parsed_value = CSSPropertyParserHelpers::ConsumeLength(
args, context->Mode(), kValueRangeNonNegative);
if (!parsed_value && use_legacy_parsing) {
double perspective;
if (!CSSPropertyParserHelpers::ConsumeNumberRaw(args, perspective) ||
perspective < 0) {
return false;
}
context->Count(WebFeature::kUnitlessPerspectiveInTransformProperty);
parsed_value = CSSPrimitiveValue::Create(
perspective, CSSPrimitiveValue::UnitType::kPixels);
}
if (!parsed_value)
return false;
transform_value->Append(*parsed_value);
return true;
}
bool ConsumeTranslate3d(CSSParserTokenRange& args,
CSSParserMode css_parser_mode,
CSSFunctionValue*& transform_value) {
unsigned number_of_arguments = 2;
CSSValue* parsed_value = nullptr;
do {
parsed_value = CSSPropertyParserHelpers::ConsumeLengthOrPercent(
args, css_parser_mode, kValueRangeAll);
if (!parsed_value)
return false;
transform_value->Append(*parsed_value);
if (!CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args))
return false;
} while (--number_of_arguments);
parsed_value = CSSPropertyParserHelpers::ConsumeLength(args, css_parser_mode,
kValueRangeAll);
if (!parsed_value)
return false;
transform_value->Append(*parsed_value);
return true;
}
CSSValue* ConsumeTransformValue(CSSParserTokenRange& range,
const CSSParserContext* context,
bool use_legacy_parsing) {
CSSValueID function_id = range.Peek().FunctionId();
if (function_id == CSSValueInvalid)
return nullptr;
CSSParserTokenRange args = CSSPropertyParserHelpers::ConsumeFunction(range);
if (args.AtEnd())
return nullptr;
CSSFunctionValue* transform_value = CSSFunctionValue::Create(function_id);
CSSValue* parsed_value = nullptr;
switch (function_id) {
case CSSValueRotate:
case CSSValueRotateX:
case CSSValueRotateY:
case CSSValueRotateZ:
case CSSValueSkewX:
case CSSValueSkewY:
case CSSValueSkew:
parsed_value = CSSPropertyParserHelpers::ConsumeAngle(
args, *context, WebFeature::kUnitlessZeroAngleTransform);
if (!parsed_value)
return nullptr;
if (function_id == CSSValueSkew &&
CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args)) {
transform_value->Append(*parsed_value);
parsed_value = CSSPropertyParserHelpers::ConsumeAngle(
args, *context, WebFeature::kUnitlessZeroAngleTransform);
if (!parsed_value)
return nullptr;
}
break;
case CSSValueScaleX:
case CSSValueScaleY:
case CSSValueScaleZ:
case CSSValueScale:
parsed_value =
CSSPropertyParserHelpers::ConsumeNumber(args, kValueRangeAll);
if (!parsed_value)
return nullptr;
if (function_id == CSSValueScale &&
CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args)) {
transform_value->Append(*parsed_value);
parsed_value =
CSSPropertyParserHelpers::ConsumeNumber(args, kValueRangeAll);
if (!parsed_value)
return nullptr;
}
break;
case CSSValuePerspective:
if (!ConsumePerspective(args, context, transform_value,
use_legacy_parsing)) {
return nullptr;
}
break;
case CSSValueTranslateX:
case CSSValueTranslateY:
case CSSValueTranslate:
parsed_value = CSSPropertyParserHelpers::ConsumeLengthOrPercent(
args, context->Mode(), kValueRangeAll);
if (!parsed_value)
return nullptr;
if (function_id == CSSValueTranslate &&
CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args)) {
transform_value->Append(*parsed_value);
parsed_value = CSSPropertyParserHelpers::ConsumeLengthOrPercent(
args, context->Mode(), kValueRangeAll);
if (!parsed_value)
return nullptr;
}
break;
case CSSValueTranslateZ:
parsed_value = CSSPropertyParserHelpers::ConsumeLength(
args, context->Mode(), kValueRangeAll);
break;
case CSSValueMatrix:
case CSSValueMatrix3d:
if (!ConsumeNumbers(args, transform_value,
(function_id == CSSValueMatrix3d) ? 16 : 6)) {
return nullptr;
}
break;
case CSSValueScale3d:
if (!ConsumeNumbers(args, transform_value, 3))
return nullptr;
break;
case CSSValueRotate3d:
if (!ConsumeNumbers(args, transform_value, 3) ||
!CSSPropertyParserHelpers::ConsumeCommaIncludingWhitespace(args)) {
return nullptr;
}
parsed_value = CSSPropertyParserHelpers::ConsumeAngle(
args, *context, WebFeature::kUnitlessZeroAngleTransform);
if (!parsed_value)
return nullptr;
break;
case CSSValueTranslate3d:
if (!ConsumeTranslate3d(args, context->Mode(), transform_value))
return nullptr;
break;
default:
return nullptr;
}
if (parsed_value)
transform_value->Append(*parsed_value);
if (!args.AtEnd())
return nullptr;
return transform_value;
}
} // namespace
CSSValue* CSSPropertyTransformUtils::ConsumeTransformList(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext& local_context) {
if (range.Peek().Id() == CSSValueNone)
return CSSPropertyParserHelpers::ConsumeIdent(range);
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
do {
CSSValue* parsed_transform_value =
ConsumeTransformValue(range, &context, local_context.UseAliasParsing());
if (!parsed_transform_value)
return nullptr;
list->Append(*parsed_transform_value);
} while (!range.AtEnd());
return list;
}
} // namespace blink