📄 cssprimitivevalue.cpp
字号:
/* * (C) 1999-2003 Lars Knoll (knoll@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#include "CSSPrimitiveValue.h"#include "CSSHelper.h"#include "CSSPropertyNames.h"#include "CSSStyleSheet.h"#include "CSSValueKeywords.h"#include "Color.h"#include "Counter.h"#include "ExceptionCode.h"#include "Node.h"#include "Pair.h"#include "Rect.h"#include "RenderStyle.h"#include <wtf/ASCIICType.h>#include <wtf/StdLibExtras.h>#if ENABLE(DASHBOARD_SUPPORT)#include "DashboardRegion.h"#endifusing namespace WTF;namespace WebCore {// A more stylish solution than sharing would be to turn CSSPrimitiveValue (or CSSValues in general) into non-virtual,// non-refcounted simple type with value semantics. In practice these sharing tricks get similar memory benefits // with less need for refactoring.PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createIdentifier(int ident){ static RefPtr<CSSPrimitiveValue>* identValueCache = new RefPtr<CSSPrimitiveValue>[numCSSValueKeywords]; if (ident >= 0 && ident < numCSSValueKeywords) { RefPtr<CSSPrimitiveValue> primitiveValue = identValueCache[ident]; if (!primitiveValue) { primitiveValue = adoptRef(new CSSPrimitiveValue(ident)); identValueCache[ident] = primitiveValue; } return primitiveValue.release(); } return adoptRef(new CSSPrimitiveValue(ident));}PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createColor(unsigned rgbValue){ typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache; static ColorValueCache* colorValueCache = new ColorValueCache; // These are the empty and deleted values of the hash table. if (rgbValue == Color::transparent) { static CSSPrimitiveValue* colorTransparent = new CSSPrimitiveValue(Color::transparent); return colorTransparent; } if (rgbValue == Color::white) { static CSSPrimitiveValue* colorWhite = new CSSPrimitiveValue(Color::white); return colorWhite; } RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue); if (primitiveValue) return primitiveValue.release(); primitiveValue = adoptRef(new CSSPrimitiveValue(rgbValue)); // Just wipe out the cache and start rebuilding when it gets too big. const int maxColorCacheSize = 512; if (colorValueCache->size() >= maxColorCacheSize) colorValueCache->clear(); colorValueCache->add(rgbValue, primitiveValue); return primitiveValue.release();}PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(double value, UnitTypes type){ // Small integers are very common. Try to share them. const int cachedIntegerCount = 128; // Other common primitive types have UnitTypes smaller than this. const int maxCachedUnitType = CSS_PX; typedef RefPtr<CSSPrimitiveValue>(* IntegerValueCache)[maxCachedUnitType + 1]; static IntegerValueCache integerValueCache = new RefPtr<CSSPrimitiveValue>[cachedIntegerCount][maxCachedUnitType + 1]; if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) { int intValue = static_cast<int>(value); if (value == intValue) { RefPtr<CSSPrimitiveValue> primitiveValue = integerValueCache[intValue][type]; if (!primitiveValue) { primitiveValue = adoptRef(new CSSPrimitiveValue(value, type)); integerValueCache[intValue][type] = primitiveValue; } return primitiveValue.release(); } } return adoptRef(new CSSPrimitiveValue(value, type));}PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type){ return adoptRef(new CSSPrimitiveValue(value, type));}static const char* valueOrPropertyName(int valueOrPropertyID){ if (const char* valueName = getValueName(valueOrPropertyID)) return valueName; return getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID));}// "ident" from the CSS tokenizer, minus backslash-escape sequencesstatic bool isCSSTokenizerIdentifier(const String& string){ const UChar* p = string.characters(); const UChar* end = p + string.length(); // -? if (p != end && p[0] == '-') ++p; // {nmstart} if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0]))) return false; ++p; // {nmchar}* for (; p != end; ++p) { if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0]))) return false; } return true;}// "url" from the CSS tokenizer, minus backslash-escape sequencesstatic bool isCSSTokenizerURL(const String& string){ const UChar* p = string.characters(); const UChar* end = p + string.length(); for (; p != end; ++p) { UChar c = p[0]; switch (c) { case '!': case '#': case '$': case '%': case '&': break; default: if (c < '*') return false; if (c <= '~') break; if (c < 128) return false; } } return true;}// We use single quotes for now because markup.cpp uses double quotes.static String quoteString(const String& string){ // FIXME: Also need to escape characters like '\n'. String s = string; s.replace('\\', "\\\\"); s.replace('\'', "\\'"); return "'" + s + "'";}static String quoteStringIfNeeded(const String& string){ return isCSSTokenizerIdentifier(string) ? string : quoteString(string);}static String quoteURLIfNeeded(const String& string){ return isCSSTokenizerURL(string) ? string : quoteString(string);}CSSPrimitiveValue::CSSPrimitiveValue() : m_type(0){}CSSPrimitiveValue::CSSPrimitiveValue(int ident) : m_type(CSS_IDENT){ m_value.ident = ident;}CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) : m_type(type){ m_value.num = num;}CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) : m_type(type){ if ((m_value.string = str.impl())) m_value.string->ref();}CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) : m_type(CSS_RGBCOLOR){ m_value.rgbcolor = color;}CSSPrimitiveValue::CSSPrimitiveValue(const Length& length){ switch (length.type()) { case Auto: m_type = CSS_IDENT; m_value.ident = CSSValueAuto; break; case WebCore::Fixed: m_type = CSS_PX; m_value.num = length.value(); break; case Intrinsic: m_type = CSS_IDENT; m_value.ident = CSSValueIntrinsic; break; case MinIntrinsic: m_type = CSS_IDENT; m_value.ident = CSSValueMinIntrinsic; break; case Percent: m_type = CSS_PERCENTAGE; m_value.num = length.percent(); break; case Relative: case Static: ASSERT_NOT_REACHED(); break; }}void CSSPrimitiveValue::init(PassRefPtr<Counter> c){ m_type = CSS_COUNTER; m_value.counter = c.releaseRef();}void CSSPrimitiveValue::init(PassRefPtr<Rect> r){ m_type = CSS_RECT; m_value.rect = r.releaseRef();}#if ENABLE(DASHBOARD_SUPPORT)void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r){ m_type = CSS_DASHBOARD_REGION; m_value.region = r.releaseRef();}#endifvoid CSSPrimitiveValue::init(PassRefPtr<Pair> p){ m_type = CSS_PAIR; m_value.pair = p.releaseRef();}CSSPrimitiveValue::~CSSPrimitiveValue(){ cleanup();}void CSSPrimitiveValue::cleanup(){ switch (m_type) { case CSS_STRING: case CSS_URI: case CSS_ATTR: case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: case CSS_PARSER_HEXCOLOR: if (m_value.string) m_value.string->deref(); break; case CSS_COUNTER: m_value.counter->deref(); break; case CSS_RECT: m_value.rect->deref(); break; case CSS_PAIR: m_value.pair->deref(); break;#if ENABLE(DASHBOARD_SUPPORT) case CSS_DASHBOARD_REGION: if (m_value.region) m_value.region->deref(); break;#endif default: break; } m_type = 0;}int CSSPrimitiveValue::computeLengthInt(RenderStyle* style){ double result = computeLengthDouble(style); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > INT_MAX || result < INT_MIN) return 0; return static_cast<int>(result);}int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, double multiplier){ double result = computeLengthDouble(style, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > INT_MAX || result < INT_MIN) return 0; return static_cast<int>(result);}const int intMaxForLength = 0x7ffffff; // max value for a 28-bit intconst int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int// Lengths expect an int that is only 28-bits, so we have to check for a different overflow.int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style){ double result = computeLengthDouble(style); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > intMaxForLength || result < intMinForLength) return 0; return static_cast<int>(result);}// Lengths expect an int that is only 28-bits, so we have to check for a different overflow.int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, double multiplier){ double result = computeLengthDouble(style, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > intMaxForLength || result < intMinForLength) return 0; return static_cast<int>(result);}short CSSPrimitiveValue::computeLengthShort(RenderStyle* style){ double result = computeLengthDouble(style); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > SHRT_MAX || result < SHRT_MIN) return 0; return static_cast<short>(result);}short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, double multiplier){ double result = computeLengthDouble(style, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > SHRT_MAX || result < SHRT_MIN) return 0; return static_cast<short>(result);}float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, bool computingFontSize){ return static_cast<float>(computeLengthDouble(style, 1.0, computingFontSize));}float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, double multiplier, bool computingFontSize){ return static_cast<float>(computeLengthDouble(style, multiplier, computingFontSize));}double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, double multiplier, bool computingFontSize){ unsigned short type = primitiveType(); // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference // as well as enforcing the implicit "smart minimum." In addition the CSS property text-size-adjust is used to // prevent text from zooming at all. Therefore we will not apply the zoom here if we are computing font-size. bool applyZoomMultiplier = !computingFontSize; double factor = 1.0; switch (type) { case CSS_EMS: applyZoomMultiplier = false; factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); break; case CSS_EXS: // FIXME: We have a bug right now where the zoom will be applied twice to EX units. // We really need to compute EX using fontMetrics for the original specifiedSize and not use // our actual constructed rendering font. applyZoomMultiplier = false; factor = style->font().xHeight(); break; case CSS_PX: break; case CSS_CM: factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) break; case CSS_MM: factor = cssPixelsPerInch / 25.4; break; case CSS_IN: factor = cssPixelsPerInch; break; case CSS_PT: factor = cssPixelsPerInch / 72.0; break; case CSS_PC: // 1 pc == 12 pt factor = cssPixelsPerInch * 12.0 / 72.0; break; default: return -1.0; } double result = getDoubleValue() * factor; if (!applyZoomMultiplier || multiplier == 1.0) return result; // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from // vanishing. double zoomedResult = result * multiplier; if (result >= 1.0) zoomedResult = max(1.0, zoomedResult); return zoomedResult;}void CSSPrimitiveValue::setFloatValue(unsigned short unitType, double floatValue, ExceptionCode& ec){ ec = 0; // FIXME: check if property supports this type if (m_type > CSS_DIMENSION) { ec = SYNTAX_ERR; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -