blob: d00c8862ef05c1555b9714d88fa3c0f01c9c0d7a [file] [log] [blame]
/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: dpeng@google.com (Daniel Peng)
#include "util/gtl/stl_util.h"
#include "webutil/css/value.h"
#include "base/logging.h"
#include "strings/memutil.h"
#include "webutil/css/fallthrough_intended.h"
#include "webutil/html/htmlcolor.h"
namespace Css {
//
// Static constants.
//
const char* const Value::kDimensionUnitText[] = {
"em", "ex", "px", "cm", "mm", "in", "pt", "pc",
"deg", "rad", "grad", "ms", "s", "hz", "khz", "%", "OTHER", "" };
//
// Constructors.
//
Value::Value(ValueType ty)
: type_(ty),
color_(0, 0, 0) {
DCHECK(ty == COMMA || ty == DEFAULT || ty == UNKNOWN);
}
Value::Value(double num, const UnicodeText& unit)
: type_(NUMBER),
num_(num),
color_(0, 0, 0) {
unit_ = UnitFromText(unit.utf8_data(), unit.utf8_length());
if (unit_ == OTHER)
str_ = unit;
}
Value::Value(double num, Unit unit)
: type_(NUMBER),
num_(num),
unit_(unit),
color_(0, 0, 0) {
DCHECK_NE(unit, OTHER);
}
Value::Value(ValueType ty, const UnicodeText& str)
: type_(ty),
str_(str),
color_(0, 0, 0) {
DCHECK(ty == STRING || ty == URI);
}
Value::Value(const Identifier& identifier)
: type_(IDENT),
identifier_(identifier),
color_(0, 0, 0) {
}
Value::Value(const Identifier::Ident ident)
: type_(IDENT),
identifier_(Identifier(ident)),
color_(0, 0, 0) {
}
Value::Value(ValueType ty, FunctionParameters* params)
: type_(ty),
params_(params),
color_(0, 0, 0) {
DCHECK(params != NULL);
DCHECK(ty == RECT);
}
Value::Value(const UnicodeText& func, FunctionParameters* params)
: type_(FUNCTION),
str_(func),
params_(params),
color_(0, 0, 0) {
DCHECK(params != NULL);
}
Value::Value(HtmlColor c)
: type_(COLOR),
color_(c) {
}
Value::Value(const Value& other)
: type_(other.type_),
num_(other.num_),
unit_(other.unit_),
identifier_(other.identifier_),
str_(other.str_),
params_(new FunctionParameters),
color_(other.color_),
bytes_in_original_buffer_(other.bytes_in_original_buffer_) {
if (other.params_.get() != NULL) {
params_->Copy(*other.params_);
}
}
Value& Value::operator=(const Value& other) {
if (this == &other) return *this;
type_ = other.type_;
num_ = other.num_;
unit_ = other.unit_;
identifier_ = other.identifier_;
str_ = other.str_;
color_ = other.color_;
bytes_in_original_buffer_ = other.bytes_in_original_buffer_;
if (other.params_.get() != NULL) {
params_->Copy(*other.params_);
} else {
params_.reset();
}
return *this;
}
bool Value::Equals(const Value& other) const {
if (type_ != other.type_) return false;
switch (type_) {
case DEFAULT:
case UNKNOWN:
return true;
case NUMBER:
return unit_ == other.unit_ && num_ == other.num_;
case URI:
case STRING:
return str_ == other.str_;
case IDENT:
if (identifier_.ident() != other.identifier_.ident())
return false;
if (identifier_.ident() == Identifier::OTHER)
return identifier_.ident_text() == other.identifier_.ident_text();
return true;
case COLOR:
return color_.Equals(other.color_);
case FUNCTION:
if (str_ != other.str_)
return false;
FALLTHROUGH_INTENDED;
case RECT:
if (params_.get() == NULL)
return other.params_.get() == NULL;
return params_->Equals(*other.params_);
default:
LOG(FATAL) << "Unknown type:" << type_;
}
}
//
// Static functions mapping between units and strings
//
Value::Unit Value::UnitFromText(const char* str, int len) {
switch (len) {
case 0:
return NO_UNIT;
case 1:
switch (str[0]) {
case '%': return PERCENT;
case 's': case 'S': return S;
default: return OTHER;
}
case 2:
switch (str[0]) {
case 'e': case 'E':
switch (str[1]) {
case 'm': case 'M': return EM;
case 'x': case 'X': return EX;
default: return OTHER;
}
case 'p': case 'P':
switch (str[1]) {
case 'x': case 'X': return PX;
case 't': case 'T': return PT;
case 'c': case 'C': return PC;
default: return OTHER;
}
case 'c': case 'C':
switch (str[1]) {
case 'm': case 'M': return CM;
default: return OTHER;
}
case 'm': case 'M':
switch (str[1]) {
case 'm': case 'M': return MM;
case 's': case 'S': return MS;
default: return OTHER;
}
case 'i': case 'I':
switch (str[1]) {
case 'n': case 'N': return IN;
default: return OTHER;
}
case 'h': case 'H':
switch (str[1]) {
case 'z': case 'Z': return HZ;
default: return OTHER;
}
default:
return OTHER;
}
case 3:
if (memcasecmp(str, "deg", 3) == 0) return DEG;
if (memcasecmp(str, "rad", 3) == 0) return RAD;
if (memcasecmp(str, "khz", 3) == 0) return KHZ;
return OTHER;
case 4:
if (memcasecmp(str, "grad", 3) == 0) return GRAD;
return OTHER;
default:
return OTHER;
}
}
const char* Value::TextFromUnit(Unit u) {
DCHECK_LT(u, NUM_UNITS);
COMPILE_ASSERT(arraysize(kDimensionUnitText) == NUM_UNITS, dimensionunitsize);
return kDimensionUnitText[u];
}
//
// Accessors.
//
Value::ValueType Value::GetLexicalUnitType() const {
return type_;
}
string Value::GetDimensionUnitText() const {
DCHECK_EQ(type_, NUMBER);
if (unit_ == OTHER)
return string(str_.utf8_data(), str_.utf8_length());
else
return TextFromUnit(unit_);
}
Value::Unit Value::GetDimension() const {
DCHECK_EQ(type_, NUMBER);
return unit_;
}
int Value::GetIntegerValue() const {
DCHECK_EQ(type_, NUMBER);
return static_cast<int>(num_);
}
double Value::GetFloatValue() const {
DCHECK_EQ(type_, NUMBER);
return num_;
}
const Values* Value::GetParameters() const {
DCHECK(type_ == FUNCTION || type_ == RECT);
return params_->values();
}
const FunctionParameters* Value::GetParametersWithSeparators() const {
DCHECK(type_ == FUNCTION || type_ == RECT);
return params_.get();
}
const UnicodeText& Value::GetFunctionName() const {
DCHECK_EQ(type_, FUNCTION);
return str_;
}
const UnicodeText& Value::GetStringValue() const {
DCHECK(type_ == URI || type_ == STRING);
return str_;
}
UnicodeText Value::GetIdentifierText() const {
DCHECK_EQ(type_, IDENT);
return identifier_.ident_text();
}
const Identifier& Value::GetIdentifier() const {
DCHECK_EQ(type_, IDENT);
return identifier_;
}
const HtmlColor& Value::GetColorValue() const {
DCHECK_EQ(type_, COLOR);
return color_;
}
Values::~Values() { STLDeleteElements(this); }
FunctionParameters::~FunctionParameters() {}
void FunctionParameters::AddSepValue(Separator separator, Value* value) {
separators_.push_back(separator);
values_->push_back(value);
DCHECK_EQ(separators_.size(), values_->size());
}
bool FunctionParameters::Equals(const FunctionParameters& other) const {
if (size() != other.size()) {
return false;
}
for (int i = 0, n = size(); i < n; ++i) {
if (!value(i)->Equals(*other.value(i)) ||
separator(i) != other.separator(i)) {
return false;
}
}
return true;
}
void FunctionParameters::Copy(const FunctionParameters& other) {
if (this != &other) {
int size = other.size();
values_->clear();
values_->reserve(size);
separators_.clear();
separators_.reserve(size);
for (int i = 0; i < size; ++i) {
values_->push_back(new Value(*other.values_->at(i)));
separators_.push_back(other.separators_[i]);
}
}
DCHECK(this->Equals(other));
}
} // namespace