blob: fd0cd1bf157099ddb4cc3c4167b5ff7c46b5685a [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 2007 Google Inc. All Rights Reserved.
// Author: dpeng@google.com (Daniel Peng)
#include "webutil/css/util.h"
#include "base/commandlineflags.h"
#include "strings/ascii_ctype.h"
#include "strings/memutil.h"
#include "strings/stringpiece_utils.h"
#include "strings/strutil.h"
#include "util/utf8/public/unicodetext.h"
#include "webutil/css/media.h"
#include "webutil/css/parser.h"
#include "webutil/css/string_util.h"
DEFINE_double(font_size_adjustment,
0.58,
"Ratio of x-height to font-size in CSS terms");
namespace Css {
namespace Util {
HtmlColor GetCssColor(const Css::Value* val,
const HtmlColor& def,
COLOR_ATTR* attr) {
if (val) {
switch (val->GetLexicalUnitType()) {
case Value::COLOR:
if (val->GetColorValue().IsDefined()) {
if (attr) *attr = ORIGINAL;
return val->GetColorValue();
}
break;
case Value::UNKNOWN:
if (attr) *attr = UNKNOWN;
return def;
case Value::IDENT:
switch (val->GetIdentifier().ident()) {
case Identifier::INHERIT:
if (attr) *attr = INHERIT;
return def;
case Identifier::TRANSPARENT:
if (attr) *attr = TRANSPARENT;
return def;
default:
break;
}
break;
default:
break;
}
}
if (attr) *attr = TRANSPARENT;
return def;
}
bool GetCssLength(const Css::Value* val, double parent_size,
double font_size, double unit,
bool can_negative, bool can_unitless,
double* size) {
if (val == NULL || val->GetLexicalUnitType() != Css::Value::NUMBER ||
(!can_negative && val->GetFloatValue() < 0))
return false;
switch (val->GetDimension()) {
case Css::Value::PERCENT:
if (parent_size != -1) {
*size = val->GetFloatValue() * parent_size / 100.0;
return true;
}
break;
case Css::Value::PX:
*size = val->GetFloatValue();
return true;
case Css::Value::EM:
*size = val->GetFloatValue() * font_size;
return true;
case Css::Value::EX:
*size = val->GetFloatValue() * font_size * FLAGS_font_size_adjustment;
return true;
case Css::Value::MM:
*size = val->GetFloatValue() / 0.265;
return true;
case Css::Value::CM:
*size = val->GetFloatValue() / 0.265 * 10;
return true;
case Css::Value::IN:
*size = val->GetFloatValue() * 96;
return true;
case Css::Value::PT:
*size = val->GetFloatValue() * 4 / 3;
return true;
case Css::Value::PC:
*size = val->GetFloatValue() * 16;
return true;
case Css::Value::NO_UNIT:
// 0 without unit is always allowed
if (can_unitless || val->GetFloatValue() == 0.0) {
*size = val->GetFloatValue() * unit;
return true;
}
break;
default:
break;
}
return false;
}
// Css system colors.
// The structure is nearly literally copied from webutil/html/htmlcolor.cc.
typedef struct RgbValue {
unsigned char r_;
unsigned char g_;
unsigned char b_;
} RgbValue;
// Color table for system colors.
// This is only a rough estimation based on a typical setup.
// when making change to known_system_color_values, please
// also change the GetKnownSystemColorValue function because
// entire table is hardcoded into the function for efficiency
static const RgbValue known_system_color_values[] = {
/* 0 activeborder */{212, 208, 200},
/* 1 activecaption */{ 0, 84, 227},
/* 2 appworkspace */{128, 128, 128},
/* 3 background */{ 0, 78, 152},
/* 4 buttonface */{236, 233, 216},
/* 5 buttonhighlight */{255, 255, 255},
/* 6 buttonshadow */{172, 168, 153},
/* 7 buttontext */{ 0, 0, 0},
/* 8 captiontext */{255, 255, 255},
/* 9 graytext */{172, 168, 153},
/*10 highlight */{ 49, 106, 197},
/*11 highlighttext */{255, 255, 255},
/*12 inactiveborder */{212, 208, 200},
/*13 inactivecaption */{122, 150, 223},
/*14 inactivecaptiontext */{216, 228, 248},
/*15 infobackground */{255, 255, 225},
/*16 infotext */{ 0, 0, 0},
/*17 menu */{255, 255, 255},
/*18 menutext */{ 0, 0, 0},
/*19 scrollbar */{212, 208, 200},
/*20 threeddarkshadow */{113, 111, 100},
/*21 threedface */{236, 233, 216},
/*22 threedhighlight */{255, 255, 255},
/*23 threedlightshadow */{241, 239, 226},
/*24 threedshadow */{172, 168, 153},
/*25 window */{255, 255, 255},
/*26 windowframe */{ 0, 0, 0},
/*27 windowtext */{ 0, 0, 0},
};
const RgbValue* GetKnownSystemColorValue(const char *colorstr) {
switch (ascii_tolower(colorstr[0])) {
case 'a':
switch (ascii_tolower(colorstr[1])) {
case 'c':
// TODO(sligocki): Use a locale-independent function instead of
// strcasecmp so that this code is more portable.
if (!strcasecmp("activeborder", colorstr)) {
return &known_system_color_values[0];
} else if (!strcasecmp("activecaption", colorstr)) {
return &known_system_color_values[1];
}
return NULL;
case 'p':
if (!strcasecmp("appworkspace", colorstr)) {
return &known_system_color_values[2];
}
return NULL;
}
return NULL;
case 'b':
switch (ascii_tolower(colorstr[1])) {
case 'a':
if (!strcasecmp("background", colorstr)) {
return &known_system_color_values[3];
}
return NULL;
case 'u':
if (!strcasecmp("buttonface", colorstr)) {
return &known_system_color_values[4];
} else if (!strcasecmp("buttonhighlight", colorstr)) {
return &known_system_color_values[5];
} else if (!strcasecmp("buttonshadow", colorstr)) {
return &known_system_color_values[6];
} else if (!strcasecmp("buttontext", colorstr)) {
return &known_system_color_values[7];
}
return NULL;
}
return NULL;
case 'c':
if (!strcasecmp("captiontext", colorstr)) {
return &known_system_color_values[8];
}
return NULL;
case 'g':
if (!strcasecmp("graytext", colorstr)) {
return &known_system_color_values[9];
}
return NULL;
case 'h':
if (!strcasecmp("highlight", colorstr)) {
return &known_system_color_values[10];
} else if (!strcasecmp("highlighttext", colorstr)) {
return &known_system_color_values[11];
}
return NULL;
case 'i':
if (!strcasecmp("inactiveborder", colorstr)) {
return &known_system_color_values[12];
} else if (!strcasecmp("inactivecaption", colorstr)) {
return &known_system_color_values[13];
} else if (!strcasecmp("inactivecaptiontext", colorstr)) {
return &known_system_color_values[14];
} else if (!strcasecmp("infobackground", colorstr)) {
return &known_system_color_values[15];
} else if (!strcasecmp("infotext", colorstr)) {
return &known_system_color_values[16];
}
return NULL;
case 'm':
if (!strcasecmp("menu", colorstr)) {
return &known_system_color_values[17];
} else if (!strcasecmp("menutext", colorstr)) {
return &known_system_color_values[18];
}
return NULL;
case 's':
if (!strcasecmp("scrollbar", colorstr)) {
return &known_system_color_values[19];
}
return NULL;
case 't':
if (!strcasecmp("threeddarkshadow", colorstr)) {
return &known_system_color_values[20];
} else if (!strcasecmp("threedface", colorstr)) {
return &known_system_color_values[21];
} else if (!strcasecmp("threedhighlight", colorstr)) {
return &known_system_color_values[22];
} else if (!strcasecmp("threedlightshadow", colorstr)) {
return &known_system_color_values[23];
} else if (!strcasecmp("threedshadow", colorstr)) {
return &known_system_color_values[24];
}
return NULL;
case 'w':
if (!strcasecmp("window", colorstr)) {
return &known_system_color_values[25];
} else if (!strcasecmp("windowframe", colorstr)) {
return &known_system_color_values[26];
} else if (!strcasecmp("windowtext", colorstr)) {
return &known_system_color_values[27];
}
return NULL;
}
return NULL;
}
bool GetSystemColor(const string& colorstr, HtmlColor* color) {
const RgbValue *p_rgb = GetKnownSystemColorValue(colorstr.c_str());
if (p_rgb) {
color->SetValueFromRGB(p_rgb->r_, p_rgb->g_, p_rgb->b_);
return true;
} else {
return false;
}
}
namespace {
bool MediumAppliesToScreen(const StringPiece& medium) {
return (StringCaseEquals(medium, "all") ||
StringCaseEquals(medium, "screen"));
}
bool MediumAppliesToScreen(const UnicodeText& medium) {
return (StringCaseEquals(medium, "all") ||
StringCaseEquals(medium, "screen"));
}
} // namespace
bool MediaAppliesToScreen(const StringPiece& media) {
std::vector<StringPiece> values = Css::SplitSkippingEmpty(media, ',');
if (values.empty()) return true;
for (std::vector<StringPiece>::iterator iter = values.begin();
iter < values.end(); ++iter) {
strings::RemoveWhitespaceContext(&(*iter));
if (MediumAppliesToScreen(*iter))
return true;
}
return false;
}
bool MediaAppliesToScreen(const std::vector<UnicodeText>& media) {
if (media.empty()) return true;
for (std::vector<UnicodeText>::const_iterator iter = media.begin();
iter < media.end(); ++iter) {
if (MediumAppliesToScreen(*iter))
return true;
}
return false;
}
bool MediaAppliesToScreen(const Css::MediaQueries& media_queries) {
if (media_queries.empty()) return true;
for (MediaQueries::const_iterator iter = media_queries.begin();
iter < media_queries.end(); ++iter) {
const Css::MediaQuery* query = *iter;
if (query->qualifier() == Css::MediaQuery::NO_QUALIFIER &&
MediumAppliesToScreen(query->media_type())) {
return true;
}
}
return false;
}
} // namespace Util
} // namespace Css