diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/css | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/css')
195 files changed, 44036 insertions, 0 deletions
diff --git a/Source/WebCore/css/CSSBorderImageValue.cpp b/Source/WebCore/css/CSSBorderImageValue.cpp new file mode 100644 index 0000000..8d4721a --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageValue.cpp @@ -0,0 +1,70 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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 "CSSBorderImageValue.h" + +#include "PlatformString.h" +#include "Rect.h" + +namespace WebCore { + +CSSBorderImageValue::CSSBorderImageValue(PassRefPtr<CSSValue> image, PassRefPtr<Rect> imageRect, int horizontalRule, int verticalRule) + : m_image(image) + , m_imageSliceRect(imageRect) + , m_horizontalSizeRule(horizontalRule) + , m_verticalSizeRule(verticalRule) +{ +} + +CSSBorderImageValue::~CSSBorderImageValue() +{ +} + +String CSSBorderImageValue::cssText() const +{ + // Image first. + String text(m_image->cssText()); + text += " "; + + // Now the rect, but it isn't really a rect, so we dump manually + text += m_imageSliceRect->top()->cssText(); + text += " "; + text += m_imageSliceRect->right()->cssText(); + text += " "; + text += m_imageSliceRect->bottom()->cssText(); + text += " "; + text += m_imageSliceRect->left()->cssText(); + + // Now the keywords. + text += " "; + text += CSSPrimitiveValue::createIdentifier(m_horizontalSizeRule)->cssText(); + text += " "; + text += CSSPrimitiveValue::createIdentifier(m_verticalSizeRule)->cssText(); + + return text; +} + +void CSSBorderImageValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + m_image->addSubresourceStyleURLs(urls, styleSheet); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSBorderImageValue.h b/Source/WebCore/css/CSSBorderImageValue.h new file mode 100644 index 0000000..6e1b964 --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageValue.h @@ -0,0 +1,64 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSBorderImageValue_h +#define CSSBorderImageValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Rect; + +class CSSBorderImageValue : public CSSValue { +public: + static PassRefPtr<CSSBorderImageValue> create(PassRefPtr<CSSValue> image, PassRefPtr<Rect> sliceRect, int horizontalRule, int verticalRule) + { + return adoptRef(new CSSBorderImageValue(image, sliceRect, horizontalRule, verticalRule)); + } + virtual ~CSSBorderImageValue(); + + virtual String cssText() const; + + CSSValue* imageValue() const { return m_image.get(); } + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + + // The border image. + RefPtr<CSSValue> m_image; + + // These four values are used to make "cuts" in the image. They can be numbers + // or percentages. + RefPtr<Rect> m_imageSliceRect; + + // Values for how to handle the scaling/stretching/tiling of the image slices. + int m_horizontalSizeRule; // Rule for how to adjust the widths of the top/middle/bottom + int m_verticalSizeRule; // Rule for how to adjust the heights of the left/middle/right + +private: + CSSBorderImageValue(PassRefPtr<CSSValue> image, PassRefPtr<Rect> sliceRect, int horizontalRule, int verticalRule); + virtual bool isBorderImageValue() const { return true; } +}; + +} // namespace WebCore + +#endif // CSSBorderImageValue_h diff --git a/Source/WebCore/css/CSSCanvasValue.cpp b/Source/WebCore/css/CSSCanvasValue.cpp new file mode 100644 index 0000000..e28def9 --- /dev/null +++ b/Source/WebCore/css/CSSCanvasValue.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSCanvasValue.h" + +#include "ImageBuffer.h" +#include "RenderObject.h" + +namespace WebCore { + +CSSCanvasValue::~CSSCanvasValue() +{ + if (m_element) + m_element->removeObserver(this); +} + +String CSSCanvasValue::cssText() const +{ + String result = "-webkit-canvas("; + result += m_name + ")"; + return result; +} + +void CSSCanvasValue::canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect) +{ + IntRect imageChangeRect = enclosingIntRect(changedRect); + RenderObjectSizeCountMap::const_iterator end = m_clients.end(); + for (RenderObjectSizeCountMap::const_iterator curr = m_clients.begin(); curr != end; ++curr) + curr->first->imageChanged(static_cast<WrappedImagePtr>(this), &imageChangeRect); +} + +void CSSCanvasValue::canvasResized(HTMLCanvasElement*) +{ + RenderObjectSizeCountMap::const_iterator end = m_clients.end(); + for (RenderObjectSizeCountMap::const_iterator curr = m_clients.begin(); curr != end; ++curr) + curr->first->imageChanged(static_cast<WrappedImagePtr>(this)); +} + +void CSSCanvasValue::canvasDestroyed(HTMLCanvasElement* element) +{ + ASSERT_UNUSED(element, element == m_element); + m_element = 0; +} + +IntSize CSSCanvasValue::fixedSize(const RenderObject* renderer) +{ + if (HTMLCanvasElement* elt = element(renderer->document())) + return IntSize(elt->width(), elt->height()); + return IntSize(); +} + +HTMLCanvasElement* CSSCanvasValue::element(Document* document) +{ + if (!m_element) { + m_element = document->getCSSCanvasElement(m_name); + if (!m_element) + return 0; + m_element->addObserver(this); + } + return m_element; +} + +Image* CSSCanvasValue::image(RenderObject* renderer, const IntSize& /*size*/) +{ + ASSERT(m_clients.contains(renderer)); + HTMLCanvasElement* elt = element(renderer->document()); + if (!elt || !elt->buffer()) + return 0; + return elt->copiedImage(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSCanvasValue.h b/Source/WebCore/css/CSSCanvasValue.h new file mode 100644 index 0000000..4cd4280 --- /dev/null +++ b/Source/WebCore/css/CSSCanvasValue.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSCanvasValue_h +#define CSSCanvasValue_h + +#include "CSSImageGeneratorValue.h" +#include "HTMLCanvasElement.h" + +namespace WebCore { + +class Document; + +class CSSCanvasValue : public CSSImageGeneratorValue, private CanvasObserver { +public: + static PassRefPtr<CSSCanvasValue> create() { return adoptRef(new CSSCanvasValue); } + virtual ~CSSCanvasValue(); + + virtual String cssText() const; + + virtual Image* image(RenderObject*, const IntSize&); + virtual bool isFixedSize() const { return true; } + virtual IntSize fixedSize(const RenderObject*); + + void setName(const String& name) { m_name = name; } + +private: + CSSCanvasValue() + : m_element(0) + { + } + + virtual void canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect); + virtual void canvasResized(HTMLCanvasElement*); + virtual void canvasDestroyed(HTMLCanvasElement*); + + HTMLCanvasElement* element(Document*); + + // The name of the canvas. + String m_name; + // The document supplies the element and owns it. + HTMLCanvasElement* m_element; +}; + +} // namespace WebCore + +#endif // CSSCanvasValue_h diff --git a/Source/WebCore/css/CSSCharsetRule.cpp b/Source/WebCore/css/CSSCharsetRule.cpp new file mode 100644 index 0000000..48229e4 --- /dev/null +++ b/Source/WebCore/css/CSSCharsetRule.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@macrules.ru) + * + * 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 "CSSCharsetRule.h" + +namespace WebCore { + +CSSCharsetRule::CSSCharsetRule(CSSStyleSheet* parent, const String& encoding) + : CSSRule(parent) + , m_encoding(encoding) +{ +} + +CSSCharsetRule::~CSSCharsetRule() +{ +} + +String CSSCharsetRule::cssText() const +{ + return "@charset \"" + m_encoding + "\";"; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSCharsetRule.h b/Source/WebCore/css/CSSCharsetRule.h new file mode 100644 index 0000000..07fb075 --- /dev/null +++ b/Source/WebCore/css/CSSCharsetRule.h @@ -0,0 +1,57 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSCharsetRule_h +#define CSSCharsetRule_h + +#include "CSSRule.h" +#include "PlatformString.h" + +namespace WebCore { + +class CSSCharsetRule : public CSSRule { +public: + static PassRefPtr<CSSCharsetRule> create(CSSStyleSheet* parent, const String& encoding) + { + return adoptRef(new CSSCharsetRule(parent, encoding)); + } + + virtual ~CSSCharsetRule(); + + const String& encoding() const { return m_encoding; } + void setEncoding(const String& encoding, ExceptionCode&) { m_encoding = encoding; } + + virtual String cssText() const; + +private: + CSSCharsetRule(CSSStyleSheet* parent, const String& encoding); + + virtual bool isCharsetRule() { return true; } + + // from CSSRule + virtual unsigned short type() const { return CHARSET_RULE; } + + String m_encoding; +}; + +} // namespace WebCore + +#endif // CSSCharsetRule_h diff --git a/Source/WebCore/css/CSSCharsetRule.idl b/Source/WebCore/css/CSSCharsetRule.idl new file mode 100644 index 0000000..2b158ff --- /dev/null +++ b/Source/WebCore/css/CSSCharsetRule.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface CSSCharsetRule : CSSRule { +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C + readonly attribute [ConvertNullStringTo=Null] DOMString encoding; +#else + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString encoding + setter raises(DOMException); +#endif + }; + +} diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp new file mode 100644 index 0000000..21cf9ac --- /dev/null +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -0,0 +1,1885 @@ +/* + * Copyright (C) 2004 Zack Rusin <zack@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "config.h" +#include "CSSComputedStyleDeclaration.h" + +#include "AnimationController.h" +#include "CSSBorderImageValue.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPrimitiveValue.h" +#include "CSSPrimitiveValueMappings.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSReflectValue.h" +#include "CSSSelector.h" +#include "CSSTimingFunctionValue.h" +#include "CSSValueList.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "Rect.h" +#include "RenderBox.h" +#include "RenderLayer.h" +#include "ShadowValue.h" +#ifdef ANDROID_LAYOUT +#include "Frame.h" +#include "Settings.h" +#endif +#include "WebKitCSSTransformValue.h" + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +namespace WebCore { + +// List of all properties we know how to compute, omitting shorthands. +static const int computedProperties[] = { + CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundClip, + CSSPropertyBackgroundColor, + CSSPropertyBackgroundImage, + CSSPropertyBackgroundOrigin, + CSSPropertyBackgroundPosition, // more-specific background-position-x/y are non-standard + CSSPropertyBackgroundRepeat, + CSSPropertyBackgroundSize, + CSSPropertyBorderBottomColor, + CSSPropertyBorderBottomLeftRadius, + CSSPropertyBorderBottomRightRadius, + CSSPropertyBorderBottomStyle, + CSSPropertyBorderBottomWidth, + CSSPropertyBorderCollapse, + CSSPropertyBorderLeftColor, + CSSPropertyBorderLeftStyle, + CSSPropertyBorderLeftWidth, + CSSPropertyBorderRightColor, + CSSPropertyBorderRightStyle, + CSSPropertyBorderRightWidth, + CSSPropertyBorderTopColor, + CSSPropertyBorderTopLeftRadius, + CSSPropertyBorderTopRightRadius, + CSSPropertyBorderTopStyle, + CSSPropertyBorderTopWidth, + CSSPropertyBottom, + CSSPropertyBoxShadow, + CSSPropertyBoxSizing, + CSSPropertyCaptionSide, + CSSPropertyClear, + CSSPropertyClip, + CSSPropertyColor, + CSSPropertyCursor, + CSSPropertyDirection, + CSSPropertyDisplay, + CSSPropertyEmptyCells, + CSSPropertyFloat, + CSSPropertyFontFamily, + CSSPropertyFontSize, + CSSPropertyFontStyle, + CSSPropertyFontVariant, + CSSPropertyFontWeight, + CSSPropertyHeight, + CSSPropertyLeft, + CSSPropertyLetterSpacing, + CSSPropertyLineHeight, + CSSPropertyListStyleImage, + CSSPropertyListStylePosition, + CSSPropertyListStyleType, + CSSPropertyMarginBottom, + CSSPropertyMarginLeft, + CSSPropertyMarginRight, + CSSPropertyMarginTop, + CSSPropertyMaxHeight, + CSSPropertyMaxWidth, + CSSPropertyMinHeight, + CSSPropertyMinWidth, + CSSPropertyOpacity, + CSSPropertyOrphans, + CSSPropertyOutlineColor, + CSSPropertyOutlineStyle, + CSSPropertyOutlineWidth, + CSSPropertyOverflowX, + CSSPropertyOverflowY, + CSSPropertyPaddingBottom, + CSSPropertyPaddingLeft, + CSSPropertyPaddingRight, + CSSPropertyPaddingTop, + CSSPropertyPageBreakAfter, + CSSPropertyPageBreakBefore, + CSSPropertyPageBreakInside, + CSSPropertyPointerEvents, + CSSPropertyPosition, + CSSPropertyResize, + CSSPropertyRight, + CSSPropertySpeak, + CSSPropertyTableLayout, + CSSPropertyTextAlign, + CSSPropertyTextDecoration, + CSSPropertyTextIndent, + CSSPropertyTextRendering, + CSSPropertyTextShadow, + CSSPropertyTextOverflow, + CSSPropertyTextTransform, + CSSPropertyTop, + CSSPropertyUnicodeBidi, + CSSPropertyVerticalAlign, + CSSPropertyVisibility, + CSSPropertyWhiteSpace, + CSSPropertyWidows, + CSSPropertyWidth, + CSSPropertyWordBreak, + CSSPropertyWordSpacing, + CSSPropertyWordWrap, + CSSPropertyZIndex, + CSSPropertyZoom, + + CSSPropertyWebkitAnimationDelay, + CSSPropertyWebkitAnimationDirection, + CSSPropertyWebkitAnimationDuration, + CSSPropertyWebkitAnimationFillMode, + CSSPropertyWebkitAnimationIterationCount, + CSSPropertyWebkitAnimationName, + CSSPropertyWebkitAnimationPlayState, + CSSPropertyWebkitAnimationTimingFunction, + CSSPropertyWebkitAppearance, + CSSPropertyWebkitBackfaceVisibility, + CSSPropertyWebkitBackgroundClip, + CSSPropertyWebkitBackgroundComposite, + CSSPropertyWebkitBackgroundOrigin, + CSSPropertyWebkitBackgroundSize, + CSSPropertyWebkitBorderFit, + CSSPropertyWebkitBorderHorizontalSpacing, + CSSPropertyWebkitBorderImage, + CSSPropertyWebkitBorderVerticalSpacing, + CSSPropertyWebkitBoxAlign, + CSSPropertyWebkitBoxDirection, + CSSPropertyWebkitBoxFlex, + CSSPropertyWebkitBoxFlexGroup, + CSSPropertyWebkitBoxLines, + CSSPropertyWebkitBoxOrdinalGroup, + CSSPropertyWebkitBoxOrient, + CSSPropertyWebkitBoxPack, + CSSPropertyWebkitBoxReflect, + CSSPropertyWebkitBoxShadow, + CSSPropertyWebkitColorCorrection, + CSSPropertyWebkitColumnBreakAfter, + CSSPropertyWebkitColumnBreakBefore, + CSSPropertyWebkitColumnBreakInside, + CSSPropertyWebkitColumnCount, + CSSPropertyWebkitColumnGap, + CSSPropertyWebkitColumnRuleColor, + CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleWidth, + CSSPropertyWebkitColumnSpan, + CSSPropertyWebkitColumnWidth, +#if ENABLE(DASHBOARD_SUPPORT) + CSSPropertyWebkitDashboardRegion, +#endif + CSSPropertyWebkitFontSmoothing, + CSSPropertyWebkitHighlight, + CSSPropertyWebkitLineBreak, + CSSPropertyWebkitLineClamp, + CSSPropertyWebkitMarginBeforeCollapse, + CSSPropertyWebkitMarginAfterCollapse, + CSSPropertyWebkitMarqueeDirection, + CSSPropertyWebkitMarqueeIncrement, + CSSPropertyWebkitMarqueeRepetition, + CSSPropertyWebkitMarqueeStyle, + CSSPropertyWebkitMaskAttachment, + CSSPropertyWebkitMaskBoxImage, + CSSPropertyWebkitMaskClip, + CSSPropertyWebkitMaskComposite, + CSSPropertyWebkitMaskImage, + CSSPropertyWebkitMaskOrigin, + CSSPropertyWebkitMaskPosition, + CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskSize, + CSSPropertyWebkitNbspMode, + CSSPropertyWebkitPerspective, + CSSPropertyWebkitPerspectiveOrigin, + CSSPropertyWebkitRtlOrdering, + CSSPropertyWebkitTextCombine, + CSSPropertyWebkitTextDecorationsInEffect, + CSSPropertyWebkitTextFillColor, + CSSPropertyWebkitTextSecurity, + CSSPropertyWebkitTextStrokeColor, + CSSPropertyWebkitTextStrokeWidth, + CSSPropertyWebkitTransform, + CSSPropertyWebkitTransformOrigin, + CSSPropertyWebkitTransformStyle, + CSSPropertyWebkitTransitionDelay, + CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionProperty, + CSSPropertyWebkitTransitionTimingFunction, + CSSPropertyWebkitUserDrag, + CSSPropertyWebkitUserModify, + CSSPropertyWebkitUserSelect, + CSSPropertyWebkitWritingMode + +#if ENABLE(SVG) + , + CSSPropertyClipPath, + CSSPropertyClipRule, + CSSPropertyMask, + CSSPropertyFilter, + CSSPropertyFloodColor, + CSSPropertyFloodOpacity, + CSSPropertyLightingColor, + CSSPropertyStopColor, + CSSPropertyStopOpacity, + CSSPropertyColorInterpolation, + CSSPropertyColorInterpolationFilters, + CSSPropertyColorRendering, + CSSPropertyFill, + CSSPropertyFillOpacity, + CSSPropertyFillRule, + CSSPropertyImageRendering, + CSSPropertyMarkerEnd, + CSSPropertyMarkerMid, + CSSPropertyMarkerStart, + CSSPropertyShapeRendering, + CSSPropertyStroke, + CSSPropertyStrokeDasharray, + CSSPropertyStrokeDashoffset, + CSSPropertyStrokeLinecap, + CSSPropertyStrokeLinejoin, + CSSPropertyStrokeMiterlimit, + CSSPropertyStrokeOpacity, + CSSPropertyStrokeWidth, + CSSPropertyAlignmentBaseline, + CSSPropertyBaselineShift, + CSSPropertyDominantBaseline, + CSSPropertyKerning, + CSSPropertyTextAnchor, + CSSPropertyWritingMode, + CSSPropertyGlyphOrientationHorizontal, + CSSPropertyGlyphOrientationVertical, + CSSPropertyWebkitSvgShadow, + CSSPropertyVectorEffect +#endif +#ifdef ANDROID_CSS_RING + , + CSSPropertyWebkitRingFillColor, + CSSPropertyWebkitRingInnerWidth, + CSSPropertyWebkitRingOuterWidth, + CSSPropertyWebkitRingOutset, + CSSPropertyWebkitRingPressedInnerColor, + CSSPropertyWebkitRingPressedOuterColor, + CSSPropertyWebkitRingRadius, + CSSPropertyWebkitRingSelectedInnerColor, + CSSPropertyWebkitRingSelectedOuterColor +#endif +#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR + , + CSSPropertyWebkitTapHighlightColor +#endif +}; + +const unsigned numComputedProperties = WTF_ARRAY_LENGTH(computedProperties); + +static int valueForRepeatRule(int rule) +{ + switch (rule) { + case RepeatImageRule: + return CSSValueRepeat; + case RoundImageRule: + return CSSValueRound; + default: + return CSSValueStretch; + } +} + +static PassRefPtr<CSSValue> valueForNinePieceImage(const NinePieceImage& image) +{ + if (!image.hasImage()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + // Image first. + RefPtr<CSSValue> imageValue; + if (image.image()) + imageValue = image.image()->cssValue(); + + // Create the slices. + RefPtr<CSSPrimitiveValue> top; + if (image.slices().top().isPercent()) + top = CSSPrimitiveValue::create(image.slices().top().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + top = CSSPrimitiveValue::create(image.slices().top().value(), CSSPrimitiveValue::CSS_NUMBER); + + RefPtr<CSSPrimitiveValue> right; + if (image.slices().right().isPercent()) + right = CSSPrimitiveValue::create(image.slices().right().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + right = CSSPrimitiveValue::create(image.slices().right().value(), CSSPrimitiveValue::CSS_NUMBER); + + RefPtr<CSSPrimitiveValue> bottom; + if (image.slices().bottom().isPercent()) + bottom = CSSPrimitiveValue::create(image.slices().bottom().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + bottom = CSSPrimitiveValue::create(image.slices().bottom().value(), CSSPrimitiveValue::CSS_NUMBER); + + RefPtr<CSSPrimitiveValue> left; + if (image.slices().left().isPercent()) + left = CSSPrimitiveValue::create(image.slices().left().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + left = CSSPrimitiveValue::create(image.slices().left().value(), CSSPrimitiveValue::CSS_NUMBER); + + RefPtr<Rect> rect = Rect::create(); + rect->setTop(top); + rect->setRight(right); + rect->setBottom(bottom); + rect->setLeft(left); + + return CSSBorderImageValue::create(imageValue, rect, valueForRepeatRule(image.horizontalRule()), valueForRepeatRule(image.verticalRule())); +} + +inline static PassRefPtr<CSSPrimitiveValue> zoomAdjustedPixelValue(int value, const RenderStyle* style) +{ + return CSSPrimitiveValue::create(adjustForAbsoluteZoom(value, style), CSSPrimitiveValue::CSS_PX); +} + +inline static PassRefPtr<CSSPrimitiveValue> zoomAdjustedNumberValue(double value, const RenderStyle* style) +{ + return CSSPrimitiveValue::create(value / style->effectiveZoom(), CSSPrimitiveValue::CSS_NUMBER); +} + +static PassRefPtr<CSSValue> zoomAdjustedPixelValueForLength(const Length& length, const RenderStyle* style) +{ + if (length.isFixed()) + return zoomAdjustedPixelValue(length.value(), style); + return CSSPrimitiveValue::create(length); +} + +static PassRefPtr<CSSValue> valueForReflection(const StyleReflection* reflection, const RenderStyle* style) +{ + if (!reflection) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + RefPtr<CSSPrimitiveValue> offset; + if (reflection->offset().isPercent()) + offset = CSSPrimitiveValue::create(reflection->offset().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + offset = zoomAdjustedPixelValue(reflection->offset().value(), style); + + return CSSReflectValue::create(reflection->direction(), offset.release(), valueForNinePieceImage(reflection->mask())); +} + +static PassRefPtr<CSSValue> getPositionOffsetValue(RenderStyle* style, int propertyID) +{ + if (!style) + return 0; + + Length l; + switch (propertyID) { + case CSSPropertyLeft: + l = style->left(); + break; + case CSSPropertyRight: + l = style->right(); + break; + case CSSPropertyTop: + l = style->top(); + break; + case CSSPropertyBottom: + l = style->bottom(); + break; + default: + return 0; + } + + if (style->position() == AbsolutePosition || style->position() == FixedPosition) { + if (l.type() == WebCore::Fixed) + return zoomAdjustedPixelValue(l.value(), style); + return CSSPrimitiveValue::create(l); + } + + if (style->position() == RelativePosition) + // FIXME: It's not enough to simply return "auto" values for one offset if the other side is defined. + // In other words if left is auto and right is not auto, then left's computed value is negative right(). + // So we should get the opposite length unit and see if it is auto. + return CSSPrimitiveValue::create(l); + + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); +} + +PassRefPtr<CSSPrimitiveValue> CSSComputedStyleDeclaration::currentColorOrValidColor(RenderStyle* style, const Color& color) const +{ + // This function does NOT look at visited information, so that computed style doesn't expose that. + if (!color.isValid()) + return CSSPrimitiveValue::createColor(style->color().rgb()); + return CSSPrimitiveValue::createColor(color.rgb()); +} + +static PassRefPtr<CSSValue> getBorderRadiusCornerValue(LengthSize radius, const RenderStyle* style) +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (radius.width() == radius.height()) { + if (radius.width().type() == Percent) + return CSSPrimitiveValue::create(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + return zoomAdjustedPixelValue(radius.width().value(), style); + } + if (radius.width().type() == Percent) + list->append(CSSPrimitiveValue::create(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); + else + list->append(zoomAdjustedPixelValue(radius.width().value(), style)); + if (radius.height().type() == Percent) + list->append(CSSPrimitiveValue::create(radius.height().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); + else + list->append(zoomAdjustedPixelValue(radius.height().value(), style)); + return list.release(); +} + +static IntRect sizingBox(RenderObject* renderer) +{ + if (!renderer->isBox()) + return IntRect(); + + RenderBox* box = toRenderBox(renderer); + return box->style()->boxSizing() == CONTENT_BOX ? box->contentBoxRect() : box->borderBoxRect(); +} + +static inline bool hasCompositedLayer(RenderObject* renderer) +{ + return renderer && renderer->hasLayer() && toRenderBoxModelObject(renderer)->layer()->isComposited(); +} + +static PassRefPtr<CSSValue> computedTransform(RenderObject* renderer, const RenderStyle* style) +{ + if (!renderer || style->transform().operations().isEmpty()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + IntRect box = sizingBox(renderer); + + TransformationMatrix transform; + style->applyTransform(transform, box.size(), RenderStyle::ExcludeTransformOrigin); + // Note that this does not flatten to an affine transform if ENABLE(3D_RENDERING) is off, by design. + + RefPtr<WebKitCSSTransformValue> transformVal; + + // FIXME: Need to print out individual functions (https://bugs.webkit.org/show_bug.cgi?id=23924) + if (transform.isAffine()) { + transformVal = WebKitCSSTransformValue::create(WebKitCSSTransformValue::MatrixTransformOperation); + + transformVal->append(CSSPrimitiveValue::create(transform.a(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.b(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.c(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.d(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(zoomAdjustedNumberValue(transform.e(), style)); + transformVal->append(zoomAdjustedNumberValue(transform.f(), style)); + } else { + transformVal = WebKitCSSTransformValue::create(WebKitCSSTransformValue::Matrix3DTransformOperation); + + transformVal->append(CSSPrimitiveValue::create(transform.m11(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m12(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m13(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m14(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(CSSPrimitiveValue::create(transform.m21(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m22(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m23(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m24(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(CSSPrimitiveValue::create(transform.m31(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m32(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m33(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(CSSPrimitiveValue::create(transform.m34(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(zoomAdjustedNumberValue(transform.m41(), style)); + transformVal->append(zoomAdjustedNumberValue(transform.m42(), style)); + transformVal->append(zoomAdjustedNumberValue(transform.m43(), style)); + transformVal->append(CSSPrimitiveValue::create(transform.m44(), CSSPrimitiveValue::CSS_NUMBER)); + } + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(transformVal); + + return list.release(); +} + +static PassRefPtr<CSSValue> getDelayValue(const AnimationList* animList) +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + if (animList) { + for (size_t i = 0; i < animList->size(); ++i) + list->append(CSSPrimitiveValue::create(animList->animation(i)->delay(), CSSPrimitiveValue::CSS_S)); + } else { + // Note that initialAnimationDelay() is used for both transitions and animations + list->append(CSSPrimitiveValue::create(Animation::initialAnimationDelay(), CSSPrimitiveValue::CSS_S)); + } + return list.release(); +} + +static PassRefPtr<CSSValue> getDurationValue(const AnimationList* animList) +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + if (animList) { + for (size_t i = 0; i < animList->size(); ++i) + list->append(CSSPrimitiveValue::create(animList->animation(i)->duration(), CSSPrimitiveValue::CSS_S)); + } else { + // Note that initialAnimationDuration() is used for both transitions and animations + list->append(CSSPrimitiveValue::create(Animation::initialAnimationDuration(), CSSPrimitiveValue::CSS_S)); + } + return list.release(); +} + +static PassRefPtr<CSSValue> getTimingFunctionValue(const AnimationList* animList) +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + if (animList) { + for (size_t i = 0; i < animList->size(); ++i) { + const TimingFunction* tf = animList->animation(i)->timingFunction().get(); + if (tf->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(tf); + list->append(CSSCubicBezierTimingFunctionValue::create(ctf->x1(), ctf->y1(), ctf->x2(), ctf->y2())); + } else if (tf->isStepsTimingFunction()) { + const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(tf); + list->append(CSSStepsTimingFunctionValue::create(stf->numberOfSteps(), stf->stepAtStart())); + } else { + list->append(CSSLinearTimingFunctionValue::create()); + } + } + } else { + // Note that initialAnimationTimingFunction() is used for both transitions and animations + RefPtr<TimingFunction> tf = Animation::initialAnimationTimingFunction(); + if (tf->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(tf.get()); + list->append(CSSCubicBezierTimingFunctionValue::create(ctf->x1(), ctf->y1(), ctf->x2(), ctf->y2())); + } else if (tf->isStepsTimingFunction()) { + const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(tf.get()); + list->append(CSSStepsTimingFunctionValue::create(stf->numberOfSteps(), stf->stepAtStart())); + } else { + list->append(CSSLinearTimingFunctionValue::create()); + } + } + return list.release(); +} + +CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(PassRefPtr<Node> n, bool allowVisitedStyle, const String& pseudoElementName) + : m_node(n) + , m_allowVisitedStyle(allowVisitedStyle) +{ + unsigned nameWithoutColonsStart = pseudoElementName[0] == ':' ? (pseudoElementName[1] == ':' ? 2 : 1) : 0; + m_pseudoElementSpecifier = CSSSelector::pseudoId(CSSSelector::parsePseudoType( + AtomicString(pseudoElementName.substring(nameWithoutColonsStart)))); +} + +CSSComputedStyleDeclaration::~CSSComputedStyleDeclaration() +{ +} + +String CSSComputedStyleDeclaration::cssText() const +{ + String result(""); + + for (unsigned i = 0; i < numComputedProperties; i++) { + if (i) + result += " "; + result += getPropertyName(static_cast<CSSPropertyID>(computedProperties[i])); + result += ": "; + result += getPropertyValue(computedProperties[i]); + result += ";"; + } + + return result; +} + +void CSSComputedStyleDeclaration::setCssText(const String&, ExceptionCode& ec) +{ + ec = NO_MODIFICATION_ALLOWED_ERR; +} + +static int cssIdentifierForFontSizeKeyword(int keywordSize) +{ + ASSERT_ARG(keywordSize, keywordSize); + ASSERT_ARG(keywordSize, keywordSize <= 8); + return CSSValueXxSmall + keywordSize - 1; +} + +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getFontSizeCSSValuePreferringKeyword() const +{ + if (!m_node) + return 0; + + m_node->document()->updateLayoutIgnorePendingStylesheets(); + + RefPtr<RenderStyle> style = m_node->computedStyle(m_pseudoElementSpecifier); + if (!style) + return 0; + + if (int keywordSize = style->fontDescription().keywordSize()) + return CSSPrimitiveValue::createIdentifier(cssIdentifierForFontSizeKeyword(keywordSize)); + + + return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style.get()); +} + +bool CSSComputedStyleDeclaration::useFixedFontDefaultSize() const +{ + if (!m_node) + return false; + + RefPtr<RenderStyle> style = m_node->computedStyle(m_pseudoElementSpecifier); + if (!style) + return false; + + return style->fontDescription().useFixedDefaultSize(); +} + +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::valueForShadow(const ShadowData* shadow, int id, RenderStyle* style) const +{ + if (!shadow) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + CSSPropertyID propertyID = static_cast<CSSPropertyID>(id); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const ShadowData* s = shadow; s; s = s->next()) { + RefPtr<CSSPrimitiveValue> x = zoomAdjustedPixelValue(s->x(), style); + RefPtr<CSSPrimitiveValue> y = zoomAdjustedPixelValue(s->y(), style); + RefPtr<CSSPrimitiveValue> blur = zoomAdjustedPixelValue(s->blur(), style); + RefPtr<CSSPrimitiveValue> spread = propertyID == CSSPropertyTextShadow ? 0 : zoomAdjustedPixelValue(s->spread(), style); + RefPtr<CSSPrimitiveValue> style = propertyID == CSSPropertyTextShadow || s->style() == Normal ? 0 : CSSPrimitiveValue::createIdentifier(CSSValueInset); + RefPtr<CSSPrimitiveValue> color = CSSPrimitiveValue::createColor(s->color().rgb()); + list->prepend(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); + } + return list.release(); +} + +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int propertyID) const +{ + return getPropertyCSSValue(propertyID, UpdateLayout); +} + +static int identifierForFamily(const AtomicString& family) +{ + DEFINE_STATIC_LOCAL(AtomicString, cursiveFamily, ("-webkit-cursive")); + DEFINE_STATIC_LOCAL(AtomicString, fantasyFamily, ("-webkit-fantasy")); + DEFINE_STATIC_LOCAL(AtomicString, monospaceFamily, ("-webkit-monospace")); + DEFINE_STATIC_LOCAL(AtomicString, sansSerifFamily, ("-webkit-sans-serif")); + DEFINE_STATIC_LOCAL(AtomicString, serifFamily, ("-webkit-serif")); + if (family == cursiveFamily) + return CSSValueCursive; + if (family == fantasyFamily) + return CSSValueFantasy; + if (family == monospaceFamily) + return CSSValueMonospace; + if (family == sansSerifFamily) + return CSSValueSansSerif; + if (family == serifFamily) + return CSSValueSerif; + return 0; +} + +static PassRefPtr<CSSPrimitiveValue> valueForFamily(const AtomicString& family) +{ + if (int familyIdentifier = identifierForFamily(family)) + return CSSPrimitiveValue::createIdentifier(familyIdentifier); + return CSSPrimitiveValue::create(family.string(), CSSPrimitiveValue::CSS_STRING); +} + +static PassRefPtr<CSSValue> renderTextDecorationFlagsToCSSValue(int textDecoration) +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (textDecoration & UNDERLINE) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueUnderline)); + if (textDecoration & OVERLINE) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueOverline)); + if (textDecoration & LINE_THROUGH) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueLineThrough)); + if (textDecoration & BLINK) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueBlink)); + + if (!list->length()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return list; +} + +static PassRefPtr<CSSValue> fillRepeatToCSSValue(EFillRepeat xRepeat, EFillRepeat yRepeat) +{ + // For backwards compatibility, if both values are equal, just return one of them. And + // if the two values are equivalent to repeat-x or repeat-y, just return the shorthand. + if (xRepeat == yRepeat) + return CSSPrimitiveValue::create(xRepeat); + if (xRepeat == RepeatFill && yRepeat == NoRepeatFill) + return CSSPrimitiveValue::createIdentifier(CSSValueRepeatX); + if (xRepeat == NoRepeatFill && yRepeat == RepeatFill) + return CSSPrimitiveValue::createIdentifier(CSSValueRepeatY); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(CSSPrimitiveValue::create(xRepeat)); + list->append(CSSPrimitiveValue::create(yRepeat)); + return list.release(); +} + +static PassRefPtr<CSSValue> fillSizeToCSSValue(const FillSize& fillSize) +{ + if (fillSize.type == Contain) + return CSSPrimitiveValue::createIdentifier(CSSValueContain); + + if (fillSize.type == Cover) + return CSSPrimitiveValue::createIdentifier(CSSValueCover); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(CSSPrimitiveValue::create(fillSize.size.width())); + list->append(CSSPrimitiveValue::create(fillSize.size.height())); + return list.release(); +} + +static void logUnimplementedPropertyID(int propertyID) +{ + DEFINE_STATIC_LOCAL(HashSet<int>, propertyIDSet, ()); + if (!propertyIDSet.add(propertyID).second) + return; + + LOG_ERROR("WebKit does not yet implement getComputedStyle for '%s'.", getPropertyName(static_cast<CSSPropertyID>(propertyID))); +} + +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int propertyID, EUpdateLayout updateLayout) const +{ + Node* node = m_node.get(); + if (!node) + return 0; + + // Make sure our layout is up to date before we allow a query on these attributes. + if (updateLayout) + node->document()->updateLayoutIgnorePendingStylesheets(); + + RenderObject* renderer = node->renderer(); + + RefPtr<RenderStyle> style; + if (renderer && hasCompositedLayer(renderer) && AnimationController::supportsAcceleratedAnimationOfProperty(static_cast<CSSPropertyID>(propertyID))) { + style = renderer->animation()->getAnimatedStyleForRenderer(renderer); + if (m_pseudoElementSpecifier) { + // FIXME: This cached pseudo style will only exist if the animation has been run at least once. + style = style->getCachedPseudoStyle(m_pseudoElementSpecifier); + } + } else + style = node->computedStyle(m_pseudoElementSpecifier); + + if (!style) + return 0; + + propertyID = CSSProperty::resolveDirectionAwareProperty(propertyID, style->direction(), style->writingMode()); +#ifdef ANDROID_LAYOUT + const Settings * settings = node->document()->frame() ? node->document()->frame()->settings() : 0; +#endif + + switch (static_cast<CSSPropertyID>(propertyID)) { + case CSSPropertyInvalid: + break; + + case CSSPropertyBackgroundColor: + return CSSPrimitiveValue::createColor(m_allowVisitedStyle? style->visitedDependentColor(CSSPropertyBackgroundColor).rgb() : style->backgroundColor().rgb()); + case CSSPropertyBackgroundImage: + case CSSPropertyWebkitMaskImage: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskImage ? style->maskLayers() : style->backgroundLayers(); + if (!layers) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + if (!layers->next()) { + if (layers->image()) + return layers->image()->cssValue(); + + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + } + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { + if (currLayer->image()) + list->append(currLayer->image()->cssValue()); + else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNone)); + } + return list.release(); + } + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitMaskSize: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskSize ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return fillSizeToCSSValue(layers->size()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(fillSizeToCSSValue(currLayer->size())); + + return list.release(); + } + case CSSPropertyBackgroundRepeat: + case CSSPropertyWebkitMaskRepeat: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskRepeat ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return fillRepeatToCSSValue(layers->repeatX(), layers->repeatY()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(fillRepeatToCSSValue(currLayer->repeatX(), currLayer->repeatY())); + + return list.release(); + } + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyWebkitMaskComposite: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskComposite ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return CSSPrimitiveValue::create(layers->composite()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(CSSPrimitiveValue::create(currLayer->composite())); + + return list.release(); + } + case CSSPropertyBackgroundAttachment: + case CSSPropertyWebkitMaskAttachment: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskAttachment ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return CSSPrimitiveValue::create(layers->attachment()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(CSSPrimitiveValue::create(currLayer->attachment())); + + return list.release(); + } + case CSSPropertyBackgroundClip: + case CSSPropertyBackgroundOrigin: + case CSSPropertyWebkitBackgroundClip: + case CSSPropertyWebkitBackgroundOrigin: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskOrigin: { + const FillLayer* layers = (propertyID == CSSPropertyWebkitMaskClip || propertyID == CSSPropertyWebkitMaskOrigin) ? style->maskLayers() : style->backgroundLayers(); + bool isClip = propertyID == CSSPropertyBackgroundClip || propertyID == CSSPropertyWebkitBackgroundClip || propertyID == CSSPropertyWebkitMaskClip; + if (!layers->next()) { + EFillBox box = isClip ? layers->clip() : layers->origin(); + return CSSPrimitiveValue::create(box); + } + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { + EFillBox box = isClip ? currLayer->clip() : currLayer->origin(); + list->append(CSSPrimitiveValue::create(box)); + } + + return list.release(); + } + case CSSPropertyBackgroundPosition: + case CSSPropertyWebkitMaskPosition: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPosition ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(CSSPrimitiveValue::create(layers->xPosition())); + list->append(CSSPrimitiveValue::create(layers->yPosition())); + return list.release(); + } + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { + RefPtr<CSSValueList> positionList = CSSValueList::createSpaceSeparated(); + positionList->append(CSSPrimitiveValue::create(currLayer->xPosition())); + positionList->append(CSSPrimitiveValue::create(currLayer->yPosition())); + list->append(positionList); + } + + return list.release(); + } + case CSSPropertyBackgroundPositionX: + case CSSPropertyWebkitMaskPositionX: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPositionX ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return CSSPrimitiveValue::create(layers->xPosition()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(CSSPrimitiveValue::create(currLayer->xPosition())); + + return list.release(); + } + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPositionY ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return CSSPrimitiveValue::create(layers->yPosition()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(CSSPrimitiveValue::create(currLayer->yPosition())); + + return list.release(); + } + case CSSPropertyBorderCollapse: + if (style->borderCollapse()) + return CSSPrimitiveValue::createIdentifier(CSSValueCollapse); + return CSSPrimitiveValue::createIdentifier(CSSValueSeparate); + case CSSPropertyBorderSpacing: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get())); + list->append(zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get())); + return list.release(); + } + case CSSPropertyWebkitBorderHorizontalSpacing: + return zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get()); + case CSSPropertyWebkitBorderVerticalSpacing: + return zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get()); + case CSSPropertyBorderTopColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyBorderTopColor).rgb()) : currentColorOrValidColor(style.get(), style->borderTopColor()); + case CSSPropertyBorderRightColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyBorderRightColor).rgb()) : currentColorOrValidColor(style.get(), style->borderRightColor()); + case CSSPropertyBorderBottomColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyBorderBottomColor).rgb()) : currentColorOrValidColor(style.get(), style->borderBottomColor()); + case CSSPropertyBorderLeftColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyBorderLeftColor).rgb()) : currentColorOrValidColor(style.get(), style->borderLeftColor()); + case CSSPropertyBorderTopStyle: + return CSSPrimitiveValue::create(style->borderTopStyle()); + case CSSPropertyBorderRightStyle: + return CSSPrimitiveValue::create(style->borderRightStyle()); + case CSSPropertyBorderBottomStyle: + return CSSPrimitiveValue::create(style->borderBottomStyle()); + case CSSPropertyBorderLeftStyle: + return CSSPrimitiveValue::create(style->borderLeftStyle()); + case CSSPropertyBorderTopWidth: + return zoomAdjustedPixelValue(style->borderTopWidth(), style.get()); + case CSSPropertyBorderRightWidth: + return zoomAdjustedPixelValue(style->borderRightWidth(), style.get()); + case CSSPropertyBorderBottomWidth: + return zoomAdjustedPixelValue(style->borderBottomWidth(), style.get()); + case CSSPropertyBorderLeftWidth: + return zoomAdjustedPixelValue(style->borderLeftWidth(), style.get()); + case CSSPropertyBottom: + return getPositionOffsetValue(style.get(), CSSPropertyBottom); + case CSSPropertyWebkitBoxAlign: + return CSSPrimitiveValue::create(style->boxAlign()); + case CSSPropertyWebkitBoxDirection: + return CSSPrimitiveValue::create(style->boxDirection()); + case CSSPropertyWebkitBoxFlex: + return CSSPrimitiveValue::create(style->boxFlex(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxFlexGroup: + return CSSPrimitiveValue::create(style->boxFlexGroup(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxLines: + return CSSPrimitiveValue::create(style->boxLines()); + case CSSPropertyWebkitBoxOrdinalGroup: + return CSSPrimitiveValue::create(style->boxOrdinalGroup(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxOrient: + return CSSPrimitiveValue::create(style->boxOrient()); + case CSSPropertyWebkitBoxPack: { + EBoxAlignment boxPack = style->boxPack(); + ASSERT(boxPack != BSTRETCH); + ASSERT(boxPack != BBASELINE); + if (boxPack == BJUSTIFY || boxPack== BBASELINE) + return 0; + return CSSPrimitiveValue::create(boxPack); + } + case CSSPropertyWebkitBoxReflect: + return valueForReflection(style->boxReflect(), style.get()); + case CSSPropertyBoxShadow: + case CSSPropertyWebkitBoxShadow: + return valueForShadow(style->boxShadow(), propertyID, style.get()); + case CSSPropertyCaptionSide: + return CSSPrimitiveValue::create(style->captionSide()); + case CSSPropertyClear: + return CSSPrimitiveValue::create(style->clear()); + case CSSPropertyColor: + return CSSPrimitiveValue::createColor(m_allowVisitedStyle ? style->visitedDependentColor(CSSPropertyColor).rgb() : style->color().rgb()); + case CSSPropertyWebkitColumnCount: + if (style->hasAutoColumnCount()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->columnCount(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitColumnGap: + if (style->hasNormalColumnGap()) + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + return CSSPrimitiveValue::create(style->columnGap(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitColumnRuleColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->columnRuleColor()); + case CSSPropertyWebkitColumnRuleStyle: + return CSSPrimitiveValue::create(style->columnRuleStyle()); + case CSSPropertyWebkitColumnRuleWidth: + return zoomAdjustedPixelValue(style->columnRuleWidth(), style.get()); + case CSSPropertyWebkitColumnSpan: + if (style->columnSpan()) + return CSSPrimitiveValue::createIdentifier(CSSValueAll); + return CSSPrimitiveValue::create(1, CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitColumnBreakAfter: + return CSSPrimitiveValue::create(style->columnBreakAfter()); + case CSSPropertyWebkitColumnBreakBefore: + return CSSPrimitiveValue::create(style->columnBreakBefore()); + case CSSPropertyWebkitColumnBreakInside: + return CSSPrimitiveValue::create(style->columnBreakInside()); + case CSSPropertyWebkitColumnWidth: + if (style->hasAutoColumnWidth()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->columnWidth(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyCursor: { + RefPtr<CSSValueList> list; + CursorList* cursors = style->cursors(); + if (cursors && cursors->size() > 0) { + list = CSSValueList::createCommaSeparated(); + for (unsigned i = 0; i < cursors->size(); ++i) + if (StyleImage* image = cursors->at(i).image()) + list->append(image->cssValue()); + } + RefPtr<CSSValue> value = CSSPrimitiveValue::create(style->cursor()); + if (list) { + list->append(value); + return list.release(); + } + return value.release(); + } + case CSSPropertyDirection: + return CSSPrimitiveValue::create(style->direction()); + case CSSPropertyDisplay: + return CSSPrimitiveValue::create(style->display()); + case CSSPropertyEmptyCells: + return CSSPrimitiveValue::create(style->emptyCells()); + case CSSPropertyFloat: +#ifdef ANDROID_LAYOUT + if (settings && settings->layoutAlgorithm() == Settings::kLayoutSSR) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); +#endif + return CSSPrimitiveValue::create(style->floating()); + case CSSPropertyFontFamily: { + const FontFamily& firstFamily = style->fontDescription().family(); + if (!firstFamily.next()) + return valueForFamily(firstFamily.family()); + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FontFamily* family = &firstFamily; family; family = family->next()) + list->append(valueForFamily(family->family())); + return list.release(); + } + case CSSPropertyFontSize: + return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style.get()); + case CSSPropertyFontStyle: + if (style->fontDescription().italic()) + return CSSPrimitiveValue::createIdentifier(CSSValueItalic); + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + case CSSPropertyFontVariant: + if (style->fontDescription().smallCaps()) + return CSSPrimitiveValue::createIdentifier(CSSValueSmallCaps); + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + case CSSPropertyFontWeight: + switch (style->fontDescription().weight()) { + case FontWeight100: + return CSSPrimitiveValue::createIdentifier(CSSValue100); + case FontWeight200: + return CSSPrimitiveValue::createIdentifier(CSSValue200); + case FontWeight300: + return CSSPrimitiveValue::createIdentifier(CSSValue300); + case FontWeightNormal: + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + case FontWeight500: + return CSSPrimitiveValue::createIdentifier(CSSValue500); + case FontWeight600: + return CSSPrimitiveValue::createIdentifier(CSSValue600); + case FontWeightBold: + return CSSPrimitiveValue::createIdentifier(CSSValueBold); + case FontWeight800: + return CSSPrimitiveValue::createIdentifier(CSSValue800); + case FontWeight900: + return CSSPrimitiveValue::createIdentifier(CSSValue900); + } + ASSERT_NOT_REACHED(); + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + case CSSPropertyHeight: + if (renderer) + return zoomAdjustedPixelValue(sizingBox(renderer).height(), style.get()); + return zoomAdjustedPixelValueForLength(style->height(), style.get()); + case CSSPropertyWebkitHighlight: + if (style->highlight() == nullAtom) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return CSSPrimitiveValue::create(style->highlight(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitHyphens: + return CSSPrimitiveValue::create(style->hyphens()); + case CSSPropertyWebkitHyphenateCharacter: + if (style->hyphenationString().isNull()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->hyphenationString(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitHyphenateLocale: + if (style->hyphenationLocale().isNull()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->hyphenationLocale(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitBorderFit: + if (style->borderFit() == BorderFitBorder) + return CSSPrimitiveValue::createIdentifier(CSSValueBorder); + return CSSPrimitiveValue::createIdentifier(CSSValueLines); + case CSSPropertyLeft: + return getPositionOffsetValue(style.get(), CSSPropertyLeft); + case CSSPropertyLetterSpacing: + if (!style->letterSpacing()) + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + return zoomAdjustedPixelValue(style->letterSpacing(), style.get()); + case CSSPropertyWebkitLineClamp: + if (style->lineClamp().isNone()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return CSSPrimitiveValue::create(style->lineClamp().value(), style->lineClamp().isPercentage() ? CSSPrimitiveValue::CSS_PERCENTAGE : CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyLineHeight: { + Length length = style->lineHeight(); + if (length.isNegative()) + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + if (length.isPercent()) + // This is imperfect, because it doesn't include the zoom factor and the real computation + // for how high to be in pixels does include things like minimum font size and the zoom factor. + // On the other hand, since font-size doesn't include the zoom factor, we really can't do + // that here either. + return zoomAdjustedPixelValue(static_cast<int>(length.percent() * style->fontDescription().specifiedSize()) / 100, style.get()); + return zoomAdjustedPixelValue(length.value(), style.get()); + } + case CSSPropertyListStyleImage: + if (style->listStyleImage()) + return style->listStyleImage()->cssValue(); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyListStylePosition: + return CSSPrimitiveValue::create(style->listStylePosition()); + case CSSPropertyListStyleType: + return CSSPrimitiveValue::create(style->listStyleType()); + case CSSPropertyMarginTop: + if (renderer && renderer->isBox()) + // FIXME: Supposed to return the percentage if percentage was specified. + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginTop(), style.get()); + return CSSPrimitiveValue::create(style->marginTop()); + case CSSPropertyMarginRight: + if (renderer && renderer->isBox()) + // FIXME: Supposed to return the percentage if percentage was specified. + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginRight(), style.get()); + return CSSPrimitiveValue::create(style->marginRight()); + case CSSPropertyMarginBottom: + if (renderer && renderer->isBox()) + // FIXME: Supposed to return the percentage if percentage was specified. + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginBottom(), style.get()); + return CSSPrimitiveValue::create(style->marginBottom()); + case CSSPropertyMarginLeft: + if (renderer && renderer->isBox()) + // FIXME: Supposed to return the percentage if percentage was specified. + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginLeft(), style.get()); + return CSSPrimitiveValue::create(style->marginLeft()); + case CSSPropertyWebkitMarqueeDirection: + return CSSPrimitiveValue::create(style->marqueeDirection()); + case CSSPropertyWebkitMarqueeIncrement: + return CSSPrimitiveValue::create(style->marqueeIncrement()); + case CSSPropertyWebkitMarqueeRepetition: + if (style->marqueeLoopCount() < 0) + return CSSPrimitiveValue::createIdentifier(CSSValueInfinite); + return CSSPrimitiveValue::create(style->marqueeLoopCount(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitMarqueeStyle: + return CSSPrimitiveValue::create(style->marqueeBehavior()); + case CSSPropertyWebkitUserModify: + return CSSPrimitiveValue::create(style->userModify()); + case CSSPropertyMaxHeight: { + const Length& maxHeight = style->maxHeight(); + if (maxHeight.isFixed() && maxHeight.value() == undefinedLength) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return CSSPrimitiveValue::create(maxHeight); + } + case CSSPropertyMaxWidth: { + const Length& maxWidth = style->maxWidth(); + if (maxWidth.isFixed() && maxWidth.value() == undefinedLength) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return CSSPrimitiveValue::create(maxWidth); + } + case CSSPropertyMinHeight: + return CSSPrimitiveValue::create(style->minHeight()); + case CSSPropertyMinWidth: + return CSSPrimitiveValue::create(style->minWidth()); + case CSSPropertyOpacity: + return CSSPrimitiveValue::create(style->opacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyOrphans: + return CSSPrimitiveValue::create(style->orphans(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyOutlineColor: + return m_allowVisitedStyle ? CSSPrimitiveValue::createColor(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->outlineColor()); + case CSSPropertyOutlineStyle: + if (style->outlineStyleIsAuto()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->outlineStyle()); + case CSSPropertyOutlineWidth: + return zoomAdjustedPixelValue(style->outlineWidth(), style.get()); + case CSSPropertyOverflow: + return CSSPrimitiveValue::create(max(style->overflowX(), style->overflowY())); + case CSSPropertyOverflowX: + return CSSPrimitiveValue::create(style->overflowX()); + case CSSPropertyOverflowY: +#ifdef ANDROID_LAYOUT + if (settings && settings->layoutAlgorithm() == Settings::kLayoutSSR) + return CSSPrimitiveValue::createIdentifier(CSSValueVisible); +#endif + return CSSPrimitiveValue::create(style->overflowY()); + case CSSPropertyPaddingTop: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingTop(false), style.get()); + return CSSPrimitiveValue::create(style->paddingTop()); + case CSSPropertyPaddingRight: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingRight(false), style.get()); + return CSSPrimitiveValue::create(style->paddingRight()); + case CSSPropertyPaddingBottom: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingBottom(false), style.get()); + return CSSPrimitiveValue::create(style->paddingBottom()); + case CSSPropertyPaddingLeft: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingLeft(false), style.get()); + return CSSPrimitiveValue::create(style->paddingLeft()); + case CSSPropertyPageBreakAfter: + return CSSPrimitiveValue::create(style->pageBreakAfter()); + case CSSPropertyPageBreakBefore: + return CSSPrimitiveValue::create(style->pageBreakBefore()); + case CSSPropertyPageBreakInside: { + EPageBreak pageBreak = style->pageBreakInside(); + ASSERT(pageBreak != PBALWAYS); + if (pageBreak == PBALWAYS) + return 0; + return CSSPrimitiveValue::create(style->pageBreakInside()); + } + case CSSPropertyPosition: +#ifdef ANDROID_LAYOUT + if (settings && settings->layoutAlgorithm() == Settings::kLayoutSSR) + return CSSPrimitiveValue::createIdentifier(CSSValueStatic); +#endif + return CSSPrimitiveValue::create(style->position()); + case CSSPropertyRight: + return getPositionOffsetValue(style.get(), CSSPropertyRight); + case CSSPropertyTableLayout: + return CSSPrimitiveValue::create(style->tableLayout()); + case CSSPropertyTextAlign: + return CSSPrimitiveValue::create(style->textAlign()); + case CSSPropertyTextDecoration: + return renderTextDecorationFlagsToCSSValue(style->textDecoration()); + case CSSPropertyWebkitTextDecorationsInEffect: + return renderTextDecorationFlagsToCSSValue(style->textDecorationsInEffect()); + case CSSPropertyWebkitTextFillColor: + return currentColorOrValidColor(style.get(), style->textFillColor()); + case CSSPropertyWebkitTextEmphasisColor: + return currentColorOrValidColor(style.get(), style->textEmphasisColor()); + case CSSPropertyWebkitTextEmphasisPosition: + return CSSPrimitiveValue::create(style->textEmphasisPosition()); + case CSSPropertyWebkitTextEmphasisStyle: + switch (style->textEmphasisMark()) { + case TextEmphasisMarkNone: + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case TextEmphasisMarkCustom: + return CSSPrimitiveValue::create(style->textEmphasisCustomMark(), CSSPrimitiveValue::CSS_STRING); + case TextEmphasisMarkAuto: + ASSERT_NOT_REACHED(); + // Fall through + case TextEmphasisMarkDot: + case TextEmphasisMarkCircle: + case TextEmphasisMarkDoubleCircle: + case TextEmphasisMarkTriangle: + case TextEmphasisMarkSesame: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(CSSPrimitiveValue::create(style->textEmphasisFill())); + list->append(CSSPrimitiveValue::create(style->textEmphasisMark())); + return list.release(); + } + } + case CSSPropertyTextIndent: + return CSSPrimitiveValue::create(style->textIndent()); + case CSSPropertyTextShadow: + return valueForShadow(style->textShadow(), propertyID, style.get()); + case CSSPropertyTextRendering: + return CSSPrimitiveValue::create(style->fontDescription().textRenderingMode()); + case CSSPropertyTextOverflow: + if (style->textOverflow()) + return CSSPrimitiveValue::createIdentifier(CSSValueEllipsis); + return CSSPrimitiveValue::createIdentifier(CSSValueClip); + case CSSPropertyWebkitTextSecurity: + return CSSPrimitiveValue::create(style->textSecurity()); + case CSSPropertyWebkitTextSizeAdjust: + if (style->textSizeAdjust()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyWebkitTextStrokeColor: + return currentColorOrValidColor(style.get(), style->textStrokeColor()); + case CSSPropertyWebkitTextStrokeWidth: + return zoomAdjustedPixelValue(style->textStrokeWidth(), style.get()); + case CSSPropertyTextTransform: + return CSSPrimitiveValue::create(style->textTransform()); + case CSSPropertyTop: + return getPositionOffsetValue(style.get(), CSSPropertyTop); + case CSSPropertyUnicodeBidi: + return CSSPrimitiveValue::create(style->unicodeBidi()); + case CSSPropertyVerticalAlign: + switch (style->verticalAlign()) { + case BASELINE: + return CSSPrimitiveValue::createIdentifier(CSSValueBaseline); + case MIDDLE: + return CSSPrimitiveValue::createIdentifier(CSSValueMiddle); + case SUB: + return CSSPrimitiveValue::createIdentifier(CSSValueSub); + case SUPER: + return CSSPrimitiveValue::createIdentifier(CSSValueSuper); + case TEXT_TOP: + return CSSPrimitiveValue::createIdentifier(CSSValueTextTop); + case TEXT_BOTTOM: + return CSSPrimitiveValue::createIdentifier(CSSValueTextBottom); + case TOP: + return CSSPrimitiveValue::createIdentifier(CSSValueTop); + case BOTTOM: + return CSSPrimitiveValue::createIdentifier(CSSValueBottom); + case BASELINE_MIDDLE: + return CSSPrimitiveValue::createIdentifier(CSSValueWebkitBaselineMiddle); + case LENGTH: + return CSSPrimitiveValue::create(style->verticalAlignLength()); + } + ASSERT_NOT_REACHED(); + return 0; + case CSSPropertyVisibility: +#ifdef ANDROID_LAYOUT + if (settings && settings->layoutAlgorithm() == Settings::kLayoutSSR) + return CSSPrimitiveValue::createIdentifier(CSSValueVisible); +#endif + return CSSPrimitiveValue::create(style->visibility()); + case CSSPropertyWhiteSpace: +#ifdef ANDROID_LAYOUT + if (settings && settings->layoutAlgorithm() == Settings::kLayoutSSR) + switch (style->whiteSpace()) { + case NORMAL: + case NOWRAP: + case KHTML_NOWRAP: + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + case PRE: + case PRE_WRAP: + return CSSPrimitiveValue::createIdentifier(CSSValuePreWrap); + case PRE_LINE: + return CSSPrimitiveValue::createIdentifier(CSSValuePreLine); + } + else +#endif + return CSSPrimitiveValue::create(style->whiteSpace()); + case CSSPropertyWidows: + return CSSPrimitiveValue::create(style->widows(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWidth: + if (renderer) + return zoomAdjustedPixelValue(sizingBox(renderer).width(), style.get()); + return zoomAdjustedPixelValueForLength(style->width(), style.get()); + case CSSPropertyWordBreak: + return CSSPrimitiveValue::create(style->wordBreak()); + case CSSPropertyWordSpacing: + return zoomAdjustedPixelValue(style->wordSpacing(), style.get()); + case CSSPropertyWordWrap: + return CSSPrimitiveValue::create(style->wordWrap()); + case CSSPropertyWebkitLineBreak: + return CSSPrimitiveValue::create(style->khtmlLineBreak()); + case CSSPropertyWebkitNbspMode: + return CSSPrimitiveValue::create(style->nbspMode()); + case CSSPropertyWebkitMatchNearestMailBlockquoteColor: + return CSSPrimitiveValue::create(style->matchNearestMailBlockquoteColor()); + case CSSPropertyResize: + return CSSPrimitiveValue::create(style->resize()); + case CSSPropertyWebkitFontSmoothing: + return CSSPrimitiveValue::create(style->fontDescription().fontSmoothing()); + case CSSPropertyZIndex: + if (style->hasAutoZIndex()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->zIndex(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyZoom: + return CSSPrimitiveValue::create(style->zoom(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyBoxSizing: + if (style->boxSizing() == CONTENT_BOX) + return CSSPrimitiveValue::createIdentifier(CSSValueContentBox); + return CSSPrimitiveValue::createIdentifier(CSSValueBorderBox); +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPropertyWebkitDashboardRegion: + { + const Vector<StyleDashboardRegion>& regions = style->dashboardRegions(); + unsigned count = regions.size(); + if (count == 1 && regions[0].type == StyleDashboardRegion::None) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + RefPtr<DashboardRegion> firstRegion; + DashboardRegion* previousRegion = 0; + for (unsigned i = 0; i < count; i++) { + RefPtr<DashboardRegion> region = DashboardRegion::create(); + StyleDashboardRegion styleRegion = regions[i]; + + region->m_label = styleRegion.label; + LengthBox offset = styleRegion.offset; + region->setTop(zoomAdjustedPixelValue(offset.top().value(), style.get())); + region->setRight(zoomAdjustedPixelValue(offset.right().value(), style.get())); + region->setBottom(zoomAdjustedPixelValue(offset.bottom().value(), style.get())); + region->setLeft(zoomAdjustedPixelValue(offset.left().value(), style.get())); + region->m_isRectangle = (styleRegion.type == StyleDashboardRegion::Rectangle); + region->m_isCircle = (styleRegion.type == StyleDashboardRegion::Circle); + + if (previousRegion) + previousRegion->m_next = region; + else + firstRegion = region; + previousRegion = region.get(); + } + return CSSPrimitiveValue::create(firstRegion.release()); + } +#endif + case CSSPropertyWebkitAnimationDelay: + return getDelayValue(style->animations()); + case CSSPropertyWebkitAnimationDirection: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->animations(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) { + if (t->animation(i)->direction()) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueAlternate)); + else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNormal)); + } + } else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNormal)); + return list.release(); + } + case CSSPropertyWebkitAnimationDuration: + return getDurationValue(style->animations()); + case CSSPropertyWebkitAnimationFillMode: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->animations(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) { + switch (t->animation(i)->fillMode()) { + case AnimationFillModeNone: + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNone)); + break; + case AnimationFillModeForwards: + list->append(CSSPrimitiveValue::createIdentifier(CSSValueForwards)); + break; + case AnimationFillModeBackwards: + list->append(CSSPrimitiveValue::createIdentifier(CSSValueBackwards)); + break; + case AnimationFillModeBoth: + list->append(CSSPrimitiveValue::createIdentifier(CSSValueBoth)); + break; + } + } + } else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNone)); + return list.release(); + } + case CSSPropertyWebkitAnimationIterationCount: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->animations(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) { + int iterationCount = t->animation(i)->iterationCount(); + if (iterationCount == Animation::IterationCountInfinite) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueInfinite)); + else + list->append(CSSPrimitiveValue::create(iterationCount, CSSPrimitiveValue::CSS_NUMBER)); + } + } else + list->append(CSSPrimitiveValue::create(Animation::initialAnimationIterationCount(), CSSPrimitiveValue::CSS_NUMBER)); + return list.release(); + } + case CSSPropertyWebkitAnimationName: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->animations(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) + list->append(CSSPrimitiveValue::create(t->animation(i)->name(), CSSPrimitiveValue::CSS_STRING)); + } else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueNone)); + return list.release(); + } + case CSSPropertyWebkitAnimationPlayState: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->animations(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) { + int prop = t->animation(i)->playState(); + if (prop == AnimPlayStatePlaying) + list->append(CSSPrimitiveValue::createIdentifier(CSSValueRunning)); + else + list->append(CSSPrimitiveValue::createIdentifier(CSSValuePaused)); + } + } else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueRunning)); + return list.release(); + } + case CSSPropertyWebkitAnimationTimingFunction: + return getTimingFunctionValue(style->animations()); + case CSSPropertyWebkitAppearance: + return CSSPrimitiveValue::create(style->appearance()); + case CSSPropertyWebkitBackfaceVisibility: + return CSSPrimitiveValue::createIdentifier((style->backfaceVisibility() == BackfaceVisibilityHidden) ? CSSValueHidden : CSSValueVisible); + case CSSPropertyWebkitBorderImage: + return valueForNinePieceImage(style->borderImage()); + case CSSPropertyWebkitMaskBoxImage: + return valueForNinePieceImage(style->maskBoxImage()); + case CSSPropertyWebkitFontSizeDelta: + // Not a real style property -- used by the editing engine -- so has no computed value. + break; + case CSSPropertyWebkitMarginBottomCollapse: + case CSSPropertyWebkitMarginAfterCollapse: + return CSSPrimitiveValue::create(style->marginAfterCollapse()); + case CSSPropertyWebkitMarginTopCollapse: + case CSSPropertyWebkitMarginBeforeCollapse: + return CSSPrimitiveValue::create(style->marginBeforeCollapse()); + case CSSPropertyWebkitPerspective: + if (!style->hasPerspective()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return CSSPrimitiveValue::create(style->perspective(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitPerspectiveOrigin: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (renderer) { + IntRect box = sizingBox(renderer); + list->append(zoomAdjustedPixelValue(style->perspectiveOriginX().calcMinValue(box.width()), style.get())); + list->append(zoomAdjustedPixelValue(style->perspectiveOriginY().calcMinValue(box.height()), style.get())); + } + else { + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginX(), style.get())); + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginY(), style.get())); + + } + return list.release(); + } + case CSSPropertyWebkitRtlOrdering: + if (style->visuallyOrdered()) + return CSSPrimitiveValue::createIdentifier(CSSValueVisual); + return CSSPrimitiveValue::createIdentifier(CSSValueLogical); + case CSSPropertyWebkitUserDrag: + return CSSPrimitiveValue::create(style->userDrag()); + case CSSPropertyWebkitUserSelect: + return CSSPrimitiveValue::create(style->userSelect()); + case CSSPropertyBorderBottomLeftRadius: + return getBorderRadiusCornerValue(style->borderBottomLeftRadius(), style.get()); + case CSSPropertyBorderBottomRightRadius: + return getBorderRadiusCornerValue(style->borderBottomRightRadius(), style.get()); + case CSSPropertyBorderTopLeftRadius: + return getBorderRadiusCornerValue(style->borderTopLeftRadius(), style.get()); + case CSSPropertyBorderTopRightRadius: + return getBorderRadiusCornerValue(style->borderTopRightRadius(), style.get()); + case CSSPropertyClip: { + if (!style->hasClip()) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + RefPtr<Rect> rect = Rect::create(); + rect->setTop(zoomAdjustedPixelValue(style->clip().top().value(), style.get())); + rect->setRight(zoomAdjustedPixelValue(style->clip().right().value(), style.get())); + rect->setBottom(zoomAdjustedPixelValue(style->clip().bottom().value(), style.get())); + rect->setLeft(zoomAdjustedPixelValue(style->clip().left().value(), style.get())); + return CSSPrimitiveValue::create(rect.release()); + } + case CSSPropertySpeak: + return CSSPrimitiveValue::create(style->speak()); + case CSSPropertyWebkitTransform: + return computedTransform(renderer, style.get()); + case CSSPropertyWebkitTransformOrigin: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (renderer) { + IntRect box = sizingBox(renderer); + list->append(zoomAdjustedPixelValue(style->transformOriginX().calcMinValue(box.width()), style.get())); + list->append(zoomAdjustedPixelValue(style->transformOriginY().calcMinValue(box.height()), style.get())); + if (style->transformOriginZ() != 0) + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get())); + } else { + list->append(zoomAdjustedPixelValueForLength(style->transformOriginX(), style.get())); + list->append(zoomAdjustedPixelValueForLength(style->transformOriginY(), style.get())); + if (style->transformOriginZ() != 0) + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get())); + } + return list.release(); + } + case CSSPropertyWebkitTransformStyle: + return CSSPrimitiveValue::createIdentifier((style->transformStyle3D() == TransformStyle3DPreserve3D) ? CSSValuePreserve3d : CSSValueFlat); + case CSSPropertyWebkitTransitionDelay: + return getDelayValue(style->transitions()); + case CSSPropertyWebkitTransitionDuration: + return getDurationValue(style->transitions()); + case CSSPropertyWebkitTransitionProperty: { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const AnimationList* t = style->transitions(); + if (t) { + for (size_t i = 0; i < t->size(); ++i) { + int prop = t->animation(i)->property(); + RefPtr<CSSValue> propertyValue; + if (prop == cAnimateNone) + propertyValue = CSSPrimitiveValue::createIdentifier(CSSValueNone); + else if (prop == cAnimateAll) + propertyValue = CSSPrimitiveValue::createIdentifier(CSSValueAll); + else + propertyValue = CSSPrimitiveValue::create(getPropertyName(static_cast<CSSPropertyID>(prop)), CSSPrimitiveValue::CSS_STRING); + list->append(propertyValue); + } + } else + list->append(CSSPrimitiveValue::createIdentifier(CSSValueAll)); + return list.release(); + } + case CSSPropertyWebkitTransitionTimingFunction: + return getTimingFunctionValue(style->transitions()); + case CSSPropertyPointerEvents: + return CSSPrimitiveValue::create(style->pointerEvents()); + case CSSPropertyWebkitColorCorrection: + return CSSPrimitiveValue::create(style->colorSpace()); + case CSSPropertyWebkitWritingMode: + return CSSPrimitiveValue::create(style->writingMode()); + case CSSPropertyWebkitTextCombine: + return CSSPrimitiveValue::create(style->textCombine()); + + /* Shorthand properties, currently not supported see bug 13658*/ + case CSSPropertyBackground: + case CSSPropertyBorder: + case CSSPropertyBorderBottom: + case CSSPropertyBorderColor: + case CSSPropertyBorderLeft: + case CSSPropertyBorderRadius: + case CSSPropertyBorderRight: + case CSSPropertyBorderStyle: + case CSSPropertyBorderTop: + case CSSPropertyBorderWidth: + case CSSPropertyFont: + case CSSPropertyListStyle: + case CSSPropertyMargin: + case CSSPropertyPadding: + break; + + /* Unimplemented CSS 3 properties (including CSS3 shorthand properties) */ + case CSSPropertyWebkitTextEmphasis: + case CSSPropertyTextLineThrough: + case CSSPropertyTextLineThroughColor: + case CSSPropertyTextLineThroughMode: + case CSSPropertyTextLineThroughStyle: + case CSSPropertyTextLineThroughWidth: + case CSSPropertyTextOverline: + case CSSPropertyTextOverlineColor: + case CSSPropertyTextOverlineMode: + case CSSPropertyTextOverlineStyle: + case CSSPropertyTextOverlineWidth: + case CSSPropertyTextUnderline: + case CSSPropertyTextUnderlineColor: + case CSSPropertyTextUnderlineMode: + case CSSPropertyTextUnderlineStyle: + case CSSPropertyTextUnderlineWidth: + break; + + /* Directional properties are resolved by resolveDirectionAwareProperty() before the switch. */ + case CSSPropertyWebkitBorderEnd: + case CSSPropertyWebkitBorderEndColor: + case CSSPropertyWebkitBorderEndStyle: + case CSSPropertyWebkitBorderEndWidth: + case CSSPropertyWebkitBorderStart: + case CSSPropertyWebkitBorderStartColor: + case CSSPropertyWebkitBorderStartStyle: + case CSSPropertyWebkitBorderStartWidth: + case CSSPropertyWebkitBorderAfter: + case CSSPropertyWebkitBorderAfterColor: + case CSSPropertyWebkitBorderAfterStyle: + case CSSPropertyWebkitBorderAfterWidth: + case CSSPropertyWebkitBorderBefore: + case CSSPropertyWebkitBorderBeforeColor: + case CSSPropertyWebkitBorderBeforeStyle: + case CSSPropertyWebkitBorderBeforeWidth: + case CSSPropertyWebkitMarginEnd: + case CSSPropertyWebkitMarginStart: + case CSSPropertyWebkitMarginAfter: + case CSSPropertyWebkitMarginBefore: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitPaddingAfter: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + case CSSPropertyWebkitMaxLogicalWidth: + case CSSPropertyWebkitMaxLogicalHeight: + ASSERT_NOT_REACHED(); + break; + + /* Unimplemented @font-face properties */ + case CSSPropertyFontStretch: + case CSSPropertySrc: + case CSSPropertyUnicodeRange: + break; + + /* Other unimplemented properties */ + case CSSPropertyBackgroundRepeatX: + case CSSPropertyBackgroundRepeatY: + case CSSPropertyContent: // FIXME: needs implementation, bug 23668 + case CSSPropertyCounterIncrement: + case CSSPropertyCounterReset: + case CSSPropertyOutline: // FIXME: needs implementation + case CSSPropertyOutlineOffset: // FIXME: needs implementation + case CSSPropertyPage: // for @page + case CSSPropertyQuotes: // FIXME: needs implementation + case CSSPropertySize: // for @page + break; + + /* Unimplemented -webkit- properties */ + case CSSPropertyWebkitAnimation: + case CSSPropertyWebkitBorderRadius: + case CSSPropertyWebkitColumns: + case CSSPropertyWebkitColumnRule: + case CSSPropertyWebkitMarginCollapse: + case CSSPropertyWebkitMarquee: + case CSSPropertyWebkitMarqueeSpeed: + case CSSPropertyWebkitMask: + case CSSPropertyWebkitMaskRepeatX: + case CSSPropertyWebkitMaskRepeatY: + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: + case CSSPropertyWebkitTextStroke: + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + case CSSPropertyWebkitTransition: + break; +#ifdef ANDROID_CSS_RING + case CSSPropertyWebkitRing: + // shorthand property currently not supported see bug 13658 + break; + case CSSPropertyWebkitRingFillColor: + return CSSPrimitiveValue::createColor(style->ringFillColor().rgb()); + case CSSPropertyWebkitRingInnerWidth: + return CSSPrimitiveValue::create(style->ringInnerWidth()); + case CSSPropertyWebkitRingOuterWidth: + return CSSPrimitiveValue::create(style->ringOuterWidth()); + case CSSPropertyWebkitRingOutset: + return CSSPrimitiveValue::create(style->ringOutset()); + case CSSPropertyWebkitRingPressedInnerColor: + return CSSPrimitiveValue::createColor(style->ringPressedInnerColor().rgb()); + case CSSPropertyWebkitRingPressedOuterColor: + return CSSPrimitiveValue::createColor(style->ringPressedOuterColor().rgb()); + case CSSPropertyWebkitRingRadius: + return CSSPrimitiveValue::create(style->ringRadius()); + case CSSPropertyWebkitRingSelectedInnerColor: + return CSSPrimitiveValue::createColor(style->ringSelectedInnerColor().rgb()); + case CSSPropertyWebkitRingSelectedOuterColor: + return CSSPrimitiveValue::createColor(style->ringSelectedOuterColor().rgb()); +#endif +#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR + case CSSPropertyWebkitTapHighlightColor: + return CSSPrimitiveValue::createColor(style->tapHighlightColor().rgb()); +#endif +#if ENABLE(SVG) + case CSSPropertyClipPath: + case CSSPropertyClipRule: + case CSSPropertyMask: + case CSSPropertyEnableBackground: + case CSSPropertyFilter: + case CSSPropertyFloodColor: + case CSSPropertyFloodOpacity: + case CSSPropertyLightingColor: + case CSSPropertyStopColor: + case CSSPropertyStopOpacity: + case CSSPropertyColorInterpolation: + case CSSPropertyColorInterpolationFilters: + case CSSPropertyColorProfile: + case CSSPropertyColorRendering: + case CSSPropertyFill: + case CSSPropertyFillOpacity: + case CSSPropertyFillRule: + case CSSPropertyImageRendering: + case CSSPropertyMarker: + case CSSPropertyMarkerEnd: + case CSSPropertyMarkerMid: + case CSSPropertyMarkerStart: + case CSSPropertyShapeRendering: + case CSSPropertyStroke: + case CSSPropertyStrokeDasharray: + case CSSPropertyStrokeDashoffset: + case CSSPropertyStrokeLinecap: + case CSSPropertyStrokeLinejoin: + case CSSPropertyStrokeMiterlimit: + case CSSPropertyStrokeOpacity: + case CSSPropertyStrokeWidth: + case CSSPropertyAlignmentBaseline: + case CSSPropertyBaselineShift: + case CSSPropertyDominantBaseline: + case CSSPropertyGlyphOrientationHorizontal: + case CSSPropertyGlyphOrientationVertical: + case CSSPropertyKerning: + case CSSPropertyTextAnchor: + case CSSPropertyVectorEffect: + case CSSPropertyWritingMode: + case CSSPropertyWebkitSvgShadow: + return getSVGPropertyCSSValue(propertyID, DoNotUpdateLayout); +#endif + } + + logUnimplementedPropertyID(propertyID); + return 0; +} + +String CSSComputedStyleDeclaration::getPropertyValue(int propertyID) const +{ + RefPtr<CSSValue> value = getPropertyCSSValue(propertyID); + if (value) + return value->cssText(); + return ""; +} + +bool CSSComputedStyleDeclaration::getPropertyPriority(int /*propertyID*/) const +{ + // All computed styles have a priority of false (not "important"). + return false; +} + +String CSSComputedStyleDeclaration::removeProperty(int /*propertyID*/, ExceptionCode& ec) +{ + ec = NO_MODIFICATION_ALLOWED_ERR; + return String(); +} + +void CSSComputedStyleDeclaration::setProperty(int /*propertyID*/, const String& /*value*/, bool /*important*/, ExceptionCode& ec) +{ + ec = NO_MODIFICATION_ALLOWED_ERR; +} + +unsigned CSSComputedStyleDeclaration::virtualLength() const +{ + Node* node = m_node.get(); + if (!node) + return 0; + + RenderStyle* style = node->computedStyle(m_pseudoElementSpecifier); + if (!style) + return 0; + + return numComputedProperties; +} + +String CSSComputedStyleDeclaration::item(unsigned i) const +{ + if (i >= length()) + return ""; + + return getPropertyName(static_cast<CSSPropertyID>(computedProperties[i])); +} + +bool CSSComputedStyleDeclaration::cssPropertyMatches(const CSSProperty* property) const +{ + if (property->id() == CSSPropertyFontSize && property->value()->isPrimitiveValue() && m_node) { + m_node->document()->updateLayoutIgnorePendingStylesheets(); + RenderStyle* style = m_node->computedStyle(m_pseudoElementSpecifier); + if (style && style->fontDescription().keywordSize()) { + int sizeValue = cssIdentifierForFontSizeKeyword(style->fontDescription().keywordSize()); + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(property->value()); + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT && primitiveValue->getIdent() == sizeValue) + return true; + } + } + + return CSSStyleDeclaration::cssPropertyMatches(property); +} + +PassRefPtr<CSSMutableStyleDeclaration> CSSComputedStyleDeclaration::copy() const +{ + return copyPropertiesInSet(computedProperties, numComputedProperties); +} + +PassRefPtr<CSSMutableStyleDeclaration> CSSComputedStyleDeclaration::makeMutable() +{ + return copy(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.h b/Source/WebCore/css/CSSComputedStyleDeclaration.h new file mode 100644 index 0000000..718eb2d --- /dev/null +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004 Zack Rusin <zack@kde.org> + * Copyright (C) 2004, 2005, 2006, 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef CSSComputedStyleDeclaration_h +#define CSSComputedStyleDeclaration_h + +#include "CSSStyleDeclaration.h" +#include "PlatformString.h" +#include "RenderStyleConstants.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Color; +class CSSMutableStyleDeclaration; +class CSSPrimitiveValue; +class Node; +class RenderStyle; +class ShadowData; + +enum EUpdateLayout { DoNotUpdateLayout = false, UpdateLayout = true }; + +class CSSComputedStyleDeclaration : public CSSStyleDeclaration { +public: + friend PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node>, bool allowVisitedStyle, const String& pseudoElementName); + virtual ~CSSComputedStyleDeclaration(); + + virtual String cssText() const; + + virtual unsigned virtualLength() const; + virtual String item(unsigned index) const; + + virtual PassRefPtr<CSSValue> getPropertyCSSValue(int propertyID) const; + virtual String getPropertyValue(int propertyID) const; + virtual bool getPropertyPriority(int propertyID) const; + virtual int getPropertyShorthand(int /*propertyID*/) const { return -1; } + virtual bool isPropertyImplicit(int /*propertyID*/) const { return false; } + + virtual PassRefPtr<CSSMutableStyleDeclaration> copy() const; + virtual PassRefPtr<CSSMutableStyleDeclaration> makeMutable(); + + PassRefPtr<CSSValue> getPropertyCSSValue(int propertyID, EUpdateLayout) const; + PassRefPtr<CSSValue> getFontSizeCSSValuePreferringKeyword() const; + bool useFixedFontDefaultSize() const; +#if ENABLE(SVG) + PassRefPtr<CSSValue> getSVGPropertyCSSValue(int propertyID, EUpdateLayout) const; +#endif + +protected: + virtual bool cssPropertyMatches(const CSSProperty*) const; + +private: + CSSComputedStyleDeclaration(PassRefPtr<Node>, bool allowVisitedStyle, const String&); + + virtual void setCssText(const String&, ExceptionCode&); + + virtual String removeProperty(int propertyID, ExceptionCode&); + virtual void setProperty(int propertyId, const String& value, bool important, ExceptionCode&); + + PassRefPtr<CSSValue> valueForShadow(const ShadowData*, int, RenderStyle*) const; + PassRefPtr<CSSPrimitiveValue> currentColorOrValidColor(RenderStyle*, const Color&) const; + + RefPtr<Node> m_node; + PseudoId m_pseudoElementSpecifier; + bool m_allowVisitedStyle; +}; + +inline PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node> node, bool allowVisitedStyle = false, const String& pseudoElementName = String()) +{ + return adoptRef(new CSSComputedStyleDeclaration(node, allowVisitedStyle, pseudoElementName)); +} + +} // namespace WebCore + +#endif // CSSComputedStyleDeclaration_h diff --git a/Source/WebCore/css/CSSCursorImageValue.cpp b/Source/WebCore/css/CSSCursorImageValue.cpp new file mode 100644 index 0000000..ab83bb7 --- /dev/null +++ b/Source/WebCore/css/CSSCursorImageValue.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2006 Rob Buis <buis@kde.org> + * (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 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 "CSSCursorImageValue.h" + +#include "CachedResourceLoader.h" +#include "Document.h" +#include "PlatformString.h" +#include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> + +#if ENABLE(SVG) +#include "SVGCursorElement.h" +#include "SVGNames.h" +#include "SVGURIReference.h" +#endif + +namespace WebCore { + +#if ENABLE(SVG) +static inline bool isSVGCursorIdentifier(const String& url) +{ + KURL kurl(ParsedURLString, url); + return kurl.hasFragmentIdentifier(); +} + +static inline SVGCursorElement* resourceReferencedByCursorElement(const String& fragmentId, Document* document) +{ + Element* element = document->getElementById(SVGURIReference::getTarget(fragmentId)); + if (element && element->hasTagName(SVGNames::cursorTag)) + return static_cast<SVGCursorElement*>(element); + + return 0; +} +#endif + +CSSCursorImageValue::CSSCursorImageValue(const String& url, const IntPoint& hotSpot) + : CSSImageValue(url) + , m_hotSpot(hotSpot) +{ +} + +CSSCursorImageValue::~CSSCursorImageValue() +{ +#if ENABLE(SVG) + const String& url = getStringValue(); + if (!isSVGCursorIdentifier(url)) + return; + + HashSet<SVGElement*>::const_iterator it = m_referencedElements.begin(); + HashSet<SVGElement*>::const_iterator end = m_referencedElements.end(); + + for (; it != end; ++it) { + SVGElement* referencedElement = *it; + referencedElement->cursorImageValueRemoved(); + if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(url, referencedElement->document())) + cursorElement->removeClient(referencedElement); + } +#endif +} + +bool CSSCursorImageValue::updateIfSVGCursorIsUsed(Element* element) +{ +#if !ENABLE(SVG) + UNUSED_PARAM(element); +#else + if (!element || !element->isSVGElement()) + return false; + + const String& url = getStringValue(); + if (!isSVGCursorIdentifier(url)) + return false; + + if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(url, element->document())) { + // FIXME: This will override hot spot specified in CSS, which is probably incorrect. + float x = roundf(cursorElement->x().value(0)); + m_hotSpot.setX(static_cast<int>(x)); + + float y = roundf(cursorElement->y().value(0)); + m_hotSpot.setY(static_cast<int>(y)); + + if (cachedImageURL() != element->document()->completeURL(cursorElement->href())) + clearCachedImage(); + + SVGElement* svgElement = static_cast<SVGElement*>(element); + m_referencedElements.add(svgElement); + svgElement->setCursorImageValue(this); + cursorElement->addClient(svgElement); + return true; + } +#endif + + return false; +} + +StyleCachedImage* CSSCursorImageValue::cachedImage(CachedResourceLoader* loader) +{ + String url = getStringValue(); + +#if ENABLE(SVG) + if (isSVGCursorIdentifier(url) && loader && loader->document()) { + if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(url, loader->document())) + url = cursorElement->href(); + } +#endif + + return CSSImageValue::cachedImage(loader, url); +} + +#if ENABLE(SVG) +void CSSCursorImageValue::removeReferencedElement(SVGElement* element) +{ + m_referencedElements.remove(element); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSCursorImageValue.h b/Source/WebCore/css/CSSCursorImageValue.h new file mode 100644 index 0000000..de03eb8 --- /dev/null +++ b/Source/WebCore/css/CSSCursorImageValue.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2006 Rob Buis <buis@kde.org> + * Copyright (C) 2008 Apple Inc. All right 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. + */ + +#ifndef CSSCursorImageValue_h +#define CSSCursorImageValue_h + +#include "CSSImageValue.h" +#include "IntPoint.h" +#include <wtf/HashSet.h> + +namespace WebCore { + +class Element; +class SVGElement; + +class CSSCursorImageValue : public CSSImageValue { +public: + static PassRefPtr<CSSCursorImageValue> create(const String& url, const IntPoint& hotSpot) + { + return adoptRef(new CSSCursorImageValue(url, hotSpot)); + } + + virtual ~CSSCursorImageValue(); + + IntPoint hotSpot() const { return m_hotSpot; } + + bool updateIfSVGCursorIsUsed(Element*); + virtual StyleCachedImage* cachedImage(CachedResourceLoader*); + +#if ENABLE(SVG) + void removeReferencedElement(SVGElement*); +#endif + +private: + CSSCursorImageValue(const String& url, const IntPoint& hotSpot); + virtual bool isCursorImageValue() const { return true; } + + IntPoint m_hotSpot; + +#if ENABLE(SVG) + HashSet<SVGElement*> m_referencedElements; +#endif +}; + +} // namespace WebCore + +#endif // CSSCursorImageValue_h diff --git a/Source/WebCore/css/CSSFontFace.cpp b/Source/WebCore/css/CSSFontFace.cpp new file mode 100644 index 0000000..2c50a04 --- /dev/null +++ b/Source/WebCore/css/CSSFontFace.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFontFace.h" + +#include "CSSFontFaceSource.h" +#include "CSSFontSelector.h" +#include "CSSSegmentedFontFace.h" +#include "FontDescription.h" +#include "SimpleFontData.h" + +namespace WebCore { + +CSSFontFace::~CSSFontFace() +{ + deleteAllValues(m_sources); +} + +bool CSSFontFace::isLoaded() const +{ + unsigned size = m_sources.size(); + for (unsigned i = 0; i < size; i++) { + if (!m_sources[i]->isLoaded()) + return false; + } + return true; +} + +bool CSSFontFace::isValid() const +{ + unsigned size = m_sources.size(); + if (!size) + return false; + for (unsigned i = 0; i < size; i++) { + if (m_sources[i]->isValid()) + return true; + } + return false; +} + +void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace) +{ + m_segmentedFontFaces.add(segmentedFontFace); +} + +void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace) +{ + m_segmentedFontFaces.remove(segmentedFontFace); +} + +void CSSFontFace::addSource(CSSFontFaceSource* source) +{ + m_sources.append(source); + source->setFontFace(this); +} + +void CSSFontFace::fontLoaded(CSSFontFaceSource* source) +{ + if (source != m_activeSource) + return; + + // FIXME: Can we assert that m_segmentedFontFaces is not empty? That may + // require stopping in-progress font loading when the last + // CSSSegmentedFontFace is removed. + if (m_segmentedFontFaces.isEmpty()) + return; + + HashSet<CSSSegmentedFontFace*>::iterator end = m_segmentedFontFaces.end(); + for (HashSet<CSSSegmentedFontFace*>::iterator it = m_segmentedFontFaces.begin(); it != end; ++it) + (*it)->fontLoaded(this); + + // Use one of the CSSSegmentedFontFaces' font selector. They all have + // the same font selector, so it's wasteful to store it in the CSSFontFace. + CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector(); + fontSelector->fontLoaded(); +} + +SimpleFontData* CSSFontFace::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) +{ + m_activeSource = 0; + if (!isValid()) + return 0; + + ASSERT(!m_segmentedFontFaces.isEmpty()); + CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector(); + + size_t size = m_sources.size(); + for (size_t i = 0; i < size; ++i) { + if (SimpleFontData* result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector)) { + m_activeSource = m_sources[i]; + return result; + } + } + + return 0; +} + +#if ENABLE(SVG_FONTS) +bool CSSFontFace::hasSVGFontFaceSource() const +{ + for (unsigned i = 0; i < m_sources.size(); i++) { + if (m_sources[i]->isSVGFontFaceSource()) + return true; + } + return false; +} +#endif + +} + diff --git a/Source/WebCore/css/CSSFontFace.h b/Source/WebCore/css/CSSFontFace.h new file mode 100644 index 0000000..55e048c --- /dev/null +++ b/Source/WebCore/css/CSSFontFace.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSFontFace_h +#define CSSFontFace_h + +#include "FontTraitsMask.h" +#include <wtf/HashSet.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class CSSFontFaceSource; +class CSSSegmentedFontFace; +class FontDescription; +class SimpleFontData; + +class CSSFontFace : public RefCounted<CSSFontFace> { +public: + static PassRefPtr<CSSFontFace> create(FontTraitsMask traitsMask, bool isLocalFallback = false) { return adoptRef(new CSSFontFace(traitsMask, isLocalFallback)); } + ~CSSFontFace(); + + FontTraitsMask traitsMask() const { return m_traitsMask; } + + struct UnicodeRange; + + void addRange(UChar32 from, UChar32 to) { m_ranges.append(UnicodeRange(from, to)); } + const Vector<UnicodeRange>& ranges() const { return m_ranges; } + + void addedToSegmentedFontFace(CSSSegmentedFontFace*); + void removedFromSegmentedFontFace(CSSSegmentedFontFace*); + + bool isLoaded() const; + bool isValid() const; + + bool isLocalFallback() const { return m_isLocalFallback; } + + void addSource(CSSFontFaceSource*); + + void fontLoaded(CSSFontFaceSource*); + + SimpleFontData* getFontData(const FontDescription&, bool syntheticBold, bool syntheticItalic); + + struct UnicodeRange { + UnicodeRange(UChar32 from, UChar32 to) + : m_from(from) + , m_to(to) + { + } + + UChar32 from() const { return m_from; } + UChar32 to() const { return m_to; } + + private: + UChar32 m_from; + UChar32 m_to; + }; + +#if ENABLE(SVG_FONTS) + bool hasSVGFontFaceSource() const; +#endif + +private: + CSSFontFace(FontTraitsMask traitsMask, bool isLocalFallback) + : m_traitsMask(traitsMask) + , m_activeSource(0) + , m_isLocalFallback(isLocalFallback) + { + } + + FontTraitsMask m_traitsMask; + Vector<UnicodeRange> m_ranges; + HashSet<CSSSegmentedFontFace*> m_segmentedFontFaces; + Vector<CSSFontFaceSource*> m_sources; + CSSFontFaceSource* m_activeSource; + bool m_isLocalFallback; +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSFontFaceRule.cpp b/Source/WebCore/css/CSSFontFaceRule.cpp new file mode 100644 index 0000000..75e9a36 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceRule.cpp @@ -0,0 +1,58 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006, 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 "CSSFontFaceRule.h" + +#include "CSSMutableStyleDeclaration.h" + +namespace WebCore { + +CSSFontFaceRule::CSSFontFaceRule(CSSStyleSheet* parent) + : CSSRule(parent) +{ +} + +CSSFontFaceRule::~CSSFontFaceRule() +{ +} + +void CSSFontFaceRule::setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) +{ + m_style = style; +} + +String CSSFontFaceRule::cssText() const +{ + String result("@font-face"); + result += " { "; + result += m_style->cssText(); + result += "}"; + return result; +} + +void CSSFontFaceRule::addSubresourceStyleURLs(ListHashSet<KURL>& urls) +{ + if (m_style) + m_style->addSubresourceStyleURLs(urls); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSFontFaceRule.h b/Source/WebCore/css/CSSFontFaceRule.h new file mode 100644 index 0000000..5148d0c --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceRule.h @@ -0,0 +1,67 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSFontFaceRule_h +#define CSSFontFaceRule_h + +#include "CSSRule.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; + +class CSSFontFaceRule : public CSSRule { +public: + static PassRefPtr<CSSFontFaceRule> create() + { + return adoptRef(new CSSFontFaceRule(0)); + } + static PassRefPtr<CSSFontFaceRule> create(CSSStyleSheet* parent) + { + return adoptRef(new CSSFontFaceRule(parent)); + } + + virtual ~CSSFontFaceRule(); + + CSSMutableStyleDeclaration* style() const { return m_style.get(); } + + virtual String cssText() const; + + void setDeclaration(PassRefPtr<CSSMutableStyleDeclaration>); + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + +private: + CSSFontFaceRule(CSSStyleSheet* parent); + + virtual bool isFontFaceRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return FONT_FACE_RULE; } + + RefPtr<CSSMutableStyleDeclaration> m_style; +}; + +} // namespace WebCore + +#endif // CSSFontFaceRule_h diff --git a/Source/WebCore/css/CSSFontFaceRule.idl b/Source/WebCore/css/CSSFontFaceRule.idl new file mode 100644 index 0000000..b9355a1 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceRule.idl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [CustomMarkFunction] CSSFontFaceRule : CSSRule { + readonly attribute CSSStyleDeclaration style; + }; + +} diff --git a/Source/WebCore/css/CSSFontFaceSource.cpp b/Source/WebCore/css/CSSFontFaceSource.cpp new file mode 100644 index 0000000..12d2e1e --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSource.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFontFaceSource.h" + +#include "CachedFont.h" +#include "CSSFontFace.h" +#include "CSSFontSelector.h" +#include "CachedResourceLoader.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "GlyphPageTreeNode.h" +#include "SimpleFontData.h" + +#if ENABLE(SVG_FONTS) +#include "FontCustomPlatformData.h" +#include "SVGFontData.h" +#include "SVGFontElement.h" +#include "SVGFontFaceElement.h" +#include "SVGNames.h" +#include "SVGURIReference.h" +#endif + +namespace WebCore { + +CSSFontFaceSource::CSSFontFaceSource(const String& str, CachedFont* font) + : m_string(str) + , m_font(font) + , m_face(0) +#if ENABLE(SVG_FONTS) + , m_svgFontFaceElement(0) +#endif +{ + if (m_font) + m_font->addClient(this); +} + +CSSFontFaceSource::~CSSFontFaceSource() +{ + if (m_font) + m_font->removeClient(this); + pruneTable(); +} + +void CSSFontFaceSource::pruneTable() +{ + if (m_fontDataTable.isEmpty()) + return; + HashMap<unsigned, SimpleFontData*>::iterator end = m_fontDataTable.end(); + for (HashMap<unsigned, SimpleFontData*>::iterator it = m_fontDataTable.begin(); it != end; ++it) + GlyphPageTreeNode::pruneTreeCustomFontData(it->second); + deleteAllValues(m_fontDataTable); + m_fontDataTable.clear(); +} + +bool CSSFontFaceSource::isLoaded() const +{ + if (m_font) + return m_font->isLoaded(); + return true; +} + +bool CSSFontFaceSource::isValid() const +{ + if (m_font) + return !m_font->errorOccurred(); + return true; +} + +void CSSFontFaceSource::fontLoaded(CachedFont*) +{ + pruneTable(); + if (m_face) + m_face->fontLoaded(this); +} + +SimpleFontData* CSSFontFaceSource::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector* fontSelector) +{ + // If the font hasn't loaded or an error occurred, then we've got nothing. + if (!isValid()) + return 0; + +#if ENABLE(SVG_FONTS) + if (!m_font && !m_svgFontFaceElement) { +#else + if (!m_font) { +#endif + SimpleFontData* fontData = fontCache()->getCachedFontData(fontDescription, m_string); + + // We're local. Just return a SimpleFontData from the normal cache. + return fontData; + } + + // See if we have a mapping in our FontData cache. + unsigned hashKey = fontDescription.computedPixelSize() << 3 | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); + if (SimpleFontData* cachedData = m_fontDataTable.get(hashKey)) + return cachedData; + + OwnPtr<SimpleFontData> fontData; + + // If we are still loading, then we let the system pick a font. + if (isLoaded()) { + if (m_font) { +#if ENABLE(SVG_FONTS) + if (m_font->isSVGFont()) { + // For SVG fonts parse the external SVG document, and extract the <font> element. + if (!m_font->ensureSVGFontData()) + return 0; + + if (!m_externalSVGFontElement) + m_externalSVGFontElement = m_font->getSVGFontById(SVGURIReference::getTarget(m_string)); + + if (!m_externalSVGFontElement) + return 0; + + SVGFontFaceElement* fontFaceElement = 0; + + // Select first <font-face> child + for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) { + if (fontChild->hasTagName(SVGNames::font_faceTag)) { + fontFaceElement = static_cast<SVGFontFaceElement*>(fontChild); + break; + } + } + + if (fontFaceElement) { + if (!m_svgFontFaceElement) { + // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement. + // Use the imported <font-face> tag as referencing font-face element for these cases. + m_svgFontFaceElement = fontFaceElement; + } + + fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(fontFaceElement)), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); + } + } else +#endif + { + // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef. + if (!m_font->ensureCustomFontData()) + return 0; + + fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.orientation(), fontDescription.renderingMode()), true, false)); + } + } else { +#if ENABLE(SVG_FONTS) + // In-Document SVG Fonts + if (m_svgFontFaceElement) + fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(m_svgFontFaceElement)), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); +#endif + } + } else { + // Kick off the load now. + if (CachedResourceLoader* cachedResourceLoader = fontSelector->cachedResourceLoader()) + m_font->beginLoadIfNeeded(cachedResourceLoader); + // FIXME: m_string is a URL so it makes no sense to pass it as a family name. + SimpleFontData* tempData = fontCache()->getCachedFontData(fontDescription, m_string); + if (!tempData) + tempData = fontCache()->getLastResortFallbackFont(fontDescription); + + fontData.set(new SimpleFontData(tempData->platformData(), true, true)); + } + + SimpleFontData* fontDataRawPtr = fontData.leakPtr(); + m_fontDataTable.set(hashKey, fontDataRawPtr); + + return fontDataRawPtr; +} + +#if ENABLE(SVG_FONTS) +bool CSSFontFaceSource::isSVGFontFaceSource() const +{ + return m_svgFontFaceElement || (m_font && m_font->isSVGFont()); +} +#endif + +} diff --git a/Source/WebCore/css/CSSFontFaceSource.h b/Source/WebCore/css/CSSFontFaceSource.h new file mode 100644 index 0000000..e2057cc --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSource.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSFontFaceSource_h +#define CSSFontFaceSource_h + +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include <wtf/HashMap.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class CachedFont; +class CSSFontFace; +class CSSFontSelector; +class FontDescription; +class SimpleFontData; +#if ENABLE(SVG_FONTS) +class SVGFontElement; +class SVGFontFaceElement; +#endif + + +class CSSFontFaceSource : public CachedResourceClient { +public: + CSSFontFaceSource(const String&, CachedFont* = 0); + virtual ~CSSFontFaceSource(); + + bool isLoaded() const; + bool isValid() const; + + const AtomicString& string() const { return m_string; } + + void setFontFace(CSSFontFace* face) { m_face = face; } + + virtual void fontLoaded(CachedFont*); + + SimpleFontData* getFontData(const FontDescription&, bool syntheticBold, bool syntheticItalic, CSSFontSelector*); + + void pruneTable(); + +#if ENABLE(SVG_FONTS) + SVGFontFaceElement* svgFontFaceElement() const { return m_svgFontFaceElement; } + void setSVGFontFaceElement(SVGFontFaceElement* element) { m_svgFontFaceElement = element; } + bool isSVGFontFaceSource() const; +#endif + +private: + AtomicString m_string; // URI for remote, built-in font name for local. + CachedResourceHandle<CachedFont> m_font; // For remote fonts, a pointer to our cached resource. + CSSFontFace* m_face; // Our owning font face. + HashMap<unsigned, SimpleFontData*> m_fontDataTable; // The hash key is composed of size synthetic styles. + +#if ENABLE(SVG_FONTS) + SVGFontFaceElement* m_svgFontFaceElement; + RefPtr<SVGFontElement> m_externalSVGFontElement; +#endif +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSFontFaceSrcValue.cpp b/Source/WebCore/css/CSSFontFaceSrcValue.cpp new file mode 100644 index 0000000..03edbcb --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSrcValue.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSStyleSheet.h" +#include "FontCustomPlatformData.h" +#include "Node.h" + +namespace WebCore { + +CSSFontFaceSrcValue::~CSSFontFaceSrcValue() +{ +} + +#if ENABLE(SVG_FONTS) +bool CSSFontFaceSrcValue::isSVGFontFaceSrc() const +{ + return equalIgnoringCase(m_format, "svg"); +} +#endif + +bool CSSFontFaceSrcValue::isSupportedFormat() const +{ + // Normally we would just check the format, but in order to avoid conflicts with the old WinIE style of font-face, + // we will also check to see if the URL ends with .eot. If so, we'll go ahead and assume that we shouldn't load it. + if (m_format.isEmpty()) { + // Check for .eot. + if (!m_resource.startsWith("data:", false) && m_resource.endsWith(".eot", false)) + return false; + return true; + } + + return FontCustomPlatformData::supportsFormat(m_format) +#if ENABLE(SVG_FONTS) + || isSVGFontFaceSrc() +#endif + ; +} + +String CSSFontFaceSrcValue::cssText() const +{ + String result; + if (isLocal()) + result += "local("; + else + result += "url("; + result += m_resource; + result += ")"; + if (!m_format.isEmpty()) + result += " format(" + m_format + ")"; + return result; +} + +void CSSFontFaceSrcValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + if (!isLocal()) + addSubresourceURL(urls, styleSheet->completeURL(m_resource)); +} + +} + diff --git a/Source/WebCore/css/CSSFontFaceSrcValue.h b/Source/WebCore/css/CSSFontFaceSrcValue.h new file mode 100644 index 0000000..570652d --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSrcValue.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSFontFaceSrcValue_h +#define CSSFontFaceSrcValue_h + +#include "CSSValue.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> + +#if ENABLE(SVG_FONTS) +#include "SVGFontFaceElement.h" +#endif + +namespace WebCore { + +class CSSFontFaceSrcValue : public CSSValue { +public: + static PassRefPtr<CSSFontFaceSrcValue> create(const String& resource) + { + return adoptRef(new CSSFontFaceSrcValue(resource, false)); + } + static PassRefPtr<CSSFontFaceSrcValue> createLocal(const String& resource) + { + return adoptRef(new CSSFontFaceSrcValue(resource, true)); + } + + virtual ~CSSFontFaceSrcValue(); + + const String& resource() const { return m_resource; } + const String& format() const { return m_format; } + bool isLocal() const { return m_isLocal; } + + void setFormat(const String& format) { m_format = format; } + + bool isSupportedFormat() const; + +#if ENABLE(SVG_FONTS) + bool isSVGFontFaceSrc() const; + + SVGFontFaceElement* svgFontFaceElement() const { return m_svgFontFaceElement; } + void setSVGFontFaceElement(SVGFontFaceElement* element) { m_svgFontFaceElement = element; } +#endif + + virtual String cssText() const; + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +private: + CSSFontFaceSrcValue(const String& resource, bool local) + : m_resource(resource) + , m_isLocal(local) +#if ENABLE(SVG_FONTS) + , m_svgFontFaceElement(0) +#endif + { + } + + String m_resource; + String m_format; + bool m_isLocal; + +#if ENABLE(SVG_FONTS) + SVGFontFaceElement* m_svgFontFaceElement; +#endif +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSFontSelector.cpp b/Source/WebCore/css/CSSFontSelector.cpp new file mode 100644 index 0000000..9c9a844 --- /dev/null +++ b/Source/WebCore/css/CSSFontSelector.cpp @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFontSelector.h" + +#include "CachedFont.h" +#include "CSSFontFace.h" +#include "CSSFontFaceRule.h" +#include "CSSFontFaceSource.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPrimitiveValue.h" +#include "CSSPropertyNames.h" +#include "CSSSegmentedFontFace.h" +#include "CSSUnicodeRangeValue.h" +#include "CSSValueKeywords.h" +#include "CSSValueList.h" +#include "CachedResourceLoader.h" +#include "Document.h" +#include "FontCache.h" +#include "FontFamilyValue.h" +#include "Frame.h" +#include "RenderObject.h" +#include "Settings.h" +#include "SimpleFontData.h" +#include <wtf/text/AtomicString.h> + +#if ENABLE(SVG) +#include "SVGFontFaceElement.h" +#include "SVGNames.h" +#endif + +namespace WebCore { + +CSSFontSelector::CSSFontSelector(Document* document) + : m_document(document) +{ + // FIXME: An old comment used to say there was no need to hold a reference to m_document + // because "we are guaranteed to be destroyed before the document". But there does not + // seem to be any such guarantee. + + ASSERT(m_document); + fontCache()->addClient(this); +} + +CSSFontSelector::~CSSFontSelector() +{ + fontCache()->removeClient(this); + deleteAllValues(m_fontFaces); + deleteAllValues(m_locallyInstalledFontFaces); + deleteAllValues(m_fonts); +} + +bool CSSFontSelector::isEmpty() const +{ + return m_fonts.isEmpty(); +} + +CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const +{ + return m_document ? m_document->cachedResourceLoader() : 0; +} + +void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule) +{ + // Obtain the font-family property and the src property. Both must be defined. + const CSSMutableStyleDeclaration* style = fontFaceRule->style(); + RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily); + RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc); + RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange); + if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList())) + return; + + CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get()); + if (!familyList->length()) + return; + + CSSValueList* srcList = static_cast<CSSValueList*>(src.get()); + if (!srcList->length()) + return; + + CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get()); + + unsigned traitsMask = 0; + + if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) { + if (fontStyle->isPrimitiveValue()) { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + list->append(fontStyle); + fontStyle = list; + } else if (!fontStyle->isValueList()) + return; + + CSSValueList* styleList = static_cast<CSSValueList*>(fontStyle.get()); + unsigned numStyles = styleList->length(); + if (!numStyles) + return; + + for (unsigned i = 0; i < numStyles; ++i) { + switch (static_cast<CSSPrimitiveValue*>(styleList->itemWithoutBoundsCheck(i))->getIdent()) { + case CSSValueAll: + traitsMask |= FontStyleMask; + break; + case CSSValueNormal: + traitsMask |= FontStyleNormalMask; + break; + case CSSValueItalic: + case CSSValueOblique: + traitsMask |= FontStyleItalicMask; + break; + default: + break; + } + } + } else + traitsMask |= FontStyleMask; + + if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) { + if (fontWeight->isPrimitiveValue()) { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + list->append(fontWeight); + fontWeight = list; + } else if (!fontWeight->isValueList()) + return; + + CSSValueList* weightList = static_cast<CSSValueList*>(fontWeight.get()); + unsigned numWeights = weightList->length(); + if (!numWeights) + return; + + for (unsigned i = 0; i < numWeights; ++i) { + switch (static_cast<CSSPrimitiveValue*>(weightList->itemWithoutBoundsCheck(i))->getIdent()) { + case CSSValueAll: + traitsMask |= FontWeightMask; + break; + case CSSValueBolder: + case CSSValueBold: + case CSSValue700: + traitsMask |= FontWeight700Mask; + break; + case CSSValueNormal: + case CSSValue400: + traitsMask |= FontWeight400Mask; + break; + case CSSValue900: + traitsMask |= FontWeight900Mask; + break; + case CSSValue800: + traitsMask |= FontWeight800Mask; + break; + case CSSValue600: + traitsMask |= FontWeight600Mask; + break; + case CSSValue500: + traitsMask |= FontWeight500Mask; + break; + case CSSValue300: + traitsMask |= FontWeight300Mask; + break; + case CSSValueLighter: + case CSSValue200: + traitsMask |= FontWeight200Mask; + break; + case CSSValue100: + traitsMask |= FontWeight100Mask; + break; + default: + break; + } + } + } else + traitsMask |= FontWeightMask; + + if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) { + if (fontVariant->isPrimitiveValue()) { + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + list->append(fontVariant); + fontVariant = list; + } else if (!fontVariant->isValueList()) + return; + + CSSValueList* variantList = static_cast<CSSValueList*>(fontVariant.get()); + unsigned numVariants = variantList->length(); + if (!numVariants) + return; + + for (unsigned i = 0; i < numVariants; ++i) { + switch (static_cast<CSSPrimitiveValue*>(variantList->itemWithoutBoundsCheck(i))->getIdent()) { + case CSSValueAll: + traitsMask |= FontVariantMask; + break; + case CSSValueNormal: + traitsMask |= FontVariantNormalMask; + break; + case CSSValueSmallCaps: + traitsMask |= FontVariantSmallCapsMask; + break; + default: + break; + } + } + } else + traitsMask |= FontVariantMask; + + // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace. + RefPtr<CSSFontFace> fontFace; + + int srcLength = srcList->length(); + + bool foundSVGFont = false; + + for (int i = 0; i < srcLength; i++) { + // An item in the list either specifies a string (local font name) or a URL (remote font to download). + CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i)); + CSSFontFaceSource* source = 0; + +#if ENABLE(SVG_FONTS) + foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement(); +#endif + if (!item->isLocal()) { + Settings* settings = m_document ? m_document->frame() ? m_document->frame()->settings() : 0 : 0; + bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled()); + if (allowDownloading && item->isSupportedFormat() && m_document) { + CachedFont* cachedFont = m_document->cachedResourceLoader()->requestFont(item->resource()); + if (cachedFont) { +#if ENABLE(SVG_FONTS) + if (foundSVGFont) + cachedFont->setSVGFont(true); +#endif + source = new CSSFontFaceSource(item->resource(), cachedFont); + } + } + } else { + source = new CSSFontFaceSource(item->resource()); + } + + if (!fontFace) + fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask)); + + if (source) { +#if ENABLE(SVG_FONTS) + source->setSVGFontFaceElement(item->svgFontFaceElement()); +#endif + fontFace->addSource(source); + } + } + + ASSERT(fontFace); + + if (fontFace && !fontFace->isValid()) + return; + + if (rangeList) { + unsigned numRanges = rangeList->length(); + for (unsigned i = 0; i < numRanges; i++) { + CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i)); + fontFace->addRange(range->from(), range->to()); + } + } + + // Hash under every single family name. + int familyLength = familyList->length(); + for (int i = 0; i < familyLength; i++) { + CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->itemWithoutBoundsCheck(i)); + String familyName; + if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING) + familyName = static_cast<FontFamilyValue*>(item)->familyName(); + else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) { + // We need to use the raw text for all the generic family types, since @font-face is a way of actually + // defining what font to use for those types. + String familyName; + switch (item->getIdent()) { + case CSSValueSerif: + familyName = "-webkit-serif"; + break; + case CSSValueSansSerif: + familyName = "-webkit-sans-serif"; + break; + case CSSValueCursive: + familyName = "-webkit-cursive"; + break; + case CSSValueFantasy: + familyName = "-webkit-fantasy"; + break; + case CSSValueMonospace: + familyName = "-webkit-monospace"; + break; + default: + break; + } + } + + if (familyName.isEmpty()) + continue; + + Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName); + if (!familyFontFaces) { + familyFontFaces = new Vector<RefPtr<CSSFontFace> >; + m_fontFaces.set(familyName, familyFontFaces); + + ASSERT(!m_locallyInstalledFontFaces.contains(familyName)); + Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces; + + Vector<unsigned> locallyInstalledFontsTraitsMasks; + fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks); + unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size(); + if (numLocallyInstalledFaces) { + familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >; + m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces); + + for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) { + RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), true); + locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName)); + ASSERT(locallyInstalledFontFace->isValid()); + familyLocallyInstalledFaces->append(locallyInstalledFontFace); + } + } + } + + familyFontFaces->append(fontFace); + } +} + +void CSSFontSelector::fontLoaded() +{ + if (!m_document || m_document->inPageCache() || !m_document->renderer()) + return; + m_document->scheduleForcedStyleRecalc(); +} + +void CSSFontSelector::fontCacheInvalidated() +{ + if (!m_document || m_document->inPageCache() || !m_document->renderer()) + return; + m_document->scheduleForcedStyleRecalc(); +} + +static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName) +{ + if (!document || !document->frame()) + return 0; + + const Settings* settings = document->frame()->settings(); + if (!settings) + return 0; + + AtomicString genericFamily; + if (familyName == "-webkit-serif") + genericFamily = settings->serifFontFamily(); + else if (familyName == "-webkit-sans-serif") + genericFamily = settings->sansSerifFontFamily(); + else if (familyName == "-webkit-cursive") + genericFamily = settings->cursiveFontFamily(); + else if (familyName == "-webkit-fantasy") + genericFamily = settings->fantasyFontFamily(); + else if (familyName == "-webkit-monospace") + genericFamily = settings->fixedFontFamily(); + else if (familyName == "-webkit-standard") + genericFamily = settings->standardFontFamily(); + + if (!genericFamily.isEmpty()) + return fontCache()->getCachedFontData(fontDescription, genericFamily); + + return 0; +} + +static FontTraitsMask desiredTraitsMaskForComparison; + +static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second) +{ + FontTraitsMask firstTraitsMask = first->traitsMask(); + FontTraitsMask secondTraitsMask = second->traitsMask(); + + bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; + bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; + + if (firstHasDesiredVariant != secondHasDesiredVariant) + return firstHasDesiredVariant; + + if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) { + // Prefer a font that has indicated that it can only support small-caps to a font that claims to support + // all variants. The specialized font is more likely to be true small-caps and not require synthesis. + bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask); + bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask); + if (firstRequiresSmallCaps != secondRequiresSmallCaps) + return firstRequiresSmallCaps; + } + + bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; + bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; + + if (firstHasDesiredStyle != secondHasDesiredStyle) + return firstHasDesiredStyle; + + if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) { + // Prefer a font that has indicated that it can only support italics to a font that claims to support + // all styles. The specialized font is more likely to be the one the author wants used. + bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); + bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); + if (firstRequiresItalics != secondRequiresItalics) + return firstRequiresItalics; + } + + if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) + return false; + if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) + return true; + + // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#q46 says: "If there are fewer then 9 weights in the family, the default algorithm + // for filling the "holes" is as follows. If '500' is unassigned, it will be assigned the same font as '400'. If any of the values '600', + // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next + // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any, + // or the next darker otherwise." + // For '400', we made up our own rule (which then '500' follows). + + static const unsigned fallbackRuleSets = 9; + static const unsigned rulesPerSet = 8; + static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { + { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } + }; + + unsigned ruleSetIndex = 0; + unsigned w = FontWeight100Bit; + while (!(desiredTraitsMaskForComparison & (1 << w))) { + w++; + ruleSetIndex++; + } + + ASSERT(ruleSetIndex < fallbackRuleSets); + const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; + for (unsigned i = 0; i < rulesPerSet; ++i) { + if (secondTraitsMask & weightFallbackRule[i]) + return false; + if (firstTraitsMask & weightFallbackRule[i]) + return true; + } + + return false; +} + +FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName) +{ + if (m_fontFaces.isEmpty()) { + if (familyName.startsWith("-webkit-")) + return fontDataForGenericFamily(m_document, fontDescription, familyName); + return 0; + } + + String family = familyName.string(); + + Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family); + // If no face was found, then return 0 and let the OS come up with its best match for the name. + if (!familyFontFaces || familyFontFaces->isEmpty()) { + // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our + // settings. + return fontDataForGenericFamily(m_document, fontDescription, familyName); + } + + HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family); + if (!segmentedFontFaceCache) { + segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >; + m_fonts.set(family, segmentedFontFaceCache); + } + + FontTraitsMask traitsMask = fontDescription.traitsMask(); + + RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask); + + if (!face) { + face = CSSSegmentedFontFace::create(this); + segmentedFontFaceCache->set(traitsMask, face); + // Collect all matching faces and sort them in order of preference. + Vector<CSSFontFace*, 32> candidateFontFaces; + for (int i = familyFontFaces->size() - 1; i >= 0; --i) { + CSSFontFace* candidate = familyFontFaces->at(i).get(); + unsigned candidateTraitsMask = candidate->traitsMask(); + if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) + continue; + if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) + continue; +#if ENABLE(SVG_FONTS) + // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable + // of small-caps synthesis and just ignore the font face as a candidate. + if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask)) + continue; +#endif + candidateFontFaces.append(candidate); + } + + if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { + unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); + for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { + CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); + unsigned candidateTraitsMask = candidate->traitsMask(); + if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) + continue; + if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) + continue; + candidateFontFaces.append(candidate); + } + } + + desiredTraitsMaskForComparison = traitsMask; + std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces); + unsigned numCandidates = candidateFontFaces.size(); + for (unsigned i = 0; i < numCandidates; ++i) + face->appendFontFace(candidateFontFaces[i]); + } + + // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over. + return face->getFontData(fontDescription); +} + +} diff --git a/Source/WebCore/css/CSSFontSelector.h b/Source/WebCore/css/CSSFontSelector.h new file mode 100644 index 0000000..93ee274 --- /dev/null +++ b/Source/WebCore/css/CSSFontSelector.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSFontSelector_h +#define CSSFontSelector_h + +#include "FontSelector.h" +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/RefPtr.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +class CSSFontFace; +class CSSFontFaceRule; +class CSSSegmentedFontFace; +class Document; +class CachedResourceLoader; +class FontDescription; + +class CSSFontSelector : public FontSelector { +public: + static PassRefPtr<CSSFontSelector> create(Document* document) + { + return adoptRef(new CSSFontSelector(document)); + } + virtual ~CSSFontSelector(); + + virtual FontData* getFontData(const FontDescription& fontDescription, const AtomicString& familyName); + + void clearDocument() { m_document = 0; } + + void addFontFaceRule(const CSSFontFaceRule*); + + void fontLoaded(); + virtual void fontCacheInvalidated(); + + bool isEmpty() const; + + CachedResourceLoader* cachedResourceLoader() const; + +private: + CSSFontSelector(Document*); + + Document* m_document; + HashMap<String, Vector<RefPtr<CSSFontFace> >*, CaseFoldingHash> m_fontFaces; + HashMap<String, Vector<RefPtr<CSSFontFace> >*, CaseFoldingHash> m_locallyInstalledFontFaces; + HashMap<String, HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >*, CaseFoldingHash> m_fonts; +}; + +} // namespace WebCore + +#endif // CSSFontSelector_h diff --git a/Source/WebCore/css/CSSFunctionValue.cpp b/Source/WebCore/css/CSSFunctionValue.cpp new file mode 100644 index 0000000..70e8174 --- /dev/null +++ b/Source/WebCore/css/CSSFunctionValue.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFunctionValue.h" + +#include "CSSValueList.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +CSSFunctionValue::CSSFunctionValue(CSSParserFunction* function) + : m_name(function->name) +{ + if (function->args) + m_args = CSSValueList::createFromParserValueList(function->args.get()); +} + +CSSFunctionValue::~CSSFunctionValue() +{ +} + +String CSSFunctionValue::cssText() const +{ + String result = m_name; // Includes the '(' + if (m_args) + result += m_args->cssText(); + result += ")"; + return result; +} + +CSSParserValue CSSFunctionValue::parserValue() const +{ + CSSParserValue val; + val.id = 0; + val.isInt = false; + val.unit = CSSParserValue::Function; + val.function = new CSSParserFunction; + val.function->name.characters = const_cast<UChar*>(m_name.characters()); + val.function->name.length = m_name.length(); + if (m_args) + val.function->args = m_args->createParserValueList(); + return val; +} + +} diff --git a/Source/WebCore/css/CSSFunctionValue.h b/Source/WebCore/css/CSSFunctionValue.h new file mode 100644 index 0000000..1d73f33 --- /dev/null +++ b/Source/WebCore/css/CSSFunctionValue.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSFunctionValue_h +#define CSSFunctionValue_h + +#include "CSSValue.h" + +namespace WebCore { + +class CSSValueList; +struct CSSParserFunction; + +class CSSFunctionValue : public CSSValue { +public: + static PassRefPtr<CSSFunctionValue> create(CSSParserFunction* function) + { + return adoptRef(new CSSFunctionValue(function)); + } + + virtual ~CSSFunctionValue(); + + virtual String cssText() const; + + virtual CSSParserValue parserValue() const; + +private: + explicit CSSFunctionValue(CSSParserFunction*); + + String m_name; + RefPtr<CSSValueList> m_args; +}; + +} +#endif + diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp new file mode 100644 index 0000000..8040c6c --- /dev/null +++ b/Source/WebCore/css/CSSGradientValue.cpp @@ -0,0 +1,833 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSGradientValue.h" + +#include "CSSValueKeywords.h" +#include "CSSStyleSelector.h" +#include "GeneratedImage.h" +#include "Gradient.h" +#include "Image.h" +#include "IntSize.h" +#include "IntSizeHash.h" +#include "NodeRenderStyle.h" +#include "PlatformString.h" +#include "RenderObject.h" + +using namespace std; + +namespace WebCore { + +Image* CSSGradientValue::image(RenderObject* renderer, const IntSize& size) +{ + ASSERT(m_clients.contains(renderer)); + + // Need to look up our size. Create a string of width*height to use as a hash key. + // FIXME: hashing based only on size is not sufficient. Color stops may use context-sensitive units (like em) + // that should force the color stop positions to be recomputed. + Image* result = getImage(renderer, size); + if (result) + return result; + + if (size.isEmpty()) + return 0; + + // We need to create an image. + RefPtr<Image> newImage = GeneratedImage::create(createGradient(renderer, size), size); + result = newImage.get(); + putImage(size, newImage.release()); + + return result; +} + +// Should only ever be called for deprecated gradients. +static inline bool compareStops(const CSSGradientColorStop& a, const CSSGradientColorStop& b) +{ + double aVal = a.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); + double bVal = b.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); + + return aVal < bVal; +} + +void CSSGradientValue::sortStopsIfNeeded() +{ + ASSERT(m_deprecatedType); + if (!m_stopsSorted) { + if (m_stops.size()) + std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); + m_stopsSorted = true; + } +} + +static inline int blend(int from, int to, float progress) +{ + return int(from + (to - from) * progress); +} + +static inline Color blend(const Color& from, const Color& to, float progress) +{ + // FIXME: when we interpolate gradients using premultiplied colors, this should also do premultiplication. + return Color(blend(from.red(), to.red(), progress), + blend(from.green(), to.green(), progress), + blend(from.blue(), to.blue(), progress), + blend(from.alpha(), to.alpha(), progress)); +} + +struct GradientStop { + Color color; + float offset; + bool specified; + + GradientStop() + : offset(0) + , specified(false) + { } +}; + +void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, RenderStyle* rootStyle, float maxLengthForRepeat) +{ + RenderStyle* style = renderer->style(); + + if (m_deprecatedType) { + sortStopsIfNeeded(); + + // We have to resolve colors. + for (unsigned i = 0; i < m_stops.size(); i++) { + const CSSGradientColorStop& stop = m_stops[i]; + Color color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(stop.m_color.get()); + + float offset; + if (stop.m_position->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; + else + offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); + + gradient->addColorStop(offset, color); + } + + // The back end already sorted the stops. + gradient->setStopsSorted(true); + return; + } + + size_t numStops = m_stops.size(); + + Vector<GradientStop> stops(numStops); + + float gradientLength = 0; + bool computedGradientLength = false; + + FloatPoint gradientStart = gradient->p0(); + FloatPoint gradientEnd; + if (isLinearGradient()) + gradientEnd = gradient->p1(); + else if (isRadialGradient()) + gradientEnd = gradientStart + FloatSize(gradient->endRadius(), 0); + + for (size_t i = 0; i < numStops; ++i) { + const CSSGradientColorStop& stop = m_stops[i]; + + stops[i].color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(stop.m_color.get()); + + if (stop.m_position) { + int type = stop.m_position->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + stops[i].offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; + else if (CSSPrimitiveValue::isUnitTypeLength(type)) { + float length = stop.m_position->computeLengthFloat(style, rootStyle, style->effectiveZoom()); + if (!computedGradientLength) { + FloatSize gradientSize(gradientStart - gradientEnd); + gradientLength = gradientSize.diagonalLength(); + } + stops[i].offset = (gradientLength > 0) ? length / gradientLength : 0; + } else { + ASSERT_NOT_REACHED(); + stops[i].offset = 0; + } + stops[i].specified = true; + } else { + // If the first color-stop does not have a position, its position defaults to 0%. + // If the last color-stop does not have a position, its position defaults to 100%. + if (!i) { + stops[i].offset = 0; + stops[i].specified = true; + } else if (numStops > 1 && i == numStops - 1) { + stops[i].offset = 1; + stops[i].specified = true; + } + } + + // If a color-stop has a position that is less than the specified position of any + // color-stop before it in the list, its position is changed to be equal to the + // largest specified position of any color-stop before it. + if (stops[i].specified && i > 0) { + size_t prevSpecifiedIndex; + for (prevSpecifiedIndex = i - 1; prevSpecifiedIndex; --prevSpecifiedIndex) { + if (stops[prevSpecifiedIndex].specified) + break; + } + + if (stops[i].offset < stops[prevSpecifiedIndex].offset) + stops[i].offset = stops[prevSpecifiedIndex].offset; + } + } + + ASSERT(stops[0].specified && stops[numStops - 1].specified); + + // If any color-stop still does not have a position, then, for each run of adjacent + // color-stops without positions, set their positions so that they are evenly spaced + // between the preceding and following color-stops with positions. + if (numStops > 2) { + size_t unspecifiedRunStart = 0; + bool inUnspecifiedRun = false; + + for (size_t i = 0; i < numStops; ++i) { + if (!stops[i].specified && !inUnspecifiedRun) { + unspecifiedRunStart = i; + inUnspecifiedRun = true; + } else if (stops[i].specified && inUnspecifiedRun) { + size_t unspecifiedRunEnd = i; + + if (unspecifiedRunStart < unspecifiedRunEnd) { + float lastSpecifiedOffset = stops[unspecifiedRunStart - 1].offset; + float nextSpecifiedOffset = stops[unspecifiedRunEnd].offset; + float delta = (nextSpecifiedOffset - lastSpecifiedOffset) / (unspecifiedRunEnd - unspecifiedRunStart + 1); + + for (size_t j = unspecifiedRunStart; j < unspecifiedRunEnd; ++j) + stops[j].offset = lastSpecifiedOffset + (j - unspecifiedRunStart + 1) * delta; + } + + inUnspecifiedRun = false; + } + } + } + + // If the gradient is repeating, repeat the color stops. + // We can't just push this logic down into the platform-specific Gradient code, + // because we have to know the extent of the gradient, and possible move the end points. + if (m_repeating && numStops > 1) { + float maxExtent = 1; + + // Radial gradients may need to extend further than the endpoints, because they have + // to repeat out to the corners of the box. + if (isRadialGradient()) { + if (!computedGradientLength) { + FloatSize gradientSize(gradientStart - gradientEnd); + gradientLength = gradientSize.diagonalLength(); + } + + if (maxLengthForRepeat > gradientLength) + maxExtent = maxLengthForRepeat / gradientLength; + } + + size_t originalNumStops = numStops; + size_t originalFirstStopIndex = 0; + + // Work backwards from the first, adding stops until we get one before 0. + float firstOffset = stops[0].offset; + if (firstOffset > 0) { + float currOffset = firstOffset; + size_t srcStopOrdinal = originalNumStops - 1; + + while (true) { + GradientStop newStop = stops[originalFirstStopIndex + srcStopOrdinal]; + newStop.offset = currOffset; + stops.prepend(newStop); + ++originalFirstStopIndex; + if (currOffset < 0) + break; + + if (srcStopOrdinal) + currOffset -= stops[originalFirstStopIndex + srcStopOrdinal].offset - stops[originalFirstStopIndex + srcStopOrdinal - 1].offset; + srcStopOrdinal = (srcStopOrdinal + originalNumStops - 1) % originalNumStops; + } + } + + // Work forwards from the end, adding stops until we get one after 1. + float lastOffset = stops[stops.size() - 1].offset; + if (lastOffset < maxExtent) { + float currOffset = lastOffset; + size_t srcStopOrdinal = 0; + + while (true) { + GradientStop newStop = stops[srcStopOrdinal]; + newStop.offset = currOffset; + stops.append(newStop); + if (currOffset > maxExtent) + break; + if (srcStopOrdinal < originalNumStops - 1) + currOffset += stops[originalFirstStopIndex + srcStopOrdinal + 1].offset - stops[originalFirstStopIndex + srcStopOrdinal].offset; + srcStopOrdinal = (srcStopOrdinal + 1) % originalNumStops; + } + } + } + + numStops = stops.size(); + + // If the gradient goes outside the 0-1 range, normalize it by moving the endpoints, and adjusting the stops. + if (numStops > 1 && (stops[0].offset < 0 || stops[numStops - 1].offset > 1)) { + if (isLinearGradient()) { + float firstOffset = stops[0].offset; + float lastOffset = stops[numStops - 1].offset; + float scale = lastOffset - firstOffset; + + for (size_t i = 0; i < numStops; ++i) + stops[i].offset = (stops[i].offset - firstOffset) / scale; + + FloatPoint p0 = gradient->p0(); + FloatPoint p1 = gradient->p1(); + gradient->setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()))); + gradient->setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()))); + } else if (isRadialGradient()) { + // Rather than scaling the points < 0, we truncate them, so only scale according to the largest point. + float firstOffset = 0; + float lastOffset = stops[numStops - 1].offset; + float scale = lastOffset - firstOffset; + + // Reset points below 0 to the first visible color. + size_t firstZeroOrGreaterIndex = numStops; + for (size_t i = 0; i < numStops; ++i) { + if (stops[i].offset >= 0) { + firstZeroOrGreaterIndex = i; + break; + } + } + + if (firstZeroOrGreaterIndex > 0) { + if (firstZeroOrGreaterIndex < numStops && stops[firstZeroOrGreaterIndex].offset > 0) { + float prevOffset = stops[firstZeroOrGreaterIndex - 1].offset; + float nextOffset = stops[firstZeroOrGreaterIndex].offset; + + float interStopProportion = -prevOffset / (nextOffset - prevOffset); + Color blendedColor = blend(stops[firstZeroOrGreaterIndex - 1].color, stops[firstZeroOrGreaterIndex].color, interStopProportion); + + // Clamp the positions to 0 and set the color. + for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) { + stops[i].offset = 0; + stops[i].color = blendedColor; + } + } else { + // All stops are below 0; just clamp them. + for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) + stops[i].offset = 0; + } + } + + for (size_t i = 0; i < numStops; ++i) + stops[i].offset /= scale; + + gradient->setStartRadius(gradient->startRadius() * scale); + gradient->setEndRadius(gradient->endRadius() * scale); + } + } + + for (unsigned i = 0; i < numStops; i++) + gradient->addColorStop(stops[i].offset, stops[i].color); + + gradient->setStopsSorted(true); +} + +static float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size, bool isHorizontal) +{ + float zoomFactor = style->effectiveZoom(); + + switch (value->primitiveType()) { + case CSSPrimitiveValue::CSS_NUMBER: + return value->getFloatValue() * zoomFactor; + + case CSSPrimitiveValue::CSS_PERCENTAGE: + return value->getFloatValue() / 100.f * (isHorizontal ? size.width() : size.height()); + + case CSSPrimitiveValue::CSS_IDENT: + switch (value->getIdent()) { + case CSSValueTop: + ASSERT(!isHorizontal); + return 0; + case CSSValueLeft: + ASSERT(isHorizontal); + return 0; + case CSSValueBottom: + ASSERT(!isHorizontal); + return size.height(); + case CSSValueRight: + ASSERT(isHorizontal); + return size.width(); + } + + default: + return value->computeLengthFloat(style, rootStyle, zoomFactor); + } +} + +FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size) +{ + FloatPoint result; + + if (first) + result.setX(positionFromValue(first, style, rootStyle, size, true)); + + if (second) + result.setY(positionFromValue(second, style, rootStyle, size, false)); + + return result; +} + +String CSSLinearGradientValue::cssText() const +{ + String result; + if (m_deprecatedType) { + result = "-webkit-gradient(linear, "; + result += m_firstX->cssText() + " "; + result += m_firstY->cssText() + ", "; + result += m_secondX->cssText() + " "; + result += m_secondY->cssText(); + + for (unsigned i = 0; i < m_stops.size(); i++) { + const CSSGradientColorStop& stop = m_stops[i]; + result += ", "; + if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) + result += "from(" + stop.m_color->cssText() + ")"; + else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) + result += "to(" + stop.m_color->cssText() + ")"; + else + result += "color-stop(" + String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)) + ", " + stop.m_color->cssText() + ")"; + } + } else { + result = m_repeating ? "-webkit-repeating-linear-gradient(" : "-webkit-linear-gradient("; + if (m_angle) + result += m_angle->cssText(); + else { + if (m_firstX && m_firstY) + result += m_firstX->cssText() + " " + m_firstY->cssText(); + else if (m_firstX || m_firstY) { + if (m_firstX) + result += m_firstX->cssText(); + + if (m_firstY) + result += m_firstY->cssText(); + } + } + + for (unsigned i = 0; i < m_stops.size(); i++) { + const CSSGradientColorStop& stop = m_stops[i]; + result += ", "; + result += stop.m_color->cssText(); + if (stop.m_position) + result += " " + stop.m_position->cssText(); + } + } + + result += ")"; + return result; +} + +// Compute the endpoints so that a gradient of the given angle covers a box of the given size. +static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint) +{ + angleDeg = fmodf(angleDeg, 360); + if (angleDeg < 0) + angleDeg += 360; + + if (!angleDeg) { + firstPoint.set(0, 0); + secondPoint.set(size.width(), 0); + return; + } + + if (angleDeg == 90) { + firstPoint.set(0, size.height()); + secondPoint.set(0, 0); + return; + } + + if (angleDeg == 180) { + firstPoint.set(size.width(), 0); + secondPoint.set(0, 0); + return; + } + + float slope = tan(deg2rad(angleDeg)); + + // We find the endpoint by computing the intersection of the line formed by the slope, + // and a line perpendicular to it that intersects the corner. + float perpendicularSlope = -1 / slope; + + // Compute start corner relative to center. + float halfHeight = size.height() / 2; + float halfWidth = size.width() / 2; + FloatPoint endCorner; + if (angleDeg < 90) + endCorner.set(halfWidth, halfHeight); + else if (angleDeg < 180) + endCorner.set(-halfWidth, halfHeight); + else if (angleDeg < 270) + endCorner.set(-halfWidth, -halfHeight); + else + endCorner.set(halfWidth, -halfHeight); + + // Compute c (of y = mx + c) using the corner point. + float c = endCorner.y() - perpendicularSlope * endCorner.x(); + float endX = c / (slope - perpendicularSlope); + float endY = perpendicularSlope * endX + c; + + // We computed the end point, so set the second point, flipping the Y to account for angles going anticlockwise. + secondPoint.set(halfWidth + endX, size.height() - (halfHeight + endY)); + // Reflect around the center for the start point. + firstPoint.set(size.width() - secondPoint.x(), size.height() - secondPoint.y()); +} + +PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* renderer, const IntSize& size) +{ + ASSERT(!size.isEmpty()); + + RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); + + FloatPoint firstPoint; + FloatPoint secondPoint; + if (m_angle) { + float angle = m_angle->getFloatValue(CSSPrimitiveValue::CSS_DEG); + endPointsFromAngle(angle, size, firstPoint, secondPoint); + } else { + firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + + if (m_secondX || m_secondY) + secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + else { + if (m_firstX) + secondPoint.setX(size.width() - firstPoint.x()); + if (m_firstY) + secondPoint.setY(size.height() - firstPoint.y()); + } + } + + RefPtr<Gradient> gradient = Gradient::create(firstPoint, secondPoint); + + // Now add the stops. + addStops(gradient.get(), renderer, rootStyle, 1); + + return gradient.release(); +} + +String CSSRadialGradientValue::cssText() const +{ + String result; + + if (m_deprecatedType) { + result = "-webkit-gradient(radial, "; + + result += m_firstX->cssText() + " "; + result += m_firstY->cssText() + ", "; + result += m_firstRadius->cssText() + ", "; + result += m_secondX->cssText() + " "; + result += m_secondY->cssText(); + result += ", "; + result += m_secondRadius->cssText(); + + // FIXME: share? + for (unsigned i = 0; i < m_stops.size(); i++) { + const CSSGradientColorStop& stop = m_stops[i]; + result += ", "; + if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) + result += "from(" + stop.m_color->cssText() + ")"; + else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) + result += "to(" + stop.m_color->cssText() + ")"; + else + result += "color-stop(" + String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)) + ", " + stop.m_color->cssText() + ")"; + } + } else { + + result = m_repeating ? "-webkit-repeating-radial-gradient(" : "-webkit-radial-gradient("; + if (m_firstX && m_firstY) { + result += m_firstX->cssText() + " " + m_firstY->cssText(); + } else if (m_firstX) + result += m_firstX->cssText(); + else if (m_firstY) + result += m_firstY->cssText(); + else + result += "center"; + + + if (m_shape || m_sizingBehavior) { + result += ", "; + if (m_shape) + result += m_shape->cssText() + " "; + else + result += "ellipse "; + + if (m_sizingBehavior) + result += m_sizingBehavior->cssText(); + else + result += "cover"; + + } else if (m_endHorizontalSize && m_endVerticalSize) { + result += ", "; + result += m_endHorizontalSize->cssText() + " " + m_endVerticalSize->cssText(); + } + + for (unsigned i = 0; i < m_stops.size(); i++) { + const CSSGradientColorStop& stop = m_stops[i]; + result += ", "; + result += stop.m_color->cssText(); + if (stop.m_position) + result += " " + stop.m_position->cssText(); + } + } + + result += ")"; + return result; +} + +float CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue* radius, RenderStyle* style, RenderStyle* rootStyle, float* widthOrHeight) +{ + float zoomFactor = style->effectiveZoom(); + + float result = 0; + if (radius->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // Can the radius be a percentage? + result = radius->getFloatValue() * zoomFactor; + else if (widthOrHeight && radius->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + result = *widthOrHeight * radius->getFloatValue() / 100; + else + result = radius->computeLengthFloat(style, rootStyle, zoomFactor); + + return result; +} + +static float distanceToClosestCorner(const FloatPoint& p, const FloatSize& size, FloatPoint& corner) +{ + FloatPoint topLeft; + float topLeftDistance = FloatSize(p - topLeft).diagonalLength(); + + FloatPoint topRight(size.width(), 0); + float topRightDistance = FloatSize(p - topRight).diagonalLength(); + + FloatPoint bottomLeft(0, size.height()); + float bottomLeftDistance = FloatSize(p - bottomLeft).diagonalLength(); + + FloatPoint bottomRight(size.width(), size.height()); + float bottomRightDistance = FloatSize(p - bottomRight).diagonalLength(); + + corner = topLeft; + float minDistance = topLeftDistance; + if (topRightDistance < minDistance) { + minDistance = topRightDistance; + corner = topRight; + } + + if (bottomLeftDistance < minDistance) { + minDistance = bottomLeftDistance; + corner = bottomLeft; + } + + if (bottomRightDistance < minDistance) { + minDistance = bottomRightDistance; + corner = bottomRight; + } + return minDistance; +} + +static float distanceToFarthestCorner(const FloatPoint& p, const FloatSize& size, FloatPoint& corner) +{ + FloatPoint topLeft; + float topLeftDistance = FloatSize(p - topLeft).diagonalLength(); + + FloatPoint topRight(size.width(), 0); + float topRightDistance = FloatSize(p - topRight).diagonalLength(); + + FloatPoint bottomLeft(0, size.height()); + float bottomLeftDistance = FloatSize(p - bottomLeft).diagonalLength(); + + FloatPoint bottomRight(size.width(), size.height()); + float bottomRightDistance = FloatSize(p - bottomRight).diagonalLength(); + + corner = topLeft; + float maxDistance = topLeftDistance; + if (topRightDistance > maxDistance) { + maxDistance = topRightDistance; + corner = topRight; + } + + if (bottomLeftDistance > maxDistance) { + maxDistance = bottomLeftDistance; + corner = bottomLeft; + } + + if (bottomRightDistance > maxDistance) { + maxDistance = bottomRightDistance; + corner = bottomRight; + } + return maxDistance; +} + +// Compute horizontal radius of ellipse with center at 0,0 which passes through p, and has +// width/height given by aspectRatio. +static inline float horizontalEllipseRadius(const FloatSize& p, float aspectRatio) +{ + // x^2/a^2 + y^2/b^2 = 1 + // a/b = aspectRatio, b = a/aspectRatio + // a = sqrt(x^2 + y^2/(1/r^2)) + return sqrtf(p.width() * p.width() + (p.height() * p.height()) / (1 / (aspectRatio * aspectRatio))); +} + +// FIXME: share code with the linear version +PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* renderer, const IntSize& size) +{ + ASSERT(!size.isEmpty()); + + RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); + + FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + if (!m_firstX) + firstPoint.setX(size.width() / 2); + if (!m_firstY) + firstPoint.setY(size.height() / 2); + + FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + if (!m_secondX) + secondPoint.setX(size.width() / 2); + if (!m_secondY) + secondPoint.setY(size.height() / 2); + + float firstRadius = 0; + if (m_firstRadius) + firstRadius = resolveRadius(m_firstRadius.get(), renderer->style(), rootStyle); + + float secondRadius = 0; + float aspectRatio = 1; // width / height. + if (m_secondRadius) + secondRadius = resolveRadius(m_secondRadius.get(), renderer->style(), rootStyle); + else if (m_endHorizontalSize || m_endVerticalSize) { + float width = size.width(); + float height = size.height(); + secondRadius = resolveRadius(m_endHorizontalSize.get(), renderer->style(), rootStyle, &width); + aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height); + } else { + enum GradientShape { Circle, Ellipse }; + GradientShape shape = Ellipse; + if (m_shape && m_shape->primitiveType() == CSSPrimitiveValue::CSS_IDENT && m_shape->getIdent() == CSSValueCircle) + shape = Circle; + + enum GradientFill { ClosestSide, ClosestCorner, FarthestSide, FarthestCorner }; + GradientFill fill = FarthestCorner; + + if (m_sizingBehavior && m_sizingBehavior->primitiveType() == CSSPrimitiveValue::CSS_IDENT) { + switch (m_sizingBehavior->getIdent()) { + case CSSValueContain: + case CSSValueClosestSide: + fill = ClosestSide; + break; + case CSSValueClosestCorner: + fill = ClosestCorner; + break; + case CSSValueFarthestSide: + fill = FarthestSide; + break; + case CSSValueCover: + case CSSValueFarthestCorner: + fill = FarthestCorner; + break; + } + } + + // Now compute the end radii based on the second point, shape and fill. + + // Horizontal + switch (fill) { + case ClosestSide: { + float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); + if (shape == Circle) { + float smaller = min(xDist, yDist); + xDist = smaller; + yDist = smaller; + } + secondRadius = xDist; + aspectRatio = xDist / yDist; + break; + } + case FarthestSide: { + float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); + if (shape == Circle) { + float larger = max(xDist, yDist); + xDist = larger; + yDist = larger; + } + secondRadius = xDist; + aspectRatio = xDist / yDist; + break; + } + case ClosestCorner: { + FloatPoint corner; + float distance = distanceToClosestCorner(secondPoint, size, corner); + if (shape == Circle) + secondRadius = distance; + else { + // If <shape> is ellipse, the gradient-shape has the same ratio of width to height + // that it would if closest-side or farthest-side were specified, as appropriate. + float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); + + secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); + aspectRatio = xDist / yDist; + } + break; + } + + case FarthestCorner: { + FloatPoint corner; + float distance = distanceToFarthestCorner(secondPoint, size, corner); + if (shape == Circle) + secondRadius = distance; + else { + // If <shape> is ellipse, the gradient-shape has the same ratio of width to height + // that it would if closest-side or farthest-side were specified, as appropriate. + float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); + + secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); + aspectRatio = xDist / yDist; + } + break; + } + } + } + + RefPtr<Gradient> gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); + + // addStops() only uses maxExtent for repeating gradients. + float maxExtent = 0; + if (m_repeating) { + FloatPoint corner; + maxExtent = distanceToFarthestCorner(secondPoint, size, corner); + } + + // Now add the stops. + addStops(gradient.get(), renderer, rootStyle, maxExtent); + + return gradient.release(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSGradientValue.h b/Source/WebCore/css/CSSGradientValue.h new file mode 100644 index 0000000..0b5ca77 --- /dev/null +++ b/Source/WebCore/css/CSSGradientValue.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSGradientValue_h +#define CSSGradientValue_h + +#include "CSSImageGeneratorValue.h" +#include "CSSPrimitiveValue.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class FloatPoint; +class Gradient; + +enum CSSGradientType { CSSLinearGradient, CSSRadialGradient }; +enum CSSGradientRepeat { NonRepeating, Repeating }; + +struct CSSGradientColorStop { + RefPtr<CSSPrimitiveValue> m_position; // percentage or length + RefPtr<CSSPrimitiveValue> m_color; +}; + +class CSSGradientValue : public CSSImageGeneratorValue { +public: + virtual Image* image(RenderObject*, const IntSize&); + + void setFirstX(PassRefPtr<CSSPrimitiveValue> val) { m_firstX = val; } + void setFirstY(PassRefPtr<CSSPrimitiveValue> val) { m_firstY = val; } + void setSecondX(PassRefPtr<CSSPrimitiveValue> val) { m_secondX = val; } + void setSecondY(PassRefPtr<CSSPrimitiveValue> val) { m_secondY = val; } + + void addStop(const CSSGradientColorStop& stop) { m_stops.append(stop); } + + Vector<CSSGradientColorStop>& stops() { return m_stops; } + + void sortStopsIfNeeded(); + + virtual bool isLinearGradient() const { return false; } + virtual bool isRadialGradient() const { return false; } + + bool isRepeating() const { return m_repeating; } + + bool deprecatedType() const { return m_deprecatedType; } // came from -webkit-gradient + +protected: + CSSGradientValue(CSSGradientRepeat repeat, bool deprecatedType = false) + : m_stopsSorted(false) + , m_deprecatedType(deprecatedType) + , m_repeating(repeat == Repeating) + { + } + + void addStops(Gradient*, RenderObject*, RenderStyle* rootStyle, float maxLengthForRepeat = 0); + + // Create the gradient for a given size. + virtual PassRefPtr<Gradient> createGradient(RenderObject*, const IntSize&) = 0; + + // Resolve points/radii to front end values. + FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, const IntSize&); + + // Points. Some of these may be null for linear gradients. + RefPtr<CSSPrimitiveValue> m_firstX; + RefPtr<CSSPrimitiveValue> m_firstY; + + RefPtr<CSSPrimitiveValue> m_secondX; + RefPtr<CSSPrimitiveValue> m_secondY; + + // Stops + Vector<CSSGradientColorStop> m_stops; + bool m_stopsSorted; + bool m_deprecatedType; // -webkit-gradient() + bool m_repeating; +}; + + +class CSSLinearGradientValue : public CSSGradientValue { +public: + static PassRefPtr<CSSLinearGradientValue> create(CSSGradientRepeat repeat, bool deprecatedType = false) + { + return adoptRef(new CSSLinearGradientValue(repeat, deprecatedType)); + } + + void setAngle(PassRefPtr<CSSPrimitiveValue> val) { m_angle = val; } + + virtual String cssText() const; + +private: + CSSLinearGradientValue(CSSGradientRepeat repeat, bool deprecatedType = false) + : CSSGradientValue(repeat, deprecatedType) + { + } + + virtual bool isLinearGradient() const { return true; } + + // Create the gradient for a given size. + virtual PassRefPtr<Gradient> createGradient(RenderObject*, const IntSize&); + + RefPtr<CSSPrimitiveValue> m_angle; // may be null. +}; + +class CSSRadialGradientValue : public CSSGradientValue { +public: + static PassRefPtr<CSSRadialGradientValue> create(CSSGradientRepeat repeat, bool deprecatedType = false) + { + return adoptRef(new CSSRadialGradientValue(repeat, deprecatedType)); + } + + virtual String cssText() const; + + void setFirstRadius(PassRefPtr<CSSPrimitiveValue> val) { m_firstRadius = val; } + void setSecondRadius(PassRefPtr<CSSPrimitiveValue> val) { m_secondRadius = val; } + + void setShape(PassRefPtr<CSSPrimitiveValue> val) { m_shape = val; } + void setSizingBehavior(PassRefPtr<CSSPrimitiveValue> val) { m_sizingBehavior = val; } + + void setEndHorizontalSize(PassRefPtr<CSSPrimitiveValue> val) { m_endHorizontalSize = val; } + void setEndVerticalSize(PassRefPtr<CSSPrimitiveValue> val) { m_endVerticalSize = val; } + +private: + CSSRadialGradientValue(CSSGradientRepeat repeat, bool deprecatedType = false) + : CSSGradientValue(repeat, deprecatedType) + { + } + + virtual bool isRadialGradient() const { return true; } + + // Create the gradient for a given size. + virtual PassRefPtr<Gradient> createGradient(RenderObject*, const IntSize&); + + // Resolve points/radii to front end values. + float resolveRadius(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, float* widthOrHeight = 0); + + // These may be null for non-deprecated gradients. + RefPtr<CSSPrimitiveValue> m_firstRadius; + RefPtr<CSSPrimitiveValue> m_secondRadius; + + // The below are only used for non-deprecated gradients. + RefPtr<CSSPrimitiveValue> m_shape; + RefPtr<CSSPrimitiveValue> m_sizingBehavior; + + RefPtr<CSSPrimitiveValue> m_endHorizontalSize; + RefPtr<CSSPrimitiveValue> m_endVerticalSize; +}; + +} // namespace WebCore + +#endif // CSSGradientValue_h diff --git a/Source/WebCore/css/CSSGrammar.y b/Source/WebCore/css/CSSGrammar.y new file mode 100644 index 0000000..ba5855d --- /dev/null +++ b/Source/WebCore/css/CSSGrammar.y @@ -0,0 +1,1552 @@ +%{ + +/* + * Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" + +#include "CSSMediaRule.h" +#include "CSSParser.h" +#include "CSSPrimitiveValue.h" +#include "CSSPropertyNames.h" +#include "CSSRuleList.h" +#include "CSSSelector.h" +#include "CSSStyleSheet.h" +#include "Document.h" +#include "HTMLNames.h" +#include "MediaList.h" +#include "MediaQueryExp.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include <wtf/FastMalloc.h> +#include <stdlib.h> +#include <string.h> + +using namespace WebCore; +using namespace HTMLNames; + +#define YYMALLOC fastMalloc +#define YYFREE fastFree + +#define YYENABLE_NLS 0 +#define YYLTYPE_IS_TRIVIAL 1 +#define YYMAXDEPTH 10000 +#define YYDEBUG 0 + +// FIXME: Replace with %parse-param { CSSParser* parser } once we can depend on bison 2.x +#define YYPARSE_PARAM parser +#define YYLEX_PARAM parser + +%} + +%pure_parser + +%union { + bool boolean; + char character; + int integer; + double number; + CSSParserString string; + + CSSRule* rule; + CSSRuleList* ruleList; + CSSSelector* selector; + Vector<CSSSelector*>* selectorList; + CSSSelector::MarginBoxType marginBox; + CSSSelector::Relation relation; + MediaList* mediaList; + MediaQuery* mediaQuery; + MediaQuery::Restrictor mediaQueryRestrictor; + MediaQueryExp* mediaQueryExp; + CSSParserValue value; + CSSParserValueList* valueList; + Vector<OwnPtr<MediaQueryExp> >* mediaQueryExpList; + WebKitCSSKeyframeRule* keyframeRule; + WebKitCSSKeyframesRule* keyframesRule; + float val; +} + +%{ + +static inline int cssyyerror(const char*) +{ + return 1; +} + +static int cssyylex(YYSTYPE* yylval, void* parser) +{ + return static_cast<CSSParser*>(parser)->lex(yylval); +} + +%} + +%expect 51 + +%nonassoc LOWEST_PREC + +%left UNIMPORTANT_TOK + +%token WHITESPACE SGML_CD +%token TOKEN_EOF 0 + +%token INCLUDES +%token DASHMATCH +%token BEGINSWITH +%token ENDSWITH +%token CONTAINS + +%token <string> STRING +%right <string> IDENT +%token <string> NTH + +%nonassoc <string> HEX +%nonassoc <string> IDSEL +%nonassoc ':' +%nonassoc '.' +%nonassoc '[' +%nonassoc <string> '*' +%nonassoc error +%left '|' + +%token IMPORT_SYM +%token PAGE_SYM +%token MEDIA_SYM +%token FONT_FACE_SYM +%token CHARSET_SYM +%token NAMESPACE_SYM +%token WEBKIT_RULE_SYM +%token WEBKIT_DECLS_SYM +%token WEBKIT_KEYFRAME_RULE_SYM +%token WEBKIT_KEYFRAMES_SYM +%token WEBKIT_VALUE_SYM +%token WEBKIT_MEDIAQUERY_SYM +%token WEBKIT_SELECTOR_SYM +%token <marginBox> TOPLEFTCORNER_SYM +%token <marginBox> TOPLEFT_SYM +%token <marginBox> TOPCENTER_SYM +%token <marginBox> TOPRIGHT_SYM +%token <marginBox> TOPRIGHTCORNER_SYM +%token <marginBox> BOTTOMLEFTCORNER_SYM +%token <marginBox> BOTTOMLEFT_SYM +%token <marginBox> BOTTOMCENTER_SYM +%token <marginBox> BOTTOMRIGHT_SYM +%token <marginBox> BOTTOMRIGHTCORNER_SYM +%token <marginBox> LEFTTOP_SYM +%token <marginBox> LEFTMIDDLE_SYM +%token <marginBox> LEFTBOTTOM_SYM +%token <marginBox> RIGHTTOP_SYM +%token <marginBox> RIGHTMIDDLE_SYM +%token <marginBox> RIGHTBOTTOM_SYM + +%token ATKEYWORD + +%token IMPORTANT_SYM +%token MEDIA_ONLY +%token MEDIA_NOT +%token MEDIA_AND + +%token <number> REMS +%token <number> QEMS +%token <number> EMS +%token <number> EXS +%token <number> PXS +%token <number> CMS +%token <number> MMS +%token <number> INS +%token <number> PTS +%token <number> PCS +%token <number> DEGS +%token <number> RADS +%token <number> GRADS +%token <number> TURNS +%token <number> MSECS +%token <number> SECS +%token <number> HERTZ +%token <number> KHERTZ +%token <string> DIMEN +%token <number> PERCENTAGE +%token <number> FLOATTOKEN +%token <number> INTEGER + +%token <string> URI +%token <string> FUNCTION +%token <string> NOTFUNCTION + +%token <string> UNICODERANGE + +%type <relation> combinator + +%type <rule> charset +%type <rule> ignored_charset +%type <rule> ruleset +%type <rule> media +%type <rule> import +%type <rule> namespace +%type <rule> page +%type <rule> margin_box +%type <rule> font_face +%type <rule> keyframes +%type <rule> invalid_rule +%type <rule> save_block +%type <rule> invalid_at +%type <rule> rule +%type <rule> valid_rule +%type <ruleList> block_rule_list +%type <rule> block_rule +%type <rule> block_valid_rule + +%type <string> maybe_ns_prefix + +%type <string> namespace_selector + +%type <string> string_or_uri +%type <string> ident_or_string +%type <string> medium +%type <string> hexcolor +%type <marginBox> margin_sym + +%type <string> media_feature +%type <mediaList> media_list +%type <mediaList> maybe_media_list +%type <mediaQuery> media_query +%type <mediaQueryRestrictor> maybe_media_restrictor +%type <valueList> maybe_media_value +%type <mediaQueryExp> media_query_exp +%type <mediaQueryExpList> media_query_exp_list +%type <mediaQueryExpList> maybe_and_media_query_exp_list + +%type <string> keyframe_name +%type <keyframeRule> keyframe_rule +%type <keyframesRule> keyframes_rule +%type <valueList> key_list +%type <value> key + +%type <integer> property + +%type <selector> specifier +%type <selector> specifier_list +%type <selector> simple_selector +%type <selector> selector +%type <selectorList> selector_list +%type <selector> selector_with_trailing_whitespace +%type <selector> class +%type <selector> attrib +%type <selector> pseudo +%type <selector> pseudo_page +%type <selector> page_selector + +%type <boolean> declaration_list +%type <boolean> decl_list +%type <boolean> declaration +%type <boolean> declarations_and_margins + +%type <boolean> prio + +%type <integer> match +%type <integer> unary_operator +%type <integer> maybe_unary_operator +%type <character> operator + +%type <valueList> expr +%type <value> term +%type <value> unary_term +%type <value> function + +%type <string> element_name +%type <string> attr_name + +%% + +stylesheet: + maybe_space maybe_charset maybe_sgml rule_list + | webkit_rule maybe_space + | webkit_decls maybe_space + | webkit_value maybe_space + | webkit_mediaquery maybe_space + | webkit_selector maybe_space + | webkit_keyframe_rule maybe_space + ; + +webkit_rule: + WEBKIT_RULE_SYM '{' maybe_space valid_rule maybe_space '}' { + static_cast<CSSParser*>(parser)->m_rule = $4; + } +; + +webkit_keyframe_rule: + WEBKIT_KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' { + static_cast<CSSParser*>(parser)->m_keyframe = $4; + } +; + +webkit_decls: + WEBKIT_DECLS_SYM '{' maybe_space_before_declaration declaration_list '}' { + /* can be empty */ + } +; + +webkit_value: + WEBKIT_VALUE_SYM '{' maybe_space expr '}' { + CSSParser* p = static_cast<CSSParser*>(parser); + if ($4) { + p->m_valueList = p->sinkFloatingValueList($4); + int oldParsedProperties = p->m_numParsedProperties; + if (!p->parseValue(p->m_id, p->m_important)) + p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties); + delete p->m_valueList; + p->m_valueList = 0; + } + } +; + +webkit_mediaquery: + WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' { + CSSParser* p = static_cast<CSSParser*>(parser); + p->m_mediaQuery = p->sinkFloatingMediaQuery($4); + } +; + +webkit_selector: + WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' { + if ($4) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (p->m_selectorListForParseSelector) + p->m_selectorListForParseSelector->adoptSelectorVector(*$4); + } + } +; + +maybe_space: + /* empty */ %prec UNIMPORTANT_TOK + | maybe_space WHITESPACE + ; + +maybe_sgml: + /* empty */ + | maybe_sgml SGML_CD + | maybe_sgml WHITESPACE + ; + +maybe_charset: + /* empty */ + | charset { + } + ; + +closing_brace: + '}' + | %prec LOWEST_PREC TOKEN_EOF + ; + +charset: + CHARSET_SYM maybe_space STRING maybe_space ';' { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = static_cast<CSSParser*>(parser)->createCharsetRule($3); + if ($$ && p->m_styleSheet) + p->m_styleSheet->append($$); + } + | CHARSET_SYM error invalid_block { + } + | CHARSET_SYM error ';' { + } +; + +ignored_charset: + CHARSET_SYM maybe_space STRING maybe_space ';' { + // Ignore any @charset rule not at the beginning of the style sheet. + $$ = 0; + } +; + +rule_list: + /* empty */ + | rule_list rule maybe_sgml { + CSSParser* p = static_cast<CSSParser*>(parser); + if ($2 && p->m_styleSheet) + p->m_styleSheet->append($2); + } + ; + +valid_rule: + before_ruleset ruleset { + $$ = $2; + } + | media + | page + | font_face + | keyframes + | namespace + | import + ; + +rule: + valid_rule { + static_cast<CSSParser*>(parser)->m_hadSyntacticallyValidCSSRule = true; + } + | ignored_charset + | invalid_rule + | invalid_at + ; + +block_rule_list: + /* empty */ { $$ = 0; } + | block_rule_list block_rule maybe_sgml { + $$ = $1; + if ($2) { + if (!$$) + $$ = static_cast<CSSParser*>(parser)->createRuleList(); + $$->append($2); + } + } + ; + +block_valid_rule: + ruleset + | page + | font_face + | keyframes + ; + +block_rule: + block_valid_rule + | invalid_rule + | invalid_at + | namespace + | import + | media + ; + + +import: + IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' { + $$ = static_cast<CSSParser*>(parser)->createImportRule($3, $5); + } + | IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list invalid_block { + $$ = 0; + } + | IMPORT_SYM error ';' { + $$ = 0; + } + | IMPORT_SYM error invalid_block { + $$ = 0; + } + ; + +namespace: +NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' { + static_cast<CSSParser*>(parser)->addNamespace($3, $4); + $$ = 0; +} +| NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space invalid_block { + $$ = 0; +} +| NAMESPACE_SYM error invalid_block { + $$ = 0; +} +| NAMESPACE_SYM error ';' { + $$ = 0; +} +; + +maybe_ns_prefix: +/* empty */ { $$.characters = 0; } +| IDENT maybe_space { $$ = $1; } +; + +string_or_uri: +STRING +| URI +; + +media_feature: + IDENT maybe_space { + $$ = $1; + } + ; + +maybe_media_value: + /*empty*/ { + $$ = 0; + } + | ':' maybe_space expr maybe_space { + $$ = $3; + } + ; + +media_query_exp: + '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space { + $3.lower(); + $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExp($3, $5); + } + ; + +media_query_exp_list: + media_query_exp { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingMediaQueryExpList(); + $$->append(p->sinkFloatingMediaQueryExp($1)); + } + | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp { + $$ = $1; + $$->append(static_cast<CSSParser*>(parser)->sinkFloatingMediaQueryExp($5)); + } + ; + +maybe_and_media_query_exp_list: + /*empty*/ { + $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExpList(); + } + | MEDIA_AND maybe_space media_query_exp_list { + $$ = $3; + } + ; + +maybe_media_restrictor: + /*empty*/ { + $$ = MediaQuery::None; + } + | MEDIA_ONLY { + $$ = MediaQuery::Only; + } + | MEDIA_NOT { + $$ = MediaQuery::Not; + } + ; + +media_query: + media_query_exp_list { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingMediaQuery(p->sinkFloatingMediaQueryExpList($1)); + } + | + maybe_media_restrictor maybe_space medium maybe_and_media_query_exp_list { + CSSParser* p = static_cast<CSSParser*>(parser); + $3.lower(); + $$ = p->createFloatingMediaQuery($1, $3, p->sinkFloatingMediaQueryExpList($4)); + } + ; + +maybe_media_list: + /* empty */ { + $$ = static_cast<CSSParser*>(parser)->createMediaList(); + } + | media_list + ; + +media_list: + media_query { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createMediaList(); + $$->appendMediaQuery(p->sinkFloatingMediaQuery($1)); + } + | media_list ',' maybe_space media_query { + $$ = $1; + if ($$) + $$->appendMediaQuery(static_cast<CSSParser*>(parser)->sinkFloatingMediaQuery($4)); + } + | media_list error { + $$ = 0; + } + ; + +media: + MEDIA_SYM maybe_space media_list '{' maybe_space block_rule_list save_block { + $$ = static_cast<CSSParser*>(parser)->createMediaRule($3, $6); + } + | MEDIA_SYM maybe_space '{' maybe_space block_rule_list save_block { + $$ = static_cast<CSSParser*>(parser)->createMediaRule(0, $5); + } + ; + +medium: + IDENT maybe_space { + $$ = $1; + } + ; + +keyframes: + WEBKIT_KEYFRAMES_SYM maybe_space keyframe_name maybe_space '{' maybe_space keyframes_rule '}' { + $$ = $7; + $7->setNameInternal($3); + } + ; + +keyframe_name: + IDENT + | STRING + ; + +keyframes_rule: + /* empty */ { $$ = static_cast<CSSParser*>(parser)->createKeyframesRule(); } + | keyframes_rule keyframe_rule maybe_space { + $$ = $1; + if ($2) + $$->append($2); + } + ; + +keyframe_rule: + key_list maybe_space '{' maybe_space declaration_list '}' { + $$ = static_cast<CSSParser*>(parser)->createKeyframeRule($1); + } + ; + +key_list: + key { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingValueList(); + $$->addValue(p->sinkFloatingValue($1)); + } + | key_list maybe_space ',' maybe_space key { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $1; + if ($$) + $$->addValue(p->sinkFloatingValue($5)); + } + ; + +key: + PERCENTAGE { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } + | IDENT { + $$.id = 0; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER; + CSSParserString& str = $1; + if (equalIgnoringCase("from", str.characters, str.length)) + $$.fValue = 0; + else if (equalIgnoringCase("to", str.characters, str.length)) + $$.fValue = 100; + else + YYERROR; + } + ; + +page: + PAGE_SYM maybe_space page_selector maybe_space + '{' maybe_space declarations_and_margins closing_brace { + CSSParser* p = static_cast<CSSParser*>(parser); + if ($3) + $$ = p->createPageRule(p->sinkFloatingSelector($3)); + else { + // Clear properties in the invalid @page rule. + p->clearProperties(); + // Also clear margin at-rules here once we fully implement margin at-rules parsing. + $$ = 0; + } + } + | PAGE_SYM error invalid_block { + $$ = 0; + } + | PAGE_SYM error ';' { + $$ = 0; + } + ; + +page_selector: + IDENT { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace); + $$->setForPage(); + } + | IDENT pseudo_page { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $2; + if ($$) { + $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace); + $$->setForPage(); + } + } + | pseudo_page { + $$ = $1; + if ($$) + $$->setForPage(); + } + | /* empty */ { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setForPage(); + } + ; + +declarations_and_margins: + declaration_list + | declarations_and_margins margin_box maybe_space declaration_list + ; + +margin_box: + margin_sym { + static_cast<CSSParser*>(parser)->startDeclarationsForMarginBox(); + } maybe_space '{' maybe_space declaration_list closing_brace { + $$ = static_cast<CSSParser*>(parser)->createMarginAtRule($1); + } + ; + +margin_sym : + TOPLEFTCORNER_SYM { + $$ = CSSSelector::TopLeftCornerMarginBox; + } + | TOPLEFT_SYM { + $$ = CSSSelector::TopLeftMarginBox; + } + | TOPCENTER_SYM { + $$ = CSSSelector::TopCenterMarginBox; + } + | TOPRIGHT_SYM { + $$ = CSSSelector::TopRightMarginBox; + } + | TOPRIGHTCORNER_SYM { + $$ = CSSSelector::TopRightCornerMarginBox; + } + | BOTTOMLEFTCORNER_SYM { + $$ = CSSSelector::BottomLeftCornerMarginBox; + } + | BOTTOMLEFT_SYM { + $$ = CSSSelector::BottomLeftMarginBox; + } + | BOTTOMCENTER_SYM { + $$ = CSSSelector::BottomCenterMarginBox; + } + | BOTTOMRIGHT_SYM { + $$ = CSSSelector::BottomRightMarginBox; + } + | BOTTOMRIGHTCORNER_SYM { + $$ = CSSSelector::BottomRightCornerMarginBox; + } + | LEFTTOP_SYM { + $$ = CSSSelector::LeftTopMarginBox; + } + | LEFTMIDDLE_SYM { + $$ = CSSSelector::LeftMiddleMarginBox; + } + | LEFTBOTTOM_SYM { + $$ = CSSSelector::LeftBottomMarginBox; + } + | RIGHTTOP_SYM { + $$ = CSSSelector::RightTopMarginBox; + } + | RIGHTMIDDLE_SYM { + $$ = CSSSelector::RightMiddleMarginBox; + } + | RIGHTBOTTOM_SYM { + $$ = CSSSelector::RightBottomMarginBox; + } + ; + +font_face: + FONT_FACE_SYM maybe_space + '{' maybe_space declaration_list '}' maybe_space { + $$ = static_cast<CSSParser*>(parser)->createFontFaceRule(); + } + | FONT_FACE_SYM error invalid_block { + $$ = 0; + } + | FONT_FACE_SYM error ';' { + $$ = 0; + } +; + +combinator: + '+' maybe_space { $$ = CSSSelector::DirectAdjacent; } + | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; } + | '>' maybe_space { $$ = CSSSelector::Child; } + ; + +maybe_unary_operator: + unary_operator { $$ = $1; } + | { $$ = 1; } + ; + +unary_operator: + '-' { $$ = -1; } + | '+' { $$ = 1; } + ; + +maybe_space_before_declaration: + maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + } + ; + +before_ruleset: + /* empty */ { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markSelectorListStart(); + } + ; + +before_rule_opening_brace: + /* empty */ { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markSelectorListEnd(); + } + ; + +ruleset: + selector_list before_rule_opening_brace '{' maybe_space_before_declaration declaration_list closing_brace { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createStyleRule($1); + } + ; + +selector_list: + selector %prec UNIMPORTANT_TOK { + if ($1) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->reusableSelectorVector(); + deleteAllValues(*$$); + $$->shrink(0); + $$->append(p->sinkFloatingSelector($1)); + p->updateLastSelectorLineAndPosition(); + } + } + | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK { + if ($1 && $4) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $1; + $$->append(p->sinkFloatingSelector($4)); + p->updateLastSelectorLineAndPosition(); + } else + $$ = 0; + } + | selector_list error { + $$ = 0; + } + ; + +selector_with_trailing_whitespace: + selector WHITESPACE { + $$ = $1; + } + ; + +selector: + simple_selector { + $$ = $1; + } + | selector_with_trailing_whitespace + { + $$ = $1; + } + | selector_with_trailing_whitespace simple_selector + { + $$ = $2; + if (!$1) + $$ = 0; + else if ($$) { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSSelector* end = $$; + while (end->tagHistory()) + end = end->tagHistory(); + end->m_relation = CSSSelector::Descendant; + end->setTagHistory(p->sinkFloatingSelector($1)); + if (Document* doc = p->document()) + doc->setUsesDescendantRules(true); + } + } + | selector combinator simple_selector { + $$ = $3; + if (!$1) + $$ = 0; + else if ($$) { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSSelector* end = $$; + while (end->tagHistory()) + end = end->tagHistory(); + end->m_relation = $2; + end->setTagHistory(p->sinkFloatingSelector($1)); + if ($2 == CSSSelector::Child) { + if (Document* doc = p->document()) + doc->setUsesDescendantRules(true); + } else if ($2 == CSSSelector::DirectAdjacent || $2 == CSSSelector::IndirectAdjacent) { + if (Document* doc = p->document()) + doc->setUsesSiblingRules(true); + } + } + } + | selector error { + $$ = 0; + } + ; + +namespace_selector: + /* empty */ '|' { $$.characters = 0; $$.length = 0; } + | '*' '|' { static UChar star = '*'; $$.characters = ☆ $$.length = 1; } + | IDENT '|' { $$ = $1; } +; + +simple_selector: + element_name { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace); + } + | element_name specifier_list { + $$ = $2; + if ($$) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace); + } + } + | specifier_list { + $$ = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + if ($$ && p->m_defaultNamespace != starAtom) + $$->m_tag = QualifiedName(nullAtom, starAtom, p->m_defaultNamespace); + } + | namespace_selector element_name { + AtomicString namespacePrefix = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + if (p->m_styleSheet) + $$->m_tag = QualifiedName(namespacePrefix, $2, + p->m_styleSheet->determineNamespace(namespacePrefix)); + else // FIXME: Shouldn't this case be an error? + $$->m_tag = QualifiedName(nullAtom, $2, p->m_defaultNamespace); + } + | namespace_selector element_name specifier_list { + $$ = $3; + if ($$) { + AtomicString namespacePrefix = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + if (p->m_styleSheet) + $$->m_tag = QualifiedName(namespacePrefix, $2, + p->m_styleSheet->determineNamespace(namespacePrefix)); + else // FIXME: Shouldn't this case be an error? + $$->m_tag = QualifiedName(nullAtom, $2, p->m_defaultNamespace); + } + } + | namespace_selector specifier_list { + $$ = $2; + if ($$) { + AtomicString namespacePrefix = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + if (p->m_styleSheet) + $$->m_tag = QualifiedName(namespacePrefix, starAtom, + p->m_styleSheet->determineNamespace(namespacePrefix)); + } + } + ; + +element_name: + IDENT { + CSSParserString& str = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + Document* doc = p->document(); + if (doc && doc->isHTMLDocument()) + str.lower(); + $$ = str; + } + | '*' { + static UChar star = '*'; + $$.characters = ☆ + $$.length = 1; + } + ; + +specifier_list: + specifier { + $$ = $1; + } + | specifier_list specifier { + if (!$2) + $$ = 0; + else if ($1) { + $$ = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + CSSSelector* end = $1; + while (end->tagHistory()) + end = end->tagHistory(); + end->m_relation = CSSSelector::SubSelector; + end->setTagHistory(p->sinkFloatingSelector($2)); + } + } + | specifier_list error { + $$ = 0; + } +; + +specifier: + IDSEL { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::Id; + if (!p->m_strict) + $1.lower(); + $$->m_value = $1; + } + | HEX { + if ($1.characters[0] >= '0' && $1.characters[0] <= '9') { + $$ = 0; + } else { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::Id; + if (!p->m_strict) + $1.lower(); + $$->m_value = $1; + } + } + | class + | attrib + | pseudo + ; + +class: + '.' IDENT { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::Class; + if (!p->m_strict) + $2.lower(); + $$->m_value = $2; + } + ; + +attr_name: + IDENT maybe_space { + CSSParserString& str = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + Document* doc = p->document(); + if (doc && doc->isHTMLDocument()) + str.lower(); + $$ = str; + } + ; + +attrib: + '[' maybe_space attr_name ']' { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); + $$->m_match = CSSSelector::Set; + } + | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); + $$->m_match = (CSSSelector::Match)$4; + $$->m_value = $6; + } + | '[' maybe_space namespace_selector attr_name ']' { + AtomicString namespacePrefix = $3; + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setAttribute(QualifiedName(namespacePrefix, $4, + p->m_styleSheet->determineNamespace(namespacePrefix))); + $$->m_match = CSSSelector::Set; + } + | '[' maybe_space namespace_selector attr_name match maybe_space ident_or_string maybe_space ']' { + AtomicString namespacePrefix = $3; + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setAttribute(QualifiedName(namespacePrefix, $4, + p->m_styleSheet->determineNamespace(namespacePrefix))); + $$->m_match = (CSSSelector::Match)$5; + $$->m_value = $7; + } + ; + +match: + '=' { + $$ = CSSSelector::Exact; + } + | INCLUDES { + $$ = CSSSelector::List; + } + | DASHMATCH { + $$ = CSSSelector::Hyphen; + } + | BEGINSWITH { + $$ = CSSSelector::Begin; + } + | ENDSWITH { + $$ = CSSSelector::End; + } + | CONTAINS { + $$ = CSSSelector::Contain; + } + ; + +ident_or_string: + IDENT + | STRING + ; + +pseudo_page: + ':' IDENT { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->m_match = CSSSelector::PagePseudoClass; + $2.lower(); + $$->m_value = $2; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + } + +pseudo: + ':' IDENT { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoClass; + $2.lower(); + $$->m_value = $2; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + else if (type == CSSSelector::PseudoEmpty || + type == CSSSelector::PseudoFirstChild || + type == CSSSelector::PseudoFirstOfType || + type == CSSSelector::PseudoLastChild || + type == CSSSelector::PseudoLastOfType || + type == CSSSelector::PseudoOnlyChild || + type == CSSSelector::PseudoOnlyOfType) { + CSSParser* p = static_cast<CSSParser*>(parser); + Document* doc = p->document(); + if (doc) + doc->setUsesSiblingRules(true); + } else if (type == CSSSelector::PseudoFirstLine) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesFirstLineRules(true); + } else if (type == CSSSelector::PseudoBefore || + type == CSSSelector::PseudoAfter) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesBeforeAfterRules(true); + } else if (type == CSSSelector::PseudoLink || type == CSSSelector::PseudoVisited) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesLinkRules(true); + } + } + | ':' ':' IDENT { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoElement; + $3.lower(); + $$->m_value = $3; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + else if (type == CSSSelector::PseudoFirstLine) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesFirstLineRules(true); + } else if (type == CSSSelector::PseudoBefore || + type == CSSSelector::PseudoAfter) { + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesBeforeAfterRules(true); + } + } + // used by :nth-*(ax+b) + | ':' FUNCTION maybe_space NTH maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoClass; + $$->setArgument($4); + $$->m_value = $2; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + else if (type == CSSSelector::PseudoNthChild || + type == CSSSelector::PseudoNthOfType || + type == CSSSelector::PseudoNthLastChild || + type == CSSSelector::PseudoNthLastOfType) { + if (p->document()) + p->document()->setUsesSiblingRules(true); + } + } + // used by :nth-* + | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoClass; + $$->setArgument(String::number($4 * $5)); + $$->m_value = $2; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + else if (type == CSSSelector::PseudoNthChild || + type == CSSSelector::PseudoNthOfType || + type == CSSSelector::PseudoNthLastChild || + type == CSSSelector::PseudoNthLastOfType) { + if (p->document()) + p->document()->setUsesSiblingRules(true); + } + } + // used by :nth-*(odd/even) and :lang + | ':' FUNCTION maybe_space IDENT maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoClass; + $$->setArgument($4); + $2.lower(); + $$->m_value = $2; + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + else if (type == CSSSelector::PseudoNthChild || + type == CSSSelector::PseudoNthOfType || + type == CSSSelector::PseudoNthLastChild || + type == CSSSelector::PseudoNthLastOfType) { + if (isValidNthToken($4)) { + if (p->document()) + p->document()->setUsesSiblingRules(true); + } else + $$ = 0; + } + } + // used by :not + | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' { + if (!$4 || !$4->isSimple()) + $$ = 0; + else { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->m_match = CSSSelector::PseudoClass; + $$->setSimpleSelector(p->sinkFloatingSelector($4)); + $2.lower(); + $$->m_value = $2; + } + } + ; + +declaration_list: + declaration { + $$ = $1; + } + | decl_list declaration { + $$ = $1; + if ( $2 ) + $$ = $2; + } + | decl_list { + $$ = $1; + } + | error invalid_block_list error { + $$ = false; + } + | error { + $$ = false; + } + | decl_list error { + $$ = $1; + } + | decl_list invalid_block_list { + $$ = $1; + } + ; + +decl_list: + declaration ';' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + $$ = $1; + } + | declaration invalid_block_list maybe_space { + $$ = false; + } + | declaration invalid_block_list ';' maybe_space { + $$ = false; + } + | error ';' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + $$ = false; + } + | error invalid_block_list error ';' maybe_space { + $$ = false; + } + | decl_list declaration ';' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + $$ = $1; + if ($2) + $$ = $2; + } + | decl_list error ';' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + $$ = $1; + } + | decl_list error invalid_block_list error ';' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyStart(); + $$ = $1; + } + ; + +declaration: + property ':' maybe_space expr prio { + $$ = false; + CSSParser* p = static_cast<CSSParser*>(parser); + bool isPropertyParsed = false; + if ($1 && $4) { + p->m_valueList = p->sinkFloatingValueList($4); + int oldParsedProperties = p->m_numParsedProperties; + $$ = p->parseValue($1, $5); + if (!$$) + p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties); + else + isPropertyParsed = true; + delete p->m_valueList; + p->m_valueList = 0; + } + p->markPropertyEnd($5, isPropertyParsed); + } + | + property error { + $$ = false; + } + | + property ':' maybe_space error expr prio { + /* The default movable type template has letter-spacing: .none; Handle this by looking for + error tokens at the start of an expr, recover the expr and then treat as an error, cleaning + up and deleting the shifted expr. */ + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyEnd(false, false); + $$ = false; + } + | + property ':' maybe_space expr prio error { + /* When we encounter something like p {color: red !important fail;} we should drop the declaration */ + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyEnd(false, false); + $$ = false; + } + | + IMPORTANT_SYM maybe_space { + /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */ + $$ = false; + } + | + property ':' maybe_space { + /* div { font-family: } Just reduce away this property with no value. */ + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyEnd(false, false); + $$ = false; + } + | + property ':' maybe_space error { + /* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */ + CSSParser* p = static_cast<CSSParser*>(parser); + p->markPropertyEnd(false, false); + $$ = false; + } + | + property invalid_block { + /* if we come across: div { color{;color:maroon} }, ignore everything within curly brackets */ + $$ = false; + } + ; + +property: + IDENT maybe_space { + $$ = cssPropertyID($1); + } + ; + +prio: + IMPORTANT_SYM maybe_space { $$ = true; } + | /* empty */ { $$ = false; } + ; + +expr: + term { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingValueList(); + $$->addValue(p->sinkFloatingValue($1)); + } + | expr operator term { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $1; + if ($$) { + if ($2) { + CSSParserValue v; + v.id = 0; + v.unit = CSSParserValue::Operator; + v.iValue = $2; + $$->addValue(v); + } + $$->addValue(p->sinkFloatingValue($3)); + } + } + | expr invalid_block_list { + $$ = 0; + } + | expr invalid_block_list error { + $$ = 0; + } + | expr error { + $$ = 0; + } + ; + +operator: + '/' maybe_space { + $$ = '/'; + } + | ',' maybe_space { + $$ = ','; + } + | /* empty */ { + $$ = 0; + } + ; + +term: + unary_term { $$ = $1; } + | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } + | STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; } + | IDENT maybe_space { + $$.id = cssValueKeywordID($1); + $$.unit = CSSPrimitiveValue::CSS_IDENT; + $$.string = $1; + } + /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */ + | DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } + | unary_operator DIMEN maybe_space { $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } + | URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; } + | UNICODERANGE maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; } + | hexcolor { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } + | '#' maybe_space { $$.id = 0; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */ + /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */ + | function { + $$ = $1; + } + | '%' maybe_space { /* Handle width: %; */ + $$.id = 0; $$.unit = 0; + } + ; + +unary_term: + INTEGER maybe_space { $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } + | FLOATTOKEN maybe_space { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } + | PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; } + | PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; } + | CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; } + | MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; } + | INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; } + | PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; } + | PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; } + | DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; } + | RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; } + | GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; } + | TURNS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; } + | MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; } + | SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; } + | HERTZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; } + | KHERTZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; } + | EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; } + | QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; } + | EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; } + | REMS maybe_space { + $$.id = 0; + $$.fValue = $1; + $$.unit = CSSPrimitiveValue::CSS_REMS; + CSSParser* p = static_cast<CSSParser*>(parser); + if (Document* doc = p->document()) + doc->setUsesRemUnits(true); + } + ; + +function: + FUNCTION maybe_space expr ')' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSParserFunction* f = p->createFloatingFunction(); + f->name = $1; + f->args = p->sinkFloatingValueList($3); + $$.id = 0; + $$.unit = CSSParserValue::Function; + $$.function = f; + } | + FUNCTION maybe_space error { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSParserFunction* f = p->createFloatingFunction(); + f->name = $1; + f->args = 0; + $$.id = 0; + $$.unit = CSSParserValue::Function; + $$.function = f; + } + ; +/* + * There is a constraint on the color that it must + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) + * after the "#"; e.g., "#000" is OK, but "#abcd" is not. + */ +hexcolor: + HEX maybe_space { $$ = $1; } + | IDSEL maybe_space { $$ = $1; } + ; + + +/* error handling rules */ + +save_block: + closing_brace { + $$ = 0; + } + | error closing_brace { + $$ = 0; + } + ; + +invalid_at: + ATKEYWORD error invalid_block { + $$ = 0; + } + | ATKEYWORD error ';' { + $$ = 0; + } + ; + +invalid_rule: + error invalid_block { + $$ = 0; + } + +/* + Seems like the two rules below are trying too much and violating + http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html + + | error ';' { + $$ = 0; + } + | error '}' { + $$ = 0; + } +*/ + ; + +invalid_block: + '{' error invalid_block_list error closing_brace { + static_cast<CSSParser*>(parser)->invalidBlockHit(); + } + | '{' error closing_brace { + static_cast<CSSParser*>(parser)->invalidBlockHit(); + } + ; + +invalid_block_list: + invalid_block + | invalid_block_list error invalid_block +; + +%% diff --git a/Source/WebCore/css/CSSHelper.h b/Source/WebCore/css/CSSHelper.h new file mode 100644 index 0000000..6f2ffca --- /dev/null +++ b/Source/WebCore/css/CSSHelper.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2009 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. + * + */ + +#ifndef CSSHelper_h +#define CSSHelper_h + +#include <wtf/Forward.h> + +namespace WebCore { + +// We always assume 96 CSS pixels in a CSS inch. This is the cold hard truth of the Web. +// At high DPI, we may scale a CSS pixel, but the ratio of the CSS pixel to the so-called +// "absolute" CSS length units like inch and pt is always fixed and never changes. +const float cssPixelsPerInch = 96; + +} // namespace WebCore + +#endif // CSSHelper_h diff --git a/Source/WebCore/css/CSSImageGeneratorValue.cpp b/Source/WebCore/css/CSSImageGeneratorValue.cpp new file mode 100644 index 0000000..784f438 --- /dev/null +++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSImageGeneratorValue.h" + +#include "Image.h" +#include "IntSize.h" +#include "IntSizeHash.h" +#include "PlatformString.h" +#include "RenderObject.h" +#include "StyleGeneratedImage.h" + +namespace WebCore { + +CSSImageGeneratorValue::CSSImageGeneratorValue() +: m_accessedImage(false) +{ +} + +CSSImageGeneratorValue::~CSSImageGeneratorValue() +{ +} + +void CSSImageGeneratorValue::addClient(RenderObject* renderer, const IntSize& size) +{ + ref(); + if (!size.isEmpty()) + m_sizes.add(size); + + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + if (it == m_clients.end()) + m_clients.add(renderer, SizeCountPair(size, 1)); + else { + SizeCountPair& sizeCount = it->second; + ++sizeCount.second; + } +} + +void CSSImageGeneratorValue::removeClient(RenderObject* renderer) +{ + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + ASSERT(it != m_clients.end()); + + SizeCountPair& sizeCount = it->second; + IntSize size = sizeCount.first; + if (!size.isEmpty()) { + m_sizes.remove(size); + if (!m_sizes.contains(size)) + m_images.remove(size); + } + + if (!--sizeCount.second) + m_clients.remove(renderer); + + deref(); +} + +Image* CSSImageGeneratorValue::getImage(RenderObject* renderer, const IntSize& size) +{ + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + ASSERT(it != m_clients.end()); + + SizeCountPair& sizeCount = it->second; + IntSize oldSize = sizeCount.first; + if (oldSize != size) { + // If renderer is the only client, make sure we don't delete this. + RefPtr<CSSImageGeneratorValue> protect(this); + removeClient(renderer); + addClient(renderer, size); + } + + // Don't generate an image for empty sizes. + if (size.isEmpty()) + return 0; + + // Look up the image in our cache. + return m_images.get(size).get(); +} + +void CSSImageGeneratorValue::putImage(const IntSize& size, PassRefPtr<Image> image) +{ + m_images.add(size, image); +} + +StyleGeneratedImage* CSSImageGeneratorValue::generatedImage() +{ + if (!m_accessedImage) { + m_accessedImage = true; + m_image = StyleGeneratedImage::create(this, isFixedSize()); + } + return m_image.get(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSImageGeneratorValue.h b/Source/WebCore/css/CSSImageGeneratorValue.h new file mode 100644 index 0000000..c053bfe --- /dev/null +++ b/Source/WebCore/css/CSSImageGeneratorValue.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSImageGeneratorValue_h +#define CSSImageGeneratorValue_h + +#include "CSSValue.h" +#include "IntSizeHash.h" +#include <wtf/HashMap.h> +#include <wtf/HashCountedSet.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Image; +class StyleGeneratedImage; +class RenderObject; + +class CSSImageGeneratorValue : public CSSValue { +public: + virtual ~CSSImageGeneratorValue(); + + void addClient(RenderObject*, const IntSize&); + void removeClient(RenderObject*); + virtual Image* image(RenderObject*, const IntSize&) = 0; + + StyleGeneratedImage* generatedImage(); + + virtual bool isFixedSize() const { return false; } + virtual IntSize fixedSize(const RenderObject*) { return IntSize(); } + +protected: + CSSImageGeneratorValue(); + + Image* getImage(RenderObject*, const IntSize&); + void putImage(const IntSize&, PassRefPtr<Image>); + + typedef pair<IntSize, int> SizeCountPair; + typedef HashMap<RenderObject*, SizeCountPair> RenderObjectSizeCountMap; + + HashCountedSet<IntSize> m_sizes; // A count of how many times a given image size is in use. + RenderObjectSizeCountMap m_clients; // A map from RenderObjects (with entry count) to image sizes. + HashMap<IntSize, RefPtr<Image> > m_images; // A cache of Image objects by image size. + + RefPtr<StyleGeneratedImage> m_image; + bool m_accessedImage; + +private: + virtual bool isImageGeneratorValue() const { return true; } +}; + +} // namespace WebCore + +#endif // CSSImageGeneratorValue_h diff --git a/Source/WebCore/css/CSSImageValue.cpp b/Source/WebCore/css/CSSImageValue.cpp new file mode 100644 index 0000000..a9038b9 --- /dev/null +++ b/Source/WebCore/css/CSSImageValue.cpp @@ -0,0 +1,98 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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 "CSSImageValue.h" + +#include "CSSValueKeywords.h" +#include "MemoryCache.h" +#include "CachedImage.h" +#include "CachedResourceLoader.h" +#include "StyleCachedImage.h" +#include "StylePendingImage.h" + +namespace WebCore { + +CSSImageValue::CSSImageValue(const String& url) + : CSSPrimitiveValue(url, CSS_URI) + , m_accessedImage(false) +{ +} + +CSSImageValue::CSSImageValue() + : CSSPrimitiveValue(CSSValueNone) + , m_accessedImage(true) +{ +} + +CSSImageValue::~CSSImageValue() +{ + if (m_image && m_image->isCachedImage()) + static_cast<StyleCachedImage*>(m_image.get())->cachedImage()->removeClient(this); +} + +StyleImage* CSSImageValue::cachedOrPendingImage() +{ + if (getIdent() == CSSValueNone) + return 0; + + if (!m_image) + m_image = StylePendingImage::create(this); + + return m_image.get(); +} + +StyleCachedImage* CSSImageValue::cachedImage(CachedResourceLoader* loader) +{ + return cachedImage(loader, getStringValue()); +} + +StyleCachedImage* CSSImageValue::cachedImage(CachedResourceLoader* loader, const String& url) +{ + ASSERT(loader); + + if (!m_accessedImage) { + m_accessedImage = true; + + if (CachedImage* cachedImage = loader->requestImage(url)) { + cachedImage->addClient(this); + m_image = StyleCachedImage::create(cachedImage); + } + } + + return (m_image && m_image->isCachedImage()) ? static_cast<StyleCachedImage*>(m_image.get()) : 0; +} + +String CSSImageValue::cachedImageURL() +{ + if (!m_image || !m_image->isCachedImage()) + return String(); + return static_cast<StyleCachedImage*>(m_image.get())->cachedImage()->url(); +} + +void CSSImageValue::clearCachedImage() +{ + if (m_image && m_image->isCachedImage()) + static_cast<StyleCachedImage*>(m_image.get())->cachedImage()->removeClient(this); + m_image = 0; + m_accessedImage = false; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSImageValue.h b/Source/WebCore/css/CSSImageValue.h new file mode 100644 index 0000000..833d7fe --- /dev/null +++ b/Source/WebCore/css/CSSImageValue.h @@ -0,0 +1,61 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSImageValue_h +#define CSSImageValue_h + +#include "CSSPrimitiveValue.h" +#include "CachedResourceClient.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CachedResourceLoader; +class StyleCachedImage; +class StyleImage; + +class CSSImageValue : public CSSPrimitiveValue, private CachedResourceClient { +public: + static PassRefPtr<CSSImageValue> create() { return adoptRef(new CSSImageValue); } + static PassRefPtr<CSSImageValue> create(const String& url) { return adoptRef(new CSSImageValue(url)); } + virtual ~CSSImageValue(); + + virtual StyleCachedImage* cachedImage(CachedResourceLoader*); + // Returns a StyleCachedImage if the image is cached already, otherwise a StylePendingImage. + StyleImage* cachedOrPendingImage(); + +protected: + CSSImageValue(const String& url); + + StyleCachedImage* cachedImage(CachedResourceLoader*, const String& url); + String cachedImageURL(); + void clearCachedImage(); + +private: + CSSImageValue(); + virtual bool isImageValue() const { return true; } + + RefPtr<StyleImage> m_image; + bool m_accessedImage; +}; + +} // namespace WebCore + +#endif // CSSImageValue_h diff --git a/Source/WebCore/css/CSSImportRule.cpp b/Source/WebCore/css/CSSImportRule.cpp new file mode 100644 index 0000000..09e313e --- /dev/null +++ b/Source/WebCore/css/CSSImportRule.cpp @@ -0,0 +1,195 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006, 2008, 2009, 2010 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 "CSSImportRule.h" + +#include "CachedCSSStyleSheet.h" +#include "CachedResourceLoader.h" +#include "Document.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +CSSImportRule::CSSImportRule(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaList> media) + : CSSRule(parent) + , m_strHref(href) + , m_lstMedia(media) + , m_cachedSheet(0) + , m_loading(false) +{ + if (m_lstMedia) + m_lstMedia->setParent(this); + else + m_lstMedia = MediaList::create(this, String()); +} + +CSSImportRule::~CSSImportRule() +{ + if (m_lstMedia) + m_lstMedia->setParent(0); + if (m_styleSheet) + m_styleSheet->setParent(0); + if (m_cachedSheet) + m_cachedSheet->removeClient(this); +} + +void CSSImportRule::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet) +{ + if (m_styleSheet) + m_styleSheet->setParent(0); + m_styleSheet = CSSStyleSheet::create(this, href, baseURL, charset); + + bool crossOriginCSS = false; + bool validMIMEType = false; + CSSStyleSheet* parent = parentStyleSheet(); + bool strict = !parent || parent->useStrictParsing(); + bool enforceMIMEType = strict; + bool needsSiteSpecificQuirks = parent && parent->document() && parent->document()->settings() && parent->document()->settings()->needsSiteSpecificQuirks(); + +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + if (enforceMIMEType && needsSiteSpecificQuirks) { + // Covers both http and https, with or without "www." + if (baseURL.string().contains("mcafee.com/japan/", false)) + enforceMIMEType = false; + } +#endif + + String sheetText = sheet->sheetText(enforceMIMEType, &validMIMEType); + m_styleSheet->parseString(sheetText, strict); + + if (!parent || !parent->document() || !parent->document()->securityOrigin()->canRequest(baseURL)) + crossOriginCSS = true; + + if (crossOriginCSS && !validMIMEType && !m_styleSheet->hasSyntacticallyValidCSSHeader()) + m_styleSheet = CSSStyleSheet::create(this, href, baseURL, charset); + + if (strict && needsSiteSpecificQuirks) { + // Work around <https://bugs.webkit.org/show_bug.cgi?id=28350>. + DEFINE_STATIC_LOCAL(const String, slashKHTMLFixesDotCss, ("/KHTMLFixes.css")); + DEFINE_STATIC_LOCAL(const String, mediaWikiKHTMLFixesStyleSheet, ("/* KHTML fix stylesheet */\n/* work around the horizontal scrollbars */\n#column-content { margin-left: 0; }\n\n")); + // There are two variants of KHTMLFixes.css. One is equal to mediaWikiKHTMLFixesStyleSheet, + // while the other lacks the second trailing newline. + if (baseURL.string().endsWith(slashKHTMLFixesDotCss) && !sheetText.isNull() && mediaWikiKHTMLFixesStyleSheet.startsWith(sheetText) + && sheetText.length() >= mediaWikiKHTMLFixesStyleSheet.length() - 1) { + ASSERT(m_styleSheet->length() == 1); + ExceptionCode ec; + m_styleSheet->deleteRule(0, ec); + } + } + + m_loading = false; + + if (parent) + parent->checkLoaded(); +} + +bool CSSImportRule::isLoading() const +{ + return m_loading || (m_styleSheet && m_styleSheet->isLoading()); +} + +void CSSImportRule::insertedIntoParent() +{ + CSSStyleSheet* parentSheet = parentStyleSheet(); + if (!parentSheet || !parentSheet->document()) + return; + + CachedResourceLoader* cachedResourceLoader = parentSheet->document()->cachedResourceLoader(); + if (!cachedResourceLoader) + return; + + String absHref = m_strHref; + if (!parentSheet->finalURL().isNull()) + // use parent styleheet's URL as the base URL + absHref = KURL(parentSheet->finalURL(), m_strHref).string(); + + // Check for a cycle in our import chain. If we encounter a stylesheet + // in our parent chain with the same URL, then just bail. + StyleBase* root = this; + for (StyleBase* curr = parent(); curr; curr = curr->parent()) { + // FIXME: This is wrong if the finalURL was updated via document::updateBaseURL. + if (curr->isCSSStyleSheet() && absHref == static_cast<CSSStyleSheet*>(curr)->finalURL().string()) + return; + root = curr; + } + + if (parentSheet->isUserStyleSheet()) + m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(absHref, parentSheet->charset()); + else + m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(absHref, parentSheet->charset()); + if (m_cachedSheet) { + // if the import rule is issued dynamically, the sheet may be + // removed from the pending sheet count, so let the doc know + // the sheet being imported is pending. + if (parentSheet && parentSheet->loadCompleted() && root == parentSheet) + parentSheet->document()->addPendingSheet(); + m_loading = true; + m_cachedSheet->addClient(this); + } +} + +String CSSImportRule::cssText() const +{ + String result = "@import url(\""; + result += m_strHref; + result += "\")"; + + if (m_lstMedia) { + result += " "; + result += m_lstMedia->mediaText(); + } + result += ";"; + + return result; +} + +void CSSImportRule::addSubresourceStyleURLs(ListHashSet<KURL>& urls) +{ + if (m_styleSheet) + addSubresourceURL(urls, m_styleSheet->baseURL()); +} + +#ifdef ANDROID_INSTRUMENT +void* CSSImportRule::operator new(size_t size) +{ + return StyleBase::operator new(size); +} + +void* CSSImportRule::operator new[](size_t size) +{ + return StyleBase::operator new[](size); +} + +void CSSImportRule::operator delete(void* p, size_t size) +{ + StyleBase::operator delete(p, size); +} + +void CSSImportRule::operator delete[](void* p, size_t size) +{ + StyleBase::operator delete[](p, size); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSImportRule.h b/Source/WebCore/css/CSSImportRule.h new file mode 100644 index 0000000..943d53e --- /dev/null +++ b/Source/WebCore/css/CSSImportRule.h @@ -0,0 +1,85 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSImportRule_h +#define CSSImportRule_h + +#include "CSSRule.h" +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include "MediaList.h" +#include "PlatformString.h" + +namespace WebCore { + +class CachedCSSStyleSheet; +class MediaList; + +class CSSImportRule : public CSSRule, private CachedResourceClient { +public: + static PassRefPtr<CSSImportRule> create(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaList> media) + { + return adoptRef(new CSSImportRule(parent, href, media)); + } + + virtual ~CSSImportRule(); + + String href() const { return m_strHref; } + MediaList* media() const { return m_lstMedia.get(); } + CSSStyleSheet* styleSheet() const { return m_styleSheet.get(); } + + virtual String cssText() const; + + // Not part of the CSSOM + bool isLoading() const; + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + +private: + CSSImportRule(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaList>); + + virtual bool isImportRule() { return true; } + virtual void insertedIntoParent(); + + // from CSSRule + virtual unsigned short type() const { return IMPORT_RULE; } + + // from CachedResourceClient + virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*); + +#ifdef ANDROID_INSTRUMENT + // Overridden to resolve the ambiguous + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void* p, size_t size); + void operator delete[](void* p, size_t size); +#endif + + String m_strHref; + RefPtr<MediaList> m_lstMedia; + RefPtr<CSSStyleSheet> m_styleSheet; + CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet; + bool m_loading; +}; + +} // namespace WebCore + +#endif // CSSImportRule_h diff --git a/Source/WebCore/css/CSSImportRule.idl b/Source/WebCore/css/CSSImportRule.idl new file mode 100644 index 0000000..5ffdee0 --- /dev/null +++ b/Source/WebCore/css/CSSImportRule.idl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [CustomMarkFunction] CSSImportRule : CSSRule { + readonly attribute [ConvertNullStringTo=Null] DOMString href; + readonly attribute MediaList media; + readonly attribute CSSStyleSheet styleSheet; + }; + +} diff --git a/Source/WebCore/css/CSSInheritedValue.cpp b/Source/WebCore/css/CSSInheritedValue.cpp new file mode 100644 index 0000000..20b73e2 --- /dev/null +++ b/Source/WebCore/css/CSSInheritedValue.cpp @@ -0,0 +1,38 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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 "CSSInheritedValue.h" + +#include "PlatformString.h" + +namespace WebCore { + +unsigned short CSSInheritedValue::cssValueType() const +{ + return CSS_INHERIT; +} + +String CSSInheritedValue::cssText() const +{ + return "inherit"; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSInheritedValue.h b/Source/WebCore/css/CSSInheritedValue.h new file mode 100644 index 0000000..e015a98 --- /dev/null +++ b/Source/WebCore/css/CSSInheritedValue.h @@ -0,0 +1,45 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSInheritedValue_h +#define CSSInheritedValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class CSSInheritedValue : public CSSValue { +public: + static PassRefPtr<CSSInheritedValue> create() + { + return adoptRef(new CSSInheritedValue); + } + + virtual String cssText() const; + +private: + CSSInheritedValue() { } + virtual unsigned short cssValueType() const; +}; + +} // namespace WebCore + +#endif // CSSInheritedValue_h diff --git a/Source/WebCore/css/CSSInitialValue.cpp b/Source/WebCore/css/CSSInitialValue.cpp new file mode 100644 index 0000000..cbe776b --- /dev/null +++ b/Source/WebCore/css/CSSInitialValue.cpp @@ -0,0 +1,38 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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 "CSSInitialValue.h" + +#include "PlatformString.h" + +namespace WebCore { + +unsigned short CSSInitialValue::cssValueType() const +{ + return CSS_INITIAL; +} + +String CSSInitialValue::cssText() const +{ + return "initial"; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSInitialValue.h b/Source/WebCore/css/CSSInitialValue.h new file mode 100644 index 0000000..70ea91c --- /dev/null +++ b/Source/WebCore/css/CSSInitialValue.h @@ -0,0 +1,63 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSInitialValue_h +#define CSSInitialValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class CSSInitialValue : public CSSValue { +public: + static PassRefPtr<CSSInitialValue> createExplicit() + { + static CSSInitialValue* explicitValue = create(false).releaseRef(); + return explicitValue; + } + static PassRefPtr<CSSInitialValue> createImplicit() + { + static CSSInitialValue* explicitValue = create(true).releaseRef(); + return explicitValue; + } + + virtual String cssText() const; + +private: + CSSInitialValue(bool implicit) + : m_implicit(implicit) + { + } + + static PassRefPtr<CSSInitialValue> create(bool implicit) + { + return adoptRef(new CSSInitialValue(implicit)); + } + + virtual unsigned short cssValueType() const; + virtual bool isImplicitInitialValue() const { return m_implicit; } + + bool m_implicit; +}; + +} // namespace WebCore + +#endif // CSSInitialValue_h diff --git a/Source/WebCore/css/CSSMediaRule.cpp b/Source/WebCore/css/CSSMediaRule.cpp new file mode 100644 index 0000000..6348762 --- /dev/null +++ b/Source/WebCore/css/CSSMediaRule.cpp @@ -0,0 +1,134 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) + * + * 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 "CSSMediaRule.h" + +#include "CSSParser.h" +#include "ExceptionCode.h" + +namespace WebCore { + +CSSMediaRule::CSSMediaRule(CSSStyleSheet* parent, PassRefPtr<MediaList> media, PassRefPtr<CSSRuleList> rules) + : CSSRule(parent) + , m_lstMedia(media) + , m_lstCSSRules(rules) +{ + int length = m_lstCSSRules->length(); + for (int i = 0; i < length; i++) + m_lstCSSRules->item(i)->setParent(this); +} + +CSSMediaRule::~CSSMediaRule() +{ + if (m_lstMedia) + m_lstMedia->setParent(0); + + int length = m_lstCSSRules->length(); + for (int i = 0; i < length; i++) + m_lstCSSRules->item(i)->setParent(0); +} + +unsigned CSSMediaRule::append(CSSRule* rule) +{ + if (!rule) + return 0; + + rule->setParent(this); + return m_lstCSSRules->insertRule(rule, m_lstCSSRules->length()); +} + +unsigned CSSMediaRule::insertRule(const String& rule, unsigned index, ExceptionCode& ec) +{ + if (index > m_lstCSSRules->length()) { + // INDEX_SIZE_ERR: Raised if the specified index is not a valid insertion point. + ec = INDEX_SIZE_ERR; + return 0; + } + + CSSParser p(useStrictParsing()); + RefPtr<CSSRule> newRule = p.parseRule(parentStyleSheet(), rule); + if (!newRule) { + // SYNTAX_ERR: Raised if the specified rule has a syntax error and is unparsable. + ec = SYNTAX_ERR; + return 0; + } + + if (newRule->isImportRule()) { + // FIXME: an HIERARCHY_REQUEST_ERR should also be thrown for a @charset or a nested + // @media rule. They are currently not getting parsed, resulting in a SYNTAX_ERR + // to get raised above. + + // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified + // index, e.g., if an @import rule is inserted after a standard rule set or other + // at-rule. + ec = HIERARCHY_REQUEST_ERR; + return 0; + } + + newRule->setParent(this); + unsigned returnedIndex = m_lstCSSRules->insertRule(newRule.get(), index); + + // stylesheet() can only return 0 for computed style declarations. + stylesheet()->styleSheetChanged(); + + return returnedIndex; +} + +void CSSMediaRule::deleteRule(unsigned index, ExceptionCode& ec) +{ + if (index >= m_lstCSSRules->length()) { + // INDEX_SIZE_ERR: Raised if the specified index does not correspond to a + // rule in the media rule list. + ec = INDEX_SIZE_ERR; + return; + } + + m_lstCSSRules->deleteRule(index); + + // stylesheet() can only return 0 for computed style declarations. + stylesheet()->styleSheetChanged(); +} + +String CSSMediaRule::cssText() const +{ + String result = "@media "; + if (m_lstMedia) { + result += m_lstMedia->mediaText(); + result += " "; + } + result += "{ \n"; + + if (m_lstCSSRules) { + unsigned len = m_lstCSSRules->length(); + for (unsigned i = 0; i < len; i++) { + result += " "; + result += m_lstCSSRules->item(i)->cssText(); + result += "\n"; + } + } + + result += "}"; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSMediaRule.h b/Source/WebCore/css/CSSMediaRule.h new file mode 100644 index 0000000..5eead7c --- /dev/null +++ b/Source/WebCore/css/CSSMediaRule.h @@ -0,0 +1,69 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) + * + * 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. + */ + +#ifndef CSSMediaRule_h +#define CSSMediaRule_h + +#include "CSSRule.h" +#include "CSSRuleList.h" +#include "MediaList.h" +#include "PlatformString.h" // needed so bindings will compile + +namespace WebCore { + +class CSSRuleList; +class MediaList; + +class CSSMediaRule : public CSSRule { +public: + static PassRefPtr<CSSMediaRule> create(CSSStyleSheet* parent, PassRefPtr<MediaList> media, PassRefPtr<CSSRuleList> rules) + { + return adoptRef(new CSSMediaRule(parent, media, rules)); + } + virtual ~CSSMediaRule(); + + MediaList* media() const { return m_lstMedia.get(); } + CSSRuleList* cssRules() { return m_lstCSSRules.get(); } + + unsigned insertRule(const String& rule, unsigned index, ExceptionCode&); + void deleteRule(unsigned index, ExceptionCode&); + + virtual String cssText() const; + + // Not part of the CSSOM + unsigned append(CSSRule*); + +private: + CSSMediaRule(CSSStyleSheet* parent, PassRefPtr<MediaList>, PassRefPtr<CSSRuleList>); + + virtual bool isMediaRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return MEDIA_RULE; } + + RefPtr<MediaList> m_lstMedia; + RefPtr<CSSRuleList> m_lstCSSRules; +}; + +} // namespace WebCore + +#endif // CSSMediaRule_h diff --git a/Source/WebCore/css/CSSMediaRule.idl b/Source/WebCore/css/CSSMediaRule.idl new file mode 100644 index 0000000..a58020a --- /dev/null +++ b/Source/WebCore/css/CSSMediaRule.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [CustomMarkFunction] CSSMediaRule : CSSRule { + readonly attribute MediaList media; + readonly attribute CSSRuleList cssRules; + + [OldStyleObjC] unsigned long insertRule(in DOMString rule, + in unsigned long index) + raises(DOMException); + void deleteRule(in unsigned long index) + raises(DOMException); + }; + +} diff --git a/Source/WebCore/css/CSSMutableStyleDeclaration.cpp b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp new file mode 100644 index 0000000..573f4c0 --- /dev/null +++ b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp @@ -0,0 +1,847 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 "CSSMutableStyleDeclaration.h" + +#include "CSSImageValue.h" +#include "CSSParser.h" +#include "CSSPropertyLonghand.h" +#include "CSSPropertyNames.h" +#include "CSSRule.h" +#include "CSSStyleSheet.h" +#include "CSSValueKeywords.h" +#include "CSSValueList.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "StyledElement.h" + +using namespace std; + +namespace WebCore { + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration() + : m_node(0) + , m_strictParsing(false) +#ifndef NDEBUG + , m_iteratorCount(0) +#endif +{ +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent) + : CSSStyleDeclaration(parent) + , m_node(0) + , m_strictParsing(!parent || parent->useStrictParsing()) +#ifndef NDEBUG + , m_iteratorCount(0) +#endif +{ +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const Vector<CSSProperty>& properties) + : CSSStyleDeclaration(parent) + , m_properties(properties) + , m_node(0) + , m_strictParsing(!parent || parent->useStrictParsing()) +#ifndef NDEBUG + , m_iteratorCount(0) +#endif +{ + m_properties.shrinkToFit(); + // FIXME: This allows duplicate properties. +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const CSSProperty* const * properties, int numProperties) + : CSSStyleDeclaration(parent) + , m_node(0) + , m_strictParsing(!parent || parent->useStrictParsing()) +#ifndef NDEBUG + , m_iteratorCount(0) +#endif +{ + m_properties.reserveInitialCapacity(numProperties); + HashSet<int> candidates; + for (int i = 0; i < numProperties; ++i) { + const CSSProperty *property = properties[i]; + ASSERT(property); + if (candidates.contains(property->id())) + removeProperty(properties[i]->id(), false); + m_properties.append(*property); + if (!getPropertyPriority(property->id()) && !property->isImportant()) + candidates.add(property->id()); + } +} + +CSSMutableStyleDeclaration& CSSMutableStyleDeclaration::operator=(const CSSMutableStyleDeclaration& other) +{ + ASSERT(!m_iteratorCount); + // don't attach it to the same node, just leave the current m_node value + m_properties = other.m_properties; + m_strictParsing = other.m_strictParsing; + return *this; +} + +String CSSMutableStyleDeclaration::getPropertyValue(int propertyID) const +{ + RefPtr<CSSValue> value = getPropertyCSSValue(propertyID); + if (value) + return value->cssText(); + + // Shorthand and 4-values properties + switch (propertyID) { + case CSSPropertyBackgroundPosition: { + // FIXME: Is this correct? The code in cssparser.cpp is confusing + const int properties[2] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; + return getLayeredShorthandValue(properties, 2); + } + case CSSPropertyBackgroundRepeat: { + const int properties[2] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; + return getLayeredShorthandValue(properties, 2); + } + case CSSPropertyBackground: { + const int properties[9] = { CSSPropertyBackgroundColor, + CSSPropertyBackgroundImage, + CSSPropertyBackgroundRepeatX, + CSSPropertyBackgroundRepeatY, + CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundPositionX, + CSSPropertyBackgroundPositionY, + CSSPropertyBackgroundClip, + CSSPropertyBackgroundOrigin }; + return getLayeredShorthandValue(properties, 9); + } + case CSSPropertyBorder: { + const int properties[3][4] = {{ CSSPropertyBorderTopWidth, + CSSPropertyBorderRightWidth, + CSSPropertyBorderBottomWidth, + CSSPropertyBorderLeftWidth }, + { CSSPropertyBorderTopStyle, + CSSPropertyBorderRightStyle, + CSSPropertyBorderBottomStyle, + CSSPropertyBorderLeftStyle }, + { CSSPropertyBorderTopColor, + CSSPropertyBorderRightColor, + CSSPropertyBorderBottomColor, + CSSPropertyBorderLeftColor }}; + String res; + for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { + String value = getCommonValue(properties[i], 4); + if (!value.isNull()) { + if (!res.isNull()) + res += " "; + res += value; + } + } + return res; + } + case CSSPropertyBorderTop: { + const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, + CSSPropertyBorderTopColor}; + return getShorthandValue(properties, 3); + } + case CSSPropertyBorderRight: { + const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, + CSSPropertyBorderRightColor}; + return getShorthandValue(properties, 3); + } + case CSSPropertyBorderBottom: { + const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, + CSSPropertyBorderBottomColor}; + return getShorthandValue(properties, 3); + } + case CSSPropertyBorderLeft: { + const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, + CSSPropertyBorderLeftColor}; + return getShorthandValue(properties, 3); + } + case CSSPropertyOutline: { + const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle, + CSSPropertyOutlineColor }; + return getShorthandValue(properties, 3); + } + case CSSPropertyBorderColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, + CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return get4Values(properties); + } + case CSSPropertyBorderWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, + CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return get4Values(properties); + } + case CSSPropertyBorderStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, + CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return get4Values(properties); + } + case CSSPropertyMargin: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, + CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return get4Values(properties); + } + case CSSPropertyOverflow: { + const int properties[2] = { CSSPropertyOverflowX, CSSPropertyOverflowY }; + return getCommonValue(properties, 2); + } + case CSSPropertyPadding: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, + CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return get4Values(properties); + } + case CSSPropertyListStyle: { + const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition, + CSSPropertyListStyleImage }; + return getShorthandValue(properties, 3); + } + case CSSPropertyWebkitMaskPosition: { + // FIXME: Is this correct? The code in cssparser.cpp is confusing + const int properties[2] = { CSSPropertyWebkitMaskPositionX, CSSPropertyWebkitMaskPositionY }; + return getLayeredShorthandValue(properties, 2); + } + case CSSPropertyWebkitMaskRepeat: { + const int properties[2] = { CSSPropertyWebkitMaskRepeatX, CSSPropertyWebkitMaskRepeatY }; + return getLayeredShorthandValue(properties, 2); + } + case CSSPropertyWebkitMask: { + const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskClip, + CSSPropertyWebkitMaskOrigin }; + return getLayeredShorthandValue(properties, 6); + } + case CSSPropertyWebkitTransformOrigin: { + const int properties[3] = { CSSPropertyWebkitTransformOriginX, + CSSPropertyWebkitTransformOriginY, + CSSPropertyWebkitTransformOriginZ }; + return getShorthandValue(properties, 3); + } + case CSSPropertyWebkitTransition: { + const int properties[4] = { CSSPropertyWebkitTransitionProperty, CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitTransitionDelay }; + return getLayeredShorthandValue(properties, 4); + } + case CSSPropertyWebkitAnimation: { + const int properties[7] = { CSSPropertyWebkitAnimationName, CSSPropertyWebkitAnimationDuration, + CSSPropertyWebkitAnimationTimingFunction, CSSPropertyWebkitAnimationDelay, + CSSPropertyWebkitAnimationIterationCount, CSSPropertyWebkitAnimationDirection, + CSSPropertyWebkitAnimationFillMode }; + return getLayeredShorthandValue(properties, 7); + } +#if ENABLE(SVG) + case CSSPropertyMarker: { + RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart); + if (value) + return value->cssText(); + } +#endif +#ifdef ANDROID_CSS_RING + case CSSPropertyWebkitRing: { + const int properties[9] = { CSSPropertyWebkitRingFillColor, + CSSPropertyWebkitRingInnerWidth, + CSSPropertyWebkitRingOuterWidth, + CSSPropertyWebkitRingOutset, + CSSPropertyWebkitRingPressedInnerColor, + CSSPropertyWebkitRingPressedOuterColor, + CSSPropertyWebkitRingRadius, + CSSPropertyWebkitRingSelectedInnerColor, + CSSPropertyWebkitRingSelectedOuterColor }; + return getLayeredShorthandValue(properties, 9); + } +#endif + } + return String(); +} + +String CSSMutableStyleDeclaration::get4Values(const int* properties) const +{ + // Assume the properties are in the usual order top, right, bottom, left. + RefPtr<CSSValue> topValue = getPropertyCSSValue(properties[0]); + RefPtr<CSSValue> rightValue = getPropertyCSSValue(properties[1]); + RefPtr<CSSValue> bottomValue = getPropertyCSSValue(properties[2]); + RefPtr<CSSValue> leftValue = getPropertyCSSValue(properties[3]); + + // All 4 properties must be specified. + if (!topValue || !rightValue || !bottomValue || !leftValue) + return String(); + + bool showLeft = rightValue->cssText() != leftValue->cssText(); + bool showBottom = (topValue->cssText() != bottomValue->cssText()) || showLeft; + bool showRight = (topValue->cssText() != rightValue->cssText()) || showBottom; + + String res = topValue->cssText(); + if (showRight) + res += " " + rightValue->cssText(); + if (showBottom) + res += " " + bottomValue->cssText(); + if (showLeft) + res += " " + leftValue->cssText(); + + return res; +} + +String CSSMutableStyleDeclaration::getLayeredShorthandValue(const int* properties, unsigned number) const +{ + String res; + + // Begin by collecting the properties into an array. + Vector< RefPtr<CSSValue> > values(number); + size_t numLayers = 0; + + for (size_t i = 0; i < number; ++i) { + values[i] = getPropertyCSSValue(properties[i]); + if (values[i]) { + if (values[i]->isValueList()) { + CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get()); + numLayers = max(valueList->length(), numLayers); + } else + numLayers = max<size_t>(1U, numLayers); + } + } + + // Now stitch the properties together. Implicit initial values are flagged as such and + // can safely be omitted. + for (size_t i = 0; i < numLayers; i++) { + String layerRes; + bool useRepeatXShorthand = false; + bool useRepeatYShorthand = false; + bool useSingleWordShorthand = false; + for (size_t j = 0; j < number; j++) { + RefPtr<CSSValue> value; + if (values[j]) { + if (values[j]->isValueList()) + value = static_cast<CSSValueList*>(values[j].get())->item(i); + else { + value = values[j]; + + // Color only belongs in the last layer. + if (properties[j] == CSSPropertyBackgroundColor) { + if (i != numLayers - 1) + value = 0; + } else if (i != 0) // Other singletons only belong in the first layer. + value = 0; + } + } + + // We need to report background-repeat as it was written in the CSS. If the property is implicit, + // then it was written with only one value. Here we figure out which value that was so we can + // report back correctly. + if (properties[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(properties[j])) { + + // BUG 49055: make sure the value was not reset in the layer check just above. + if (j < number - 1 && properties[j + 1] == CSSPropertyBackgroundRepeatY && value) { + RefPtr<CSSValue> yValue; + RefPtr<CSSValue> nextValue = values[j + 1]; + if (nextValue->isValueList()) + yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i); + else + yValue = nextValue; + + int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent(); + int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent(); + if (xId != yId) { + if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) { + useRepeatXShorthand = true; + ++j; + } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) { + useRepeatYShorthand = true; + continue; + } + } else { + useSingleWordShorthand = true; + ++j; + } + } + } + + if (value && !value->isImplicitInitialValue()) { + if (!layerRes.isNull()) + layerRes += " "; + if (useRepeatXShorthand) { + useRepeatXShorthand = false; + layerRes += getValueName(CSSValueRepeatX); + } else if (useRepeatYShorthand) { + useRepeatYShorthand = false; + layerRes += getValueName(CSSValueRepeatY); + } else if (useSingleWordShorthand) { + useSingleWordShorthand = false; + layerRes += value->cssText(); + } else + layerRes += value->cssText(); + } + } + + if (!layerRes.isNull()) { + if (!res.isNull()) + res += ", "; + res += layerRes; + } + } + + return res; +} + +String CSSMutableStyleDeclaration::getShorthandValue(const int* properties, int number) const +{ + String res; + for (int i = 0; i < number; ++i) { + if (!isPropertyImplicit(properties[i])) { + RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]); + // FIXME: provide default value if !value + if (value) { + if (!res.isNull()) + res += " "; + res += value->cssText(); + } + } + } + return res; +} + +// only returns a non-null value if all properties have the same, non-null value +String CSSMutableStyleDeclaration::getCommonValue(const int* properties, int number) const +{ + String res; + for (int i = 0; i < number; ++i) { + RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]); + if (!value) + return String(); + String text = value->cssText(); + if (text.isNull()) + return String(); + if (res.isNull()) + res = text; + else if (res != text) + return String(); + } + return res; +} + +PassRefPtr<CSSValue> CSSMutableStyleDeclaration::getPropertyCSSValue(int propertyID) const +{ + const CSSProperty* property = findPropertyWithId(propertyID); + return property ? property->value() : 0; +} + +bool CSSMutableStyleDeclaration::removeShorthandProperty(int propertyID, bool notifyChanged) +{ + CSSPropertyLonghand longhand = longhandForProperty(propertyID); + if (longhand.length()) { + removePropertiesInSet(longhand.properties(), longhand.length(), notifyChanged); + return true; + } + return false; +} + +String CSSMutableStyleDeclaration::removeProperty(int propertyID, bool notifyChanged, bool returnText) +{ + ASSERT(!m_iteratorCount); + + if (removeShorthandProperty(propertyID, notifyChanged)) { + // FIXME: Return an equivalent shorthand when possible. + return String(); + } + + CSSProperty* foundProperty = findPropertyWithId(propertyID); + if (!foundProperty) + return String(); + + String value = returnText ? foundProperty->value()->cssText() : String(); + + // A more efficient removal strategy would involve marking entries as empty + // and sweeping them when the vector grows too big. + m_properties.remove(foundProperty - m_properties.data()); + + if (notifyChanged) + setNeedsStyleRecalc(); + + return value; +} + +void CSSMutableStyleDeclaration::setNeedsStyleRecalc() +{ + if (m_node) { + // FIXME: Ideally, this should be factored better and there + // should be a subclass of CSSMutableStyleDeclaration just + // for inline style declarations that handles this + bool isInlineStyleDeclaration = m_node->isStyledElement() && this == static_cast<StyledElement*>(m_node)->inlineStyleDecl(); + if (isInlineStyleDeclaration) { + m_node->setNeedsStyleRecalc(InlineStyleChange); + static_cast<StyledElement*>(m_node)->invalidateStyleAttribute(); + } else + m_node->setNeedsStyleRecalc(FullStyleChange); + return; + } + + StyleBase* root = this; + while (StyleBase* parent = root->parent()) + root = parent; + if (root->isCSSStyleSheet()) { + if (Document* document = static_cast<CSSStyleSheet*>(root)->document()) + document->styleSelectorChanged(DeferRecalcStyle); + } +} + +bool CSSMutableStyleDeclaration::getPropertyPriority(int propertyID) const +{ + const CSSProperty* property = findPropertyWithId(propertyID); + return property ? property->isImportant() : false; +} + +int CSSMutableStyleDeclaration::getPropertyShorthand(int propertyID) const +{ + const CSSProperty* property = findPropertyWithId(propertyID); + return property ? property->shorthandID() : 0; +} + +bool CSSMutableStyleDeclaration::isPropertyImplicit(int propertyID) const +{ + const CSSProperty* property = findPropertyWithId(propertyID); + return property ? property->isImplicit() : false; +} + +void CSSMutableStyleDeclaration::setProperty(int propertyID, const String& value, bool important, ExceptionCode& ec) +{ + ec = 0; + setProperty(propertyID, value, important, true); +} + +String CSSMutableStyleDeclaration::removeProperty(int propertyID, ExceptionCode& ec) +{ + ec = 0; + return removeProperty(propertyID, true, true); +} + +bool CSSMutableStyleDeclaration::setProperty(int propertyID, const String& value, bool important, bool notifyChanged) +{ + ASSERT(!m_iteratorCount); + + // Setting the value to an empty string just removes the property in both IE and Gecko. + // Setting it to null seems to produce less consistent results, but we treat it just the same. + if (value.isEmpty()) { + removeProperty(propertyID, notifyChanged, false); + return true; + } + + // When replacing an existing property value, this moves the property to the end of the list. + // Firefox preserves the position, and MSIE moves the property to the beginning. + CSSParser parser(useStrictParsing()); + bool success = parser.parseValue(this, propertyID, value, important); + if (!success) { + // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility, + // see <http://bugs.webkit.org/show_bug.cgi?id=7296>. + } else if (notifyChanged) + setNeedsStyleRecalc(); + + return success; +} + +void CSSMutableStyleDeclaration::setPropertyInternal(const CSSProperty& property, CSSProperty* slot) +{ + ASSERT(!m_iteratorCount); + + if (!removeShorthandProperty(property.id(), false)) { + CSSProperty* toReplace = slot ? slot : findPropertyWithId(property.id()); + if (toReplace) { + *toReplace = property; + return; + } + } + m_properties.append(property); +} + +bool CSSMutableStyleDeclaration::setProperty(int propertyID, int value, bool important, bool notifyChanged) +{ + CSSProperty property(propertyID, CSSPrimitiveValue::createIdentifier(value), important); + setPropertyInternal(property); + if (notifyChanged) + setNeedsStyleRecalc(); + return true; +} + +void CSSMutableStyleDeclaration::setStringProperty(int propertyId, const String &value, CSSPrimitiveValue::UnitTypes type, bool important) +{ + ASSERT(!m_iteratorCount); + + setPropertyInternal(CSSProperty(propertyId, CSSPrimitiveValue::create(value, type), important)); + setNeedsStyleRecalc(); +} + +void CSSMutableStyleDeclaration::setImageProperty(int propertyId, const String& url, bool important) +{ + ASSERT(!m_iteratorCount); + + setPropertyInternal(CSSProperty(propertyId, CSSImageValue::create(url), important)); + setNeedsStyleRecalc(); +} + +void CSSMutableStyleDeclaration::parseDeclaration(const String& styleDeclaration) +{ + ASSERT(!m_iteratorCount); + + m_properties.clear(); + CSSParser parser(useStrictParsing()); + parser.parseDeclaration(this, styleDeclaration); + setNeedsStyleRecalc(); +} + +void CSSMutableStyleDeclaration::addParsedProperties(const CSSProperty* const* properties, int numProperties) +{ + ASSERT(!m_iteratorCount); + + m_properties.reserveCapacity(numProperties); + + for (int i = 0; i < numProperties; ++i) { + // Only add properties that have no !important counterpart present + if (!getPropertyPriority(properties[i]->id()) || properties[i]->isImportant()) { + removeProperty(properties[i]->id(), false); + ASSERT(properties[i]); + m_properties.append(*properties[i]); + } + } + // FIXME: This probably should have a call to setNeedsStyleRecalc() if something changed. We may also wish to add + // a notifyChanged argument to this function to follow the model of other functions in this class. +} + +void CSSMutableStyleDeclaration::addParsedProperty(const CSSProperty& property) +{ + ASSERT(!m_iteratorCount); + + setPropertyInternal(property); +} + +void CSSMutableStyleDeclaration::setLengthProperty(int propertyId, const String& value, bool important, bool /*multiLength*/) +{ + ASSERT(!m_iteratorCount); + + bool parseMode = useStrictParsing(); + setStrictParsing(false); + setProperty(propertyId, value, important); + setStrictParsing(parseMode); +} + +unsigned CSSMutableStyleDeclaration::virtualLength() const +{ + return length(); +} + +String CSSMutableStyleDeclaration::item(unsigned i) const +{ + if (i >= m_properties.size()) + return ""; + return getPropertyName(static_cast<CSSPropertyID>(m_properties[i].id())); +} + +String CSSMutableStyleDeclaration::cssText() const +{ + String result = ""; + + const CSSProperty* positionXProp = 0; + const CSSProperty* positionYProp = 0; + const CSSProperty* repeatXProp = 0; + const CSSProperty* repeatYProp = 0; + + unsigned size = m_properties.size(); + for (unsigned n = 0; n < size; ++n) { + const CSSProperty& prop = m_properties[n]; + if (prop.id() == CSSPropertyBackgroundPositionX) + positionXProp = ∝ + else if (prop.id() == CSSPropertyBackgroundPositionY) + positionYProp = ∝ + else if (prop.id() == CSSPropertyBackgroundRepeatX) + repeatXProp = ∝ + else if (prop.id() == CSSPropertyBackgroundRepeatY) + repeatYProp = ∝ + else + result += prop.cssText(); + } + + // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output. + // It is required because background-position-x/y are non-standard properties and WebKit generated output + // would not work in Firefox (<rdar://problem/5143183>) + // It would be a better solution if background-position was CSS_PAIR. + if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) { + String positionValue; + const int properties[2] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; + if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList()) + positionValue = getLayeredShorthandValue(properties, 2); + else + positionValue = positionXProp->value()->cssText() + " " + positionYProp->value()->cssText(); + result += "background-position: " + positionValue + (positionXProp->isImportant() ? " !important" : "") + "; "; + } else { + if (positionXProp) + result += positionXProp->cssText(); + if (positionYProp) + result += positionYProp->cssText(); + } + + // FIXME: We need to do the same for background-repeat. + if (repeatXProp && repeatYProp && repeatXProp->isImportant() == repeatYProp->isImportant()) { + String repeatValue; + const int repeatProperties[2] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; + if (repeatXProp->value()->isValueList() || repeatYProp->value()->isValueList()) + repeatValue = getLayeredShorthandValue(repeatProperties, 2); + else + repeatValue = repeatXProp->value()->cssText() + " " + repeatYProp->value()->cssText(); + result += "background-repeat: " + repeatValue + (repeatXProp->isImportant() ? " !important" : "") + "; "; + } else { + if (repeatXProp) + result += repeatXProp->cssText(); + if (repeatYProp) + result += repeatYProp->cssText(); + } + + return result; +} + +void CSSMutableStyleDeclaration::setCssText(const String& text, ExceptionCode& ec) +{ + ASSERT(!m_iteratorCount); + + ec = 0; + m_properties.clear(); + CSSParser parser(useStrictParsing()); + parser.parseDeclaration(this, text); + // FIXME: Detect syntax errors and set ec. + setNeedsStyleRecalc(); +} + +void CSSMutableStyleDeclaration::merge(const CSSMutableStyleDeclaration* other, bool argOverridesOnConflict) +{ + ASSERT(!m_iteratorCount); + + unsigned size = other->m_properties.size(); + for (unsigned n = 0; n < size; ++n) { + const CSSProperty& toMerge = other->m_properties[n]; + CSSProperty* old = findPropertyWithId(toMerge.id()); + if (old) { + if (!argOverridesOnConflict && old->value()) + continue; + setPropertyInternal(toMerge, old); + } else + m_properties.append(toMerge); + } + // FIXME: This probably should have a call to setNeedsStyleRecalc() if something changed. We may also wish to add + // a notifyChanged argument to this function to follow the model of other functions in this class. +} + +void CSSMutableStyleDeclaration::addSubresourceStyleURLs(ListHashSet<KURL>& urls) +{ + CSSStyleSheet* sheet = static_cast<CSSStyleSheet*>(stylesheet()); + size_t size = m_properties.size(); + for (size_t i = 0; i < size; ++i) + m_properties[i].value()->addSubresourceStyleURLs(urls, sheet); +} + +// This is the list of properties we want to copy in the copyBlockProperties() function. +// It is the list of CSS properties that apply specially to block-level elements. +static const int blockProperties[] = { + CSSPropertyOrphans, + CSSPropertyOverflow, // This can be also be applied to replaced elements + CSSPropertyWebkitColumnCount, + CSSPropertyWebkitColumnGap, + CSSPropertyWebkitColumnRuleColor, + CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleWidth, + CSSPropertyWebkitColumnBreakBefore, + CSSPropertyWebkitColumnBreakAfter, + CSSPropertyWebkitColumnBreakInside, + CSSPropertyWebkitColumnWidth, + CSSPropertyPageBreakAfter, + CSSPropertyPageBreakBefore, + CSSPropertyPageBreakInside, + CSSPropertyTextAlign, + CSSPropertyTextIndent, + CSSPropertyWidows +}; + +const unsigned numBlockProperties = WTF_ARRAY_LENGTH(blockProperties); + +PassRefPtr<CSSMutableStyleDeclaration> CSSMutableStyleDeclaration::copyBlockProperties() const +{ + return copyPropertiesInSet(blockProperties, numBlockProperties); +} + +void CSSMutableStyleDeclaration::removeBlockProperties() +{ + removePropertiesInSet(blockProperties, numBlockProperties); +} + +void CSSMutableStyleDeclaration::removePropertiesInSet(const int* set, unsigned length, bool notifyChanged) +{ + ASSERT(!m_iteratorCount); + + if (m_properties.isEmpty()) + return; + + // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless. + HashSet<int> toRemove; + for (unsigned i = 0; i < length; ++i) + toRemove.add(set[i]); + + Vector<CSSProperty, 4> newProperties; + newProperties.reserveInitialCapacity(m_properties.size()); + + unsigned size = m_properties.size(); + for (unsigned n = 0; n < size; ++n) { + const CSSProperty& property = m_properties[n]; + // Not quite sure if the isImportant test is needed but it matches the existing behavior. + if (!property.isImportant()) { + if (toRemove.contains(property.id())) + continue; + } + newProperties.append(property); + } + + bool changed = newProperties.size() != m_properties.size(); + m_properties = newProperties; + + if (changed && notifyChanged) + setNeedsStyleRecalc(); +} + +PassRefPtr<CSSMutableStyleDeclaration> CSSMutableStyleDeclaration::makeMutable() +{ + return this; +} + +PassRefPtr<CSSMutableStyleDeclaration> CSSMutableStyleDeclaration::copy() const +{ + return adoptRef(new CSSMutableStyleDeclaration(0, m_properties)); +} + +const CSSProperty* CSSMutableStyleDeclaration::findPropertyWithId(int propertyID) const +{ + for (int n = m_properties.size() - 1 ; n >= 0; --n) { + if (propertyID == m_properties[n].m_id) + return &m_properties[n]; + } + return 0; +} + +CSSProperty* CSSMutableStyleDeclaration::findPropertyWithId(int propertyID) +{ + for (int n = m_properties.size() - 1 ; n >= 0; --n) { + if (propertyID == m_properties[n].m_id) + return &m_properties[n]; + } + return 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSMutableStyleDeclaration.h b/Source/WebCore/css/CSSMutableStyleDeclaration.h new file mode 100644 index 0000000..f7d8ca9 --- /dev/null +++ b/Source/WebCore/css/CSSMutableStyleDeclaration.h @@ -0,0 +1,223 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSMutableStyleDeclaration_h +#define CSSMutableStyleDeclaration_h + +#include "CSSStyleDeclaration.h" +#include "CSSPrimitiveValue.h" +#include "CSSProperty.h" +#include "KURLHash.h" +#include "PlatformString.h" +#include <wtf/ListHashSet.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class Node; + +class CSSMutableStyleDeclarationConstIterator { +public: + CSSMutableStyleDeclarationConstIterator(const CSSMutableStyleDeclaration* decl, CSSProperty* current); + CSSMutableStyleDeclarationConstIterator(const CSSMutableStyleDeclarationConstIterator& o); + ~CSSMutableStyleDeclarationConstIterator(); + + const CSSProperty& operator*() const { return *m_current; } + const CSSProperty* operator->() const { return m_current; } + + bool operator!=(const CSSMutableStyleDeclarationConstIterator& o) { ASSERT(m_decl == o.m_decl); return m_current != o.m_current; } + bool operator==(const CSSMutableStyleDeclarationConstIterator& o) { ASSERT(m_decl == o.m_decl); return m_current == o.m_current; } + + CSSMutableStyleDeclarationConstIterator& operator=(const CSSMutableStyleDeclarationConstIterator& o); + + CSSMutableStyleDeclarationConstIterator& operator++(); + CSSMutableStyleDeclarationConstIterator& operator--(); + +private: + const CSSMutableStyleDeclaration* m_decl; + CSSProperty* m_current; +}; + +class CSSMutableStyleDeclaration : public CSSStyleDeclaration { +public: + static PassRefPtr<CSSMutableStyleDeclaration> create() + { + return adoptRef(new CSSMutableStyleDeclaration); + } + static PassRefPtr<CSSMutableStyleDeclaration> create(CSSRule* parentRule) + { + return adoptRef(new CSSMutableStyleDeclaration(parentRule)); + } + static PassRefPtr<CSSMutableStyleDeclaration> create(CSSRule* parentRule, const CSSProperty* const* properties, int numProperties) + { + return adoptRef(new CSSMutableStyleDeclaration(parentRule, properties, numProperties)); + } + static PassRefPtr<CSSMutableStyleDeclaration> create(const Vector<CSSProperty>& properties) + { + return adoptRef(new CSSMutableStyleDeclaration(0, properties)); + } + + CSSMutableStyleDeclaration& operator=(const CSSMutableStyleDeclaration&); + + typedef CSSMutableStyleDeclarationConstIterator const_iterator; + + const_iterator begin() { return const_iterator(this, m_properties.begin()); } + const_iterator end() { return const_iterator(this, m_properties.end()); } + + void setNode(Node* node) { m_node = node; } + + Node* node() const { return m_node; } + + virtual bool isMutableStyleDeclaration() const { return true; } + + virtual String cssText() const; + virtual void setCssText(const String&, ExceptionCode&); + + virtual unsigned virtualLength() const; + unsigned length() const { return m_properties.size(); } + + virtual String item(unsigned index) const; + + virtual PassRefPtr<CSSValue> getPropertyCSSValue(int propertyID) const; + virtual String getPropertyValue(int propertyID) const; + virtual bool getPropertyPriority(int propertyID) const; + virtual int getPropertyShorthand(int propertyID) const; + virtual bool isPropertyImplicit(int propertyID) const; + + virtual void setProperty(int propertyId, const String& value, bool important, ExceptionCode&); + virtual String removeProperty(int propertyID, ExceptionCode&); + + virtual PassRefPtr<CSSMutableStyleDeclaration> copy() const; + + bool setProperty(int propertyID, int value, bool important = false, bool notifyChanged = true); + bool setProperty(int propertyID, const String& value, bool important = false, bool notifyChanged = true); + + String removeProperty(int propertyID, bool notifyChanged = true, bool returnText = false); + + // setLengthProperty treats integers as pixels! (Needed for conversion of HTML attributes.) + void setLengthProperty(int propertyId, const String& value, bool important, bool multiLength = false); + void setStringProperty(int propertyId, const String& value, CSSPrimitiveValue::UnitTypes, bool important = false); // parsed string value + void setImageProperty(int propertyId, const String& url, bool important = false); + + // The following parses an entire new style declaration. + void parseDeclaration(const String& styleDeclaration); + + // Besides adding the properties, this also removes any existing properties with these IDs. + // It does no notification since it's called by the parser. + void addParsedProperties(const CSSProperty* const *, int numProperties); + // This does no change notifications since it's only called by createMarkup. + void addParsedProperty(const CSSProperty&); + + PassRefPtr<CSSMutableStyleDeclaration> copyBlockProperties() const; + void removeBlockProperties(); + void removePropertiesInSet(const int* set, unsigned length, bool notifyChanged = true); + + void merge(const CSSMutableStyleDeclaration*, bool argOverridesOnConflict = true); + + void setStrictParsing(bool b) { m_strictParsing = b; } + bool useStrictParsing() const { return m_strictParsing; } + + void addSubresourceStyleURLs(ListHashSet<KURL>&); + +protected: + CSSMutableStyleDeclaration(CSSRule* parentRule); + +private: + CSSMutableStyleDeclaration(); + CSSMutableStyleDeclaration(CSSRule* parentRule, const Vector<CSSProperty>&); + CSSMutableStyleDeclaration(CSSRule* parentRule, const CSSProperty* const *, int numProperties); + + virtual PassRefPtr<CSSMutableStyleDeclaration> makeMutable(); + + void setNeedsStyleRecalc(); + + String getShorthandValue(const int* properties, int number) const; + String getCommonValue(const int* properties, int number) const; + String getLayeredShorthandValue(const int* properties, unsigned number) const; + String get4Values(const int* properties) const; + + void setPropertyInternal(const CSSProperty&, CSSProperty* slot = 0); + bool removeShorthandProperty(int propertyID, bool notifyChanged); + + Vector<CSSProperty>::const_iterator findPropertyWithId(int propertyId) const; + Vector<CSSProperty>::iterator findPropertyWithId(int propertyId); + + Vector<CSSProperty, 4> m_properties; + + Node* m_node; + bool m_strictParsing : 1; +#ifndef NDEBUG + unsigned m_iteratorCount : 4; +#endif + + friend class CSSMutableStyleDeclarationConstIterator; +}; + +inline CSSMutableStyleDeclarationConstIterator::CSSMutableStyleDeclarationConstIterator(const CSSMutableStyleDeclaration* decl, CSSProperty* current) +: m_decl(decl) +, m_current(current) +{ +#ifndef NDEBUG + const_cast<CSSMutableStyleDeclaration*>(m_decl)->m_iteratorCount++; +#endif +} + +inline CSSMutableStyleDeclarationConstIterator::CSSMutableStyleDeclarationConstIterator(const CSSMutableStyleDeclarationConstIterator& o) +: m_decl(o.m_decl) +, m_current(o.m_current) +{ +#ifndef NDEBUG + const_cast<CSSMutableStyleDeclaration*>(m_decl)->m_iteratorCount++; +#endif +} + +inline CSSMutableStyleDeclarationConstIterator::~CSSMutableStyleDeclarationConstIterator() +{ +#ifndef NDEBUG + const_cast<CSSMutableStyleDeclaration*>(m_decl)->m_iteratorCount--; +#endif +} + +inline CSSMutableStyleDeclarationConstIterator& CSSMutableStyleDeclarationConstIterator::operator=(const CSSMutableStyleDeclarationConstIterator& o) +{ + m_decl = o.m_decl; + m_current = o.m_current; +#ifndef NDEBUG + const_cast<CSSMutableStyleDeclaration*>(m_decl)->m_iteratorCount++; +#endif + return *this; +} + +inline CSSMutableStyleDeclarationConstIterator& CSSMutableStyleDeclarationConstIterator::operator++() +{ + ASSERT(m_current != const_cast<CSSMutableStyleDeclaration*>(m_decl)->m_properties.end()); + ++m_current; + return *this; +} + +inline CSSMutableStyleDeclarationConstIterator& CSSMutableStyleDeclarationConstIterator::operator--() +{ + --m_current; + return *this; +} + +} // namespace WebCore + +#endif // CSSMutableStyleDeclaration_h diff --git a/Source/WebCore/css/CSSNamespace.h b/Source/WebCore/css/CSSNamespace.h new file mode 100644 index 0000000..6225c36 --- /dev/null +++ b/Source/WebCore/css/CSSNamespace.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * Copyright (C) 2004, 2006, 2010 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. + */ + +#ifndef CSSNamespace_h +#define CSSNamespace_h + +#include <wtf/text/AtomicString.h> + +namespace WebCore { + + struct CSSNamespace : Noncopyable { + AtomicString prefix; + AtomicString uri; + OwnPtr<CSSNamespace> parent; + + CSSNamespace(const AtomicString& prefix, const AtomicString& uri, PassOwnPtr<CSSNamespace> parent) + : prefix(prefix) + , uri(uri) + , parent(parent) + { + } + + CSSNamespace* namespaceForPrefix(const AtomicString& prefix) + { + for (CSSNamespace* candidate = this; candidate; candidate = candidate->parent.get()) { + if (candidate->prefix == prefix) + return candidate; + } + return 0; + } + }; + +} // namespace WebCore + +#endif // CSSNamespace_h diff --git a/Source/WebCore/css/CSSOMUtils.cpp b/Source/WebCore/css/CSSOMUtils.cpp new file mode 100644 index 0000000..d1e9638 --- /dev/null +++ b/Source/WebCore/css/CSSOMUtils.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSOMUtils.h" + +#include "PlatformString.h" + +namespace WebCore { + +static void appendCharacter(UChar32 c, Vector<UChar>& appendTo) +{ + if (U16_LENGTH(c) == 1) + appendTo.append(static_cast<UChar>(c)); + else { + appendTo.append(U16_LEAD(c)); + appendTo.append(U16_TRAIL(c)); + } +} + +void serializeCharacter(UChar32 c, Vector<UChar>& appendTo) +{ + appendTo.append('\\'); + appendCharacter(c, appendTo); +} + +void serializeCharacterAsCodePoint(UChar32 c, Vector<UChar>& appendTo) +{ + append(appendTo, String::format("\\%x ", c)); +} + +void serializeIdentifier(const String& identifier, String& appendTo) +{ + Vector<UChar> addend; + serializeIdentifier(identifier, addend); + appendTo.append(String::adopt(addend)); +} + +void serializeIdentifier(const String& identifier, Vector<UChar>& appendTo) +{ + bool isFirst = true; + bool isSecond = false; + bool isFirstCharHyphen = false; + unsigned index = 0; + while (index < identifier.length()) { + UChar32 c = identifier.characterStartingAt(index); + index += U16_LENGTH(c); + + if (c <= 0x1f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen)))) + serializeCharacterAsCodePoint(c, appendTo); + else if (c == 0x2d && isSecond && isFirstCharHyphen) + serializeCharacter(c, appendTo); + else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a)) + appendCharacter(c, appendTo); + else + serializeCharacter(c, appendTo); + + if (isFirst) { + isFirst = false; + isSecond = true; + isFirstCharHyphen = (c == 0x2d); + } else if (isSecond) { + isSecond = false; + } + } +} + +void serializeString(const String& string, String& appendTo) +{ + Vector<UChar> addend; + serializeString(string, addend); + appendTo.append(String::adopt(addend)); +} + +void serializeString(const String& string, Vector<UChar>& appendTo) +{ + appendTo.append('\"'); + + unsigned index = 0; + while (index < string.length()) { + UChar32 c = string.characterStartingAt(index); + index += U16_LENGTH(c); + if (c <= 0x1f) + serializeCharacterAsCodePoint(c, appendTo); + else if (c == 0x22 || c == 0x5c) + serializeCharacter(c, appendTo); + else + appendCharacter(c, appendTo); + } + + appendTo.append('\"'); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSOMUtils.h b/Source/WebCore/css/CSSOMUtils.h new file mode 100644 index 0000000..749cb25 --- /dev/null +++ b/Source/WebCore/css/CSSOMUtils.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSOMUtils_h +#define CSSOMUtils_h + +#include <wtf/Forward.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +// Utilities for CSSOM http://dev.w3.org/csswg/cssom/ + +namespace WebCore { + +// Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms +void serializeCharacter(UChar32, Vector<UChar>& appendTo); +void serializeCharacterAsCodePoint(UChar32, Vector<UChar>& appendTo); +void serializeIdentifier(const String& identifier, String& appendTo); +void serializeIdentifier(const String& identifier, Vector<UChar>& appendTo); +void serializeString(const String& string, String& appendTo); +void serializeString(const String& string, Vector<UChar>& appendTo); + +} // namespace WebCore + +#endif // CSSOMUtils_h diff --git a/Source/WebCore/css/CSSPageRule.cpp b/Source/WebCore/css/CSSPageRule.cpp new file mode 100644 index 0000000..c85c1aa --- /dev/null +++ b/Source/WebCore/css/CSSPageRule.cpp @@ -0,0 +1,54 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006, 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 "CSSPageRule.h" + +#include "CSSMutableStyleDeclaration.h" +#include <wtf/Vector.h> + +namespace WebCore { + +CSSPageRule::CSSPageRule(CSSStyleSheet* parent, CSSSelector* selector, int sourceLine) + : CSSStyleRule(parent, sourceLine) +{ + Vector<CSSSelector*> selectors; + selectors.append(selector); + adoptSelectorVector(selectors); +} + +CSSPageRule::~CSSPageRule() +{ +} + +String CSSPageRule::selectorText() const +{ + String text = "@page"; + CSSSelector* selector = selectorList().first(); + if (selector) { + String pageSpecification = selector->selectorText(); + if (!pageSpecification.isEmpty() && pageSpecification != starAtom) + text += " " + pageSpecification; + } + return text; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSPageRule.h b/Source/WebCore/css/CSSPageRule.h new file mode 100644 index 0000000..bdfb751 --- /dev/null +++ b/Source/WebCore/css/CSSPageRule.h @@ -0,0 +1,57 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSPageRule_h +#define CSSPageRule_h + +#include "CSSStyleRule.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; +class CSSSelector; +class CSSSelectorList; + +class CSSPageRule : public CSSStyleRule { +public: + static PassRefPtr<CSSPageRule> create(CSSStyleSheet* parent, CSSSelector* selector, int sourceLine) + { + return adoptRef(new CSSPageRule(parent, selector, sourceLine)); + } + + virtual ~CSSPageRule(); + + virtual String selectorText() const; + +private: + CSSPageRule(CSSStyleSheet* parent, CSSSelector* selector, int sourceLine); + + virtual bool isPageRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return PAGE_RULE; } +}; + +} // namespace WebCore + +#endif // CSSPageRule_h diff --git a/Source/WebCore/css/CSSPageRule.idl b/Source/WebCore/css/CSSPageRule.idl new file mode 100644 index 0000000..709222b --- /dev/null +++ b/Source/WebCore/css/CSSPageRule.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [CustomMarkFunction] CSSPageRule : CSSRule { + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString selectorText; + + readonly attribute CSSStyleDeclaration style; + + }; + +} diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp new file mode 100644 index 0000000..abc9300 --- /dev/null +++ b/Source/WebCore/css/CSSParser.cpp @@ -0,0 +1,6441 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * 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 "CSSParser.h" + +#include "CSSBorderImageValue.h" +#include "CSSCanvasValue.h" +#include "CSSCharsetRule.h" +#include "CSSCursorImageValue.h" +#include "CSSFontFaceRule.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSGradientValue.h" +#include "CSSImageValue.h" +#include "CSSImportRule.h" +#include "CSSInheritedValue.h" +#include "CSSInitialValue.h" +#include "CSSMediaRule.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPageRule.h" +#include "CSSPrimitiveValue.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSPropertySourceData.h" +#include "CSSQuirkPrimitiveValue.h" +#include "CSSReflectValue.h" +#include "CSSRuleList.h" +#include "CSSSelector.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSTimingFunctionValue.h" +#include "CSSUnicodeRangeValue.h" +#include "CSSValueKeywords.h" +#include "CSSValueList.h" +#include "Counter.h" +#include "Document.h" +#include "FloatConversion.h" +#include "FontFamilyValue.h" +#include "FontValue.h" +#include "HTMLParserIdioms.h" +#include "HashTools.h" +#include "MediaList.h" +#include "MediaQueryExp.h" +#include "Pair.h" +#include "Rect.h" +#include "ShadowValue.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSTransformValue.h" +#include <limits.h> +#include <wtf/dtoa.h> +#include <wtf/text/StringBuffer.h> + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +#define YYDEBUG 0 + +#if YYDEBUG > 0 +extern int cssyydebug; +#endif + +extern int cssyyparse(void* parser); + +using namespace std; +using namespace WTF; + +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif + +namespace WebCore { + +static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; + +static bool equal(const CSSParserString& a, const char* b) +{ + for (int i = 0; i < a.length; ++i) { + if (!b[i]) + return false; + if (a.characters[i] != b[i]) + return false; + } + return !b[a.length]; +} + +static bool equalIgnoringCase(const CSSParserString& a, const char* b) +{ + for (int i = 0; i < a.length; ++i) { + if (!b[i]) + return false; + ASSERT(!isASCIIUpper(b[i])); + if (toASCIILower(a.characters[i]) != b[i]) + return false; + } + return !b[a.length]; +} + +static bool hasPrefix(const char* string, unsigned length, const char* prefix) +{ + for (unsigned i = 0; i < length; ++i) { + if (!prefix[i]) + return true; + if (string[i] != prefix[i]) + return false; + } + return false; +} + +static int clampToSignedInteger(double d) +{ + const double minIntAsDouble = std::numeric_limits<int>::min(); + const double maxIntAsDouble = std::numeric_limits<int>::max(); + return static_cast<int>(max(minIntAsDouble, min(d, maxIntAsDouble))); +} + +CSSParser::CSSParser(bool strictParsing) + : m_strict(strictParsing) + , m_important(false) + , m_id(0) + , m_styleSheet(0) + , m_valueList(0) + , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*)))) + , m_numParsedProperties(0) + , m_maxParsedProperties(32) + , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES) + , m_inParseShorthand(0) + , m_currentShorthand(0) + , m_implicitShorthand(false) + , m_hasFontFaceOnlyValues(false) + , m_hadSyntacticallyValidCSSRule(false) + , m_defaultNamespace(starAtom) + , m_inStyleRuleOrDeclaration(false) + , m_selectorListRange(0, 0) + , m_ruleBodyRange(0, 0) + , m_propertyRange(UINT_MAX, UINT_MAX) + , m_ruleRangeMap(0) + , m_currentRuleData(0) + , m_data(0) + , yy_start(1) + , m_lineNumber(0) + , m_lastSelectorLineNumber(0) + , m_allowImportRules(true) + , m_allowNamespaceDeclarations(true) +{ +#if YYDEBUG > 0 + cssyydebug = 1; +#endif + CSSPropertySourceData::init(); +} + +CSSParser::~CSSParser() +{ + clearProperties(); + fastFree(m_parsedProperties); + + delete m_valueList; + + fastFree(m_data); + + fastDeleteAllValues(m_floatingSelectors); + deleteAllValues(m_floatingValueLists); + deleteAllValues(m_floatingFunctions); + deleteAllValues(m_reusableSelectorVector); +} + +void CSSParserString::lower() +{ + // FIXME: If we need Unicode lowercasing here, then we probably want the real kind + // that can potentially change the length of the string rather than the character + // by character kind. If we don't need Unicode lowercasing, it would be good to + // simplify this function. + + if (charactersAreAllASCII(characters, length)) { + // Fast case for all-ASCII. + for (int i = 0; i < length; i++) + characters[i] = toASCIILower(characters[i]); + } else { + for (int i = 0; i < length; i++) + characters[i] = Unicode::toLower(characters[i]); + } +} + +void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix) +{ + int length = string.length() + strlen(prefix) + strlen(suffix) + 2; + + fastFree(m_data); + m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar))); + for (unsigned i = 0; i < strlen(prefix); i++) + m_data[i] = prefix[i]; + + memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar)); + + unsigned start = strlen(prefix) + string.length(); + unsigned end = start + strlen(suffix); + for (unsigned i = start; i < end; i++) + m_data[i] = suffix[i - start]; + + m_data[length - 1] = 0; + m_data[length - 2] = 0; + + yy_hold_char = 0; + yyleng = 0; + yytext = yy_c_buf_p = m_data; + yy_hold_char = *yy_c_buf_p; + resetRuleBodyMarks(); +} + +void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRangeMap* ruleRangeMap) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + m_styleSheet = sheet; + m_defaultNamespace = starAtom; // Reset the default namespace. + m_ruleRangeMap = ruleRangeMap; + if (ruleRangeMap) { + m_currentRuleData = CSSRuleSourceData::create(); + m_currentRuleData->styleSourceData = CSSStyleSourceData::create(); + } + + m_lineNumber = startLineNumber; + setupParser("", string, ""); + cssyyparse(this); + m_ruleRangeMap = 0; + m_currentRuleData = 0; + m_rule = 0; +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif +} + +PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + m_styleSheet = sheet; + m_allowNamespaceDeclarations = false; + setupParser("@-webkit-rule{", string, "} "); + cssyyparse(this); +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return m_rule.release(); +} + +PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + m_styleSheet = sheet; + setupParser("@-webkit-keyframe-rule{ ", string, "} "); + cssyyparse(this); +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return m_keyframe.release(); +} + +bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); + m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); + + setupParser("@-webkit-value{", string, "} "); + + m_id = id; + m_important = important; + + cssyyparse(this); + + m_rule = 0; + + bool ok = false; + if (m_hasFontFaceOnlyValues) + deleteFontFaceOnlyValues(); + if (m_numParsedProperties) { + ok = true; + declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties); + clearProperties(); + } + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return ok; +} + +// color will only be changed when string contains a valid css color, making it +// possible to set up a default color. +bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) +{ + // First try creating a color specified by name, rgba(), rgb() or "#" syntax. + if (parseColor(string, color, strict)) + return true; + + CSSParser parser(true); + RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create(); + + // Now try to create a color from rgba() syntax. + if (!parser.parseColor(dummyStyleDeclaration.get(), string)) + return false; + + CSSValue* value = parser.m_parsedProperties[0]->value(); + if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + color = primitiveValue->getRGBA32Value(); + } + + return true; +} + +bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); + m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); + + setupParser("@-webkit-decls{color:", string, "} "); + cssyyparse(this); + m_rule = 0; + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor); +} + +void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc); + + m_styleSheet = dummyStyleSheet.get(); + m_selectorListForParseSelector = &selectorList; + + setupParser("@-webkit-selector{", string, "}"); + + cssyyparse(this); + + m_selectorListForParseSelector = 0; + + // The style sheet will be deleted right away, so it won't outlive the document. + ASSERT(dummyStyleSheet->hasOneRef()); + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif +} + +bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string, RefPtr<CSSStyleSourceData>* styleSourceData) +{ +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + + // Length of the "@-webkit-decls{" prefix. + static const unsigned prefixLength = 15; + + ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); + m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet()); + if (styleSourceData) { + m_currentRuleData = CSSRuleSourceData::create(); + m_currentRuleData->styleSourceData = CSSStyleSourceData::create(); + m_inStyleRuleOrDeclaration = true; + } + + setupParser("@-webkit-decls{", string, "} "); + cssyyparse(this); + m_rule = 0; + + bool ok = false; + if (m_hasFontFaceOnlyValues) + deleteFontFaceOnlyValues(); + if (m_numParsedProperties) { + ok = true; + declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties); + clearProperties(); + } + + if (m_currentRuleData) { + m_currentRuleData->styleSourceData->styleBodyRange.start = 0; + m_currentRuleData->styleSourceData->styleBodyRange.end = string.length(); + for (Vector<CSSPropertySourceData>::iterator it = m_currentRuleData->styleSourceData->propertyData.begin(), endIt = m_currentRuleData->styleSourceData->propertyData.end(); it != endIt; ++it) { + (*it).range.start -= prefixLength; + (*it).range.end -= prefixLength; + } + } + + if (styleSourceData) { + *styleSourceData = m_currentRuleData->styleSourceData.release(); + m_currentRuleData = 0; + m_inStyleRuleOrDeclaration = false; + } +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return ok; +} + +bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) +{ + if (string.isEmpty()) + return true; + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); +#endif + ASSERT(!m_mediaQuery); + + // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token. + // instead insert one " " (which is WHITESPACE in CSSGrammar.y) + setupParser("@-webkit-mediaquery ", string, "} "); + cssyyparse(this); + + bool ok = false; + if (m_mediaQuery) { + ok = true; + queries->appendMediaQuery(m_mediaQuery.release()); + } + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); +#endif + return ok; +} + + +void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important) +{ + OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand)); + if (m_numParsedProperties >= m_maxParsedProperties) { + m_maxParsedProperties += 32; + if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*)) + return; + m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties, + m_maxParsedProperties * sizeof(CSSProperty*))); + } + m_parsedProperties[m_numParsedProperties++] = prop.leakPtr(); +} + +void CSSParser::rollbackLastProperties(int num) +{ + ASSERT(num >= 0); + ASSERT(m_numParsedProperties >= static_cast<unsigned>(num)); + + for (int i = 0; i < num; ++i) + delete m_parsedProperties[--m_numParsedProperties]; +} + +void CSSParser::clearProperties() +{ + for (unsigned i = 0; i < m_numParsedProperties; i++) + delete m_parsedProperties[i]; + m_numParsedProperties = 0; + m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; + m_hasFontFaceOnlyValues = false; +} + +Document* CSSParser::document() const +{ + StyleBase* root = m_styleSheet; + while (root && root->parent()) + root = root->parent(); + if (!root) + return 0; + if (!root->isCSSStyleSheet()) + return 0; + return static_cast<CSSStyleSheet*>(root)->document(); +} + +bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict) +{ + bool b = false; + switch (value->unit) { + case CSSPrimitiveValue::CSS_NUMBER: + b = (unitflags & FNumber); + if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) { + value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX : + ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS); + b = true; + } + if (!b && (unitflags & FInteger) && value->isInt) + b = true; + break; + case CSSPrimitiveValue::CSS_PERCENTAGE: + b = (unitflags & FPercent); + break; + case CSSParserValue::Q_EMS: + case CSSPrimitiveValue::CSS_EMS: + case CSSPrimitiveValue::CSS_REMS: + case CSSPrimitiveValue::CSS_EXS: + case CSSPrimitiveValue::CSS_PX: + case CSSPrimitiveValue::CSS_CM: + case CSSPrimitiveValue::CSS_MM: + case CSSPrimitiveValue::CSS_IN: + case CSSPrimitiveValue::CSS_PT: + case CSSPrimitiveValue::CSS_PC: + b = (unitflags & FLength); + break; + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + b = (unitflags & FTime); + break; + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: + b = (unitflags & FAngle); + break; + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + case CSSPrimitiveValue::CSS_DIMENSION: + default: + break; + } + if (b && unitflags & FNonNeg && value->fValue < 0) + b = false; + return b; +} + +static int unitFromString(CSSParserValue* value) +{ + if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id) + return 0; + + if (equal(value->string, "em")) + return CSSPrimitiveValue::CSS_EMS; + if (equal(value->string, "rem")) + return CSSPrimitiveValue::CSS_REMS; + if (equal(value->string, "ex")) + return CSSPrimitiveValue::CSS_EXS; + if (equal(value->string, "px")) + return CSSPrimitiveValue::CSS_PX; + if (equal(value->string, "cm")) + return CSSPrimitiveValue::CSS_CM; + if (equal(value->string, "mm")) + return CSSPrimitiveValue::CSS_MM; + if (equal(value->string, "in")) + return CSSPrimitiveValue::CSS_IN; + if (equal(value->string, "pt")) + return CSSPrimitiveValue::CSS_PT; + if (equal(value->string, "pc")) + return CSSPrimitiveValue::CSS_PC; + if (equal(value->string, "deg")) + return CSSPrimitiveValue::CSS_DEG; + if (equal(value->string, "rad")) + return CSSPrimitiveValue::CSS_RAD; + if (equal(value->string, "grad")) + return CSSPrimitiveValue::CSS_GRAD; + if (equal(value->string, "turn")) + return CSSPrimitiveValue::CSS_TURN; + if (equal(value->string, "ms")) + return CSSPrimitiveValue::CSS_MS; + if (equal(value->string, "s")) + return CSSPrimitiveValue::CSS_S; + if (equal(value->string, "Hz")) + return CSSPrimitiveValue::CSS_HZ; + if (equal(value->string, "kHz")) + return CSSPrimitiveValue::CSS_KHZ; + + return 0; +} + +void CSSParser::checkForOrphanedUnits() +{ + if (m_strict || inShorthand()) + return; + + // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values + // by whitespace, so e.g., width: 20 px instead of width:20px. This is invalid CSS, so we don't do this in strict mode. + CSSParserValue* numericVal = 0; + unsigned size = m_valueList->size(); + for (unsigned i = 0; i < size; i++) { + CSSParserValue* value = m_valueList->valueAt(i); + + if (numericVal) { + // Change the unit type of the numeric val to match. + int unit = unitFromString(value); + if (unit) { + numericVal->unit = unit; + numericVal = 0; + + // Now delete the bogus unit value. + m_valueList->deleteValueAt(i); + i--; // We're safe even though |i| is unsigned, since we only hit this code if we had a previous numeric value (so |i| is always > 0 here). + size--; + continue; + } + } + + numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0; + } +} + +bool CSSParser::parseValue(int propId, bool important) +{ + if (!m_valueList) + return false; + + CSSParserValue* value = m_valueList->current(); + + if (!value) + return false; + + int id = value->id; + + // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to + // by a space. We go ahead and associate the unit with the number even though it is invalid CSS. + checkForOrphanedUnits(); + + int num = inShorthand() ? 1 : m_valueList->size(); + + if (id == CSSValueInherit) { + if (num != 1) + return false; + addProperty(propId, CSSInheritedValue::create(), important); + return true; + } + else if (id == CSSValueInitial) { + if (num != 1) + return false; + addProperty(propId, CSSInitialValue::createExplicit(), important); + return true; + } + + bool validPrimitive = false; + RefPtr<CSSValue> parsedValue; + + switch (static_cast<CSSPropertyID>(propId)) { + /* The comment to the left defines all valid value of this properties as defined + * in CSS 2, Appendix F. Property index + */ + + /* All the CSS properties are not supported by the renderer at the moment. + * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined + * (see parseAuralValues). As we don't support them at all this seems reasonable. + */ + + case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ] + return parseSize(propId, important); + + case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit + if (id) + validPrimitive = true; + break; + case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | inherit + if (id == CSSValueNormal || + id == CSSValueEmbed || + id == CSSValueBidiOverride) + validPrimitive = true; + break; + + case CSSPropertyPosition: // static | relative | absolute | fixed | inherit + if (id == CSSValueStatic || + id == CSSValueRelative || + id == CSSValueAbsolute || + id == CSSValueFixed) + validPrimitive = true; + break; + + case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit + case CSSPropertyPageBreakBefore: + case CSSPropertyWebkitColumnBreakAfter: + case CSSPropertyWebkitColumnBreakBefore: + if (id == CSSValueAuto || + id == CSSValueAlways || + id == CSSValueAvoid || + id == CSSValueLeft || + id == CSSValueRight) + validPrimitive = true; + break; + + case CSSPropertyPageBreakInside: // avoid | auto | inherit + case CSSPropertyWebkitColumnBreakInside: + if (id == CSSValueAuto || id == CSSValueAvoid) + validPrimitive = true; + break; + + case CSSPropertyEmptyCells: // show | hide | inherit + if (id == CSSValueShow || + id == CSSValueHide) + validPrimitive = true; + break; + + case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote | + // close-quote | no-open-quote | no-close-quote ]+ | inherit + return parseContent(propId, important); + + case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit + if (id == CSSValueNormal || + id == CSSValuePre || + id == CSSValuePreWrap || + id == CSSValuePreLine || + id == CSSValueNowrap) + validPrimitive = true; + break; + + case CSSPropertyClip: // <shape> | auto | inherit + if (id == CSSValueAuto) + validPrimitive = true; + else if (value->unit == CSSParserValue::Function) + return parseShape(propId, important); + break; + + /* Start of supported CSS properties with validation. This is needed for parseShorthand to work + * correctly and allows optimization in WebCore::applyRule(..) + */ + case CSSPropertyCaptionSide: // top | bottom | left | right | inherit + if (id == CSSValueLeft || id == CSSValueRight || + id == CSSValueTop || id == CSSValueBottom) + validPrimitive = true; + break; + + case CSSPropertyBorderCollapse: // collapse | separate | inherit + if (id == CSSValueCollapse || id == CSSValueSeparate) + validPrimitive = true; + break; + + case CSSPropertyVisibility: // visible | hidden | collapse | inherit + if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse) + validPrimitive = true; + break; + + case CSSPropertyOverflow: { + ShorthandScope scope(this, propId); + if (num != 1 || !parseValue(CSSPropertyOverflowX, important)) + return false; + CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value(); + addProperty(CSSPropertyOverflowY, value, important); + return true; + } + case CSSPropertyOverflowX: + case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit + if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto || + id == CSSValueOverlay || id == CSSValueWebkitMarquee) + validPrimitive = true; + break; + + case CSSPropertyListStylePosition: // inside | outside | inherit + if (id == CSSValueInside || id == CSSValueOutside) + validPrimitive = true; + break; + + case CSSPropertyListStyleType: + // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in + // for the list of supported list-style-types. + if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone) + validPrimitive = true; + break; + + case CSSPropertyDisplay: + // inline | block | list-item | run-in | inline-block | table | + // inline-table | table-row-group | table-header-group | table-footer-group | table-row | + // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit +#if ENABLE(WCSS) + if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone) +#else + if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone) +#endif + validPrimitive = true; + break; + + case CSSPropertyDirection: // ltr | rtl | inherit + if (id == CSSValueLtr || id == CSSValueRtl) + validPrimitive = true; + break; + + case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit + if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone) + validPrimitive = true; + break; + + case CSSPropertyFloat: // left | right | none | inherit + center for buggy CSS + if (id == CSSValueLeft || id == CSSValueRight || + id == CSSValueNone || id == CSSValueCenter) + validPrimitive = true; + break; + + case CSSPropertyClear: // none | left | right | both | inherit + if (id == CSSValueNone || id == CSSValueLeft || + id == CSSValueRight|| id == CSSValueBoth) + validPrimitive = true; + break; + + case CSSPropertyTextAlign: + // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit + if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd || + value->unit == CSSPrimitiveValue::CSS_STRING) + validPrimitive = true; + break; + + case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit + if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble)) + validPrimitive = true; + break; + + case CSSPropertyBorderTopStyle: //// <border-style> | inherit + case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed | + case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset + case CSSPropertyBorderLeftStyle: + case CSSPropertyWebkitBorderStartStyle: + case CSSPropertyWebkitBorderEndStyle: + case CSSPropertyWebkitBorderBeforeStyle: + case CSSPropertyWebkitBorderAfterStyle: + case CSSPropertyWebkitColumnRuleStyle: + if (id >= CSSValueNone && id <= CSSValueDouble) + validPrimitive = true; + break; + + case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit + return parseFontWeight(important); + + case CSSPropertyBorderSpacing: { + const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing, + CSSPropertyWebkitBorderVerticalSpacing }; + if (num == 1) { + ShorthandScope scope(this, CSSPropertyBorderSpacing); + if (!parseValue(properties[0], important)) + return false; + CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value(); + addProperty(properties[1], value, important); + return true; + } + else if (num == 2) { + ShorthandScope scope(this, CSSPropertyBorderSpacing); + if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) + return false; + return true; + } + return false; + } + case CSSPropertyWebkitBorderHorizontalSpacing: + case CSSPropertyWebkitBorderVerticalSpacing: + validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); + break; + case CSSPropertyOutlineColor: // <color> | invert | inherit + // Outline color has "invert" as additional keyword. + // Also, we want to allow the special focus color even in strict parsing mode. + if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) { + validPrimitive = true; + break; + } + /* nobreak */ + case CSSPropertyBackgroundColor: // <color> | inherit + case CSSPropertyBorderTopColor: // <color> | inherit + case CSSPropertyBorderRightColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyWebkitBorderStartColor: + case CSSPropertyWebkitBorderEndColor: + case CSSPropertyWebkitBorderBeforeColor: + case CSSPropertyWebkitBorderAfterColor: + case CSSPropertyColor: // <color> | inherit + case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors + case CSSPropertyTextUnderlineColor: + case CSSPropertyTextOverlineColor: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextFillColor: + case CSSPropertyWebkitTextStrokeColor: + if (id == CSSValueWebkitText) + validPrimitive = true; // Always allow this, even when strict parsing is on, + // since we use this in our UA sheets. + else if (id == CSSValueCurrentcolor) + validPrimitive = true; + else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || + (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) { + validPrimitive = true; + } else { + parsedValue = parseColor(); + if (parsedValue) + m_valueList->next(); + } + break; + + case CSSPropertyCursor: { + // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize | + // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize | + // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help | + // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in + // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit + RefPtr<CSSValueList> list; + while (value && value->unit == CSSPrimitiveValue::CSS_URI) { + if (!list) + list = CSSValueList::createCommaSeparated(); + String uri = value->string; + Vector<int> coords; + value = m_valueList->next(); + while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) { + coords.append(int(value->fValue)); + value = m_valueList->next(); + } + IntPoint hotSpot(-1, -1); + int nrcoords = coords.size(); + if (nrcoords > 0 && nrcoords != 2) + return false; + if (nrcoords == 2) + hotSpot = IntPoint(coords[0], coords[1]); + + if (!uri.isNull() && m_styleSheet) { + // FIXME: The completeURL call should be done when using the CSSCursorImageValue, + // not when creating it. + list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot)); + } + + if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ','))) + return false; + value = m_valueList->next(); // comma + } + if (list) { + if (!value) { // no value after url list (MSIE 5 compatibility) + if (list->length() != 1) + return false; + } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/ + list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer)); + else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)) + list->append(CSSPrimitiveValue::createIdentifier(value->id)); + m_valueList->next(); + parsedValue = list.release(); + break; + } + id = value->id; + if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/ + id = CSSValuePointer; + validPrimitive = true; + } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone) + validPrimitive = true; + break; + } + + case CSSPropertyBackgroundAttachment: + case CSSPropertyBackgroundClip: + case CSSPropertyWebkitBackgroundClip: + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyBackgroundImage: + case CSSPropertyBackgroundOrigin: + case CSSPropertyWebkitBackgroundOrigin: + case CSSPropertyBackgroundPosition: + case CSSPropertyBackgroundPositionX: + case CSSPropertyBackgroundPositionY: + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyBackgroundRepeat: + case CSSPropertyBackgroundRepeatX: + case CSSPropertyBackgroundRepeatY: + case CSSPropertyWebkitMaskAttachment: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskComposite: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskOrigin: + case CSSPropertyWebkitMaskPosition: + case CSSPropertyWebkitMaskPositionX: + case CSSPropertyWebkitMaskPositionY: + case CSSPropertyWebkitMaskSize: + case CSSPropertyWebkitMaskRepeat: + case CSSPropertyWebkitMaskRepeatX: + case CSSPropertyWebkitMaskRepeatY: { + RefPtr<CSSValue> val1; + RefPtr<CSSValue> val2; + int propId1, propId2; + bool result = false; + if (parseFillProperty(propId, propId1, propId2, val1, val2)) { + OwnPtr<ShorthandScope> shorthandScope; + if (propId == CSSPropertyBackgroundPosition || + propId == CSSPropertyBackgroundRepeat || + propId == CSSPropertyWebkitMaskPosition || + propId == CSSPropertyWebkitMaskRepeat) { + shorthandScope.set(new ShorthandScope(this, propId)); + } + addProperty(propId1, val1.release(), important); + if (val2) + addProperty(propId2, val2.release(), important); + result = true; + } + m_implicitShorthand = false; + return result; + } + case CSSPropertyListStyleImage: // <uri> | none | inherit + if (id == CSSValueNone) { + parsedValue = CSSImageValue::create(); + m_valueList->next(); + } else if (value->unit == CSSPrimitiveValue::CSS_URI) { + if (m_styleSheet) { + // FIXME: The completeURL call should be done when using the CSSImageValue, + // not when creating it. + parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string)); + m_valueList->next(); + } + } else if (isGeneratedImageValue(value)) { + if (parseGeneratedImage(parsedValue)) + m_valueList->next(); + else + return false; + } + break; + + case CSSPropertyWebkitTextStrokeWidth: + case CSSPropertyOutlineWidth: // <border-width> | inherit + case CSSPropertyBorderTopWidth: //// <border-width> | inherit + case CSSPropertyBorderRightWidth: // Which is defined as + case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length> + case CSSPropertyBorderLeftWidth: + case CSSPropertyWebkitBorderStartWidth: + case CSSPropertyWebkitBorderEndWidth: + case CSSPropertyWebkitBorderBeforeWidth: + case CSSPropertyWebkitBorderAfterWidth: + case CSSPropertyWebkitColumnRuleWidth: + if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) + validPrimitive = true; + else + validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); + break; + + case CSSPropertyLetterSpacing: // normal | <length> | inherit + case CSSPropertyWordSpacing: // normal | <length> | inherit + if (id == CSSValueNormal) + validPrimitive = true; + else + validPrimitive = validUnit(value, FLength, m_strict); + break; + + case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension) + if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord) + validPrimitive = true; + break; + + case CSSPropertyWordWrap: // normal | break-word + if (id == CSSValueNormal || id == CSSValueBreakWord) + validPrimitive = true; + break; + case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit + if (id == CSSValueNone || id == CSSValueNormal || id == CSSValueSpellOut || id == CSSValueDigits + || id == CSSValueLiteralPunctuation || id == CSSValueNoPunctuation) + validPrimitive = true; + break; + + case CSSPropertyTextIndent: // <length> | <percentage> | inherit + validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); + break; + + case CSSPropertyPaddingTop: //// <padding-width> | inherit + case CSSPropertyPaddingRight: // Which is defined as + case CSSPropertyPaddingBottom: // <length> | <percentage> + case CSSPropertyPaddingLeft: //// + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitPaddingAfter: + validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); + break; + + case CSSPropertyMaxHeight: // <length> | <percentage> | none | inherit + case CSSPropertyMaxWidth: // <length> | <percentage> | none | inherit + case CSSPropertyWebkitMaxLogicalWidth: + case CSSPropertyWebkitMaxLogicalHeight: + if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) { + validPrimitive = true; + break; + } + /* nobreak */ + case CSSPropertyMinHeight: // <length> | <percentage> | inherit + case CSSPropertyMinWidth: // <length> | <percentage> | inherit + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) + validPrimitive = true; + else + validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); + break; + + case CSSPropertyFontSize: + // <absolute-size> | <relative-size> | <length> | <percentage> | inherit + if (id >= CSSValueXxSmall && id <= CSSValueLarger) + validPrimitive = true; + else + validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict)); + break; + + case CSSPropertyFontStyle: // normal | italic | oblique | inherit + return parseFontStyle(important); + + case CSSPropertyFontVariant: // normal | small-caps | inherit + return parseFontVariant(important); + + case CSSPropertyVerticalAlign: + // baseline | sub | super | top | text-top | middle | bottom | text-bottom | + // <percentage> | <length> | inherit + + if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) + validPrimitive = true; + else + validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); + break; + + case CSSPropertyHeight: // <length> | <percentage> | auto | inherit + case CSSPropertyWidth: // <length> | <percentage> | auto | inherit + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) + validPrimitive = true; + else + // ### handle multilength case where we allow relative units + validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)); + break; + + case CSSPropertyBottom: // <length> | <percentage> | auto | inherit + case CSSPropertyLeft: // <length> | <percentage> | auto | inherit + case CSSPropertyRight: // <length> | <percentage> | auto | inherit + case CSSPropertyTop: // <length> | <percentage> | auto | inherit + case CSSPropertyMarginTop: //// <margin-width> | inherit + case CSSPropertyMarginRight: // Which is defined as + case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit + case CSSPropertyMarginLeft: //// + case CSSPropertyWebkitMarginStart: + case CSSPropertyWebkitMarginEnd: + case CSSPropertyWebkitMarginBefore: + case CSSPropertyWebkitMarginAfter: + if (id == CSSValueAuto) + validPrimitive = true; + else + validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict)); + break; + + case CSSPropertyZIndex: // auto | <integer> | inherit + if (id == CSSValueAuto) { + validPrimitive = true; + break; + } + /* nobreak */ + case CSSPropertyOrphans: // <integer> | inherit + case CSSPropertyWidows: // <integer> | inherit + // ### not supported later on + validPrimitive = (!id && validUnit(value, FInteger, false)); + break; + + case CSSPropertyLineHeight: // normal | <number> | <length> | <percentage> | inherit + if (id == CSSValueNormal) + validPrimitive = true; + else + validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)); + break; + case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit + if (id != CSSValueNone) + return parseCounter(propId, 1, important); + validPrimitive = true; + break; + case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit + if (id != CSSValueNone) + return parseCounter(propId, 0, important); + validPrimitive = true; + break; + case CSSPropertyFontFamily: + // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit + { + parsedValue = parseFontFamily(); + break; + } + + case CSSPropertyTextDecoration: + case CSSPropertyWebkitTextDecorationsInEffect: + // none | [ underline || overline || line-through || blink ] | inherit + if (id == CSSValueNone) { + validPrimitive = true; + } else { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + bool isValid = true; + while (isValid && value) { + switch (value->id) { + case CSSValueBlink: + break; + case CSSValueUnderline: + case CSSValueOverline: + case CSSValueLineThrough: + list->append(CSSPrimitiveValue::createIdentifier(value->id)); + break; + default: + isValid = false; + } + value = m_valueList->next(); + } + if (list->length() && isValid) { + parsedValue = list.release(); + m_valueList->next(); + } + } + break; + + case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit + if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument) + validPrimitive = true; + else + validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true)); + break; + + case CSSPropertyTableLayout: // auto | fixed | inherit + if (id == CSSValueAuto || id == CSSValueFixed) + validPrimitive = true; + break; + + case CSSPropertySrc: // Only used within @font-face, so cannot use inherit | initial or be !important. This is a list of urls or local references. + return parseFontFaceSrc(); + + case CSSPropertyUnicodeRange: + return parseFontFaceUnicodeRange(); + + /* CSS3 properties */ + case CSSPropertyWebkitAppearance: + if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone) + validPrimitive = true; + break; + + case CSSPropertyWebkitBorderImage: + case CSSPropertyWebkitMaskBoxImage: + if (id == CSSValueNone) + validPrimitive = true; + else { + RefPtr<CSSValue> result; + if (parseBorderImage(propId, important, result)) { + addProperty(propId, result, important); + return true; + } + } + break; + case CSSPropertyBorderTopRightRadius: + case CSSPropertyBorderTopLeftRadius: + case CSSPropertyBorderBottomLeftRadius: + case CSSPropertyBorderBottomRightRadius: { + if (num != 1 && num != 2) + return false; + validPrimitive = validUnit(value, FLength | FPercent, m_strict); + if (!validPrimitive) + return false; + RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + RefPtr<CSSPrimitiveValue> parsedValue2; + if (num == 2) { + value = m_valueList->next(); + validPrimitive = validUnit(value, FLength | FPercent, m_strict); + if (!validPrimitive) + return false; + parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + } else + parsedValue2 = parsedValue1; + + RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release()); + RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release()); + addProperty(propId, val.release(), important); + return true; + } + case CSSPropertyBorderRadius: + case CSSPropertyWebkitBorderRadius: + return parseBorderRadius(propId, important); + case CSSPropertyOutlineOffset: + validPrimitive = validUnit(value, FLength | FPercent, m_strict); + break; + case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3 + case CSSPropertyBoxShadow: + case CSSPropertyWebkitBoxShadow: + if (id == CSSValueNone) + validPrimitive = true; + else + return parseShadow(propId, important); + break; + case CSSPropertyWebkitBoxReflect: + if (id == CSSValueNone) + validPrimitive = true; + else + return parseReflect(propId, important); + break; + case CSSPropertyOpacity: + validPrimitive = validUnit(value, FNumber, m_strict); + break; + case CSSPropertyWebkitBoxAlign: + if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd || + id == CSSValueCenter || id == CSSValueBaseline) + validPrimitive = true; + break; + case CSSPropertyWebkitBoxDirection: + if (id == CSSValueNormal || id == CSSValueReverse) + validPrimitive = true; + break; + case CSSPropertyWebkitBoxLines: + if (id == CSSValueSingle || id == CSSValueMultiple) + validPrimitive = true; + break; + case CSSPropertyWebkitBoxOrient: + if (id == CSSValueHorizontal || id == CSSValueVertical || + id == CSSValueInlineAxis || id == CSSValueBlockAxis) + validPrimitive = true; + break; + case CSSPropertyWebkitBoxPack: + if (id == CSSValueStart || id == CSSValueEnd || + id == CSSValueCenter || id == CSSValueJustify) + validPrimitive = true; + break; + case CSSPropertyWebkitBoxFlex: + validPrimitive = validUnit(value, FNumber, m_strict); + break; + case CSSPropertyWebkitBoxFlexGroup: + case CSSPropertyWebkitBoxOrdinalGroup: + validPrimitive = validUnit(value, FInteger | FNonNeg, true); + break; + case CSSPropertyBoxSizing: + validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox; + break; + case CSSPropertyWebkitColorCorrection: + validPrimitive = id == CSSValueSrgb || id == CSSValueDefault; + break; + case CSSPropertyWebkitMarquee: { + const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement, + CSSPropertyWebkitMarqueeRepetition, + CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed }; + return parseShorthand(propId, properties, 5, important); + } + case CSSPropertyWebkitMarqueeDirection: + if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead || + id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown || + id == CSSValueUp || id == CSSValueAuto) + validPrimitive = true; + break; + case CSSPropertyWebkitMarqueeIncrement: + if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium) + validPrimitive = true; + else + validPrimitive = validUnit(value, FLength | FPercent, m_strict); + break; + case CSSPropertyWebkitMarqueeStyle: + if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate) + validPrimitive = true; + break; + case CSSPropertyWebkitMarqueeRepetition: + if (id == CSSValueInfinite) + validPrimitive = true; + else + validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict); + break; + case CSSPropertyWebkitMarqueeSpeed: + if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) + validPrimitive = true; + else + validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict); + break; +#if ENABLE(WCSS) + case CSSPropertyWapMarqueeDir: + if (id == CSSValueLtr || id == CSSValueRtl) + validPrimitive = true; + break; + case CSSPropertyWapMarqueeStyle: + if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate) + validPrimitive = true; + break; + case CSSPropertyWapMarqueeLoop: + if (id == CSSValueInfinite) + validPrimitive = true; + else + validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict); + break; + case CSSPropertyWapMarqueeSpeed: + if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) + validPrimitive = true; + else + validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict); + break; +#endif + case CSSPropertyWebkitUserDrag: // auto | none | element + if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement) + validPrimitive = true; + break; + case CSSPropertyWebkitUserModify: // read-only | read-write + if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly) + validPrimitive = true; + break; + case CSSPropertyWebkitUserSelect: // auto | none | text + if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText) + validPrimitive = true; + break; + case CSSPropertyTextOverflow: // clip | ellipsis + if (id == CSSValueClip || id == CSSValueEllipsis) + validPrimitive = true; + break; + case CSSPropertyWebkitTransform: + if (id == CSSValueNone) + validPrimitive = true; + else { + PassRefPtr<CSSValue> val = parseTransform(); + if (val) { + addProperty(propId, val, important); + return true; + } + return false; + } + break; + case CSSPropertyWebkitTransformOrigin: + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: { + RefPtr<CSSValue> val1; + RefPtr<CSSValue> val2; + RefPtr<CSSValue> val3; + int propId1, propId2, propId3; + if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) { + addProperty(propId1, val1.release(), important); + if (val2) + addProperty(propId2, val2.release(), important); + if (val3) + addProperty(propId3, val3.release(), important); + return true; + } + return false; + } + case CSSPropertyWebkitTransformStyle: + if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d) + validPrimitive = true; + break; + case CSSPropertyWebkitBackfaceVisibility: + if (value->id == CSSValueVisible || value->id == CSSValueHidden) + validPrimitive = true; + break; + case CSSPropertyWebkitPerspective: + if (id == CSSValueNone) + validPrimitive = true; + else { + // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property. + if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) { + RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + if (val) { + addProperty(propId, val.release(), important); + return true; + } + return false; + } + } + break; + case CSSPropertyWebkitPerspectiveOrigin: + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: { + RefPtr<CSSValue> val1; + RefPtr<CSSValue> val2; + int propId1, propId2; + if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) { + addProperty(propId1, val1.release(), important); + if (val2) + addProperty(propId2, val2.release(), important); + return true; + } + return false; + } + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitAnimationDirection: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitAnimationFillMode: + case CSSPropertyWebkitAnimationName: + case CSSPropertyWebkitAnimationPlayState: + case CSSPropertyWebkitAnimationIterationCount: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitTransitionDelay: + case CSSPropertyWebkitTransitionDuration: + case CSSPropertyWebkitTransitionTimingFunction: + case CSSPropertyWebkitTransitionProperty: { + RefPtr<CSSValue> val; + if (parseAnimationProperty(propId, val)) { + addProperty(propId, val.release(), important); + return true; + } + return false; + } + case CSSPropertyWebkitMarginCollapse: { + const int properties[2] = { CSSPropertyWebkitMarginBeforeCollapse, + CSSPropertyWebkitMarginAfterCollapse }; + if (num == 1) { + ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); + if (!parseValue(properties[0], important)) + return false; + CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value(); + addProperty(properties[1], value, important); + return true; + } + else if (num == 2) { + ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); + if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) + return false; + return true; + } + return false; + } + case CSSPropertyWebkitMarginBeforeCollapse: + case CSSPropertyWebkitMarginAfterCollapse: + case CSSPropertyWebkitMarginTopCollapse: + case CSSPropertyWebkitMarginBottomCollapse: + if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard) + validPrimitive = true; + break; + case CSSPropertyTextLineThroughMode: + case CSSPropertyTextOverlineMode: + case CSSPropertyTextUnderlineMode: + if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace) + validPrimitive = true; + break; + case CSSPropertyTextLineThroughStyle: + case CSSPropertyTextOverlineStyle: + case CSSPropertyTextUnderlineStyle: + if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble || + id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash || + id == CSSValueWave) + validPrimitive = true; + break; + case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision + if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility + || id == CSSValueGeometricprecision) + validPrimitive = true; + break; + case CSSPropertyTextLineThroughWidth: + case CSSPropertyTextOverlineWidth: + case CSSPropertyTextUnderlineWidth: + if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin || + id == CSSValueMedium || id == CSSValueThick) + validPrimitive = true; + else + validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict); + break; + case CSSPropertyResize: // none | both | horizontal | vertical | auto + if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto) + validPrimitive = true; + break; + case CSSPropertyWebkitColumnCount: + if (id == CSSValueAuto) + validPrimitive = true; + else + validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false); + break; + case CSSPropertyWebkitColumnGap: // normal | <length> + if (id == CSSValueNormal) + validPrimitive = true; + else + validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); + break; + case CSSPropertyWebkitColumnSpan: // all | 1 + if (id == CSSValueAll) + validPrimitive = true; + else + validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1; + break; + case CSSPropertyWebkitColumnWidth: // auto | <length> + if (id == CSSValueAuto) + validPrimitive = true; + else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property. + validPrimitive = validUnit(value, FLength, true); + break; + case CSSPropertyPointerEvents: + // none | visiblePainted | visibleFill | visibleStroke | visible | + // painted | fill | stroke | auto | all | inherit + if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto || + (id >= CSSValueVisiblepainted && id <= CSSValueStroke)) + validPrimitive = true; + break; + + // End of CSS3 properties + + // Apple specific properties. These will never be standardized and are purely to + // support custom WebKit-based Apple applications. + case CSSPropertyWebkitLineClamp: + // When specifying number of lines, don't allow 0 as a valid value + // When specifying either type of unit, require non-negative integers + validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false)); + break; + case CSSPropertyWebkitTextSizeAdjust: + if (id == CSSValueAuto || id == CSSValueNone) + validPrimitive = true; + break; + case CSSPropertyWebkitRtlOrdering: + if (id == CSSValueLogical || id == CSSValueVisual) + validPrimitive = true; + break; + + case CSSPropertyWebkitFontSizeDelta: // <length> + validPrimitive = validUnit(value, FLength, m_strict); + break; + + case CSSPropertyWebkitNbspMode: // normal | space + if (id == CSSValueNormal || id == CSSValueSpace) + validPrimitive = true; + break; + + case CSSPropertyWebkitLineBreak: // normal | after-white-space + if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace) + validPrimitive = true; + break; + + case CSSPropertyWebkitMatchNearestMailBlockquoteColor: // normal | match + if (id == CSSValueNormal || id == CSSValueMatch) + validPrimitive = true; + break; + + case CSSPropertyWebkitHighlight: + if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING) + validPrimitive = true; + break; + + case CSSPropertyWebkitHyphens: + if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto) + validPrimitive = true; + break; + + case CSSPropertyWebkitHyphenateCharacter: + if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) + validPrimitive = true; + break; + + case CSSPropertyWebkitHyphenateLocale: + if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) + validPrimitive = true; + break; + + case CSSPropertyWebkitBorderFit: + if (id == CSSValueBorder || id == CSSValueLines) + validPrimitive = true; + break; + + case CSSPropertyWebkitTextSecurity: + // disc | circle | square | none | inherit + if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone) + validPrimitive = true; + break; + + case CSSPropertyWebkitFontSmoothing: + if (id == CSSValueAuto || id == CSSValueNone + || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased) + validPrimitive = true; + break; + +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region> + if (value->unit == CSSParserValue::Function || id == CSSValueNone) + return parseDashboardRegions(propId, important); + break; +#endif + // End Apple-specific properties + + /* shorthand properties */ + case CSSPropertyBackground: { + // Position must come before color in this array because a plain old "0" is a legal color + // in quirks mode but it's usually the X coordinate of a position. + // FIXME: Add CSSPropertyBackgroundSize to the shorthand. + const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, + CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin, + CSSPropertyBackgroundColor }; + return parseFillShorthand(propId, properties, 6, important); + } + case CSSPropertyWebkitMask: { + const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, + CSSPropertyWebkitMaskOrigin }; + return parseFillShorthand(propId, properties, 5, important); + } + case CSSPropertyBorder: + // [ 'border-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, + CSSPropertyBorderColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyBorderTop: + // [ 'border-top-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, + CSSPropertyBorderTopColor}; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyBorderRight: + // [ 'border-right-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, + CSSPropertyBorderRightColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyBorderBottom: + // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, + CSSPropertyBorderBottomColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyBorderLeft: + // [ 'border-left-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, + CSSPropertyBorderLeftColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitBorderStart: + { + const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle, + CSSPropertyWebkitBorderStartColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitBorderEnd: + { + const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle, + CSSPropertyWebkitBorderEndColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitBorderBefore: + { + const int properties[3] = { CSSPropertyWebkitBorderBeforeWidth, CSSPropertyWebkitBorderBeforeStyle, + CSSPropertyWebkitBorderBeforeColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitBorderAfter: + { + const int properties[3] = { CSSPropertyWebkitBorderAfterWidth, CSSPropertyWebkitBorderAfterStyle, + CSSPropertyWebkitBorderAfterColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyOutline: + // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit + { + const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle, + CSSPropertyOutlineColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyBorderColor: + // <color>{1,4} | inherit + { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, + CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return parse4Values(propId, properties, important); + } + case CSSPropertyBorderWidth: + // <border-width>{1,4} | inherit + { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, + CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return parse4Values(propId, properties, important); + } + case CSSPropertyBorderStyle: + // <border-style>{1,4} | inherit + { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, + CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return parse4Values(propId, properties, important); + } + case CSSPropertyMargin: + // <margin-width>{1,4} | inherit + { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, + CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return parse4Values(propId, properties, important); + } + case CSSPropertyPadding: + // <padding-width>{1,4} | inherit + { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, + CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return parse4Values(propId, properties, important); + } + case CSSPropertyFont: + // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? + // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit + if (id >= CSSValueCaption && id <= CSSValueStatusBar) + validPrimitive = true; + else + return parseFont(important); + break; + case CSSPropertyListStyle: + { + const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition, + CSSPropertyListStyleImage }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitColumns: { + const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount }; + return parseShorthand(propId, properties, 2, important); + } + case CSSPropertyWebkitColumnRule: { + const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleColor }; + return parseShorthand(propId, properties, 3, important); + } + case CSSPropertyWebkitTextStroke: { + const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor }; + return parseShorthand(propId, properties, 2, important); + } + case CSSPropertyWebkitAnimation: + return parseAnimationShorthand(important); + case CSSPropertyWebkitTransition: + return parseTransitionShorthand(important); + case CSSPropertyInvalid: + return false; + case CSSPropertyPage: + return parsePage(propId, important); + case CSSPropertyFontStretch: + case CSSPropertyTextLineThrough: + case CSSPropertyTextOverline: + case CSSPropertyTextUnderline: + return false; + +#if ENABLE(WCSS) + case CSSPropertyWapInputFormat: + validPrimitive = true; + break; + case CSSPropertyWapInputRequired: + parsedValue = parseWCSSInputProperty(); + break; +#endif + + // CSS Text Layout Module Level 3: Vertical writing support + case CSSPropertyWebkitWritingMode: + if (id >= CSSValueHorizontalTb && id <= CSSValueHorizontalBt) + validPrimitive = true; + break; + + case CSSPropertyWebkitTextCombine: + if (id == CSSValueNone || id == CSSValueHorizontal) + validPrimitive = true; + break; + + case CSSPropertyWebkitTextEmphasis: { + const int properties[] = { CSSPropertyWebkitTextEmphasisStyle, CSSPropertyWebkitTextEmphasisColor }; + return parseShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); + } + + case CSSPropertyWebkitTextEmphasisPosition: + if (id == CSSValueOver || id == CSSValueUnder) + validPrimitive = true; + break; + + case CSSPropertyWebkitTextEmphasisStyle: + return parseTextEmphasisStyle(important); + +#ifdef ANDROID_CSS_RING + case CSSPropertyWebkitRing: + { + const int properties[9] = { CSSPropertyWebkitRingFillColor, + CSSPropertyWebkitRingInnerWidth, + CSSPropertyWebkitRingOuterWidth, + CSSPropertyWebkitRingOutset, + CSSPropertyWebkitRingPressedInnerColor, + CSSPropertyWebkitRingPressedOuterColor, + CSSPropertyWebkitRingRadius, + CSSPropertyWebkitRingSelectedInnerColor, + CSSPropertyWebkitRingSelectedOuterColor }; + return parseShorthand(propId, properties, 9, important); + } + case CSSPropertyWebkitRingFillColor: + case CSSPropertyWebkitRingPressedInnerColor: + case CSSPropertyWebkitRingPressedOuterColor: + case CSSPropertyWebkitRingSelectedInnerColor: + case CSSPropertyWebkitRingSelectedOuterColor: + parsedValue = parseColor(); + if (parsedValue) + m_valueList->next(); + break; + case CSSPropertyWebkitRingInnerWidth: + case CSSPropertyWebkitRingOuterWidth: + case CSSPropertyWebkitRingOutset: + case CSSPropertyWebkitRingRadius: + validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); + break; +#endif +#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR + case CSSPropertyWebkitTapHighlightColor: + parsedValue = parseColor(); + if (parsedValue) + m_valueList->next(); + break; +#endif + +#if ENABLE(SVG) + default: + return parseSVGValue(propId, important); +#endif + } + + if (validPrimitive) { + if (id != 0) + parsedValue = CSSPrimitiveValue::createIdentifier(id); + else if (value->unit == CSSPrimitiveValue::CSS_STRING) + parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) + parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS) + parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSParserValue::Q_EMS) + parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS); + m_valueList->next(); + } + if (parsedValue) { + if (!m_valueList->current() || inShorthand()) { + addProperty(propId, parsedValue.release(), important); + return true; + } + } + return false; +} + +#if ENABLE(WCSS) +PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty() +{ + RefPtr<CSSValue> parsedValue = 0; + CSSParserValue* value = m_valueList->current(); + String inputProperty; + if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) + inputProperty = String(value->string); + + if (!inputProperty.isEmpty()) + parsedValue = CSSPrimitiveValue::create(inputProperty, CSSPrimitiveValue::CSS_STRING); + + while (m_valueList->next()) { + // pass all other values, if any. If we don't do this, + // the parser will think that it's not done and won't process this property + } + + return parsedValue; +} +#endif + +void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) +{ + if (lval) { + if (lval->isValueList()) + static_cast<CSSValueList*>(lval.get())->append(rval); + else { + PassRefPtr<CSSValue> oldlVal(lval.release()); + PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + list->append(oldlVal); + list->append(rval); + lval = list; + } + } + else + lval = rval; +} + +static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue) +{ + if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox || parserValue->id == CSSValueWebkitText) { + cssValue = CSSPrimitiveValue::createIdentifier(parserValue->id); + return true; + } + return false; +} + +const int cMaxFillProperties = 9; + +bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important) +{ + ASSERT(numProperties <= cMaxFillProperties); + if (numProperties > cMaxFillProperties) + return false; + + ShorthandScope scope(this, propId); + + bool parsedProperty[cMaxFillProperties] = { false }; + RefPtr<CSSValue> values[cMaxFillProperties]; + RefPtr<CSSValue> clipValue; + RefPtr<CSSValue> positionYValue; + RefPtr<CSSValue> repeatYValue; + int i; + + while (m_valueList->current()) { + CSSParserValue* val = m_valueList->current(); + if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + // We hit the end. Fill in all remaining values with the initial value. + m_valueList->next(); + for (i = 0; i < numProperties; ++i) { + if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i]) + // Color is not allowed except as the last item in a list for backgrounds. + // Reject the entire property. + return false; + + if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) { + addFillValue(values[i], CSSInitialValue::createImplicit()); + if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) + addFillValue(positionYValue, CSSInitialValue::createImplicit()); + if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) + addFillValue(repeatYValue, CSSInitialValue::createImplicit()); + if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { + // If background-origin wasn't present, then reset background-clip also. + addFillValue(clipValue, CSSInitialValue::createImplicit()); + } + } + parsedProperty[i] = false; + } + if (!m_valueList->current()) + break; + } + + bool found = false; + for (i = 0; !found && i < numProperties; ++i) { + if (!parsedProperty[i]) { + RefPtr<CSSValue> val1; + RefPtr<CSSValue> val2; + int propId1, propId2; + CSSParserValue* parserValue = m_valueList->current(); + if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) { + parsedProperty[i] = found = true; + addFillValue(values[i], val1.release()); + if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) + addFillValue(positionYValue, val2.release()); + if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) + addFillValue(repeatYValue, val2.release()); + if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) { + // Reparse the value as a clip, and see if we succeed. + if (parseBackgroundClip(parserValue, val1)) + addFillValue(clipValue, val1.release()); // The property parsed successfully. + else + addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead. + } + } + } + } + + // if we didn't find at least one match, this is an + // invalid shorthand and we have to ignore it + if (!found) + return false; + } + + // Fill in any remaining properties with the initial value. + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) { + addFillValue(values[i], CSSInitialValue::createImplicit()); + if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) + addFillValue(positionYValue, CSSInitialValue::createImplicit()); + if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) + addFillValue(repeatYValue, CSSInitialValue::createImplicit()); + if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { + // If background-origin wasn't present, then reset background-clip also. + addFillValue(clipValue, CSSInitialValue::createImplicit()); + } + } + } + + // Now add all of the properties we found. + for (i = 0; i < numProperties; i++) { + if (properties[i] == CSSPropertyBackgroundPosition) { + addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important); + // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once + addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important); + } else if (properties[i] == CSSPropertyWebkitMaskPosition) { + addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important); + // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once + addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important); + } else if (properties[i] == CSSPropertyBackgroundRepeat) { + addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important); + // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once + addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important); + } else if (properties[i] == CSSPropertyWebkitMaskRepeat) { + addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important); + // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once + addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important); + } else + addProperty(properties[i], values[i].release(), important); + + // Add in clip values when we hit the corresponding origin property. + if (properties[i] == CSSPropertyBackgroundOrigin) + addProperty(CSSPropertyBackgroundClip, clipValue.release(), important); + else if (properties[i] == CSSPropertyWebkitMaskOrigin) + addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important); + } + + return true; +} + +void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval) +{ + if (lval) { + if (lval->isValueList()) + static_cast<CSSValueList*>(lval.get())->append(rval); + else { + PassRefPtr<CSSValue> oldVal(lval.release()); + PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + list->append(oldVal); + list->append(rval); + lval = list; + } + } + else + lval = rval; +} + +bool CSSParser::parseAnimationShorthand(bool important) +{ + const int properties[] = { CSSPropertyWebkitAnimationName, + CSSPropertyWebkitAnimationDuration, + CSSPropertyWebkitAnimationTimingFunction, + CSSPropertyWebkitAnimationDelay, + CSSPropertyWebkitAnimationIterationCount, + CSSPropertyWebkitAnimationDirection, + CSSPropertyWebkitAnimationFillMode }; + const int numProperties = WTF_ARRAY_LENGTH(properties); + + ShorthandScope scope(this, CSSPropertyWebkitAnimation); + + bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary + RefPtr<CSSValue> values[numProperties]; + + int i; + while (m_valueList->current()) { + CSSParserValue* val = m_valueList->current(); + if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + // We hit the end. Fill in all remaining values with the initial value. + m_valueList->next(); + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) + addAnimationValue(values[i], CSSInitialValue::createImplicit()); + parsedProperty[i] = false; + } + if (!m_valueList->current()) + break; + } + + bool found = false; + for (i = 0; !found && i < numProperties; ++i) { + if (!parsedProperty[i]) { + RefPtr<CSSValue> val; + if (parseAnimationProperty(properties[i], val)) { + parsedProperty[i] = found = true; + addAnimationValue(values[i], val.release()); + } + } + } + + // if we didn't find at least one match, this is an + // invalid shorthand and we have to ignore it + if (!found) + return false; + } + + // Fill in any remaining properties with the initial value. + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) + addAnimationValue(values[i], CSSInitialValue::createImplicit()); + } + + // Now add all of the properties we found. + for (i = 0; i < numProperties; i++) + addProperty(properties[i], values[i].release(), important); + + return true; +} + +bool CSSParser::parseTransitionShorthand(bool important) +{ + const int properties[] = { CSSPropertyWebkitTransitionProperty, + CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionTimingFunction, + CSSPropertyWebkitTransitionDelay }; + const int numProperties = WTF_ARRAY_LENGTH(properties); + + ShorthandScope scope(this, CSSPropertyWebkitTransition); + + bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary + RefPtr<CSSValue> values[numProperties]; + + int i; + while (m_valueList->current()) { + CSSParserValue* val = m_valueList->current(); + if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + // We hit the end. Fill in all remaining values with the initial value. + m_valueList->next(); + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) + addAnimationValue(values[i], CSSInitialValue::createImplicit()); + parsedProperty[i] = false; + } + if (!m_valueList->current()) + break; + } + + bool found = false; + for (i = 0; !found && i < numProperties; ++i) { + if (!parsedProperty[i]) { + RefPtr<CSSValue> val; + if (parseAnimationProperty(properties[i], val)) { + parsedProperty[i] = found = true; + addAnimationValue(values[i], val.release()); + } + } + } + + // if we didn't find at least one match, this is an + // invalid shorthand and we have to ignore it + if (!found) + return false; + } + + // Fill in any remaining properties with the initial value. + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) + addAnimationValue(values[i], CSSInitialValue::createImplicit()); + } + + // Now add all of the properties we found. + for (i = 0; i < numProperties; i++) + addProperty(properties[i], values[i].release(), important); + + return true; +} + +bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important) +{ + // We try to match as many properties as possible + // We set up an array of booleans to mark which property has been found, + // and we try to search for properties until it makes no longer any sense. + ShorthandScope scope(this, propId); + + bool found = false; + bool fnd[6]; // Trust me ;) + for (int i = 0; i < numProperties; i++) + fnd[i] = false; + + while (m_valueList->current()) { + found = false; + for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) { + if (!fnd[propIndex]) { + if (parseValue(properties[propIndex], important)) + fnd[propIndex] = found = true; + } + } + + // if we didn't find at least one match, this is an + // invalid shorthand and we have to ignore it + if (!found) + return false; + } + + // Fill in any remaining properties with the initial value. + m_implicitShorthand = true; + for (int i = 0; i < numProperties; ++i) { + if (!fnd[i]) + addProperty(properties[i], CSSInitialValue::createImplicit(), important); + } + m_implicitShorthand = false; + + return true; +} + +bool CSSParser::parse4Values(int propId, const int *properties, bool important) +{ + /* From the CSS 2 specs, 8.3 + * If there is only one value, it applies to all sides. If there are two values, the top and + * bottom margins are set to the first value and the right and left margins are set to the second. + * If there are three values, the top is set to the first value, the left and right are set to the + * second, and the bottom is set to the third. If there are four values, they apply to the top, + * right, bottom, and left, respectively. + */ + + int num = inShorthand() ? 1 : m_valueList->size(); + + ShorthandScope scope(this, propId); + + // the order is top, right, bottom, left + switch (num) { + case 1: { + if (!parseValue(properties[0], important)) + return false; + CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value(); + m_implicitShorthand = true; + addProperty(properties[1], value, important); + addProperty(properties[2], value, important); + addProperty(properties[3], value, important); + m_implicitShorthand = false; + break; + } + case 2: { + if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) + return false; + CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value(); + m_implicitShorthand = true; + addProperty(properties[2], value, important); + value = m_parsedProperties[m_numParsedProperties-2]->value(); + addProperty(properties[3], value, important); + m_implicitShorthand = false; + break; + } + case 3: { + if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important)) + return false; + CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value(); + m_implicitShorthand = true; + addProperty(properties[3], value, important); + m_implicitShorthand = false; + break; + } + case 4: { + if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || + !parseValue(properties[2], important) || !parseValue(properties[3], important)) + return false; + break; + } + default: { + return false; + } + } + + return true; +} + +// auto | <identifier> +bool CSSParser::parsePage(int propId, bool important) +{ + ASSERT(propId == CSSPropertyPage); + + if (m_valueList->size() != 1) + return false; + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + if (value->id == CSSValueAuto) { + addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important); + return true; + } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) { + addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING), important); + return true; + } + return false; +} + +// <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ] +bool CSSParser::parseSize(int propId, bool important) +{ + ASSERT(propId == CSSPropertySize); + + if (m_valueList->size() > 2) + return false; + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); + + // First parameter. + SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None); + if (paramType == None) + return false; + + // Second parameter, if any. + value = m_valueList->next(); + if (value) { + paramType = parseSizeParameter(parsedValues.get(), value, paramType); + if (paramType == None) + return false; + } + + addProperty(propId, parsedValues.release(), important); + return true; +} + +CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType) +{ + switch (value->id) { + case CSSValueAuto: + if (prevParamType == None) { + parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id)); + return Auto; + } + return None; + case CSSValueLandscape: + case CSSValuePortrait: + if (prevParamType == None || prevParamType == PageSize) { + parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id)); + return Orientation; + } + return None; + case CSSValueA3: + case CSSValueA4: + case CSSValueA5: + case CSSValueB4: + case CSSValueB5: + case CSSValueLedger: + case CSSValueLegal: + case CSSValueLetter: + if (prevParamType == None || prevParamType == Orientation) { + // Normalize to Page Size then Orientation order by prepending. + // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty). + parsedValues->prepend(CSSPrimitiveValue::createIdentifier(value->id)); + return PageSize; + } + return None; + case 0: + if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) { + parsedValues->append(CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit))); + return Length; + } + return None; + default: + return None; + } +} + +// [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit +// in CSS 2.1 this got somewhat reduced: +// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit +bool CSSParser::parseContent(int propId, bool important) +{ + RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); + + while (CSSParserValue* val = m_valueList->current()) { + RefPtr<CSSValue> parsedValue; + if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { + // url + // FIXME: The completeURL call should be done when using the CSSImageValue, + // not when creating it. + parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string)); + } else if (val->unit == CSSParserValue::Function) { + // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...) + CSSParserValueList* args = val->function->args.get(); + if (!args) + return false; + if (equalIgnoringCase(val->function->name, "attr(")) { + parsedValue = parseAttr(args); + if (!parsedValue) + return false; + } else if (equalIgnoringCase(val->function->name, "counter(")) { + parsedValue = parseCounterContent(args, false); + if (!parsedValue) + return false; + } else if (equalIgnoringCase(val->function->name, "counters(")) { + parsedValue = parseCounterContent(args, true); + if (!parsedValue) + return false; + } else if (isGeneratedImageValue(val)) { + if (!parseGeneratedImage(parsedValue)) + return false; + } else + return false; + } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) { + // open-quote + // close-quote + // no-open-quote + // no-close-quote + // inherit + // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503). + // none + // normal + switch (val->id) { + case CSSValueOpenQuote: + case CSSValueCloseQuote: + case CSSValueNoOpenQuote: + case CSSValueNoCloseQuote: + case CSSValueNone: + case CSSValueNormal: + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + } + } else if (val->unit == CSSPrimitiveValue::CSS_STRING) { + parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); + } + if (!parsedValue) + break; + values->append(parsedValue.release()); + m_valueList->next(); + } + + if (values->length()) { + addProperty(propId, values.release(), important); + m_valueList->next(); + return true; + } + + return false; +} + +PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args) +{ + if (args->size() != 1) + return 0; + + CSSParserValue* a = args->current(); + + if (a->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + + String attrName = a->string; + // CSS allows identifiers with "-" at the start, like "-webkit-mask-image". + // But HTML attribute names can't have those characters, and we should not + // even parse them inside attr(). + if (attrName[0] == '-') + return 0; + + if (document() && document()->isHTMLDocument()) + attrName = attrName.lower(); + + return CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::CSS_ATTR); +} + +PassRefPtr<CSSValue> CSSParser::parseBackgroundColor() +{ + int id = m_valueList->current()->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor || + (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict)) + return CSSPrimitiveValue::createIdentifier(id); + return parseColor(); +} + +bool CSSParser::parseFillImage(RefPtr<CSSValue>& value) +{ + if (m_valueList->current()->id == CSSValueNone) { + value = CSSImageValue::create(); + return true; + } + if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) { + // FIXME: The completeURL call should be done when using the CSSImageValue, + // not when creating it. + if (m_styleSheet) + value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string)); + return true; + } + + if (isGeneratedImageValue(m_valueList->current())) + return parseGeneratedImage(value); + + return false; +} + +PassRefPtr<CSSValue> CSSParser::parseFillPositionXY(CSSParserValueList* valueList, bool& xFound, bool& yFound) +{ + int id = valueList->current()->id; + if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) { + int percent = 0; + if (id == CSSValueLeft || id == CSSValueRight) { + if (xFound) + return 0; + xFound = true; + if (id == CSSValueRight) + percent = 100; + } + else if (id == CSSValueTop || id == CSSValueBottom) { + if (yFound) + return 0; + yFound = true; + if (id == CSSValueBottom) + percent = 100; + } + else if (id == CSSValueCenter) + // Center is ambiguous, so we're not sure which position we've found yet, an x or a y. + percent = 50; + return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + } + if (validUnit(valueList->current(), FPercent | FLength, m_strict)) + return CSSPrimitiveValue::create(valueList->current()->fValue, + (CSSPrimitiveValue::UnitTypes)valueList->current()->unit); + + return 0; +} + +void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) +{ + CSSParserValue* value = valueList->current(); + + // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length. + bool value1IsX = false, value1IsY = false; + value1 = parseFillPositionXY(valueList, value1IsX, value1IsY); + if (!value1) + return; + + // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we + // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the + // value was explicitly specified for our property. + value = valueList->next(); + + // First check for the comma. If so, we are finished parsing this value or value pair. + if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') + value = 0; + + bool value2IsX = false, value2IsY = false; + if (value) { + value2 = parseFillPositionXY(valueList, value2IsX, value2IsY); + if (value2) + valueList->next(); + else { + if (!inShorthand()) { + value1.clear(); + return; + } + } + } + + if (!value2) + // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position + // is simply 50%. This is our default. + // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center). + // For left/right/center, the default of 50% in the y is still correct. + value2 = CSSPrimitiveValue::create(50, CSSPrimitiveValue::CSS_PERCENTAGE); + + if (value1IsY || value2IsX) + value1.swap(value2); +} + +void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2) +{ + CSSParserValue* value = m_valueList->current(); + + int id = m_valueList->current()->id; + if (id == CSSValueRepeatX) { + m_implicitShorthand = true; + value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat); + value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat); + m_valueList->next(); + return; + } + if (id == CSSValueRepeatY) { + m_implicitShorthand = true; + value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat); + value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat); + m_valueList->next(); + return; + } + if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) + value1 = CSSPrimitiveValue::createIdentifier(id); + else { + value1 = 0; + return; + } + + value = m_valueList->next(); + + // First check for the comma. If so, we are finished parsing this value or value pair. + if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') + value = 0; + + if (value) + id = m_valueList->current()->id; + + if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) { + value2 = CSSPrimitiveValue::createIdentifier(id); + m_valueList->next(); + } else { + // If only one value was specified, value2 is the same as value1. + m_implicitShorthand = true; + value2 = CSSPrimitiveValue::createIdentifier(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent()); + } +} + +PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma) +{ + allowComma = true; + CSSParserValue* value = m_valueList->current(); + + if (value->id == CSSValueContain || value->id == CSSValueCover) + return CSSPrimitiveValue::createIdentifier(value->id); + + RefPtr<CSSPrimitiveValue> parsedValue1; + + if (value->id == CSSValueAuto) + parsedValue1 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); + else { + if (!validUnit(value, FLength | FPercent, m_strict)) + return 0; + parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + } + + CSSPropertyID property = static_cast<CSSPropertyID>(propId); + RefPtr<CSSPrimitiveValue> parsedValue2; + if ((value = m_valueList->next())) { + if (value->id == CSSValueAuto) + parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); + else if (value->unit == CSSParserValue::Operator && value->iValue == ',') + allowComma = false; + else { + if (!validUnit(value, FLength | FPercent, m_strict)) + return 0; + parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + } + } + if (!parsedValue2) { + if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize) + parsedValue2 = parsedValue1; + else + parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN); + } + + return CSSPrimitiveValue::create(Pair::create(parsedValue1.release(), parsedValue2.release())); +} + +bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2, + RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2) +{ + RefPtr<CSSValueList> values; + RefPtr<CSSValueList> values2; + CSSParserValue* val; + RefPtr<CSSValue> value; + RefPtr<CSSValue> value2; + + bool allowComma = false; + + retValue1 = retValue2 = 0; + propId1 = propId; + propId2 = propId; + if (propId == CSSPropertyBackgroundPosition) { + propId1 = CSSPropertyBackgroundPositionX; + propId2 = CSSPropertyBackgroundPositionY; + } else if (propId == CSSPropertyWebkitMaskPosition) { + propId1 = CSSPropertyWebkitMaskPositionX; + propId2 = CSSPropertyWebkitMaskPositionY; + } else if (propId == CSSPropertyBackgroundRepeat) { + propId1 = CSSPropertyBackgroundRepeatX; + propId2 = CSSPropertyBackgroundRepeatY; + } else if (propId == CSSPropertyWebkitMaskRepeat) { + propId1 = CSSPropertyWebkitMaskRepeatX; + propId2 = CSSPropertyWebkitMaskRepeatY; + } + + while ((val = m_valueList->current())) { + RefPtr<CSSValue> currValue; + RefPtr<CSSValue> currValue2; + + if (allowComma) { + if (val->unit != CSSParserValue::Operator || val->iValue != ',') + return false; + m_valueList->next(); + allowComma = false; + } else { + allowComma = true; + switch (propId) { + case CSSPropertyBackgroundColor: + currValue = parseBackgroundColor(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyBackgroundAttachment: + case CSSPropertyWebkitMaskAttachment: + if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) { + currValue = CSSPrimitiveValue::createIdentifier(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundImage: + case CSSPropertyWebkitMaskImage: + if (parseFillImage(currValue)) + m_valueList->next(); + break; + case CSSPropertyWebkitBackgroundClip: + case CSSPropertyWebkitBackgroundOrigin: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskOrigin: + // The first three values here are deprecated and do not apply to the version of the property that has + // the -webkit- prefix removed. + if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent || + val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox || + ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) && + (val->id == CSSValueText || val->id == CSSValueWebkitText))) { + currValue = CSSPrimitiveValue::createIdentifier(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundClip: + if (parseBackgroundClip(val, currValue)) + m_valueList->next(); + break; + case CSSPropertyBackgroundOrigin: + if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { + currValue = CSSPrimitiveValue::createIdentifier(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundPosition: + case CSSPropertyWebkitMaskPosition: + parseFillPosition(m_valueList, currValue, currValue2); + // parseFillPosition advances the m_valueList pointer + break; + case CSSPropertyBackgroundPositionX: + case CSSPropertyWebkitMaskPositionX: { + bool xFound = false, yFound = true; + currValue = parseFillPositionXY(m_valueList, xFound, yFound); + if (currValue) + m_valueList->next(); + break; + } + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: { + bool xFound = true, yFound = false; + currValue = parseFillPositionXY(m_valueList, xFound, yFound); + if (currValue) + m_valueList->next(); + break; + } + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyWebkitMaskComposite: + if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) { + currValue = CSSPrimitiveValue::createIdentifier(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundRepeat: + case CSSPropertyWebkitMaskRepeat: + parseFillRepeat(currValue, currValue2); + // parseFillRepeat advances the m_valueList pointer + break; + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitMaskSize: { + currValue = parseFillSize(propId, allowComma); + if (currValue) + m_valueList->next(); + break; + } + } + if (!currValue) + return false; + + if (value && !values) { + values = CSSValueList::createCommaSeparated(); + values->append(value.release()); + } + + if (value2 && !values2) { + values2 = CSSValueList::createCommaSeparated(); + values2->append(value2.release()); + } + + if (values) + values->append(currValue.release()); + else + value = currValue.release(); + if (currValue2) { + if (values2) + values2->append(currValue2.release()); + else + value2 = currValue2.release(); + } + } + + // When parsing any fill shorthand property, we let it handle building up the lists for all + // properties. + if (inShorthand()) + break; + } + + if (values && values->length()) { + retValue1 = values.release(); + if (values2 && values2->length()) + retValue2 = values2.release(); + return true; + } + if (value) { + retValue1 = value.release(); + retValue2 = value2.release(); + return true; + } + return false; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationDelay() +{ + CSSParserValue* value = m_valueList->current(); + if (validUnit(value, FTime, m_strict)) + return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationDirection() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueNormal || value->id == CSSValueAlternate) + return CSSPrimitiveValue::createIdentifier(value->id); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationDuration() +{ + CSSParserValue* value = m_valueList->current(); + if (validUnit(value, FTime | FNonNeg, m_strict)) + return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth) + return CSSPrimitiveValue::createIdentifier(value->id); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueInfinite) + return CSSPrimitiveValue::createIdentifier(value->id); + if (validUnit(value, FInteger | FNonNeg, m_strict)) + return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationName() +{ + CSSParserValue* value = m_valueList->current(); + if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) { + if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) { + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + } else { + return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING); + } + } + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueRunning || value->id == CSSValuePaused) + return CSSPrimitiveValue::createIdentifier(value->id); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationProperty() +{ + CSSParserValue* value = m_valueList->current(); + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + int result = cssPropertyID(value->string); + if (result) + return CSSPrimitiveValue::createIdentifier(result); + if (equalIgnoringCase(value->string, "all")) + return CSSPrimitiveValue::createIdentifier(CSSValueAll); + if (equalIgnoringCase(value->string, "none")) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + return 0; +} + +bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) +{ + parseFillPosition(m_valueList, value1, value2); + + // now get z + if (m_valueList->current()) { + if (validUnit(m_valueList->current(), FLength, m_strict)) { + value3 = CSSPrimitiveValue::create(m_valueList->current()->fValue, + (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit); + m_valueList->next(); + return true; + } + return false; + } + return true; +} + +bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result) +{ + CSSParserValue* v = args->current(); + if (!validUnit(v, FNumber, m_strict)) + return false; + result = v->fValue; + if (result < 0 || result > 1.0) + return false; + v = args->next(); + if (!v) + // The last number in the function has no comma after it, so we're done. + return true; + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return false; + v = args->next(); + return true; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut + || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd) + return CSSPrimitiveValue::createIdentifier(value->id); + + // We must be a function. + if (value->unit != CSSParserValue::Function) + return 0; + + CSSParserValueList* args = value->function->args.get(); + + if (equalIgnoringCase(value->function->name, "steps(")) { + // For steps, 1 or 2 params must be specified (comma-separated) + if (!args || (args->size() != 1 && args->size() != 3)) + return 0; + + // There are two values. + int numSteps; + bool stepAtStart = false; + + CSSParserValue* v = args->current(); + if (!validUnit(v, FInteger, m_strict)) + return 0; + numSteps = (int) min(v->fValue, (double)INT_MAX); + if (numSteps < 1) + return 0; + v = args->next(); + + if (v) { + // There is a comma so we need to parse the second value + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return 0; + v = args->next(); + if (v->id != CSSValueStart && v->id != CSSValueEnd) + return 0; + stepAtStart = v->id == CSSValueStart; + } + + return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart); + } + + if (equalIgnoringCase(value->function->name, "cubic-bezier(")) { + // For cubic bezier, 4 values must be specified. + if (!args || args->size() != 7) + return 0; + + // There are two points specified. The values must be between 0 and 1. + double x1, y1, x2, y2; + + if (!parseCubicBezierTimingFunctionValue(args, x1)) + return 0; + if (!parseCubicBezierTimingFunctionValue(args, y1)) + return 0; + if (!parseCubicBezierTimingFunctionValue(args, x2)) + return 0; + if (!parseCubicBezierTimingFunctionValue(args, y2)) + return 0; + + return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2); + } + + return 0; +} + +bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result) +{ + RefPtr<CSSValueList> values; + CSSParserValue* val; + RefPtr<CSSValue> value; + bool allowComma = false; + + result = 0; + + while ((val = m_valueList->current())) { + RefPtr<CSSValue> currValue; + if (allowComma) { + if (val->unit != CSSParserValue::Operator || val->iValue != ',') + return false; + m_valueList->next(); + allowComma = false; + } + else { + switch (propId) { + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitTransitionDelay: + currValue = parseAnimationDelay(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationDirection: + currValue = parseAnimationDirection(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitTransitionDuration: + currValue = parseAnimationDuration(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationFillMode: + currValue = parseAnimationFillMode(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationIterationCount: + currValue = parseAnimationIterationCount(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationName: + currValue = parseAnimationName(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationPlayState: + currValue = parseAnimationPlayState(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitTransitionProperty: + currValue = parseAnimationProperty(); + if (currValue) + m_valueList->next(); + break; + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitTransitionTimingFunction: + currValue = parseAnimationTimingFunction(); + if (currValue) + m_valueList->next(); + break; + } + + if (!currValue) + return false; + + if (value && !values) { + values = CSSValueList::createCommaSeparated(); + values->append(value.release()); + } + + if (values) + values->append(currValue.release()); + else + value = currValue.release(); + + allowComma = true; + } + + // When parsing the 'transition' shorthand property, we let it handle building up the lists for all + // properties. + if (inShorthand()) + break; + } + + if (values && values->length()) { + result = values.release(); + return true; + } + if (value) { + result = value.release(); + return true; + } + return false; +} + + + +#if ENABLE(DASHBOARD_SUPPORT) + +#define DASHBOARD_REGION_NUM_PARAMETERS 6 +#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2 + +static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args) +{ + if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) || + args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { + CSSParserValue* current = args->current(); + if (current->unit == CSSParserValue::Operator && current->iValue == ',') + return args->next(); + } + return args->current(); +} + +bool CSSParser::parseDashboardRegions(int propId, bool important) +{ + bool valid = true; + + CSSParserValue* value = m_valueList->current(); + + if (value->id == CSSValueNone) { + if (m_valueList->next()) + return false; + addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important); + return valid; + } + + RefPtr<DashboardRegion> firstRegion = DashboardRegion::create(); + DashboardRegion* region = 0; + + while (value) { + if (region == 0) { + region = firstRegion.get(); + } else { + RefPtr<DashboardRegion> nextRegion = DashboardRegion::create(); + region->m_next = nextRegion; + region = nextRegion.get(); + } + + if (value->unit != CSSParserValue::Function) { + valid = false; + break; + } + + // Commas count as values, so allow: + // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) + // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) + // also allow + // dashboard-region(label, type) or dashboard-region(label type) + // dashboard-region(label, type) or dashboard-region(label type) + CSSParserValueList* args = value->function->args.get(); + if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) { + valid = false; + break; + } + + int numArgs = args->size(); + if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) && + (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) { + valid = false; + break; + } + + // First arg is a label. + CSSParserValue* arg = args->current(); + if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { + valid = false; + break; + } + + region->m_label = arg->string; + + // Second arg is a type. + arg = args->next(); + arg = skipCommaInDashboardRegion(args); + if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { + valid = false; + break; + } + + if (equalIgnoringCase(arg->string, "circle")) + region->m_isCircle = true; + else if (equalIgnoringCase(arg->string, "rectangle")) + region->m_isRectangle = true; + else { + valid = false; + break; + } + + region->m_geometryType = arg->string; + + if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) { + // This originally used CSSValueInvalid by accident. It might be more logical to use something else. + RefPtr<CSSPrimitiveValue> amount = CSSPrimitiveValue::createIdentifier(CSSValueInvalid); + + region->setTop(amount); + region->setRight(amount); + region->setBottom(amount); + region->setLeft(amount); + } else { + // Next four arguments must be offset numbers + int i; + for (i = 0; i < 4; i++) { + arg = args->next(); + arg = skipCommaInDashboardRegion(args); + + valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict); + if (!valid) + break; + + RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ? + CSSPrimitiveValue::createIdentifier(CSSValueAuto) : + CSSPrimitiveValue::create(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit); + + if (i == 0) + region->setTop(amount); + else if (i == 1) + region->setRight(amount); + else if (i == 2) + region->setBottom(amount); + else + region->setLeft(amount); + } + } + + if (args->next()) + return false; + + value = m_valueList->next(); + } + + if (valid) + addProperty(propId, CSSPrimitiveValue::create(firstRegion.release()), important); + + return valid; +} + +#endif /* ENABLE(DASHBOARD_SUPPORT) */ + +PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters) +{ + unsigned numArgs = args->size(); + if (counters && numArgs != 3 && numArgs != 5) + return 0; + if (!counters && numArgs != 1 && numArgs != 3) + return 0; + + CSSParserValue* i = args->current(); + if (i->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + RefPtr<CSSPrimitiveValue> identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING); + + RefPtr<CSSPrimitiveValue> separator; + if (!counters) + separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::CSS_STRING); + else { + i = args->next(); + if (i->unit != CSSParserValue::Operator || i->iValue != ',') + return 0; + + i = args->next(); + if (i->unit != CSSPrimitiveValue::CSS_STRING) + return 0; + + separator = CSSPrimitiveValue::create(i->string, (CSSPrimitiveValue::UnitTypes) i->unit); + } + + RefPtr<CSSPrimitiveValue> listStyle; + i = args->next(); + if (!i) // Make the list style default decimal + listStyle = CSSPrimitiveValue::create(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER); + else { + if (i->unit != CSSParserValue::Operator || i->iValue != ',') + return 0; + + i = args->next(); + if (i->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + + short ls = 0; + if (i->id == CSSValueNone) + ls = CSSValueKatakanaIroha - CSSValueDisc + 1; + else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha) + ls = i->id - CSSValueDisc; + else + return 0; + + listStyle = CSSPrimitiveValue::create(ls, (CSSPrimitiveValue::UnitTypes) i->unit); + } + + return CSSPrimitiveValue::create(Counter::create(identifier.release(), listStyle.release(), separator.release())); +} + +bool CSSParser::parseShape(int propId, bool important) +{ + CSSParserValue* value = m_valueList->current(); + CSSParserValueList* args = value->function->args.get(); + + if (!equalIgnoringCase(value->function->name, "rect(") || !args) + return false; + + // rect(t, r, b, l) || rect(t r b l) + if (args->size() != 4 && args->size() != 7) + return false; + RefPtr<Rect> rect = Rect::create(); + bool valid = true; + int i = 0; + CSSParserValue* a = args->current(); + while (a) { + valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict); + if (!valid) + break; + RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ? + CSSPrimitiveValue::createIdentifier(CSSValueAuto) : + CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit); + if (i == 0) + rect->setTop(length); + else if (i == 1) + rect->setRight(length); + else if (i == 2) + rect->setBottom(length); + else + rect->setLeft(length); + a = args->next(); + if (a && args->size() == 7) { + if (a->unit == CSSParserValue::Operator && a->iValue == ',') { + a = args->next(); + } else { + valid = false; + break; + } + } + i++; + } + if (valid) { + addProperty(propId, CSSPrimitiveValue::create(rect.release()), important); + m_valueList->next(); + return true; + } + return false; +} + +// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' +bool CSSParser::parseFont(bool important) +{ + bool valid = true; + CSSParserValue *value = m_valueList->current(); + RefPtr<FontValue> font = FontValue::create(); + // optional font-style, font-variant and font-weight + while (value) { + int id = value->id; + if (id) { + if (id == CSSValueNormal) { + // do nothing, it's the inital value for all three + } else if (id == CSSValueItalic || id == CSSValueOblique) { + if (font->style) + return false; + font->style = CSSPrimitiveValue::createIdentifier(id); + } else if (id == CSSValueSmallCaps) { + if (font->variant) + return false; + font->variant = CSSPrimitiveValue::createIdentifier(id); + } else if (id >= CSSValueBold && id <= CSSValueLighter) { + if (font->weight) + return false; + font->weight = CSSPrimitiveValue::createIdentifier(id); + } else { + valid = false; + } + } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) { + int weight = (int)value->fValue; + int val = 0; + if (weight == 100) + val = CSSValue100; + else if (weight == 200) + val = CSSValue200; + else if (weight == 300) + val = CSSValue300; + else if (weight == 400) + val = CSSValue400; + else if (weight == 500) + val = CSSValue500; + else if (weight == 600) + val = CSSValue600; + else if (weight == 700) + val = CSSValue700; + else if (weight == 800) + val = CSSValue800; + else if (weight == 900) + val = CSSValue900; + + if (val) + font->weight = CSSPrimitiveValue::createIdentifier(val); + else + valid = false; + } else { + valid = false; + } + if (!valid) + break; + value = m_valueList->next(); + } + if (!value) + return false; + + // set undefined values to default + if (!font->style) + font->style = CSSPrimitiveValue::createIdentifier(CSSValueNormal); + if (!font->variant) + font->variant = CSSPrimitiveValue::createIdentifier(CSSValueNormal); + if (!font->weight) + font->weight = CSSPrimitiveValue::createIdentifier(CSSValueNormal); + + // now a font size _must_ come + // <absolute-size> | <relative-size> | <length> | <percentage> | inherit + if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger) + font->size = CSSPrimitiveValue::createIdentifier(value->id); + else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict)) + font->size = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + value = m_valueList->next(); + if (!font->size || !value) + return false; + + if (value->unit == CSSParserValue::Operator && value->iValue == '/') { + // line-height + value = m_valueList->next(); + if (!value) + return false; + if (value->id == CSSValueNormal) { + // default value, nothing to do + } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)) + font->lineHeight = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + else + return false; + value = m_valueList->next(); + if (!value) + return false; + } + + if (!font->lineHeight) + font->lineHeight = CSSPrimitiveValue::createIdentifier(CSSValueNormal); + + // font family must come now + font->family = parseFontFamily(); + + if (m_valueList->current() || !font->family) + return false; + + addProperty(CSSPropertyFont, font.release(), important); + return true; +} + +PassRefPtr<CSSValueList> CSSParser::parseFontFamily() +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + CSSParserValue* value = m_valueList->current(); + + FontFamilyValue* currFamily = 0; + while (value) { + CSSParserValue* nextValue = m_valueList->next(); + bool nextValBreaksFont = !nextValue || + (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ','); + bool nextValIsFontName = nextValue && + ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) || + (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT)); + + if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) { + if (currFamily) + currFamily->appendSpaceSeparated(value->string.characters, value->string.length); + else if (nextValBreaksFont || !nextValIsFontName) + list->append(CSSPrimitiveValue::createIdentifier(value->id)); + else { + RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string); + currFamily = newFamily.get(); + list->append(newFamily.release()); + } + } else if (value->unit == CSSPrimitiveValue::CSS_STRING) { + // Strings never share in a family name. + currFamily = 0; + list->append(FontFamilyValue::create(value->string)); + } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { + if (currFamily) + currFamily->appendSpaceSeparated(value->string.characters, value->string.length); + else if (nextValBreaksFont || !nextValIsFontName) + list->append(FontFamilyValue::create(value->string)); + else { + RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string); + currFamily = newFamily.get(); + list->append(newFamily.release()); + } + } else { + break; + } + + if (!nextValue) + break; + + if (nextValBreaksFont) { + value = m_valueList->next(); + currFamily = 0; + } + else if (nextValIsFontName) + value = nextValue; + else + break; + } + if (!list->length()) + list = 0; + return list.release(); +} + +bool CSSParser::parseFontStyle(bool important) +{ + RefPtr<CSSValueList> values; + if (m_valueList->size() > 1) + values = CSSValueList::createCommaSeparated(); + CSSParserValue* val; + bool expectComma = false; + while ((val = m_valueList->current())) { + RefPtr<CSSPrimitiveValue> parsedValue; + if (!expectComma) { + expectComma = true; + if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique) + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + else if (val->id == CSSValueAll && !values) { + // 'all' is only allowed in @font-face and with no other values. Make a value list to + // indicate that we are in the @font-face case. + values = CSSValueList::createCommaSeparated(); + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + } + } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + expectComma = false; + m_valueList->next(); + continue; + } + + if (!parsedValue) + return false; + + m_valueList->next(); + + if (values) + values->append(parsedValue.release()); + else { + addProperty(CSSPropertyFontStyle, parsedValue.release(), important); + return true; + } + } + + if (values && values->length()) { + m_hasFontFaceOnlyValues = true; + addProperty(CSSPropertyFontStyle, values.release(), important); + return true; + } + + return false; +} + +bool CSSParser::parseFontVariant(bool important) +{ + RefPtr<CSSValueList> values; + if (m_valueList->size() > 1) + values = CSSValueList::createCommaSeparated(); + CSSParserValue* val; + bool expectComma = false; + while ((val = m_valueList->current())) { + RefPtr<CSSPrimitiveValue> parsedValue; + if (!expectComma) { + expectComma = true; + if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps) + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + else if (val->id == CSSValueAll && !values) { + // 'all' is only allowed in @font-face and with no other values. Make a value list to + // indicate that we are in the @font-face case. + values = CSSValueList::createCommaSeparated(); + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + } + } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + expectComma = false; + m_valueList->next(); + continue; + } + + if (!parsedValue) + return false; + + m_valueList->next(); + + if (values) + values->append(parsedValue.release()); + else { + addProperty(CSSPropertyFontVariant, parsedValue.release(), important); + return true; + } + } + + if (values && values->length()) { + m_hasFontFaceOnlyValues = true; + addProperty(CSSPropertyFontVariant, values.release(), important); + return true; + } + + return false; +} + +bool CSSParser::parseFontWeight(bool important) +{ + RefPtr<CSSValueList> values; + if (m_valueList->size() > 1) + values = CSSValueList::createCommaSeparated(); + CSSParserValue* val; + bool expectComma = false; + while ((val = m_valueList->current())) { + RefPtr<CSSPrimitiveValue> parsedValue; + if (!expectComma) { + expectComma = true; + if (val->unit == CSSPrimitiveValue::CSS_IDENT) { + if (val->id >= CSSValueNormal && val->id <= CSSValue900) + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + else if (val->id == CSSValueAll && !values) { + // 'all' is only allowed in @font-face and with no other values. Make a value list to + // indicate that we are in the @font-face case. + values = CSSValueList::createCommaSeparated(); + parsedValue = CSSPrimitiveValue::createIdentifier(val->id); + } + } else if (validUnit(val, FInteger | FNonNeg, false)) { + int weight = static_cast<int>(val->fValue); + if (!(weight % 100) && weight >= 100 && weight <= 900) + parsedValue = CSSPrimitiveValue::createIdentifier(CSSValue100 + weight / 100 - 1); + } + } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') { + expectComma = false; + m_valueList->next(); + continue; + } + + if (!parsedValue) + return false; + + m_valueList->next(); + + if (values) + values->append(parsedValue.release()); + else { + addProperty(CSSPropertyFontWeight, parsedValue.release(), important); + return true; + } + } + + if (values && values->length()) { + m_hasFontFaceOnlyValues = true; + addProperty(CSSPropertyFontWeight, values.release(), important); + return true; + } + + return false; +} + +static bool isValidFormatFunction(CSSParserValue* val) +{ + CSSParserValueList* args = val->function->args.get(); + return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT); +} + +bool CSSParser::parseFontFaceSrc() +{ + RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated()); + CSSParserValue* val; + bool expectComma = false; + bool allowFormat = false; + bool failed = false; + RefPtr<CSSFontFaceSrcValue> uriValue; + while ((val = m_valueList->current())) { + RefPtr<CSSFontFaceSrcValue> parsedValue; + if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) { + // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue, + // not when creating it. + parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string)); + uriValue = parsedValue; + allowFormat = true; + expectComma = true; + } else if (val->unit == CSSParserValue::Function) { + // There are two allowed functions: local() and format(). + CSSParserValueList* args = val->function->args.get(); + if (args && args->size() == 1) { + if (equalIgnoringCase(val->function->name, "local(") && !expectComma && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT)) { + expectComma = true; + allowFormat = false; + CSSParserValue* a = args->current(); + uriValue.clear(); + parsedValue = CSSFontFaceSrcValue::createLocal(a->string); + } else if (allowFormat && uriValue && isValidFormatFunction(val)) { + expectComma = true; + allowFormat = false; + uriValue->setFormat(args->current()->string); + uriValue.clear(); + m_valueList->next(); + continue; + } + } + } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) { + expectComma = false; + allowFormat = false; + uriValue.clear(); + m_valueList->next(); + continue; + } + + if (parsedValue) + values->append(parsedValue.release()); + else { + failed = true; + break; + } + m_valueList->next(); + } + + if (values->length() && !failed) { + addProperty(CSSPropertySrc, values.release(), m_important); + m_valueList->next(); + return true; + } + + return false; +} + +bool CSSParser::parseFontFaceUnicodeRange() +{ + RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); + bool failed = false; + bool operatorExpected = false; + for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) { + if (operatorExpected) { + if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',') + continue; + failed = true; + break; + } + if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) { + failed = true; + break; + } + + String rangeString = m_valueList->current()->string; + UChar32 from = 0; + UChar32 to = 0; + unsigned length = rangeString.length(); + + if (length < 3) { + failed = true; + break; + } + + unsigned i = 2; + while (i < length) { + UChar c = rangeString[i]; + if (c == '-' || c == '?') + break; + from *= 16; + if (c >= '0' && c <= '9') + from += c - '0'; + else if (c >= 'A' && c <= 'F') + from += 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + from += 10 + c - 'a'; + else { + failed = true; + break; + } + i++; + } + if (failed) + break; + + if (i == length) + to = from; + else if (rangeString[i] == '?') { + unsigned span = 1; + while (i < length && rangeString[i] == '?') { + span *= 16; + from *= 16; + i++; + } + if (i < length) + failed = true; + to = from + span - 1; + } else { + if (length < i + 2) { + failed = true; + break; + } + i++; + while (i < length) { + UChar c = rangeString[i]; + to *= 16; + if (c >= '0' && c <= '9') + to += c - '0'; + else if (c >= 'A' && c <= 'F') + to += 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + to += 10 + c - 'a'; + else { + failed = true; + break; + } + i++; + } + if (failed) + break; + } + if (from <= to) + values->append(CSSUnicodeRangeValue::create(from, to)); + } + if (failed || !values->length()) + return false; + addProperty(CSSPropertyUnicodeRange, values.release(), m_important); + return true; +} + +static inline bool parseColorInt(const UChar*& string, const UChar* end, UChar terminator, int& value) +{ + const UChar* current = string; + int localValue = 0; + bool negative = false; + while (current != end && isHTMLSpace(*current)) + current++; + if (current != end && *current == '-') { + negative = true; + current++; + } + if (current == end || !isASCIIDigit(*current)) + return false; + while (current != end && isASCIIDigit(*current)) { + int newValue = localValue * 10 + *current++ - '0'; + if (newValue >= 255) { + // Clamp values at 255. + localValue = 255; + while (current != end && isASCIIDigit(*current)) + ++current; + break; + } + localValue = newValue; + } + while (current != end && isHTMLSpace(*current)) + current++; + if (current == end || *current++ != terminator) + return false; + // Clamp negative values at zero. + value = negative ? 0 : localValue; + string = current; + return true; +} + +static inline bool isTenthAlpha(const UChar* string, const int length) +{ + // "0.X" + if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2])) + return true; + + // ".X" + if (length == 2 && string[0] == '.' && isASCIIDigit(string[1])) + return true; + + return false; +} + +static inline bool parseAlphaValue(const UChar*& string, const UChar* end, UChar terminator, int& value) +{ + while (string != end && isHTMLSpace(*string)) + string++; + + value = 0; + + int length = end - string; + if (length < 2) + return false; + + if (string[0] != '0' && string[0] != '1' && string[0] != '.') + return false; + + if (string[length - 1] != terminator) + return false; + + if (length == 2 && string[0] != '.') { + value = string[0] == '1' ? 255 : 0; + string = end; + return true; + } + + if (isTenthAlpha(string, length - 1)) { + static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 }; + value = tenthAlphaValues[string[length - 2] - '0']; + string = end; + return true; + } + + Vector<char, 8> bytes(length + 1); + for (int i = 0; i < length; ++i) { + if (!isASCIIDigit(string[i]) && string[i] != '.' && string[i] != terminator) + return false; + bytes[i] = string[i]; + } + bytes[length] = '\0'; + char* foundTerminator; + double d = WTF::strtod(bytes.data(), &foundTerminator); + value = static_cast<int>(d * nextafter(256.0, 0.0)); + string += (foundTerminator - bytes.data()) + 1; + return *foundTerminator == terminator; +} + +static inline bool mightBeRGBA(const UChar* characters, unsigned length) +{ + if (length < 5) + return false; + return characters[4] == '(' + && (characters[0] | 0x20) == 'r' + && (characters[1] | 0x20) == 'g' + && (characters[2] | 0x20) == 'b' + && (characters[3] | 0x20) == 'a'; +} + +static inline bool mightBeRGB(const UChar* characters, unsigned length) +{ + if (length < 4) + return false; + return characters[3] == '(' + && (characters[0] | 0x20) == 'r' + && (characters[1] | 0x20) == 'g' + && (characters[2] | 0x20) == 'b'; +} + +bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict) +{ + const UChar* characters = name.characters(); + unsigned length = name.length(); + + if (!strict && length >= 3) { + if (name[0] == '#') { + if (Color::parseHexColor(characters + 1, length - 1, rgb)) + return true; + } else { + if (Color::parseHexColor(characters, length, rgb)) + return true; + } + } + + // Try rgba() syntax. + if (mightBeRGBA(characters, length)) { + const UChar* current = characters + 5; + const UChar* end = characters + length; + int red; + int green; + int blue; + int alpha; + if (!parseColorInt(current, end, ',', red)) + return false; + if (!parseColorInt(current, end, ',', green)) + return false; + if (!parseColorInt(current, end, ',', blue)) + return false; + if (!parseAlphaValue(current, end, ')', alpha)) + return false; + if (current != end) + return false; + rgb = makeRGBA(red, green, blue, alpha); + return true; + } + + // Try rgb() syntax. + if (mightBeRGB(characters, length)) { + const UChar* current = characters + 4; + const UChar* end = characters + length; + int red; + int green; + int blue; + if (!parseColorInt(current, end, ',', red)) + return false; + if (!parseColorInt(current, end, ',', green)) + return false; + if (!parseColorInt(current, end, ')', blue)) + return false; + if (current != end) + return false; + rgb = makeRGB(red, green, blue); + return true; + } + + // Try named colors. + Color tc; + tc.setNamedColor(name); + if (tc.isValid()) { + rgb = tc.rgb(); + return true; + } + return false; +} + +static inline int colorIntFromValue(CSSParserValue* v) +{ + if (v->fValue <= 0.0) + return 0; + + if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) { + if (v->fValue >= 100.0) + return 255; + return static_cast<int>(v->fValue * 256.0 / 100.0); + } + + if (v->fValue >= 255.0) + return 255; + + return static_cast<int>(v->fValue); +} + +bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha) +{ + CSSParserValueList* args = value->function->args.get(); + CSSParserValue* v = args->current(); + Units unitType = FUnknown; + // Get the first value and its type + if (validUnit(v, FInteger, true)) + unitType = FInteger; + else if (validUnit(v, FPercent, true)) + unitType = FPercent; + else + return false; + colorArray[0] = colorIntFromValue(v); + for (int i = 1; i < 3; i++) { + v = args->next(); + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return false; + v = args->next(); + if (!validUnit(v, unitType, true)) + return false; + colorArray[i] = colorIntFromValue(v); + } + if (parseAlpha) { + v = args->next(); + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return false; + v = args->next(); + if (!validUnit(v, FNumber, true)) + return false; + // Convert the floating pointer number of alpha to an integer in the range [0, 256), + // with an equal distribution across all 256 values. + colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0)); + } + return true; +} + +// The CSS3 specification defines the format of a HSL color as +// hsl(<number>, <percent>, <percent>) +// and with alpha, the format is +// hsla(<number>, <percent>, <percent>, <number>) +// The first value, HUE, is in an angle with a value between 0 and 360 +bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha) +{ + CSSParserValueList* args = value->function->args.get(); + CSSParserValue* v = args->current(); + // Get the first value + if (!validUnit(v, FNumber, true)) + return false; + // normalize the Hue value and change it to be between 0 and 1.0 + colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0; + for (int i = 1; i < 3; i++) { + v = args->next(); + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return false; + v = args->next(); + if (!validUnit(v, FPercent, true)) + return false; + colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0 + } + if (parseAlpha) { + v = args->next(); + if (v->unit != CSSParserValue::Operator && v->iValue != ',') + return false; + v = args->next(); + if (!validUnit(v, FNumber, true)) + return false; + colorArray[3] = max(0.0, min(1.0, v->fValue)); + } + return true; +} + +PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value) +{ + RGBA32 c = Color::transparent; + if (!parseColorFromValue(value ? value : m_valueList->current(), c)) + return 0; + return CSSPrimitiveValue::createColor(c); +} + +bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c) +{ + if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && + value->fValue >= 0. && value->fValue < 1000000.) { + String str = String::format("%06d", (int)(value->fValue+.5)); + if (!CSSParser::parseColor(str, c, m_strict)) + return false; + } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR || + value->unit == CSSPrimitiveValue::CSS_IDENT || + (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) { + if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT)) + return false; + } else if (value->unit == CSSParserValue::Function && + value->function->args != 0 && + value->function->args->size() == 5 /* rgb + two commas */ && + equalIgnoringCase(value->function->name, "rgb(")) { + int colorValues[3]; + if (!parseColorParameters(value, colorValues, false)) + return false; + c = makeRGB(colorValues[0], colorValues[1], colorValues[2]); + } else { + if (value->unit == CSSParserValue::Function && + value->function->args != 0 && + value->function->args->size() == 7 /* rgba + three commas */ && + equalIgnoringCase(value->function->name, "rgba(")) { + int colorValues[4]; + if (!parseColorParameters(value, colorValues, true)) + return false; + c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); + } else if (value->unit == CSSParserValue::Function && + value->function->args != 0 && + value->function->args->size() == 5 /* hsl + two commas */ && + equalIgnoringCase(value->function->name, "hsl(")) { + double colorValues[3]; + if (!parseHSLParameters(value, colorValues, false)) + return false; + c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0); + } else if (value->unit == CSSParserValue::Function && + value->function->args != 0 && + value->function->args->size() == 7 /* hsla + three commas */ && + equalIgnoringCase(value->function->name, "hsla(")) { + double colorValues[4]; + if (!parseHSLParameters(value, colorValues, true)) + return false; + c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); + } else + return false; + } + + return true; +} + +// This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return) +// without the allowBreak bit being set, then it will clean up all of the objects and destroy them. +struct ShadowParseContext { + ShadowParseContext(CSSPropertyID prop) + : property(prop) + , allowX(true) + , allowY(false) + , allowBlur(false) + , allowSpread(false) + , allowColor(true) + , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow) + , allowBreak(true) + { + } + + bool allowLength() { return allowX || allowY || allowBlur || allowSpread; } + + void commitValue() + { + // Handle the ,, case gracefully by doing nothing. + if (x || y || blur || spread || color || style) { + if (!values) + values = CSSValueList::createCommaSeparated(); + + // Construct the current shadow value and add it to the list. + values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); + } + + // Now reset for the next shadow value. + x = 0; + y = 0; + blur = 0; + spread = 0; + style = 0; + color = 0; + + allowX = true; + allowColor = true; + allowBreak = true; + allowY = false; + allowBlur = false; + allowSpread = false; + allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; + } + + void commitLength(CSSParserValue* v) + { + RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit); + + if (allowX) { + x = val.release(); + allowX = false; + allowY = true; + allowColor = false; + allowStyle = false; + allowBreak = false; + } else if (allowY) { + y = val.release(); + allowY = false; + allowBlur = true; + allowColor = true; + allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; + allowBreak = true; + } else if (allowBlur) { + blur = val.release(); + allowBlur = false; + allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; + } else if (allowSpread) { + spread = val.release(); + allowSpread = false; + } + } + + void commitColor(PassRefPtr<CSSPrimitiveValue> val) + { + color = val; + allowColor = false; + if (allowX) { + allowStyle = false; + allowBreak = false; + } else { + allowBlur = false; + allowSpread = false; + allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; + } + } + + void commitStyle(CSSParserValue* v) + { + style = CSSPrimitiveValue::createIdentifier(v->id); + allowStyle = false; + if (allowX) + allowBreak = false; + else { + allowBlur = false; + allowSpread = false; + allowColor = false; + } + } + + CSSPropertyID property; + + RefPtr<CSSValueList> values; + RefPtr<CSSPrimitiveValue> x; + RefPtr<CSSPrimitiveValue> y; + RefPtr<CSSPrimitiveValue> blur; + RefPtr<CSSPrimitiveValue> spread; + RefPtr<CSSPrimitiveValue> style; + RefPtr<CSSPrimitiveValue> color; + + bool allowX; + bool allowY; + bool allowBlur; + bool allowSpread; + bool allowColor; + bool allowStyle; // inset or not. + bool allowBreak; +}; + +bool CSSParser::parseShadow(int propId, bool important) +{ + ShadowParseContext context(static_cast<CSSPropertyID>(propId)); + CSSParserValue* val; + while ((val = m_valueList->current())) { + // Check for a comma break first. + if (val->unit == CSSParserValue::Operator) { + if (val->iValue != ',' || !context.allowBreak) + // Other operators aren't legal or we aren't done with the current shadow + // value. Treat as invalid. + return false; +#if ENABLE(SVG) + // -webkit-svg-shadow does not support multiple values. + if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow) + return false; +#endif + // The value is good. Commit it. + context.commitValue(); + } else if (validUnit(val, FLength, true)) { + // We required a length and didn't get one. Invalid. + if (!context.allowLength()) + return false; + + // A length is allowed here. Construct the value and add it. + context.commitLength(val); + } else if (val->id == CSSValueInset) { + if (!context.allowStyle) + return false; + + context.commitStyle(val); + } else { + // The only other type of value that's ok is a color value. + RefPtr<CSSPrimitiveValue> parsedColor; + bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu || + (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && !m_strict)); + if (isColor) { + if (!context.allowColor) + return false; + parsedColor = CSSPrimitiveValue::createIdentifier(val->id); + } + + if (!parsedColor) + // It's not built-in. Try to parse it as a color. + parsedColor = parseColor(val); + + if (!parsedColor || !context.allowColor) + return false; // This value is not a color or length and is invalid or + // it is a color, but a color isn't allowed at this point. + + context.commitColor(parsedColor.release()); + } + + m_valueList->next(); + } + + if (context.allowBreak) { + context.commitValue(); + if (context.values->length()) { + addProperty(propId, context.values.release(), important); + m_valueList->next(); + return true; + } + } + + return false; +} + +bool CSSParser::parseReflect(int propId, bool important) +{ + // box-reflect: <direction> <offset> <mask> + + // Direction comes first. + CSSParserValue* val = m_valueList->current(); + CSSReflectionDirection direction; + switch (val->id) { + case CSSValueAbove: + direction = ReflectionAbove; + break; + case CSSValueBelow: + direction = ReflectionBelow; + break; + case CSSValueLeft: + direction = ReflectionLeft; + break; + case CSSValueRight: + direction = ReflectionRight; + break; + default: + return false; + } + + // The offset comes next. + val = m_valueList->next(); + RefPtr<CSSPrimitiveValue> offset; + if (!val) + offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX); + else { + if (!validUnit(val, FLength | FPercent, m_strict)) + return false; + offset = CSSPrimitiveValue::create(val->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(val->unit)); + } + + // Now for the mask. + RefPtr<CSSValue> mask; + val = m_valueList->next(); + if (val) { + if (!parseBorderImage(propId, important, mask)) + return false; + } + + RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release()); + addProperty(propId, reflectValue.release(), important); + m_valueList->next(); + return true; +} + +struct BorderImageParseContext { + BorderImageParseContext() + : m_allowBreak(false) + , m_allowNumber(false) + , m_allowSlash(false) + , m_allowWidth(false) + , m_allowRule(false) + , m_borderTop(0) + , m_borderRight(0) + , m_borderBottom(0) + , m_borderLeft(0) + , m_horizontalRule(0) + , m_verticalRule(0) + {} + + bool allowBreak() const { return m_allowBreak; } + bool allowNumber() const { return m_allowNumber; } + bool allowSlash() const { return m_allowSlash; } + bool allowWidth() const { return m_allowWidth; } + bool allowRule() const { return m_allowRule; } + + void commitImage(PassRefPtr<CSSValue> image) { m_image = image; m_allowNumber = true; } + void commitNumber(CSSParserValue* v) + { + PassRefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit); + if (!m_top) + m_top = val; + else if (!m_right) + m_right = val; + else if (!m_bottom) + m_bottom = val; + else { + ASSERT(!m_left); + m_left = val; + } + + m_allowBreak = m_allowSlash = m_allowRule = true; + m_allowNumber = !m_left; + } + void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; } + void commitWidth(CSSParserValue* val) + { + if (!m_borderTop) + m_borderTop = val; + else if (!m_borderRight) + m_borderRight = val; + else if (!m_borderBottom) + m_borderBottom = val; + else { + ASSERT(!m_borderLeft); + m_borderLeft = val; + } + + m_allowBreak = m_allowRule = true; + m_allowWidth = !m_borderLeft; + } + void commitRule(int keyword) + { + if (!m_horizontalRule) + m_horizontalRule = keyword; + else if (!m_verticalRule) + m_verticalRule = keyword; + m_allowRule = !m_verticalRule; + } + PassRefPtr<CSSValue> commitBorderImage(CSSParser* p, bool important) + { + // We need to clone and repeat values for any omissions. + if (!m_right) { + m_right = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + } + if (!m_bottom) { + m_bottom = CSSPrimitiveValue::create(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + } + if (!m_left) + m_left = CSSPrimitiveValue::create(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + + // Now build a rect value to hold all four of our primitive values. + RefPtr<Rect> rect = Rect::create(); + rect->setTop(m_top); + rect->setRight(m_right); + rect->setBottom(m_bottom); + rect->setLeft(m_left); + + // Fill in STRETCH as the default if it wasn't specified. + if (!m_horizontalRule) + m_horizontalRule = CSSValueStretch; + + // The vertical rule should match the horizontal rule if unspecified. + if (!m_verticalRule) + m_verticalRule = m_horizontalRule; + + // Now we have to deal with the border widths. The best way to deal with these is to actually put these values into a value + // list and then make our parsing machinery do the parsing. + if (m_borderTop) { + CSSParserValueList newList; + newList.addValue(*m_borderTop); + if (m_borderRight) + newList.addValue(*m_borderRight); + if (m_borderBottom) + newList.addValue(*m_borderBottom); + if (m_borderLeft) + newList.addValue(*m_borderLeft); + CSSParserValueList* oldList = p->m_valueList; + p->m_valueList = &newList; + p->parseValue(CSSPropertyBorderWidth, important); + p->m_valueList = oldList; + } + + // Make our new border image value now. + return CSSBorderImageValue::create(m_image, rect.release(), m_horizontalRule, m_verticalRule); + } + + bool m_allowBreak; + bool m_allowNumber; + bool m_allowSlash; + bool m_allowWidth; + bool m_allowRule; + + RefPtr<CSSValue> m_image; + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_right; + RefPtr<CSSPrimitiveValue> m_bottom; + RefPtr<CSSPrimitiveValue> m_left; + + CSSParserValue* m_borderTop; + CSSParserValue* m_borderRight; + CSSParserValue* m_borderBottom; + CSSParserValue* m_borderLeft; + + int m_horizontalRule; + int m_verticalRule; +}; + +bool CSSParser::parseBorderImage(int propId, bool important, RefPtr<CSSValue>& result) +{ + // Look for an image initially. If the first value is not a URI, then we're done. + BorderImageParseContext context; + CSSParserValue* val = m_valueList->current(); + if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { + // FIXME: The completeURL call should be done when using the CSSImageValue, + // not when creating it. + context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string))); + } else if (isGeneratedImageValue(val)) { + RefPtr<CSSValue> value; + if (parseGeneratedImage(value)) + context.commitImage(value); + else + return false; + } else + return false; + + while ((val = m_valueList->next())) { + if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) { + context.commitNumber(val); + } else if (propId == CSSPropertyWebkitBorderImage && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') { + context.commitSlash(); + } else if (context.allowWidth() && + (val->id == CSSValueThin || val->id == CSSValueMedium || val->id == CSSValueThick || validUnit(val, FLength, m_strict))) { + context.commitWidth(val); + } else if (context.allowRule() && + (val->id == CSSValueStretch || val->id == CSSValueRound || val->id == CSSValueRepeat)) { + context.commitRule(val->id); + } else { + // Something invalid was encountered. + return false; + } + } + + if (context.allowNumber() && propId != CSSPropertyWebkitBorderImage) { + // Allow the slices to be omitted for images that don't fit to a border. We just set the slices to be 0. + context.m_top = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER); + context.m_allowBreak = true; + } + + if (context.allowBreak()) { + // Need to fully commit as a single value. + result = context.commitBorderImage(this, important); + return true; + } + + return false; +} + +static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4]) +{ + if (radii[3]) + return; + if (!radii[2]) { + if (!radii[1]) + radii[1] = radii[0]; + radii[2] = radii[0]; + } + radii[3] = radii[1]; +} + +bool CSSParser::parseBorderRadius(int propId, bool important) +{ + unsigned num = m_valueList->size(); + if (num > 9) + return false; + + ShorthandScope scope(this, propId); + RefPtr<CSSPrimitiveValue> radii[2][4]; + + unsigned indexAfterSlash = 0; + for (unsigned i = 0; i < num; ++i) { + CSSParserValue* value = m_valueList->valueAt(i); + if (value->unit == CSSParserValue::Operator) { + if (value->iValue != '/') + return false; + + if (!i || indexAfterSlash || i + 1 == num || num > i + 5) + return false; + + indexAfterSlash = i + 1; + completeBorderRadii(radii[0]); + continue; + } + + if (i - indexAfterSlash >= 4) + return false; + + if (!validUnit(value, FLength | FPercent, m_strict)) + return false; + + RefPtr<CSSPrimitiveValue> radius = CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); + + if (!indexAfterSlash) { + radii[0][i] = radius; + + // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2; + if (num == 2 && propId == CSSPropertyWebkitBorderRadius) { + indexAfterSlash = 1; + completeBorderRadii(radii[0]); + } + } else + radii[1][i - indexAfterSlash] = radius.release(); + } + + if (!indexAfterSlash) { + completeBorderRadii(radii[0]); + for (unsigned i = 0; i < 4; ++i) + radii[1][i] = radii[0][i]; + } else + completeBorderRadii(radii[1]); + + m_implicitShorthand = true; + addProperty(CSSPropertyBorderTopLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][0].release(), radii[1][0].release())), important); + addProperty(CSSPropertyBorderTopRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][1].release(), radii[1][1].release())), important); + addProperty(CSSPropertyBorderBottomRightRadius, CSSPrimitiveValue::create(Pair::create(radii[0][2].release(), radii[1][2].release())), important); + addProperty(CSSPropertyBorderBottomLeftRadius, CSSPrimitiveValue::create(Pair::create(radii[0][3].release(), radii[1][3].release())), important); + m_implicitShorthand = false; + return true; +} + +bool CSSParser::parseCounter(int propId, int defaultValue, bool important) +{ + enum { ID, VAL } state = ID; + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + RefPtr<CSSPrimitiveValue> counterName; + + while (true) { + CSSParserValue* val = m_valueList->current(); + switch (state) { + case ID: + if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) { + counterName = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); + state = VAL; + m_valueList->next(); + continue; + } + break; + case VAL: { + int i = defaultValue; + if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) { + i = clampToSignedInteger(val->fValue); + m_valueList->next(); + } + + list->append(CSSPrimitiveValue::create(Pair::create(counterName.release(), + CSSPrimitiveValue::create(i, CSSPrimitiveValue::CSS_NUMBER)))); + state = ID; + continue; + } + } + break; + } + + if (list->length() > 0) { + addProperty(propId, list.release(), important); + return true; + } + + return false; +} + +// This should go away once we drop support for -webkit-gradient +static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal) +{ + RefPtr<CSSPrimitiveValue> result; + if (a->unit == CSSPrimitiveValue::CSS_IDENT) { + if ((equalIgnoringCase(a->string, "left") && horizontal) || + (equalIgnoringCase(a->string, "top") && !horizontal)) + result = CSSPrimitiveValue::create(0., CSSPrimitiveValue::CSS_PERCENTAGE); + else if ((equalIgnoringCase(a->string, "right") && horizontal) || + (equalIgnoringCase(a->string, "bottom") && !horizontal)) + result = CSSPrimitiveValue::create(100., CSSPrimitiveValue::CSS_PERCENTAGE); + else if (equalIgnoringCase(a->string, "center")) + result = CSSPrimitiveValue::create(50., CSSPrimitiveValue::CSS_PERCENTAGE); + } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) + result = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit); + return result; +} + +static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop) +{ + if (a->unit != CSSParserValue::Function) + return false; + + if (!equalIgnoringCase(a->function->name, "from(") && + !equalIgnoringCase(a->function->name, "to(") && + !equalIgnoringCase(a->function->name, "color-stop(")) + return false; + + CSSParserValueList* args = a->function->args.get(); + if (!args) + return false; + + if (equalIgnoringCase(a->function->name, "from(") || + equalIgnoringCase(a->function->name, "to(")) { + // The "from" and "to" stops expect 1 argument. + if (args->size() != 1) + return false; + + if (equalIgnoringCase(a->function->name, "from(")) + stop.m_position = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER); + else + stop.m_position = CSSPrimitiveValue::create(1, CSSPrimitiveValue::CSS_NUMBER); + + int id = args->current()->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) + stop.m_color = CSSPrimitiveValue::createIdentifier(id); + else + stop.m_color = p->parseColor(args->current()); + if (!stop.m_color) + return false; + } + + // The "color-stop" function expects 3 arguments. + if (equalIgnoringCase(a->function->name, "color-stop(")) { + if (args->size() != 3) + return false; + + CSSParserValue* stopArg = args->current(); + if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE) + stop.m_position = CSSPrimitiveValue::create(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER); + else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER) + stop.m_position = CSSPrimitiveValue::create(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER); + else + return false; + + stopArg = args->next(); + if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',') + return false; + + stopArg = args->next(); + int id = stopArg->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) + stop.m_color = CSSPrimitiveValue::createIdentifier(id); + else + stop.m_color = p->parseColor(stopArg); + if (!stop.m_color) + return false; + } + + return true; +} + +bool CSSParser::parseDeprecatedGradient(RefPtr<CSSValue>& gradient) +{ + // Walk the arguments. + CSSParserValueList* args = m_valueList->current()->function->args.get(); + if (!args || args->size() == 0) + return false; + + // The first argument is the gradient type. It is an identifier. + CSSGradientType gradientType; + CSSParserValue* a = args->current(); + if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + if (equalIgnoringCase(a->string, "linear")) + gradientType = CSSLinearGradient; + else if (equalIgnoringCase(a->string, "radial")) + gradientType = CSSRadialGradient; + else + return false; + + RefPtr<CSSGradientValue> result; + switch (gradientType) { + case CSSLinearGradient: + result = CSSLinearGradientValue::create(NonRepeating, true); + break; + case CSSRadialGradient: + result = CSSRadialGradientValue::create(NonRepeating, true); + break; + } + + // Comma. + a = args->next(); + if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + // Next comes the starting point for the gradient as an x y pair. There is no + // comma between the x and the y values. + // First X. It can be left, right, number or percent. + a = args->next(); + if (!a) + return false; + RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true); + if (!point) + return false; + result->setFirstX(point.release()); + + // First Y. It can be top, bottom, number or percent. + a = args->next(); + if (!a) + return false; + point = parseDeprecatedGradientPoint(a, false); + if (!point) + return false; + result->setFirstY(point.release()); + + // Comma after the first point. + a = args->next(); + if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + // For radial gradients only, we now expect a numeric radius. + if (gradientType == CSSRadialGradient) { + a = args->next(); + if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) + return false; + static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER)); + + // Comma after the first radius. + a = args->next(); + if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + } + + // Next is the ending point for the gradient as an x, y pair. + // Second X. It can be left, right, number or percent. + a = args->next(); + if (!a) + return false; + point = parseDeprecatedGradientPoint(a, true); + if (!point) + return false; + result->setSecondX(point.release()); + + // Second Y. It can be top, bottom, number or percent. + a = args->next(); + if (!a) + return false; + point = parseDeprecatedGradientPoint(a, false); + if (!point) + return false; + result->setSecondY(point.release()); + + // For radial gradients only, we now expect the second radius. + if (gradientType == CSSRadialGradient) { + // Comma after the second point. + a = args->next(); + if (!a || a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + a = args->next(); + if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) + return false; + static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(CSSPrimitiveValue::create(a->fValue, CSSPrimitiveValue::CSS_NUMBER)); + } + + // We now will accept any number of stops (0 or more). + a = args->next(); + while (a) { + // Look for the comma before the next stop. + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + // Now examine the stop itself. + a = args->next(); + if (!a) + return false; + + // The function name needs to be one of "from", "to", or "color-stop." + CSSGradientColorStop stop; + if (!parseDeprecatedGradientColorStop(this, a, stop)) + return false; + result->addStop(stop); + + // Advance + a = args->next(); + } + + gradient = result.release(); + return true; +} + +static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal) +{ + if (a->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + + switch (a->id) { + case CSSValueLeft: + case CSSValueRight: + isHorizontal = true; + break; + case CSSValueTop: + case CSSValueBottom: + isHorizontal = false; + break; + default: + return 0; + } + return CSSPrimitiveValue::createIdentifier(a->id); +} + +static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value) +{ + int id = value->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) + return CSSPrimitiveValue::createIdentifier(id); + + return p->parseColor(value); +} + +bool CSSParser::parseLinearGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +{ + RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating); + + // Walk the arguments. + CSSParserValueList* args = m_valueList->current()->function->args.get(); + if (!args || !args->size()) + return false; + + CSSParserValue* a = args->current(); + if (!a) + return false; + + bool expectComma = false; + // Look for angle. + if (validUnit(a, FAngle, true)) { + result->setAngle(CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit)); + + a = args->next(); + expectComma = true; + } else { + + // Look one or two optional keywords that indicate a side or corner. + RefPtr<CSSPrimitiveValue> startX, startY; + + RefPtr<CSSPrimitiveValue> location; + bool isHorizontal = false; + if ((location = valueFromSideKeyword(a, isHorizontal))) { + if (isHorizontal) + startX = location; + else + startY = location; + + a = args->next(); + if (a) { + if ((location = valueFromSideKeyword(a, isHorizontal))) { + if (isHorizontal) { + if (startX) + return false; + startX = location; + } else { + if (startY) + return false; + startY = location; + } + + a = args->next(); + } + } + + expectComma = true; + } + + if (!startX && !startY) + startY = CSSPrimitiveValue::createIdentifier(CSSValueTop); + + result->setFirstX(startX.release()); + result->setFirstY(startY.release()); + } + + // Now look for 0 or more color stops. + while (a) { + // Look for the comma before the next stop. + if (expectComma) { + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + a = args->next(); + if (!a) + return false; + } + + // <color-stop> = <color> [ <percentage> | <length> ]? + CSSGradientColorStop stop; + stop.m_color = parseGradientColorOrKeyword(this, a); + if (!stop.m_color) + return false; + + a = args->next(); + if (a) { + if (validUnit(a, FLength | FPercent, m_strict)) { + stop.m_position = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit); + a = args->next(); + } + } + + result->addStop(stop); + expectComma = true; + } + + Vector<CSSGradientColorStop>& stops = result->stops(); + if (stops.isEmpty()) + return false; + + gradient = result.release(); + return true; +} + +bool CSSParser::parseRadialGradient(RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +{ + RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating); + + // Walk the arguments. + CSSParserValueList* args = m_valueList->current()->function->args.get(); + if (!args || !args->size()) + return false; + + CSSParserValue* a = args->current(); + if (!a) + return false; + + bool expectComma = false; + + // Optional background-position + RefPtr<CSSValue> centerX; + RefPtr<CSSValue> centerY; + // parseFillPosition advances the args next pointer. + parseFillPosition(args, centerX, centerY); + a = args->current(); + + if (centerX || centerY) { + // Comma + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + a = args->next(); + if (!a) + return false; + } + + ASSERT(!centerX || centerX->isPrimitiveValue()); + ASSERT(!centerY || centerY->isPrimitiveValue()); + + result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get())); + result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get())); + // CSS3 radial gradients always share the same start and end point. + result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get())); + result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get())); + + RefPtr<CSSPrimitiveValue> shapeValue; + RefPtr<CSSPrimitiveValue> sizeValue; + + // Optional shape and/or size in any order. + for (int i = 0; i < 2; ++i) { + if (a->unit != CSSPrimitiveValue::CSS_IDENT) + break; + + bool foundValue = false; + switch (a->id) { + case CSSValueCircle: + case CSSValueEllipse: + shapeValue = CSSPrimitiveValue::createIdentifier(a->id); + foundValue = true; + break; + case CSSValueClosestSide: + case CSSValueClosestCorner: + case CSSValueFarthestSide: + case CSSValueFarthestCorner: + case CSSValueContain: + case CSSValueCover: + sizeValue = CSSPrimitiveValue::createIdentifier(a->id); + foundValue = true; + break; + } + + if (foundValue) { + a = args->next(); + if (!a) + return false; + + expectComma = true; + } + } + + result->setShape(shapeValue); + result->setSizingBehavior(sizeValue); + + // Or, two lengths or percentages + RefPtr<CSSPrimitiveValue> horizontalSize; + RefPtr<CSSPrimitiveValue> verticalSize; + + if (!shapeValue && !sizeValue) { + if (validUnit(a, FLength | FPercent, m_strict)) { + horizontalSize = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit); + a = args->next(); + if (!a) + return false; + + expectComma = true; + } + + if (validUnit(a, FLength | FPercent, m_strict)) { + verticalSize = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit); + + a = args->next(); + if (!a) + return false; + expectComma = true; + } + } + + // Must have neither or both. + if (!horizontalSize != !verticalSize) + return false; + + result->setEndHorizontalSize(horizontalSize); + result->setEndVerticalSize(verticalSize); + + // Now look for 0 or more color stops. + while (a) { + // Look for the comma before the next stop. + if (expectComma) { + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + a = args->next(); + if (!a) + return false; + } + + // <color-stop> = <color> [ <percentage> | <length> ]? + CSSGradientColorStop stop; + stop.m_color = parseGradientColorOrKeyword(this, a); + if (!stop.m_color) + return false; + + a = args->next(); + if (a) { + if (validUnit(a, FLength | FPercent, m_strict)) { + stop.m_position = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit); + a = args->next(); + } + } + + result->addStop(stop); + expectComma = true; + } + + Vector<CSSGradientColorStop>& stops = result->stops(); + if (stops.isEmpty()) + return false; + + gradient = result.release(); + return true; +} + +bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const +{ + if (val->unit != CSSParserValue::Function) + return false; + + return equalIgnoringCase(val->function->name, "-webkit-gradient(") + || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(") + || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(") + || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(") + || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(") + || equalIgnoringCase(val->function->name, "-webkit-canvas("); +} + +bool CSSParser::parseGeneratedImage(RefPtr<CSSValue>& value) +{ + CSSParserValue* val = m_valueList->current(); + + if (val->unit != CSSParserValue::Function) + return false; + + if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) + return parseDeprecatedGradient(value); + + if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) + return parseLinearGradient(value, NonRepeating); + + if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) + return parseLinearGradient(value, Repeating); + + if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) + return parseRadialGradient(value, NonRepeating); + + if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) + return parseRadialGradient(value, Repeating); + + if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) + return parseCanvas(value); + + return false; +} + +bool CSSParser::parseCanvas(RefPtr<CSSValue>& canvas) +{ + RefPtr<CSSCanvasValue> result = CSSCanvasValue::create(); + + // Walk the arguments. + CSSParserValueList* args = m_valueList->current()->function->args.get(); + if (!args || args->size() != 1) + return false; + + // The first argument is the canvas name. It is an identifier. + CSSParserValue* a = args->current(); + if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + result->setName(a->string); + canvas = result; + return true; +} + +class TransformOperationInfo { +public: + TransformOperationInfo(const CSSParserString& name) + : m_type(WebKitCSSTransformValue::UnknownTransformOperation) + , m_argCount(1) + , m_allowSingleArgument(false) + , m_unit(CSSParser::FUnknown) + { + if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) { + m_unit = CSSParser::FNumber; + if (equalIgnoringCase(name, "scale(")) + m_type = WebKitCSSTransformValue::ScaleTransformOperation; + else if (equalIgnoringCase(name, "scalex(")) + m_type = WebKitCSSTransformValue::ScaleXTransformOperation; + else if (equalIgnoringCase(name, "scaley(")) + m_type = WebKitCSSTransformValue::ScaleYTransformOperation; + else + m_type = WebKitCSSTransformValue::ScaleZTransformOperation; + } else if (equalIgnoringCase(name, "scale3d(")) { + m_type = WebKitCSSTransformValue::Scale3DTransformOperation; + m_argCount = 5; + m_unit = CSSParser::FNumber; + } else if (equalIgnoringCase(name, "rotate(")) { + m_type = WebKitCSSTransformValue::RotateTransformOperation; + m_unit = CSSParser::FAngle; + } else if (equalIgnoringCase(name, "rotatex(") || + equalIgnoringCase(name, "rotatey(") || + equalIgnoringCase(name, "rotatez(")) { + m_unit = CSSParser::FAngle; + if (equalIgnoringCase(name, "rotatex(")) + m_type = WebKitCSSTransformValue::RotateXTransformOperation; + else if (equalIgnoringCase(name, "rotatey(")) + m_type = WebKitCSSTransformValue::RotateYTransformOperation; + else + m_type = WebKitCSSTransformValue::RotateZTransformOperation; + } else if (equalIgnoringCase(name, "rotate3d(")) { + m_type = WebKitCSSTransformValue::Rotate3DTransformOperation; + m_argCount = 7; + m_unit = CSSParser::FNumber; + } else if (equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "skewx(") || equalIgnoringCase(name, "skewy(")) { + m_unit = CSSParser::FAngle; + if (equalIgnoringCase(name, "skew(")) + m_type = WebKitCSSTransformValue::SkewTransformOperation; + else if (equalIgnoringCase(name, "skewx(")) + m_type = WebKitCSSTransformValue::SkewXTransformOperation; + else + m_type = WebKitCSSTransformValue::SkewYTransformOperation; + } else if (equalIgnoringCase(name, "translate(") || equalIgnoringCase(name, "translatex(") || equalIgnoringCase(name, "translatey(") || equalIgnoringCase(name, "translatez(")) { + m_unit = CSSParser::FLength | CSSParser::FPercent; + if (equalIgnoringCase(name, "translate(")) + m_type = WebKitCSSTransformValue::TranslateTransformOperation; + else if (equalIgnoringCase(name, "translatex(")) + m_type = WebKitCSSTransformValue::TranslateXTransformOperation; + else if (equalIgnoringCase(name, "translatey(")) + m_type = WebKitCSSTransformValue::TranslateYTransformOperation; + else + m_type = WebKitCSSTransformValue::TranslateZTransformOperation; + } else if (equalIgnoringCase(name, "translate3d(")) { + m_type = WebKitCSSTransformValue::Translate3DTransformOperation; + m_argCount = 5; + m_unit = CSSParser::FLength | CSSParser::FPercent; + } else if (equalIgnoringCase(name, "matrix(")) { + m_type = WebKitCSSTransformValue::MatrixTransformOperation; + m_argCount = 11; + m_unit = CSSParser::FNumber; + } else if (equalIgnoringCase(name, "matrix3d(")) { + m_type = WebKitCSSTransformValue::Matrix3DTransformOperation; + m_argCount = 31; + m_unit = CSSParser::FNumber; + } else if (equalIgnoringCase(name, "perspective(")) { + m_type = WebKitCSSTransformValue::PerspectiveTransformOperation; + m_unit = CSSParser::FNumber; + } + + if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "skew(") || equalIgnoringCase(name, "translate(")) { + m_allowSingleArgument = true; + m_argCount = 3; + } + } + + WebKitCSSTransformValue::TransformOperationType type() const { return m_type; } + unsigned argCount() const { return m_argCount; } + CSSParser::Units unit() const { return m_unit; } + + bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; } + bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); } + +private: + WebKitCSSTransformValue::TransformOperationType m_type; + unsigned m_argCount; + bool m_allowSingleArgument; + CSSParser::Units m_unit; +}; + +PassRefPtr<CSSValueList> CSSParser::parseTransform() +{ + if (!m_valueList) + return 0; + + // The transform is a list of functional primitives that specify transform operations. + // We collect a list of WebKitCSSTransformValues, where each value specifies a single operation. + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit != CSSParserValue::Function || !value->function) + return 0; + + // Every primitive requires at least one argument. + CSSParserValueList* args = value->function->args.get(); + if (!args) + return 0; + + // See if the specified primitive is one we understand. + TransformOperationInfo info(value->function->name); + if (info.unknown()) + return 0; + + if (!info.hasCorrectArgCount(args->size())) + return 0; + + // Create the new WebKitCSSTransformValue for this operation and add it to our list. + RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(info.type()); + list->append(transformValue); + + // Snag our values. + CSSParserValue* a = args->current(); + unsigned argNumber = 0; + while (a) { + CSSParser::Units unit = info.unit(); + + if (info.type() == WebKitCSSTransformValue::Rotate3DTransformOperation && argNumber == 3) { + // 4th param of rotate3d() is an angle rather than a bare number, validate it as such + if (!validUnit(a, FAngle, true)) + return 0; + } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) { + // 3rd param of translate3d() cannot be a percentage + if (!validUnit(a, FLength, true)) + return 0; + } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && argNumber == 0) { + // 1st param of translateZ() cannot be a percentage + if (!validUnit(a, FLength, true)) + return 0; + } else if (!validUnit(a, unit, true)) + return 0; + + // Add the value to the current transform operation. + transformValue->append(CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit)); + + a = args->next(); + if (!a) + break; + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return 0; + a = args->next(); + + argNumber++; + } + } + + return list.release(); +} + +bool CSSParser::parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) +{ + propId1 = propId; + propId2 = propId; + propId3 = propId; + if (propId == CSSPropertyWebkitTransformOrigin) { + propId1 = CSSPropertyWebkitTransformOriginX; + propId2 = CSSPropertyWebkitTransformOriginY; + propId3 = CSSPropertyWebkitTransformOriginZ; + } + + switch (propId) { + case CSSPropertyWebkitTransformOrigin: + if (!parseTransformOriginShorthand(value, value2, value3)) + return false; + // parseTransformOriginShorthand advances the m_valueList pointer + break; + case CSSPropertyWebkitTransformOriginX: { + bool xFound = false, yFound = true; + value = parseFillPositionXY(m_valueList, xFound, yFound); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitTransformOriginY: { + bool xFound = true, yFound = false; + value = parseFillPositionXY(m_valueList, xFound, yFound); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitTransformOriginZ: { + if (validUnit(m_valueList->current(), FLength, m_strict)) + value = CSSPrimitiveValue::create(m_valueList->current()->fValue, (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit); + if (value) + m_valueList->next(); + break; + } + } + + return value; +} + +bool CSSParser::parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2) +{ + propId1 = propId; + propId2 = propId; + if (propId == CSSPropertyWebkitPerspectiveOrigin) { + propId1 = CSSPropertyWebkitPerspectiveOriginX; + propId2 = CSSPropertyWebkitPerspectiveOriginY; + } + + switch (propId) { + case CSSPropertyWebkitPerspectiveOrigin: + parseFillPosition(m_valueList, value, value2); + break; + case CSSPropertyWebkitPerspectiveOriginX: { + bool xFound = false, yFound = true; + value = parseFillPositionXY(m_valueList, xFound, yFound); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitPerspectiveOriginY: { + bool xFound = true, yFound = false; + value = parseFillPositionXY(m_valueList, xFound, yFound); + if (value) + m_valueList->next(); + break; + } + } + + return value; +} + +bool CSSParser::parseTextEmphasisStyle(bool important) +{ + unsigned valueListSize = m_valueList->size(); + + RefPtr<CSSPrimitiveValue> fill; + RefPtr<CSSPrimitiveValue> shape; + + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit == CSSPrimitiveValue::CSS_STRING) { + if (fill || shape || (valueListSize != 1 && !inShorthand())) + return false; + addProperty(CSSPropertyWebkitTextEmphasisStyle, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING), important); + m_valueList->next(); + return true; + } + + if (value->id == CSSValueNone) { + if (fill || shape || (valueListSize != 1 && !inShorthand())) + return false; + addProperty(CSSPropertyWebkitTextEmphasisStyle, CSSPrimitiveValue::createIdentifier(CSSValueNone), important); + m_valueList->next(); + return true; + } + + if (value->id == CSSValueOpen || value->id == CSSValueFilled) { + if (fill) + return false; + fill = CSSPrimitiveValue::createIdentifier(value->id); + } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) { + if (shape) + return false; + shape = CSSPrimitiveValue::createIdentifier(value->id); + } else if (!inShorthand()) + return false; + else + break; + } + + if (fill && shape) { + RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); + parsedValues->append(fill.release()); + parsedValues->append(shape.release()); + addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important); + return true; + } + if (fill) { + addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important); + return true; + } + if (shape) { + addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important); + return true; + } + + return false; +} + +static inline int yyerror(const char*) { return 1; } + +#define END_TOKEN 0 + +#include "CSSGrammar.h" + +int CSSParser::lex(void* yylvalWithoutType) +{ + YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType); + int length; + + lex(); + + UChar* t = text(&length); + + switch (token()) { + case WHITESPACE: + case SGML_CD: + case INCLUDES: + case DASHMATCH: + break; + + case URI: + case STRING: + case IDENT: + case NTH: + case HEX: + case IDSEL: + case DIMEN: + case UNICODERANGE: + case FUNCTION: + case NOTFUNCTION: + yylval->string.characters = t; + yylval->string.length = length; + break; + + case IMPORT_SYM: + case PAGE_SYM: + case MEDIA_SYM: + case FONT_FACE_SYM: + case CHARSET_SYM: + case NAMESPACE_SYM: + case WEBKIT_KEYFRAMES_SYM: + + case IMPORTANT_SYM: + break; + + case QEMS: + length--; + case GRADS: + case TURNS: + length--; + case DEGS: + case RADS: + case KHERTZ: + case REMS: + length--; + case MSECS: + case HERTZ: + case EMS: + case EXS: + case PXS: + case CMS: + case MMS: + case INS: + case PTS: + case PCS: + length--; + case SECS: + case PERCENTAGE: + length--; + case FLOATTOKEN: + case INTEGER: + yylval->number = charactersToDouble(t, length); + break; + + default: + break; + } + + return token(); +} + +void CSSParser::recheckAtKeyword(const UChar* str, int len) +{ + String ruleName(str, len); + if (equalIgnoringCase(ruleName, "@import")) + yyTok = IMPORT_SYM; + else if (equalIgnoringCase(ruleName, "@page")) + yyTok = PAGE_SYM; + else if (equalIgnoringCase(ruleName, "@media")) + yyTok = MEDIA_SYM; + else if (equalIgnoringCase(ruleName, "@font-face")) + yyTok = FONT_FACE_SYM; + else if (equalIgnoringCase(ruleName, "@charset")) + yyTok = CHARSET_SYM; + else if (equalIgnoringCase(ruleName, "@namespace")) + yyTok = NAMESPACE_SYM; + else if (equalIgnoringCase(ruleName, "@-webkit-keyframes")) + yyTok = WEBKIT_KEYFRAMES_SYM; + else if (equalIgnoringCase(ruleName, "@-webkit-mediaquery")) + yyTok = WEBKIT_MEDIAQUERY_SYM; +} + +UChar* CSSParser::text(int *length) +{ + UChar* start = yytext; + int l = yyleng; + switch (yyTok) { + case STRING: + l--; + /* nobreak */ + case HEX: + case IDSEL: + start++; + l--; + break; + case URI: + // "url("{w}{string}{w}")" + // "url("{w}{url}{w}")" + // strip "url(" and ")" + start += 4; + l -= 5; + // strip {w} + while (l && isHTMLSpace(*start)) { + ++start; + --l; + } + while (l && isHTMLSpace(start[l - 1])) + --l; + if (l && (*start == '"' || *start == '\'')) { + ASSERT(l >= 2 && start[l - 1] == *start); + ++start; + l -= 2; + } + break; + default: + break; + } + + // process escapes + UChar* out = start; + UChar* escape = 0; + + bool sawEscape = false; + + for (int i = 0; i < l; i++) { + UChar* current = start + i; + if (escape == current - 1) { + if (isASCIIHexDigit(*current)) + continue; + if (yyTok == STRING && + (*current == '\n' || *current == '\r' || *current == '\f')) { + // ### handle \r\n case + if (*current != '\r') + escape = 0; + continue; + } + // in all other cases copy the char to output + // ### + *out++ = *current; + escape = 0; + continue; + } + if (escape == current - 2 && yyTok == STRING && + *(current-1) == '\r' && *current == '\n') { + escape = 0; + continue; + } + if (escape > current - 7 && isASCIIHexDigit(*current)) + continue; + if (escape) { + // add escaped char + unsigned uc = 0; + escape++; + while (escape < current) { + uc *= 16; + uc += toASCIIHexValue(*escape); + escape++; + } + // can't handle chars outside ucs2 + if (uc > 0xffff) + uc = 0xfffd; + *out++ = uc; + escape = 0; + if (isHTMLSpace(*current)) + continue; + } + if (!escape && *current == '\\') { + escape = current; + sawEscape = true; + continue; + } + *out++ = *current; + } + if (escape) { + // add escaped char + unsigned uc = 0; + escape++; + while (escape < start+l) { + uc *= 16; + uc += toASCIIHexValue(*escape); + escape++; + } + // can't handle chars outside ucs2 + if (uc > 0xffff) + uc = 0xfffd; + *out++ = uc; + } + + *length = out - start; + + // If we have an unrecognized @-keyword, and if we handled any escapes at all, then + // we should attempt to adjust yyTok to the correct type. + if (yyTok == ATKEYWORD && sawEscape) + recheckAtKeyword(start, *length); + + return start; +} + +void CSSParser::countLines() +{ + for (UChar* current = yytext; current < yytext + yyleng; ++current) { + if (*current == '\n') + ++m_lineNumber; + } +} + +CSSSelector* CSSParser::createFloatingSelector() +{ + CSSSelector* selector = fastNew<CSSSelector>(); + m_floatingSelectors.add(selector); + return selector; +} + +CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector) +{ + if (selector) { + ASSERT(m_floatingSelectors.contains(selector)); + m_floatingSelectors.remove(selector); + } + return selector; +} + +CSSParserValueList* CSSParser::createFloatingValueList() +{ + CSSParserValueList* list = new CSSParserValueList; + m_floatingValueLists.add(list); + return list; +} + +CSSParserValueList* CSSParser::sinkFloatingValueList(CSSParserValueList* list) +{ + if (list) { + ASSERT(m_floatingValueLists.contains(list)); + m_floatingValueLists.remove(list); + } + return list; +} + +CSSParserFunction* CSSParser::createFloatingFunction() +{ + CSSParserFunction* function = new CSSParserFunction; + m_floatingFunctions.add(function); + return function; +} + +CSSParserFunction* CSSParser::sinkFloatingFunction(CSSParserFunction* function) +{ + if (function) { + ASSERT(m_floatingFunctions.contains(function)); + m_floatingFunctions.remove(function); + } + return function; +} + +CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value) +{ + if (value.unit == CSSParserValue::Function) { + ASSERT(m_floatingFunctions.contains(value.function)); + m_floatingFunctions.remove(value.function); + } + return value; +} + +MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values) +{ + m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values); + return m_floatingMediaQueryExp.get(); +} + +PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression) +{ + ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp); + return m_floatingMediaQueryExp.release(); +} + +Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList() +{ + m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >); + return m_floatingMediaQueryExpList.get(); +} + +PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list) +{ + ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList); + return m_floatingMediaQueryExpList.release(); +} + +MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions) +{ + m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions)); + return m_floatingMediaQuery.get(); +} + +MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions) +{ + return createFloatingMediaQuery(MediaQuery::None, "all", expressions); +} + +PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query) +{ + ASSERT_UNUSED(query, query == m_floatingMediaQuery); + return m_floatingMediaQuery.release(); +} + +MediaList* CSSParser::createMediaList() +{ + RefPtr<MediaList> list = MediaList::create(); + MediaList* result = list.get(); + m_parsedStyleObjects.append(list.release()); + return result; +} + +CSSRule* CSSParser::createCharsetRule(const CSSParserString& charset) +{ + if (!m_styleSheet) + return 0; + RefPtr<CSSCharsetRule> rule = CSSCharsetRule::create(m_styleSheet, charset); + CSSCharsetRule* result = rule.get(); + m_parsedStyleObjects.append(rule.release()); + return result; +} + +CSSRule* CSSParser::createImportRule(const CSSParserString& url, MediaList* media) +{ + if (!media || !m_styleSheet || !m_allowImportRules) + return 0; + RefPtr<CSSImportRule> rule = CSSImportRule::create(m_styleSheet, url, media); + CSSImportRule* result = rule.get(); + m_parsedStyleObjects.append(rule.release()); + return result; +} + +CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules) +{ + if (!media || !rules || !m_styleSheet) + return 0; + m_allowImportRules = m_allowNamespaceDeclarations = false; + RefPtr<CSSMediaRule> rule = CSSMediaRule::create(m_styleSheet, media, rules); + CSSMediaRule* result = rule.get(); + m_parsedStyleObjects.append(rule.release()); + return result; +} + +CSSRuleList* CSSParser::createRuleList() +{ + RefPtr<CSSRuleList> list = CSSRuleList::create(); + CSSRuleList* listPtr = list.get(); + + m_parsedRuleLists.append(list.release()); + return listPtr; +} + +WebKitCSSKeyframesRule* CSSParser::createKeyframesRule() +{ + m_allowImportRules = m_allowNamespaceDeclarations = false; + RefPtr<WebKitCSSKeyframesRule> rule = WebKitCSSKeyframesRule::create(m_styleSheet); + WebKitCSSKeyframesRule* rulePtr = rule.get(); + m_parsedStyleObjects.append(rule.release()); + return rulePtr; +} + +CSSRule* CSSParser::createStyleRule(Vector<CSSSelector*>* selectors) +{ + CSSStyleRule* result = 0; + markRuleBodyEnd(); + if (selectors) { + m_allowImportRules = m_allowNamespaceDeclarations = false; + RefPtr<CSSStyleRule> rule = CSSStyleRule::create(m_styleSheet, m_lastSelectorLineNumber); + rule->adoptSelectorVector(*selectors); + if (m_hasFontFaceOnlyValues) + deleteFontFaceOnlyValues(); + rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); + result = rule.get(); + m_parsedStyleObjects.append(rule.release()); + if (m_ruleRangeMap) { + ASSERT(m_currentRuleData); + m_currentRuleData->styleSourceData->styleBodyRange = m_ruleBodyRange; + m_currentRuleData->selectorListRange = m_selectorListRange; + m_ruleRangeMap->set(result, m_currentRuleData.release()); + m_currentRuleData = CSSRuleSourceData::create(); + m_currentRuleData->styleSourceData = CSSStyleSourceData::create(); + m_inStyleRuleOrDeclaration = false; + } + } + resetSelectorListMarks(); + resetRuleBodyMarks(); + clearProperties(); + return result; +} + +CSSRule* CSSParser::createFontFaceRule() +{ + m_allowImportRules = m_allowNamespaceDeclarations = false; + for (unsigned i = 0; i < m_numParsedProperties; ++i) { + CSSProperty* property = m_parsedProperties[i]; + int id = property->id(); + if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isPrimitiveValue()) { + RefPtr<CSSValue> value = property->m_value.release(); + property->m_value = CSSValueList::createCommaSeparated(); + static_cast<CSSValueList*>(property->m_value.get())->append(value.release()); + } else if (id == CSSPropertyFontFamily && static_cast<CSSValueList*>(property->m_value.get())->length() != 1) { + // Unlike font-family property, font-family descriptor in @font-face rule can take only one family name. + // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc + clearProperties(); + return 0; + } + } + RefPtr<CSSFontFaceRule> rule = CSSFontFaceRule::create(m_styleSheet); + rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); + clearProperties(); + CSSFontFaceRule* result = rule.get(); + m_parsedStyleObjects.append(rule.release()); + return result; +} + +void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri) +{ + if (!m_styleSheet || !m_allowNamespaceDeclarations) + return; + m_allowImportRules = false; + m_styleSheet->addNamespace(this, prefix, uri); +} + +CSSRule* CSSParser::createPageRule(CSSSelector* pageSelector) +{ + // FIXME: Margin at-rules are ignored. + m_allowImportRules = m_allowNamespaceDeclarations = false; + CSSPageRule* pageRule = 0; + if (pageSelector) { + RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, pageSelector, m_lastSelectorLineNumber); + rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); + pageRule = rule.get(); + m_parsedStyleObjects.append(rule.release()); + } + clearProperties(); + return pageRule; +} + +CSSRule* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */) +{ + // FIXME: Implement margin at-rule here, using: + // - marginBox: margin box + // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_numParsedProperties) are for this at-rule. + // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid. + + endDeclarationsForMarginBox(); + return 0; // until this method is implemented. +} + +void CSSParser::startDeclarationsForMarginBox() +{ + m_numParsedPropertiesBeforeMarginBox = m_numParsedProperties; +} + +void CSSParser::endDeclarationsForMarginBox() +{ + ASSERT(m_numParsedPropertiesBeforeMarginBox != INVALID_NUM_PARSED_PROPERTIES); + rollbackLastProperties(m_numParsedProperties - m_numParsedPropertiesBeforeMarginBox); + m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; +} + +void CSSParser::deleteFontFaceOnlyValues() +{ + ASSERT(m_hasFontFaceOnlyValues); + int deletedProperties = 0; + + for (unsigned i = 0; i < m_numParsedProperties; ++i) { + CSSProperty* property = m_parsedProperties[i]; + int id = property->id(); + if ((id == CSSPropertyFontWeight || id == CSSPropertyFontStyle || id == CSSPropertyFontVariant) && property->value()->isValueList()) { + delete property; + deletedProperties++; + } else if (deletedProperties) + m_parsedProperties[i - deletedProperties] = m_parsedProperties[i]; + } + + m_numParsedProperties -= deletedProperties; +} + +WebKitCSSKeyframeRule* CSSParser::createKeyframeRule(CSSParserValueList* keys) +{ + // Create a key string from the passed keys + String keyString; + for (unsigned i = 0; i < keys->size(); ++i) { + float key = (float) keys->valueAt(i)->fValue; + if (i != 0) + keyString += ","; + keyString += String::number(key); + keyString += "%"; + } + + RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(m_styleSheet); + keyframe->setKeyText(keyString); + keyframe->setDeclaration(CSSMutableStyleDeclaration::create(0, m_parsedProperties, m_numParsedProperties)); + + clearProperties(); + + WebKitCSSKeyframeRule* keyframePtr = keyframe.get(); + m_parsedStyleObjects.append(keyframe.release()); + return keyframePtr; +} + +void CSSParser::invalidBlockHit() +{ + if (m_styleSheet && !m_hadSyntacticallyValidCSSRule) + m_styleSheet->setHasSyntacticallyValidCSSHeader(false); +} + +void CSSParser::updateLastSelectorLineAndPosition() +{ + m_lastSelectorLineNumber = m_lineNumber; + markRuleBodyStart(); +} + +void CSSParser::markSelectorListStart() +{ + m_selectorListRange.start = yytext - m_data; +} + +void CSSParser::markSelectorListEnd() +{ + if (!m_currentRuleData) + return; + UChar* listEnd = yytext; + while (listEnd > m_data + 1) { + if (isHTMLSpace(*(listEnd - 1))) + --listEnd; + else + break; + } + m_selectorListRange.end = listEnd - m_data; +} + +void CSSParser::markRuleBodyStart() +{ + unsigned offset = yytext - m_data; + if (*yytext == '{') + ++offset; // Skip the rule body opening brace. + if (offset > m_ruleBodyRange.start) + m_ruleBodyRange.start = offset; + m_inStyleRuleOrDeclaration = true; +} + +void CSSParser::markRuleBodyEnd() +{ + unsigned offset = yytext - m_data; + if (offset > m_ruleBodyRange.end) + m_ruleBodyRange.end = offset; +} + +void CSSParser::markPropertyStart() +{ + if (!m_inStyleRuleOrDeclaration) + return; + m_propertyRange.start = yytext - m_data; +} + +void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) +{ + if (!m_inStyleRuleOrDeclaration) + return; + unsigned offset = yytext - m_data; + if (*yytext == ';') // Include semicolon into the property text. + ++offset; + m_propertyRange.end = offset; + if (m_propertyRange.start != UINT_MAX && m_currentRuleData) { + // This stuff is only executed when the style data retrieval is requested by client. + const unsigned start = m_propertyRange.start; + const unsigned end = m_propertyRange.end; + ASSERT(start < end); + String propertyString = String(m_data + start, end - start).stripWhiteSpace(); + if (propertyString.endsWith(";", true)) + propertyString = propertyString.left(propertyString.length() - 1); + Vector<String> propertyComponents; + size_t colonIndex = propertyString.find(":"); + ASSERT(colonIndex != notFound); + + String name = propertyString.left(colonIndex).stripWhiteSpace(); + String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace(); + // The property range is relative to the declaration start offset. + m_currentRuleData->styleSourceData->propertyData.append( + CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - m_ruleBodyRange.start, end - m_ruleBodyRange.start))); + } + resetPropertyMarks(); +} + +static int cssPropertyID(const UChar* propertyName, unsigned length) +{ + if (!length) + return 0; + if (length > maxCSSPropertyNameLength) + return 0; + + char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character + + for (unsigned i = 0; i != length; ++i) { + UChar c = propertyName[i]; + if (c == 0 || c >= 0x7F) + return 0; // illegal character + buffer[i] = toASCIILower(c); + } + buffer[length] = '\0'; + + const char* name = buffer; + if (buffer[0] == '-') { + // If the prefix is -apple- or -khtml-, change it to -webkit-. + // This makes the string one character longer. + if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) { + memmove(buffer + 7, buffer + 6, length + 1 - 6); + memcpy(buffer, "-webkit", 7); + ++length; + } + + if (hasPrefix(buffer, length, "-webkit")) { + if (!strcmp(buffer, "-webkit-box-sizing")) { + // -webkit-box-sizing worked in Safari 4 and earlier. + const char* const boxSizing = "box-sizing"; + name = boxSizing; + length = strlen(boxSizing); + } else if (!strcmp(buffer, "-webkit-opacity")) { + // Honor -webkit-opacity as a synonym for opacity. + // This was the only syntax that worked in Safari 1.1, and may be in use on some websites and widgets. + const char* const opacity = "opacity"; + name = opacity; + length = strlen(opacity); + } else if (hasPrefix(buffer + 7, length - 7, "-border-")) { + // -webkit-border-*-*-radius worked in Safari 4 and earlier. -webkit-border-radius syntax + // differs from border-radius, so it is remains as a distinct property. + if (!strcmp(buffer + 15, "top-left-radius") + || !strcmp(buffer + 15, "top-right-radius") + || !strcmp(buffer + 15, "bottom-right-radius") + || !strcmp(buffer + 15, "bottom-left-radius")) { + name = buffer + 8; + length -= 8; + } + } + } + } + + const Property* hashTableEntry = findProperty(name, length); + return hashTableEntry ? hashTableEntry->id : 0; +} + +int cssPropertyID(const String& string) +{ + return cssPropertyID(string.characters(), string.length()); +} + +int cssPropertyID(const CSSParserString& string) +{ + return cssPropertyID(string.characters, string.length); +} + +int cssValueKeywordID(const CSSParserString& string) +{ + unsigned length = string.length; + if (!length) + return 0; + if (length > maxCSSValueKeywordLength) + return 0; + + char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character + + for (unsigned i = 0; i != length; ++i) { + UChar c = string.characters[i]; + if (c == 0 || c >= 0x7F) + return 0; // illegal character + buffer[i] = WTF::toASCIILower(c); + } + buffer[length] = '\0'; + + if (buffer[0] == '-') { + // If the prefix is -apple- or -khtml-, change it to -webkit-. + // This makes the string one character longer. + if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) { + memmove(buffer + 7, buffer + 6, length + 1 - 6); + memcpy(buffer, "-webkit", 7); + ++length; + } + } + + const Value* hashTableEntry = findValue(buffer, length); + return hashTableEntry ? hashTableEntry->id : 0; +} + +// "ident" from the CSS tokenizer, minus backslash-escape sequences +static 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 sequences +static 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. +String quoteCSSString(const String& string) +{ + // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one. + // Please see below for the actual logic. + unsigned quotedStringSize = 2; // Two quotes surrounding the entire string. + bool afterEscape = false; + for (unsigned i = 0; i < string.length(); ++i) { + UChar ch = string[i]; + if (ch == '\\' || ch == '\'') { + quotedStringSize += 2; + afterEscape = false; + } else if (ch < 0x20 || ch == 0x7F) { + quotedStringSize += 2 + (ch >= 0x10); + afterEscape = true; + } else { + quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' ')); + afterEscape = false; + } + } + + StringBuffer buffer(quotedStringSize); + unsigned index = 0; + buffer[index++] = '\''; + afterEscape = false; + for (unsigned i = 0; i < string.length(); ++i) { + UChar ch = string[i]; + if (ch == '\\' || ch == '\'') { + buffer[index++] = '\\'; + buffer[index++] = ch; + afterEscape = false; + } else if (ch < 0x20 || ch == 0x7F) { // Control characters. + static const char hexDigits[17] = "0123456789abcdef"; + buffer[index++] = '\\'; + if (ch >= 0x10) + buffer[index++] = hexDigits[ch >> 4]; + buffer[index++] = hexDigits[ch & 0xF]; + afterEscape = true; + } else { + // Space character may be required to separate backslash-escape sequence and normal characters. + if (afterEscape && (isASCIIHexDigit(ch) || ch == ' ')) + buffer[index++] = ' '; + buffer[index++] = ch; + afterEscape = false; + } + } + buffer[index++] = '\''; + + ASSERT(quotedStringSize == index); + return String::adopt(buffer); +} + +String quoteCSSStringIfNeeded(const String& string) +{ + return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string); +} + +String quoteCSSURLIfNeeded(const String& string) +{ + return isCSSTokenizerURL(string) ? string : quoteCSSString(string); +} + +bool isValidNthToken(const CSSParserString& token) +{ + // The tokenizer checks for the construct of an+b. + // nth can also accept "odd" or "even" but should not accept any other token. + return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even"); +} + +#define YY_DECL int CSSParser::lex() +#define yyconst const +typedef int yy_state_type; +typedef unsigned YY_CHAR; +// The following line makes sure we treat non-Latin-1 Unicode characters correctly. +#define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c) +#define YY_DO_BEFORE_ACTION \ + yytext = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = 0; \ + yy_c_buf_p = yy_cp; +#define YY_BREAK break; +#define ECHO +#define YY_RULE_SETUP +#define INITIAL 0 +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +#define yyterminate() yyTok = END_TOKEN; return yyTok +#define YY_FATAL_ERROR(a) +// The following line is needed to build the tokenizer with a condition stack. +// The macro is used in the tokenizer grammar with lines containing +// BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to +// tokenizer transition table, and 'mediaqueries' and 'initial' are +// offset multipliers that specify which transitions are active +// in the tokenizer during in each condition (tokenizer state). +#define BEGIN yy_start = 1 + 2 * + +#include "tokenizer.cpp" + +} diff --git a/Source/WebCore/css/CSSParser.h b/Source/WebCore/css/CSSParser.h new file mode 100644 index 0000000..e60519e --- /dev/null +++ b/Source/WebCore/css/CSSParser.h @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 - 2010 Torch Mobile (Beijing) Co. Ltd. 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. + */ + +#ifndef CSSParser_h +#define CSSParser_h + +#include "CSSGradientValue.h" +#include "CSSParserValues.h" +#include "CSSPropertySourceData.h" +#include "CSSSelectorList.h" +#include "Color.h" +#include "MediaQuery.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + + class CSSMutableStyleDeclaration; + class CSSPrimitiveValue; + class CSSProperty; + class CSSRule; + class CSSRuleList; + class CSSSelector; + class CSSStyleRule; + class CSSStyleSheet; + class CSSValue; + class CSSValueList; + class Document; + class MediaList; + class MediaQueryExp; + class StyleBase; + class StyleList; + class WebKitCSSKeyframeRule; + class WebKitCSSKeyframesRule; + + class CSSParser { + public: + CSSParser(bool strictParsing = true); + ~CSSParser(); + + void parseSheet(CSSStyleSheet*, const String&, int startLineNumber = 0, StyleRuleRangeMap* ruleRangeMap = 0); + PassRefPtr<CSSRule> parseRule(CSSStyleSheet*, const String&); + PassRefPtr<CSSRule> parseKeyframeRule(CSSStyleSheet*, const String&); + bool parseValue(CSSMutableStyleDeclaration*, int propId, const String&, bool important); + static bool parseColor(RGBA32& color, const String&, bool strict = false); + bool parseColor(CSSMutableStyleDeclaration*, const String&); + bool parseDeclaration(CSSMutableStyleDeclaration*, const String&, RefPtr<CSSStyleSourceData>* styleSourceData = 0); + bool parseMediaQuery(MediaList*, const String&); + + Document* document() const; + + void addProperty(int propId, PassRefPtr<CSSValue>, bool important); + void rollbackLastProperties(int num); + bool hasProperties() const { return m_numParsedProperties > 0; } + + bool parseValue(int propId, bool important); + bool parseShorthand(int propId, const int* properties, int numProperties, bool important); + bool parse4Values(int propId, const int* properties, bool important); + bool parseContent(int propId, bool important); + + PassRefPtr<CSSValue> parseAttr(CSSParserValueList* args); + + PassRefPtr<CSSValue> parseBackgroundColor(); + + bool parseFillImage(RefPtr<CSSValue>&); + PassRefPtr<CSSValue> parseFillPositionXY(CSSParserValueList*, bool& xFound, bool& yFound); + void parseFillPosition(CSSParserValueList*, RefPtr<CSSValue>&, RefPtr<CSSValue>&); + void parseFillRepeat(RefPtr<CSSValue>&, RefPtr<CSSValue>&); + PassRefPtr<CSSValue> parseFillSize(int propId, bool &allowComma); + + bool parseFillProperty(int propId, int& propId1, int& propId2, RefPtr<CSSValue>&, RefPtr<CSSValue>&); + bool parseFillShorthand(int propId, const int* properties, int numProperties, bool important); + + void addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval); + + void addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval); + + PassRefPtr<CSSValue> parseAnimationDelay(); + PassRefPtr<CSSValue> parseAnimationDirection(); + PassRefPtr<CSSValue> parseAnimationDuration(); + PassRefPtr<CSSValue> parseAnimationFillMode(); + PassRefPtr<CSSValue> parseAnimationIterationCount(); + PassRefPtr<CSSValue> parseAnimationName(); + PassRefPtr<CSSValue> parseAnimationPlayState(); + PassRefPtr<CSSValue> parseAnimationProperty(); + PassRefPtr<CSSValue> parseAnimationTimingFunction(); + + bool parseTransformOriginShorthand(RefPtr<CSSValue>&, RefPtr<CSSValue>&, RefPtr<CSSValue>&); + bool parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result); + bool parseAnimationProperty(int propId, RefPtr<CSSValue>&); + bool parseTransitionShorthand(bool important); + bool parseAnimationShorthand(bool important); + + bool parseDashboardRegions(int propId, bool important); + + bool parseShape(int propId, bool important); + + bool parseFont(bool important); + PassRefPtr<CSSValueList> parseFontFamily(); + + bool parseCounter(int propId, int defaultValue, bool important); + PassRefPtr<CSSValue> parseCounterContent(CSSParserValueList* args, bool counters); + + bool parseColorParameters(CSSParserValue*, int* colorValues, bool parseAlpha); + bool parseHSLParameters(CSSParserValue*, double* colorValues, bool parseAlpha); + PassRefPtr<CSSPrimitiveValue> parseColor(CSSParserValue* = 0); + bool parseColorFromValue(CSSParserValue*, RGBA32&); + void parseSelector(const String&, Document* doc, CSSSelectorList&); + + static bool parseColor(const String&, RGBA32& rgb, bool strict); + + bool parseFontStyle(bool important); + bool parseFontVariant(bool important); + bool parseFontWeight(bool important); + bool parseFontFaceSrc(); + bool parseFontFaceUnicodeRange(); + +#if ENABLE(SVG) + bool parseSVGValue(int propId, bool important); + PassRefPtr<CSSValue> parseSVGPaint(); + PassRefPtr<CSSValue> parseSVGColor(); + PassRefPtr<CSSValue> parseSVGStrokeDasharray(); +#endif + +#if ENABLE(WCSS) + PassRefPtr<CSSValue> parseWCSSInputProperty(); +#endif + + // CSS3 Parsing Routines (for properties specific to CSS3) + bool parseShadow(int propId, bool important); + bool parseBorderImage(int propId, bool important, RefPtr<CSSValue>&); + bool parseBorderRadius(int propId, bool important); + + bool parseReflect(int propId, bool important); + + // Image generators + bool parseCanvas(RefPtr<CSSValue>&); + + bool parseDeprecatedGradient(RefPtr<CSSValue>&); + bool parseLinearGradient(RefPtr<CSSValue>&, CSSGradientRepeat repeating); + bool parseRadialGradient(RefPtr<CSSValue>&, CSSGradientRepeat repeating); + + PassRefPtr<CSSValueList> parseTransform(); + bool parseTransformOrigin(int propId, int& propId1, int& propId2, int& propId3, RefPtr<CSSValue>&, RefPtr<CSSValue>&, RefPtr<CSSValue>&); + bool parsePerspectiveOrigin(int propId, int& propId1, int& propId2, RefPtr<CSSValue>&, RefPtr<CSSValue>&); + + bool parseTextEmphasisStyle(bool important); + + int yyparse(); + + CSSSelector* createFloatingSelector(); + CSSSelector* sinkFloatingSelector(CSSSelector*); + + CSSParserValueList* createFloatingValueList(); + CSSParserValueList* sinkFloatingValueList(CSSParserValueList*); + + CSSParserFunction* createFloatingFunction(); + CSSParserFunction* sinkFloatingFunction(CSSParserFunction*); + + CSSParserValue& sinkFloatingValue(CSSParserValue&); + + MediaList* createMediaList(); + CSSRule* createCharsetRule(const CSSParserString&); + CSSRule* createImportRule(const CSSParserString&, MediaList*); + WebKitCSSKeyframeRule* createKeyframeRule(CSSParserValueList*); + WebKitCSSKeyframesRule* createKeyframesRule(); + CSSRule* createMediaRule(MediaList*, CSSRuleList*); + CSSRuleList* createRuleList(); + CSSRule* createStyleRule(Vector<CSSSelector*>* selectors); + CSSRule* createFontFaceRule(); + CSSRule* createPageRule(CSSSelector* pageSelector); + CSSRule* createMarginAtRule(CSSSelector::MarginBoxType marginBox); + void startDeclarationsForMarginBox(); + void endDeclarationsForMarginBox(); + + MediaQueryExp* createFloatingMediaQueryExp(const AtomicString&, CSSParserValueList*); + PassOwnPtr<MediaQueryExp> sinkFloatingMediaQueryExp(MediaQueryExp*); + Vector<OwnPtr<MediaQueryExp> >* createFloatingMediaQueryExpList(); + PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >*); + MediaQuery* createFloatingMediaQuery(MediaQuery::Restrictor, const String&, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > >); + MediaQuery* createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > >); + PassOwnPtr<MediaQuery> sinkFloatingMediaQuery(MediaQuery*); + + void addNamespace(const AtomicString& prefix, const AtomicString& uri); + + void invalidBlockHit(); + + Vector<CSSSelector*>* reusableSelectorVector() { return &m_reusableSelectorVector; } + + void updateLastSelectorLineAndPosition(); + + void clearProperties(); + + bool m_strict; + bool m_important; + int m_id; + CSSStyleSheet* m_styleSheet; + RefPtr<CSSRule> m_rule; + RefPtr<CSSRule> m_keyframe; + OwnPtr<MediaQuery> m_mediaQuery; + CSSParserValueList* m_valueList; + CSSProperty** m_parsedProperties; + CSSSelectorList* m_selectorListForParseSelector; + unsigned m_numParsedProperties; + unsigned m_maxParsedProperties; + unsigned m_numParsedPropertiesBeforeMarginBox; + + int m_inParseShorthand; + int m_currentShorthand; + bool m_implicitShorthand; + + bool m_hasFontFaceOnlyValues; + bool m_hadSyntacticallyValidCSSRule; + + AtomicString m_defaultNamespace; + + // tokenizer methods and data + bool m_inStyleRuleOrDeclaration; + SourceRange m_selectorListRange; + SourceRange m_ruleBodyRange; + SourceRange m_propertyRange; + StyleRuleRangeMap* m_ruleRangeMap; + RefPtr<CSSRuleSourceData> m_currentRuleData; + void markSelectorListStart(); + void markSelectorListEnd(); + void markRuleBodyStart(); + void markRuleBodyEnd(); + void markPropertyStart(); + void markPropertyEnd(bool isImportantFound, bool isPropertyParsed); + void resetSelectorListMarks() { m_selectorListRange.start = m_selectorListRange.end = 0; } + void resetRuleBodyMarks() { m_ruleBodyRange.start = m_ruleBodyRange.end = 0; } + void resetPropertyMarks() { m_propertyRange.start = m_propertyRange.end = UINT_MAX; } + int lex(void* yylval); + int token() { return yyTok; } + UChar* text(int* length); + void countLines(); + int lex(); + + private: + void recheckAtKeyword(const UChar* str, int len); + + void setupParser(const char* prefix, const String&, const char* suffix); + + bool inShorthand() const { return m_inParseShorthand; } + + void checkForOrphanedUnits(); + + void deleteFontFaceOnlyValues(); + + bool isGeneratedImageValue(CSSParserValue*) const; + bool parseGeneratedImage(RefPtr<CSSValue>&); + + enum SizeParameterType { + None, + Auto, + Length, + PageSize, + Orientation, + }; + + bool parsePage(int propId, bool important); + bool parseSize(int propId, bool important); + SizeParameterType parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType); + + UChar* m_data; + UChar* yytext; + UChar* yy_c_buf_p; + UChar yy_hold_char; + int yy_last_accepting_state; + UChar* yy_last_accepting_cpos; + int yyleng; + int yyTok; + int yy_start; + int m_lineNumber; + int m_lastSelectorLineNumber; + + bool m_allowImportRules; + bool m_allowNamespaceDeclarations; + + Vector<RefPtr<StyleBase> > m_parsedStyleObjects; + Vector<RefPtr<CSSRuleList> > m_parsedRuleLists; + HashSet<CSSSelector*> m_floatingSelectors; + HashSet<CSSParserValueList*> m_floatingValueLists; + HashSet<CSSParserFunction*> m_floatingFunctions; + + OwnPtr<MediaQuery> m_floatingMediaQuery; + OwnPtr<MediaQueryExp> m_floatingMediaQueryExp; + OwnPtr<Vector<OwnPtr<MediaQueryExp> > > m_floatingMediaQueryExpList; + + Vector<CSSSelector*> m_reusableSelectorVector; + + // defines units allowed for a certain property, used in parseUnit + enum Units { + FUnknown = 0x0000, + FInteger = 0x0001, + FNumber = 0x0002, // Real Numbers + FPercent = 0x0004, + FLength = 0x0008, + FAngle = 0x0010, + FTime = 0x0020, + FFrequency = 0x0040, + FRelative = 0x0100, + FNonNeg = 0x0200 + }; + + friend inline Units operator|(Units a, Units b) + { + return static_cast<Units>(static_cast<unsigned>(a) | static_cast<unsigned>(b)); + } + + static bool validUnit(CSSParserValue*, Units, bool strict); + + friend class TransformOperationInfo; + }; + + int cssPropertyID(const CSSParserString&); + int cssPropertyID(const String&); + int cssValueKeywordID(const CSSParserString&); + + class ShorthandScope : public FastAllocBase { + public: + ShorthandScope(CSSParser* parser, int propId) : m_parser(parser) + { + if (!(m_parser->m_inParseShorthand++)) + m_parser->m_currentShorthand = propId; + } + ~ShorthandScope() + { + if (!(--m_parser->m_inParseShorthand)) + m_parser->m_currentShorthand = 0; + } + + private: + CSSParser* m_parser; + }; + + String quoteCSSString(const String&); + String quoteCSSStringIfNeeded(const String&); + String quoteCSSURLIfNeeded(const String&); + + bool isValidNthToken(const CSSParserString&); +} // namespace WebCore + +#endif // CSSParser_h diff --git a/Source/WebCore/css/CSSParserValues.cpp b/Source/WebCore/css/CSSParserValues.cpp new file mode 100644 index 0000000..06651f1 --- /dev/null +++ b/Source/WebCore/css/CSSParserValues.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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 "CSSParserValues.h" +#include "CSSPrimitiveValue.h" +#include "CSSFunctionValue.h" +#include "CSSQuirkPrimitiveValue.h" + +namespace WebCore { + +CSSParserValueList::~CSSParserValueList() +{ + size_t numValues = m_values.size(); + for (size_t i = 0; i < numValues; i++) { + if (m_values[i].unit == CSSParserValue::Function) + delete m_values[i].function; + } +} + +void CSSParserValueList::addValue(const CSSParserValue& v) +{ + m_values.append(v); +} + +void CSSParserValueList::deleteValueAt(unsigned i) +{ + m_values.remove(i); +} + +PassRefPtr<CSSValue> CSSParserValue::createCSSValue() +{ + RefPtr<CSSValue> parsedValue; + if (id) + parsedValue = CSSPrimitiveValue::createIdentifier(id); + else if (unit == CSSPrimitiveValue::CSS_IDENT) + parsedValue = CSSPrimitiveValue::create(string, CSSPrimitiveValue::CSS_PARSER_IDENTIFIER); + else if (unit == CSSPrimitiveValue::CSS_NUMBER && isInt) + parsedValue = CSSPrimitiveValue::create(fValue, CSSPrimitiveValue::CSS_PARSER_INTEGER); + else if (unit == CSSParserValue::Operator) { + RefPtr<CSSPrimitiveValue> primitiveValue = CSSPrimitiveValue::createIdentifier(iValue); + primitiveValue->setPrimitiveType(CSSPrimitiveValue::CSS_PARSER_OPERATOR); + parsedValue = primitiveValue; + } else if (unit == CSSParserValue::Function) + parsedValue = CSSFunctionValue::create(function); + else if (unit == CSSPrimitiveValue::CSS_STRING || unit == CSSPrimitiveValue::CSS_URI || unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR) + parsedValue = CSSPrimitiveValue::create(string, (CSSPrimitiveValue::UnitTypes)unit); + else if (unit >= CSSPrimitiveValue::CSS_NUMBER && unit <= CSSPrimitiveValue::CSS_KHZ) + parsedValue = CSSPrimitiveValue::create(fValue, (CSSPrimitiveValue::UnitTypes)unit); + else if (unit >= CSSPrimitiveValue::CSS_TURN && unit <= CSSPrimitiveValue::CSS_REMS) // CSS3 Values and Units + parsedValue = CSSPrimitiveValue::create(fValue, (CSSPrimitiveValue::UnitTypes)unit); + else if (unit >= CSSParserValue::Q_EMS) + parsedValue = CSSQuirkPrimitiveValue::create(fValue, CSSPrimitiveValue::CSS_EMS); + return parsedValue; +} + +} + diff --git a/Source/WebCore/css/CSSParserValues.h b/Source/WebCore/css/CSSParserValues.h new file mode 100644 index 0000000..993ae28 --- /dev/null +++ b/Source/WebCore/css/CSSParserValues.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 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. + */ + +#ifndef CSSParserValues_h +#define CSSParserValues_h + +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class CSSValue; + +struct CSSParserString { + UChar* characters; + int length; + + void lower(); + + operator String() const { return String(characters, length); } + operator AtomicString() const { return AtomicString(characters, length); } +}; + +struct CSSParserFunction; + +struct CSSParserValue { + int id; + bool isInt; + union { + double fValue; + int iValue; + CSSParserString string; + CSSParserFunction* function; + }; + enum { + Operator = 0x100000, + Function = 0x100001, + Q_EMS = 0x100002 + }; + int unit; + + + PassRefPtr<CSSValue> createCSSValue(); +}; + +class CSSParserValueList : public FastAllocBase { +public: + CSSParserValueList() + : m_current(0) + { + } + ~CSSParserValueList(); + + void addValue(const CSSParserValue&); + void deleteValueAt(unsigned); + + unsigned size() const { return m_values.size(); } + CSSParserValue* current() { return m_current < m_values.size() ? &m_values[m_current] : 0; } + CSSParserValue* next() { ++m_current; return current(); } + + CSSParserValue* valueAt(unsigned i) { return i < m_values.size() ? &m_values[i] : 0; } + + void clear() { m_values.clear(); } + +private: + unsigned m_current; + Vector<CSSParserValue, 4> m_values; +}; + +struct CSSParserFunction : FastAllocBase { + CSSParserString name; + OwnPtr<CSSParserValueList> args; +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSPrimitiveValue.cpp b/Source/WebCore/css/CSSPrimitiveValue.cpp new file mode 100644 index 0000000..ce1b87b --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValue.cpp @@ -0,0 +1,998 @@ +/* + * (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 "CSSParser.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 "RGBColor.h" +#include "Rect.h" +#include "RenderStyle.h" +#include <wtf/ASCIICType.h> +#include <wtf/DecimalNumber.h> +#include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> +#include <wtf/text/StringBuffer.h> + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +using namespace WTF; + +namespace WebCore { + +static CSSPrimitiveValue::UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes type) +{ + // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions + // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment). + switch (type) { + case CSSPrimitiveValue::CSS_NUMBER: + return CSSPrimitiveValue::UNumber; + case CSSPrimitiveValue::CSS_PERCENTAGE: + return CSSPrimitiveValue::UPercent; + case CSSPrimitiveValue::CSS_PX: + case CSSPrimitiveValue::CSS_CM: + case CSSPrimitiveValue::CSS_MM: + case CSSPrimitiveValue::CSS_IN: + case CSSPrimitiveValue::CSS_PT: + case CSSPrimitiveValue::CSS_PC: + return CSSPrimitiveValue::ULength; + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + return CSSPrimitiveValue::UTime; + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: + return CSSPrimitiveValue::UAngle; + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + return CSSPrimitiveValue::UFrequency; + default: + return CSSPrimitiveValue::UOther; + } +} + +typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache; +static CSSTextCache& cssTextCache() +{ + DEFINE_STATIC_LOCAL(CSSTextCache, cache, ()); + return cache; +} + +// 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. + +inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncachedIdentifier(int identifier) +{ + return adoptRef(new CSSPrimitiveValue(identifier)); +} + +inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncachedColor(unsigned rgbValue) +{ + return adoptRef(new CSSPrimitiveValue(rgbValue)); +} + +inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncached(double value, UnitTypes type) +{ + return adoptRef(new CSSPrimitiveValue(value, type)); +} + +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 = createUncachedIdentifier(ident); + identValueCache[ident] = primitiveValue; + } + return primitiveValue.release(); + } + return createUncachedIdentifier(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 = createUncachedColor(Color::transparent).releaseRef(); + return colorTransparent; + } + if (rgbValue == Color::white) { + static CSSPrimitiveValue* colorWhite = createUncachedColor(Color::white).releaseRef(); + return colorWhite; + } + RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue); + if (primitiveValue) + return primitiveValue.release(); + primitiveValue = createUncachedColor(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 = createUncached(value, type); + integerValueCache[intValue][type] = primitiveValue; + } + return primitiveValue.release(); + } + } + + return createUncached(value, type); +} + +PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type) +{ + return adoptRef(new CSSPrimitiveValue(value, type)); +} + +static const AtomicString& valueOrPropertyName(int valueOrPropertyID) +{ + ASSERT_ARG(valueOrPropertyID, valueOrPropertyID >= 0); + ASSERT_ARG(valueOrPropertyID, valueOrPropertyID < numCSSValueKeywords || (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties)); + + if (valueOrPropertyID < 0) + return nullAtom; + + if (valueOrPropertyID < numCSSValueKeywords) { + static AtomicString* cssValueKeywordStrings[numCSSValueKeywords]; + if (!cssValueKeywordStrings[valueOrPropertyID]) + cssValueKeywordStrings[valueOrPropertyID] = new AtomicString(getValueName(valueOrPropertyID)); + return *cssValueKeywordStrings[valueOrPropertyID]; + } + + if (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties) { + static AtomicString* cssPropertyStrings[numCSSProperties]; + int propertyIndex = valueOrPropertyID - firstCSSProperty; + if (!cssPropertyStrings[propertyIndex]) + cssPropertyStrings[propertyIndex] = new AtomicString(getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID))); + return *cssPropertyStrings[propertyIndex]; + } + + return nullAtom; +} + +CSSPrimitiveValue::CSSPrimitiveValue() + : m_type(0) + , m_hasCachedCSSText(false) +{ +} + +CSSPrimitiveValue::CSSPrimitiveValue(int ident) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + m_value.ident = ident; +} + +CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) + : m_type(type) + , m_hasCachedCSSText(false) +{ + m_value.num = num; +} + +CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) + : m_type(type) + , m_hasCachedCSSText(false) +{ + if ((m_value.string = str.impl())) + m_value.string->ref(); +} + +CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) + : m_type(CSS_RGBCOLOR) + , m_hasCachedCSSText(false) +{ + m_value.rgbcolor = color; +} + +CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) + : m_hasCachedCSSText(false) +{ + 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_hasCachedCSSText = false; + m_value.counter = c.releaseRef(); +} + +void CSSPrimitiveValue::init(PassRefPtr<Rect> r) +{ + m_type = CSS_RECT; + m_hasCachedCSSText = false; + m_value.rect = r.releaseRef(); +} + +#if ENABLE(DASHBOARD_SUPPORT) +void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r) +{ + m_type = CSS_DASHBOARD_REGION; + m_hasCachedCSSText = false; + m_value.region = r.releaseRef(); +} +#endif + +void CSSPrimitiveValue::init(PassRefPtr<Pair> p) +{ + m_type = CSS_PAIR; + m_hasCachedCSSText = false; + 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_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; + if (m_hasCachedCSSText) { + cssTextCache().remove(this); + m_hasCachedCSSText = false; + } +} + +int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle) +{ + return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle)); +} + +int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier) +{ + return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle, multiplier)); +} + +// Lengths expect an int that is only 28-bits, so we have to check for a +// different overflow. +int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle) +{ + return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle)); +} + +int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier) +{ + return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle, multiplier)); +} + +short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle) +{ + return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle)); +} + +short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier) +{ + return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle, multiplier)); +} + +float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize) +{ + return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize)); +} + +float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); +} + +double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, 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_REMS: + applyZoomMultiplier = false; + factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); + 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, double, ExceptionCode& ec) +{ + // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. + // No other engine supports mutating style through this API. Computed style is always read-only anyway. + // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. + ec = NO_MODIFICATION_ALLOWED_ERR; +} + +static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType) +{ + double factor = 1.0; + // FIXME: the switch can be replaced by an array of scale factors. + switch (unitType) { + // These are "canonical" units in their respective categories. + case CSSPrimitiveValue::CSS_PX: + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_HZ: + break; + case CSSPrimitiveValue::CSS_CM: + factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) + break; + case CSSPrimitiveValue::CSS_MM: + factor = cssPixelsPerInch / 25.4; + break; + case CSSPrimitiveValue::CSS_IN: + factor = cssPixelsPerInch; + break; + case CSSPrimitiveValue::CSS_PT: + factor = cssPixelsPerInch / 72.0; + break; + case CSSPrimitiveValue::CSS_PC: + factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt + break; + case CSSPrimitiveValue::CSS_RAD: + factor = 180 / piDouble; + break; + case CSSPrimitiveValue::CSS_GRAD: + factor = 0.9; + break; + case CSSPrimitiveValue::CSS_TURN: + factor = 360; + break; + case CSSPrimitiveValue::CSS_S: + case CSSPrimitiveValue::CSS_KHZ: + factor = 1000; + break; + default: + break; + } + + return factor; +} + +double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const +{ + double result = 0; + bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); + if (!success) { + ec = INVALID_ACCESS_ERR; + return 0.0; + } + + ec = 0; + return result; +} + +double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const +{ + double result = 0; + getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); + return result; +} + +CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) +{ + // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit + // in each category (based on unitflags). + switch (category) { + case UNumber: + return CSS_NUMBER; + case ULength: + return CSS_PX; + case UPercent: + return CSS_UNKNOWN; // Cannot convert between numbers and percent. + case UTime: + return CSS_MS; + case UAngle: + return CSS_DEG; + case UFrequency: + return CSS_HZ; + default: + return CSS_UNKNOWN; + } +} + +bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const +{ + if (m_type < CSS_NUMBER || (m_type > CSS_DIMENSION && m_type < CSS_TURN) || requestedUnitType < CSS_NUMBER || (requestedUnitType > CSS_DIMENSION && requestedUnitType < CSS_TURN)) + return false; + if (requestedUnitType == m_type || requestedUnitType == CSS_DIMENSION) { + *result = m_value.num; + return true; + } + + UnitTypes sourceUnitType = static_cast<UnitTypes>(m_type); + UnitCategory sourceCategory = unitCategory(sourceUnitType); + ASSERT(sourceCategory != UOther); + + UnitTypes targetUnitType = requestedUnitType; + UnitCategory targetCategory = unitCategory(targetUnitType); + ASSERT(targetCategory != UOther); + + // Cannot convert between unrelated unit categories if one of them is not UNumber. + if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber) + return false; + + if (targetCategory == UNumber) { + // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category. + targetUnitType = canonicalUnitTypeForCategory(sourceCategory); + if (targetUnitType == CSS_UNKNOWN) + return false; + } + + if (sourceUnitType == CSS_NUMBER) { + // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode. + sourceUnitType = canonicalUnitTypeForCategory(targetCategory); + if (sourceUnitType == CSS_UNKNOWN) + return false; + } + + double convertedValue = m_value.num; + + // First convert the value from m_type to canonical type. + double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType); + convertedValue *= factor; + + // Now convert from canonical type to the target unitType. + factor = conversionToCanonicalUnitsScaleFactor(targetUnitType); + convertedValue /= factor; + + *result = convertedValue; + return true; +} + +void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec) +{ + // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. + // No other engine supports mutating style through this API. Computed style is always read-only anyway. + // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. + ec = NO_MODIFICATION_ALLOWED_ERR; +} + +String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const +{ + ec = 0; + switch (m_type) { + case CSS_STRING: + case CSS_ATTR: + case CSS_URI: + return m_value.string; + case CSS_IDENT: + return valueOrPropertyName(m_value.ident); + default: + ec = INVALID_ACCESS_ERR; + break; + } + + return String(); +} + +String CSSPrimitiveValue::getStringValue() const +{ + switch (m_type) { + case CSS_STRING: + case CSS_ATTR: + case CSS_URI: + return m_value.string; + case CSS_IDENT: + return valueOrPropertyName(m_value.ident); + default: + break; + } + + return String(); +} + +Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_type != CSS_COUNTER) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.counter; +} + +Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_type != CSS_RECT) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.rect; +} + +PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_type != CSS_RGBCOLOR) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + // FIMXE: This should not return a new object for each invocation. + return RGBColor::create(m_value.rgbcolor); +} + +Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_type != CSS_PAIR) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.pair; +} + +unsigned short CSSPrimitiveValue::cssValueType() const +{ + return CSS_PRIMITIVE_VALUE; +} + +bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/) +{ + // FIXME + return false; +} + +int CSSPrimitiveValue::getIdent() const +{ + if (m_type != CSS_IDENT) + return 0; + return m_value.ident; +} + +static String formatNumber(double number) +{ + DecimalNumber decimal(number); + + StringBuffer buffer(decimal.bufferLengthForStringDecimal()); + unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length()); + ASSERT_UNUSED(length, length == buffer.length()); + + return String::adopt(buffer); +} + +String CSSPrimitiveValue::cssText() const +{ + // FIXME: return the original value instead of a generated one (e.g. color + // name if it was specified) - check what spec says about this + + if (m_hasCachedCSSText) { + ASSERT(cssTextCache().contains(this)); + return cssTextCache().get(this); + } + + String text; + switch (m_type) { + case CSS_UNKNOWN: + // FIXME + break; + case CSS_NUMBER: + case CSS_PARSER_INTEGER: + text = formatNumber(m_value.num); + break; + case CSS_PERCENTAGE: + text = formatNumber(m_value.num) + "%"; + break; + case CSS_EMS: + text = formatNumber(m_value.num) + "em"; + break; + case CSS_EXS: + text = formatNumber(m_value.num) + "ex"; + break; + case CSS_REMS: + text = formatNumber(m_value.num) + "rem"; + break; + case CSS_PX: + text = formatNumber(m_value.num) + "px"; + break; + case CSS_CM: + text = formatNumber(m_value.num) + "cm"; + break; + case CSS_MM: + text = formatNumber(m_value.num) + "mm"; + break; + case CSS_IN: + text = formatNumber(m_value.num) + "in"; + break; + case CSS_PT: + text = formatNumber(m_value.num) + "pt"; + break; + case CSS_PC: + text = formatNumber(m_value.num) + "pc"; + break; + case CSS_DEG: + text = formatNumber(m_value.num) + "deg"; + break; + case CSS_RAD: + text = formatNumber(m_value.num) + "rad"; + break; + case CSS_GRAD: + text = formatNumber(m_value.num) + "grad"; + break; + case CSS_MS: + text = formatNumber(m_value.num) + "ms"; + break; + case CSS_S: + text = formatNumber(m_value.num) + "s"; + break; + case CSS_HZ: + text = formatNumber(m_value.num) + "hz"; + break; + case CSS_KHZ: + text = formatNumber(m_value.num) + "khz"; + break; + case CSS_TURN: + text = formatNumber(m_value.num) + "turn"; + break; + case CSS_DIMENSION: + // FIXME + break; + case CSS_STRING: + text = quoteCSSStringIfNeeded(m_value.string); + break; + case CSS_URI: + text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")"; + break; + case CSS_IDENT: + text = valueOrPropertyName(m_value.ident); + break; + case CSS_ATTR: { + DEFINE_STATIC_LOCAL(const String, attrParen, ("attr(")); + + Vector<UChar> result; + result.reserveInitialCapacity(6 + m_value.string->length()); + + append(result, attrParen); + append(result, m_value.string); + result.uncheckedAppend(')'); + + text = String::adopt(result); + break; + } + case CSS_COUNTER: + text = "counter("; + text += String::number(m_value.num); + text += ")"; + // FIXME: Add list-style and separator + break; + case CSS_RECT: { + DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); + + Rect* rectVal = getRectValue(); + Vector<UChar> result; + result.reserveInitialCapacity(32); + append(result, rectParen); + + append(result, rectVal->top()->cssText()); + result.append(' '); + + append(result, rectVal->right()->cssText()); + result.append(' '); + + append(result, rectVal->bottom()->cssText()); + result.append(' '); + + append(result, rectVal->left()->cssText()); + result.append(')'); + + text = String::adopt(result); + break; + } + case CSS_RGBCOLOR: + case CSS_PARSER_HEXCOLOR: { + DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); + DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb(")); + DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba(")); + + RGBA32 rgbColor = m_value.rgbcolor; + if (m_type == CSS_PARSER_HEXCOLOR) + Color::parseHexColor(m_value.string, rgbColor); + Color color(rgbColor); + + Vector<UChar> result; + result.reserveInitialCapacity(32); + if (color.hasAlpha()) + append(result, rgbaParen); + else + append(result, rgbParen); + + appendNumber(result, static_cast<unsigned char>(color.red())); + append(result, commaSpace); + + appendNumber(result, static_cast<unsigned char>(color.green())); + append(result, commaSpace); + + appendNumber(result, static_cast<unsigned char>(color.blue())); + if (color.hasAlpha()) { + append(result, commaSpace); + append(result, String::number(color.alpha() / 256.0f)); + } + + result.append(')'); + text = String::adopt(result); + break; + } + case CSS_PAIR: + text = m_value.pair->first()->cssText(); + text += " "; + text += m_value.pair->second()->cssText(); + break; +#if ENABLE(DASHBOARD_SUPPORT) + case CSS_DASHBOARD_REGION: + for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { + if (!text.isEmpty()) + text.append(' '); + text += "dashboard-region("; + text += region->m_label; + if (region->m_isCircle) + text += " circle"; + else if (region->m_isRectangle) + text += " rectangle"; + else + break; + if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) { + ASSERT(region->right()->m_type == CSS_IDENT); + ASSERT(region->bottom()->m_type == CSS_IDENT); + ASSERT(region->left()->m_type == CSS_IDENT); + ASSERT(region->right()->getIdent() == CSSValueInvalid); + ASSERT(region->bottom()->getIdent() == CSSValueInvalid); + ASSERT(region->left()->getIdent() == CSSValueInvalid); + } else { + text.append(' '); + text += region->top()->cssText() + " "; + text += region->right()->cssText() + " "; + text += region->bottom()->cssText() + " "; + text += region->left()->cssText(); + } + text += ")"; + } + break; +#endif + case CSS_PARSER_OPERATOR: { + char c = static_cast<char>(m_value.ident); + text = String(&c, 1U); + break; + } + case CSS_PARSER_IDENTIFIER: + text = quoteCSSStringIfNeeded(m_value.string); + break; + } + + ASSERT(!cssTextCache().contains(this)); + cssTextCache().set(this, text); + m_hasCachedCSSText = true; + return text; +} + +CSSParserValue CSSPrimitiveValue::parserValue() const +{ + // We only have to handle a subset of types. + CSSParserValue value; + value.id = 0; + value.isInt = false; + value.unit = CSSPrimitiveValue::CSS_IDENT; + switch (m_type) { + case CSS_NUMBER: + case CSS_PERCENTAGE: + case CSS_EMS: + case CSS_EXS: + case CSS_REMS: + case CSS_PX: + case CSS_CM: + case CSS_MM: + case CSS_IN: + case CSS_PT: + case CSS_PC: + case CSS_DEG: + case CSS_RAD: + case CSS_GRAD: + case CSS_MS: + case CSS_S: + case CSS_HZ: + case CSS_KHZ: + case CSS_DIMENSION: + case CSS_TURN: + value.fValue = m_value.num; + value.unit = m_type; + break; + case CSS_STRING: + case CSS_URI: + case CSS_PARSER_HEXCOLOR: + value.string.characters = const_cast<UChar*>(m_value.string->characters()); + value.string.length = m_value.string->length(); + value.unit = m_type; + break; + case CSS_IDENT: { + value.id = m_value.ident; + const AtomicString& name = valueOrPropertyName(m_value.ident); + value.string.characters = const_cast<UChar*>(name.characters()); + value.string.length = name.length(); + break; + } + case CSS_PARSER_OPERATOR: + value.iValue = m_value.ident; + value.unit = CSSParserValue::Operator; + break; + case CSS_PARSER_INTEGER: + value.fValue = m_value.num; + value.unit = CSSPrimitiveValue::CSS_NUMBER; + value.isInt = true; + break; + case CSS_PARSER_IDENTIFIER: + value.string.characters = const_cast<UChar*>(m_value.string->characters()); + value.string.length = m_value.string->length(); + value.unit = CSSPrimitiveValue::CSS_IDENT; + break; + case CSS_UNKNOWN: + case CSS_ATTR: + case CSS_COUNTER: + case CSS_RECT: + case CSS_RGBCOLOR: + case CSS_PAIR: +#if ENABLE(DASHBOARD_SUPPORT) + case CSS_DASHBOARD_REGION: +#endif + ASSERT_NOT_REACHED(); + break; + } + + return value; +} + +void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + if (m_type == CSS_URI) + addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSPrimitiveValue.h b/Source/WebCore/css/CSSPrimitiveValue.h new file mode 100644 index 0000000..e12cd4c --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValue.h @@ -0,0 +1,243 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + * + * 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. + */ + +#ifndef CSSPrimitiveValue_h +#define CSSPrimitiveValue_h + +#include "CSSValue.h" +#include "Color.h" +#include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class Counter; +class DashboardRegion; +class Pair; +class RGBColor; +class Rect; +class RenderStyle; + +struct Length; + +template<typename T, T max, T min> inline T roundForImpreciseConversion(double value) +{ + // Dimension calculations are 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. + value += (value < 0) ? -0.01 : +0.01; + return ((value > max) || (value < min)) ? 0 : static_cast<T>(value); +} + +class CSSPrimitiveValue : public CSSValue { +public: + enum UnitTypes { + CSS_UNKNOWN = 0, + CSS_NUMBER = 1, + CSS_PERCENTAGE = 2, + CSS_EMS = 3, + CSS_EXS = 4, + CSS_PX = 5, + CSS_CM = 6, + CSS_MM = 7, + CSS_IN = 8, + CSS_PT = 9, + CSS_PC = 10, + CSS_DEG = 11, + CSS_RAD = 12, + CSS_GRAD = 13, + CSS_MS = 14, + CSS_S = 15, + CSS_HZ = 16, + CSS_KHZ = 17, + CSS_DIMENSION = 18, + CSS_STRING = 19, + CSS_URI = 20, + CSS_IDENT = 21, + CSS_ATTR = 22, + CSS_COUNTER = 23, + CSS_RECT = 24, + CSS_RGBCOLOR = 25, + CSS_PAIR = 100, // We envision this being exposed as a means of getting computed style values for pairs (border-spacing/radius, background-position, etc.) + CSS_DASHBOARD_REGION = 101, // FIXME: Dashboard region should not be a primitive value. + CSS_UNICODE_RANGE = 102, + + // These next types are just used internally to allow us to translate back and forth from CSSPrimitiveValues to CSSParserValues. + CSS_PARSER_OPERATOR = 103, + CSS_PARSER_INTEGER = 104, + CSS_PARSER_HEXCOLOR = 105, + + // This is used internally for unknown identifiers + CSS_PARSER_IDENTIFIER = 106, + + // These are from CSS3 Values and Units, but that isn't a finished standard yet + CSS_TURN = 107, + CSS_REMS = 108 + }; + + // This enum follows the CSSParser::Units enum augmented with UNIT_FREQUENCY for frequencies. + enum UnitCategory { + UNumber, + UPercent, + ULength, + UAngle, + UTime, + UFrequency, + UOther + }; + + static bool isUnitTypeLength(int type) { return (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) || + type == CSSPrimitiveValue::CSS_REMS; } + + static PassRefPtr<CSSPrimitiveValue> createIdentifier(int ident); + static PassRefPtr<CSSPrimitiveValue> createColor(unsigned rgbValue); + static PassRefPtr<CSSPrimitiveValue> create(double value, UnitTypes type); + static PassRefPtr<CSSPrimitiveValue> create(const String& value, UnitTypes type); + + template<typename T> static PassRefPtr<CSSPrimitiveValue> create(T value) + { + return adoptRef(new CSSPrimitiveValue(value)); + } + + virtual ~CSSPrimitiveValue(); + + void cleanup(); + + unsigned short primitiveType() const { return m_type; } + + /* + * computes a length in pixels out of the given CSSValue. Need the RenderStyle to get + * the fontinfo in case val is defined in em or ex. + * + * The metrics have to be a bit different for screen and printer output. + * For screen output we assume 1 inch == 72 px, for printer we assume 300 dpi + * + * this is screen/printer dependent, so we probably need a config option for this, + * and some tool to calibrate. + */ + int computeLengthInt(RenderStyle* currStyle, RenderStyle* rootStyle); + int computeLengthInt(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier); + int computeLengthIntForLength(RenderStyle* currStyle, RenderStyle* rootStyle); + int computeLengthIntForLength(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier); + short computeLengthShort(RenderStyle* currStyle, RenderStyle* rootStyle); + short computeLengthShort(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier); + float computeLengthFloat(RenderStyle* currStyle, RenderStyle* rootStyle, bool computingFontSize = false); + float computeLengthFloat(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier, bool computingFontSize = false); + double computeLengthDouble(RenderStyle* currentStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false); + + // use with care!!! + void setPrimitiveType(unsigned short type) { m_type = type; } + + double getDoubleValue(unsigned short unitType, ExceptionCode&) const; + double getDoubleValue(unsigned short unitType) const; + double getDoubleValue() const { return m_value.num; } + + void setFloatValue(unsigned short unitType, double floatValue, ExceptionCode&); + float getFloatValue(unsigned short unitType, ExceptionCode& ec) const { return static_cast<float>(getDoubleValue(unitType, ec)); } + float getFloatValue(unsigned short unitType) const { return static_cast<float>(getDoubleValue(unitType)); } + float getFloatValue() const { return static_cast<float>(m_value.num); } + + int getIntValue(unsigned short unitType, ExceptionCode& ec) const { return static_cast<int>(getDoubleValue(unitType, ec)); } + int getIntValue(unsigned short unitType) const { return static_cast<int>(getDoubleValue(unitType)); } + int getIntValue() const { return static_cast<int>(m_value.num); } + + void setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode&); + String getStringValue(ExceptionCode&) const; + String getStringValue() const; + + Counter* getCounterValue(ExceptionCode&) const; + Counter* getCounterValue() const { return m_type != CSS_COUNTER ? 0 : m_value.counter; } + + Rect* getRectValue(ExceptionCode&) const; + Rect* getRectValue() const { return m_type != CSS_RECT ? 0 : m_value.rect; } + + PassRefPtr<RGBColor> getRGBColorValue(ExceptionCode&) const; + RGBA32 getRGBA32Value() const { return m_type != CSS_RGBCOLOR ? 0 : m_value.rgbcolor; } + + Pair* getPairValue(ExceptionCode&) const; + Pair* getPairValue() const { return m_type != CSS_PAIR ? 0 : m_value.pair; } + + DashboardRegion* getDashboardRegionValue() const { return m_type != CSS_DASHBOARD_REGION ? 0 : m_value.region; } + + int getIdent() const; + template<typename T> inline operator T() const; // Defined in CSSPrimitiveValueMappings.h + + virtual bool parseString(const String&, bool = false); + virtual String cssText() const; + + virtual bool isQuirkValue() { return false; } + + virtual CSSParserValue parserValue() const; + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +protected: + // FIXME: int vs. unsigned overloading is too subtle to distinguish the color and identifier cases. + CSSPrimitiveValue(int ident); + CSSPrimitiveValue(double, UnitTypes); + CSSPrimitiveValue(const String&, UnitTypes); + +private: + CSSPrimitiveValue(); + CSSPrimitiveValue(unsigned color); // RGB value + CSSPrimitiveValue(const Length&); + + template<typename T> CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h + template<typename T> CSSPrimitiveValue(T* val) { init(PassRefPtr<T>(val)); } + template<typename T> CSSPrimitiveValue(PassRefPtr<T> val) { init(val); } + + static void create(int); // compile-time guard + static void create(unsigned); // compile-time guard + template<typename T> operator T*(); // compile-time guard + + static PassRefPtr<CSSPrimitiveValue> createUncachedIdentifier(int identifier); + static PassRefPtr<CSSPrimitiveValue> createUncachedColor(unsigned rgbValue); + static PassRefPtr<CSSPrimitiveValue> createUncached(double value, UnitTypes type); + + static UnitTypes canonicalUnitTypeForCategory(UnitCategory category); + + void init(PassRefPtr<Counter>); + void init(PassRefPtr<Rect>); + void init(PassRefPtr<Pair>); + void init(PassRefPtr<DashboardRegion>); // FIXME: Dashboard region should not be a primitive value. + bool getDoubleValueInternal(UnitTypes targetUnitType, double* result) const; + + virtual bool isPrimitiveValue() const { return true; } + + virtual unsigned short cssValueType() const; + + int m_type : 31; + mutable unsigned m_hasCachedCSSText : 1; + union { + int ident; + double num; + StringImpl* string; + Counter* counter; + Rect* rect; + unsigned rgbcolor; + Pair* pair; + DashboardRegion* region; + } m_value; +}; + +} // namespace WebCore + +#endif // CSSPrimitiveValue_h diff --git a/Source/WebCore/css/CSSPrimitiveValue.idl b/Source/WebCore/css/CSSPrimitiveValue.idl new file mode 100644 index 0000000..8580664 --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValue.idl @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006, 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. + */ + +module css { + + interface CSSPrimitiveValue : CSSValue { + + // UnitTypes + const unsigned short CSS_UNKNOWN = 0; + const unsigned short CSS_NUMBER = 1; + const unsigned short CSS_PERCENTAGE = 2; + const unsigned short CSS_EMS = 3; + const unsigned short CSS_EXS = 4; + const unsigned short CSS_PX = 5; + const unsigned short CSS_CM = 6; + const unsigned short CSS_MM = 7; + const unsigned short CSS_IN = 8; + const unsigned short CSS_PT = 9; + const unsigned short CSS_PC = 10; + const unsigned short CSS_DEG = 11; + const unsigned short CSS_RAD = 12; + const unsigned short CSS_GRAD = 13; + const unsigned short CSS_MS = 14; + const unsigned short CSS_S = 15; + const unsigned short CSS_HZ = 16; + const unsigned short CSS_KHZ = 17; + const unsigned short CSS_DIMENSION = 18; + const unsigned short CSS_STRING = 19; + const unsigned short CSS_URI = 20; + const unsigned short CSS_IDENT = 21; + const unsigned short CSS_ATTR = 22; + const unsigned short CSS_COUNTER = 23; + const unsigned short CSS_RECT = 24; + const unsigned short CSS_RGBCOLOR = 25; + + readonly attribute unsigned short primitiveType; + + [OldStyleObjC] void setFloatValue(in unsigned short unitType, + in float floatValue) + raises(DOMException); + float getFloatValue(in unsigned short unitType) + raises(DOMException); + [OldStyleObjC] void setStringValue(in unsigned short stringType, + in DOMString stringValue) + raises(DOMException); + DOMString getStringValue() + raises(DOMException); + Counter getCounterValue() + raises(DOMException); + Rect getRectValue() + raises(DOMException); + RGBColor getRGBColorValue() + raises(DOMException); + }; + +} diff --git a/Source/WebCore/css/CSSPrimitiveValueMappings.h b/Source/WebCore/css/CSSPrimitiveValueMappings.h new file mode 100644 index 0000000..fb4aff3 --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValueMappings.h @@ -0,0 +1,2926 @@ +/* + * Copyright (C) 2007 Alexey Proskuryakov <ap@nypop.com>. + * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSPrimitiveValueMappings_h +#define CSSPrimitiveValueMappings_h + +#include "ColorSpace.h" +#include "CSSPrimitiveValue.h" +#include "CSSValueKeywords.h" +#include "FontSmoothingMode.h" +#include "GraphicsTypes.h" +#include "Path.h" +#include "RenderStyleConstants.h" +#include "SVGRenderStyleDefs.h" +#include "TextDirection.h" +#include "TextRenderingMode.h" +#include "ThemeTypes.h" + +namespace WebCore { + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBorderStyle e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case BNONE: + m_value.ident = CSSValueNone; + break; + case BHIDDEN: + m_value.ident = CSSValueHidden; + break; + case INSET: + m_value.ident = CSSValueInset; + break; + case GROOVE: + m_value.ident = CSSValueGroove; + break; + case RIDGE: + m_value.ident = CSSValueRidge; + break; + case OUTSET: + m_value.ident = CSSValueOutset; + break; + case DOTTED: + m_value.ident = CSSValueDotted; + break; + case DASHED: + m_value.ident = CSSValueDashed; + break; + case SOLID: + m_value.ident = CSSValueSolid; + break; + case DOUBLE: + m_value.ident = CSSValueDouble; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBorderStyle() const +{ + return (EBorderStyle)(m_value.ident - CSSValueNone); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CompositeOperator e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CompositeClear: + m_value.ident = CSSValueClear; + break; + case CompositeCopy: + m_value.ident = CSSValueCopy; + break; + case CompositeSourceOver: + m_value.ident = CSSValueSourceOver; + break; + case CompositeSourceIn: + m_value.ident = CSSValueSourceIn; + break; + case CompositeSourceOut: + m_value.ident = CSSValueSourceOut; + break; + case CompositeSourceAtop: + m_value.ident = CSSValueSourceAtop; + break; + case CompositeDestinationOver: + m_value.ident = CSSValueDestinationOver; + break; + case CompositeDestinationIn: + m_value.ident = CSSValueDestinationIn; + break; + case CompositeDestinationOut: + m_value.ident = CSSValueDestinationOut; + break; + case CompositeDestinationAtop: + m_value.ident = CSSValueDestinationAtop; + break; + case CompositeXOR: + m_value.ident = CSSValueXor; + break; + case CompositePlusDarker: + m_value.ident = CSSValuePlusDarker; + break; + case CompositeHighlight: + m_value.ident = CSSValueHighlight; + break; + case CompositePlusLighter: + m_value.ident = CSSValuePlusLighter; + break; + } +} + +template<> inline CSSPrimitiveValue::operator CompositeOperator() const +{ + switch (m_value.ident) { + case CSSValueClear: + return CompositeClear; + case CSSValueCopy: + return CompositeCopy; + case CSSValueSourceOver: + return CompositeSourceOver; + case CSSValueSourceIn: + return CompositeSourceIn; + case CSSValueSourceOut: + return CompositeSourceOut; + case CSSValueSourceAtop: + return CompositeSourceAtop; + case CSSValueDestinationOver: + return CompositeDestinationOver; + case CSSValueDestinationIn: + return CompositeDestinationIn; + case CSSValueDestinationOut: + return CompositeDestinationOut; + case CSSValueDestinationAtop: + return CompositeDestinationAtop; + case CSSValueXor: + return CompositeXOR; + case CSSValuePlusDarker: + return CompositePlusDarker; + case CSSValueHighlight: + return CompositeHighlight; + case CSSValuePlusLighter: + return CompositePlusLighter; + default: + ASSERT_NOT_REACHED(); + return CompositeClear; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case NoControlPart: + m_value.ident = CSSValueNone; + break; + case CheckboxPart: + m_value.ident = CSSValueCheckbox; + break; + case RadioPart: + m_value.ident = CSSValueRadio; + break; + case PushButtonPart: + m_value.ident = CSSValuePushButton; + break; + case SquareButtonPart: + m_value.ident = CSSValueSquareButton; + break; + case ButtonPart: + m_value.ident = CSSValueButton; + break; + case ButtonBevelPart: + m_value.ident = CSSValueButtonBevel; + break; + case DefaultButtonPart: + m_value.ident = CSSValueDefaultButton; + break; + case InnerSpinButtonPart: + m_value.ident = CSSValueInnerSpinButton; + break; + case ListboxPart: + m_value.ident = CSSValueListbox; + break; + case ListButtonPart: +#if ENABLE(DATALIST) + m_value.ident = CSSValueListButton; +#endif + break; + case ListItemPart: + m_value.ident = CSSValueListitem; + break; + case MediaFullscreenButtonPart: + m_value.ident = CSSValueMediaFullscreenButton; + break; + case MediaPlayButtonPart: + m_value.ident = CSSValueMediaPlayButton; + break; + case MediaMuteButtonPart: + m_value.ident = CSSValueMediaMuteButton; + break; + case MediaSeekBackButtonPart: + m_value.ident = CSSValueMediaSeekBackButton; + break; + case MediaSeekForwardButtonPart: + m_value.ident = CSSValueMediaSeekForwardButton; + break; + case MediaRewindButtonPart: + m_value.ident = CSSValueMediaRewindButton; + break; + case MediaReturnToRealtimeButtonPart: + m_value.ident = CSSValueMediaReturnToRealtimeButton; + break; + case MediaToggleClosedCaptionsButtonPart: + m_value.ident = CSSValueMediaToggleClosedCaptionsButton; + break; + case MediaSliderPart: + m_value.ident = CSSValueMediaSlider; + break; + case MediaSliderThumbPart: + m_value.ident = CSSValueMediaSliderthumb; + break; + case MediaVolumeSliderContainerPart: + m_value.ident = CSSValueMediaVolumeSliderContainer; + break; + case MediaVolumeSliderPart: + m_value.ident = CSSValueMediaVolumeSlider; + break; + case MediaVolumeSliderMuteButtonPart: + m_value.ident = CSSValueMediaVolumeSliderMuteButton; + break; + case MediaVolumeSliderThumbPart: + m_value.ident = CSSValueMediaVolumeSliderthumb; + break; + case MediaControlsBackgroundPart: + m_value.ident = CSSValueMediaControlsBackground; + break; + case MediaControlsFullscreenBackgroundPart: + m_value.ident = CSSValueMediaControlsFullscreenBackground; + break; + case MediaCurrentTimePart: + m_value.ident = CSSValueMediaCurrentTimeDisplay; + break; + case MediaTimeRemainingPart: + m_value.ident = CSSValueMediaTimeRemainingDisplay; + break; + case MenulistPart: + m_value.ident = CSSValueMenulist; + break; + case MenulistButtonPart: + m_value.ident = CSSValueMenulistButton; + break; + case MenulistTextPart: + m_value.ident = CSSValueMenulistText; + break; + case MenulistTextFieldPart: + m_value.ident = CSSValueMenulistTextfield; + break; + case MeterPart: + m_value.ident = CSSValueMeter; + break; + case RelevancyLevelIndicatorPart: + m_value.ident = CSSValueRelevancyLevelIndicator; + break; + case ContinuousCapacityLevelIndicatorPart: + m_value.ident = CSSValueContinuousCapacityLevelIndicator; + break; + case DiscreteCapacityLevelIndicatorPart: + m_value.ident = CSSValueDiscreteCapacityLevelIndicator; + break; + case RatingLevelIndicatorPart: + m_value.ident = CSSValueRatingLevelIndicator; + break; + case OuterSpinButtonPart: + m_value.ident = CSSValueOuterSpinButton; + break; + case ProgressBarPart: +#if ENABLE(PROGRESS_TAG) + m_value.ident = CSSValueProgressBar; +#endif + break; + case ProgressBarValuePart: +#if ENABLE(PROGRESS_TAG) + m_value.ident = CSSValueProgressBarValue; +#endif + break; + case SliderHorizontalPart: + m_value.ident = CSSValueSliderHorizontal; + break; + case SliderVerticalPart: + m_value.ident = CSSValueSliderVertical; + break; + case SliderThumbHorizontalPart: + m_value.ident = CSSValueSliderthumbHorizontal; + break; + case SliderThumbVerticalPart: + m_value.ident = CSSValueSliderthumbVertical; + break; + case CaretPart: + m_value.ident = CSSValueCaret; + break; + case SearchFieldPart: + m_value.ident = CSSValueSearchfield; + break; + case SearchFieldDecorationPart: + m_value.ident = CSSValueSearchfieldDecoration; + break; + case SearchFieldResultsDecorationPart: + m_value.ident = CSSValueSearchfieldResultsDecoration; + break; + case SearchFieldResultsButtonPart: + m_value.ident = CSSValueSearchfieldResultsButton; + break; + case SearchFieldCancelButtonPart: + m_value.ident = CSSValueSearchfieldCancelButton; + break; + case TextFieldPart: + m_value.ident = CSSValueTextfield; + break; + case TextAreaPart: + m_value.ident = CSSValueTextarea; + break; + case CapsLockIndicatorPart: + m_value.ident = CSSValueCapsLockIndicator; + break; + case InputSpeechButtonPart: +#if ENABLE(INPUT_SPEECH) + m_value.ident = CSSValueWebkitInputSpeechButton; +#endif + break; + } +} + +template<> inline CSSPrimitiveValue::operator ControlPart() const +{ + if (m_value.ident == CSSValueNone) + return NoControlPart; + else + return ControlPart(m_value.ident - CSSValueCheckbox + 1); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillAttachment e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case ScrollBackgroundAttachment: + m_value.ident = CSSValueScroll; + break; + case LocalBackgroundAttachment: + m_value.ident = CSSValueLocal; + break; + case FixedBackgroundAttachment: + m_value.ident = CSSValueFixed; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFillAttachment() const +{ + switch (m_value.ident) { + case CSSValueScroll: + return ScrollBackgroundAttachment; + case CSSValueLocal: + return LocalBackgroundAttachment; + case CSSValueFixed: + return FixedBackgroundAttachment; + default: + ASSERT_NOT_REACHED(); + return ScrollBackgroundAttachment; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillBox e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case BorderFillBox: + m_value.ident = CSSValueBorderBox; + break; + case PaddingFillBox: + m_value.ident = CSSValuePaddingBox; + break; + case ContentFillBox: + m_value.ident = CSSValueContentBox; + break; + case TextFillBox: + m_value.ident = CSSValueText; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFillBox() const +{ + switch (m_value.ident) { + case CSSValueBorder: + case CSSValueBorderBox: + return BorderFillBox; + case CSSValuePadding: + case CSSValuePaddingBox: + return PaddingFillBox; + case CSSValueContent: + case CSSValueContentBox: + return ContentFillBox; + case CSSValueText: + case CSSValueWebkitText: + return TextFillBox; + default: + ASSERT_NOT_REACHED(); + return BorderFillBox; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillRepeat e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case RepeatFill: + m_value.ident = CSSValueRepeat; + break; + case NoRepeatFill: + m_value.ident = CSSValueNoRepeat; + break; + case RoundFill: + m_value.ident = CSSValueRound; + break; + case SpaceFill: + m_value.ident = CSSValueSpace; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFillRepeat() const +{ + switch (m_value.ident) { + case CSSValueRepeat: + return RepeatFill; + case CSSValueNoRepeat: + return NoRepeatFill; + case CSSValueRound: + return RoundFill; + case CSSValueSpace: + return SpaceFill; + default: + ASSERT_NOT_REACHED(); + return RepeatFill; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxAlignment e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case BSTRETCH: + m_value.ident = CSSValueStretch; + break; + case BSTART: + m_value.ident = CSSValueStart; + break; + case BCENTER: + m_value.ident = CSSValueCenter; + break; + case BEND: + m_value.ident = CSSValueEnd; + break; + case BBASELINE: + m_value.ident = CSSValueBaseline; + break; + case BJUSTIFY: + m_value.ident = CSSValueJustify; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxAlignment() const +{ + switch (m_value.ident) { + case CSSValueStretch: + return BSTRETCH; + case CSSValueStart: + return BSTART; + case CSSValueEnd: + return BEND; + case CSSValueCenter: + return BCENTER; + case CSSValueBaseline: + return BBASELINE; + case CSSValueJustify: + return BJUSTIFY; + default: + ASSERT_NOT_REACHED(); + return BSTRETCH; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxDirection e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case BNORMAL: + m_value.ident = CSSValueNormal; + break; + case BREVERSE: + m_value.ident = CSSValueReverse; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxDirection() const +{ + switch (m_value.ident) { + case CSSValueNormal: + return BNORMAL; + case CSSValueReverse: + return BREVERSE; + default: + ASSERT_NOT_REACHED(); + return BNORMAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxLines e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case SINGLE: + m_value.ident = CSSValueSingle; + break; + case MULTIPLE: + m_value.ident = CSSValueMultiple; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxLines() const +{ + switch (m_value.ident) { + case CSSValueSingle: + return SINGLE; + case CSSValueMultiple: + return MULTIPLE; + default: + ASSERT_NOT_REACHED(); + return SINGLE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxOrient e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case HORIZONTAL: + m_value.ident = CSSValueHorizontal; + break; + case VERTICAL: + m_value.ident = CSSValueVertical; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxOrient() const +{ + switch (m_value.ident) { + case CSSValueHorizontal: + case CSSValueInlineAxis: + return HORIZONTAL; + case CSSValueVertical: + case CSSValueBlockAxis: + return VERTICAL; + default: + ASSERT_NOT_REACHED(); + return HORIZONTAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECaptionSide e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CAPLEFT: + m_value.ident = CSSValueLeft; + break; + case CAPRIGHT: + m_value.ident = CSSValueRight; + break; + case CAPTOP: + m_value.ident = CSSValueTop; + break; + case CAPBOTTOM: + m_value.ident = CSSValueBottom; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ECaptionSide() const +{ + switch (m_value.ident) { + case CSSValueLeft: + return CAPLEFT; + case CSSValueRight: + return CAPRIGHT; + case CSSValueTop: + return CAPTOP; + case CSSValueBottom: + return CAPBOTTOM; + default: + ASSERT_NOT_REACHED(); + return CAPTOP; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EClear e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CNONE: + m_value.ident = CSSValueNone; + break; + case CLEFT: + m_value.ident = CSSValueLeft; + break; + case CRIGHT: + m_value.ident = CSSValueRight; + break; + case CBOTH: + m_value.ident = CSSValueBoth; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EClear() const +{ + switch (m_value.ident) { + case CSSValueNone: + return CNONE; + case CSSValueLeft: + return CLEFT; + case CSSValueRight: + return CRIGHT; + case CSSValueBoth: + return CBOTH; + default: + ASSERT_NOT_REACHED(); + return CNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECursor e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CURSOR_AUTO: + m_value.ident = CSSValueAuto; + break; + case CURSOR_CROSS: + m_value.ident = CSSValueCrosshair; + break; + case CURSOR_DEFAULT: + m_value.ident = CSSValueDefault; + break; + case CURSOR_POINTER: + m_value.ident = CSSValuePointer; + break; + case CURSOR_MOVE: + m_value.ident = CSSValueMove; + break; + case CURSOR_CELL: + m_value.ident = CSSValueCell; + break; + case CURSOR_VERTICAL_TEXT: + m_value.ident = CSSValueVerticalText; + break; + case CURSOR_CONTEXT_MENU: + m_value.ident = CSSValueContextMenu; + break; + case CURSOR_ALIAS: + m_value.ident = CSSValueAlias; + break; + case CURSOR_COPY: + m_value.ident = CSSValueCopy; + break; + case CURSOR_NONE: + m_value.ident = CSSValueNone; + break; + case CURSOR_PROGRESS: + m_value.ident = CSSValueProgress; + break; + case CURSOR_NO_DROP: + m_value.ident = CSSValueNoDrop; + break; + case CURSOR_NOT_ALLOWED: + m_value.ident = CSSValueNotAllowed; + break; + case CURSOR_WEBKIT_ZOOM_IN: + m_value.ident = CSSValueWebkitZoomIn; + break; + case CURSOR_WEBKIT_ZOOM_OUT: + m_value.ident = CSSValueWebkitZoomOut; + break; + case CURSOR_E_RESIZE: + m_value.ident = CSSValueEResize; + break; + case CURSOR_NE_RESIZE: + m_value.ident = CSSValueNeResize; + break; + case CURSOR_NW_RESIZE: + m_value.ident = CSSValueNwResize; + break; + case CURSOR_N_RESIZE: + m_value.ident = CSSValueNResize; + break; + case CURSOR_SE_RESIZE: + m_value.ident = CSSValueSeResize; + break; + case CURSOR_SW_RESIZE: + m_value.ident = CSSValueSwResize; + break; + case CURSOR_S_RESIZE: + m_value.ident = CSSValueSResize; + break; + case CURSOR_W_RESIZE: + m_value.ident = CSSValueWResize; + break; + case CURSOR_EW_RESIZE: + m_value.ident = CSSValueEwResize; + break; + case CURSOR_NS_RESIZE: + m_value.ident = CSSValueNsResize; + break; + case CURSOR_NESW_RESIZE: + m_value.ident = CSSValueNeswResize; + break; + case CURSOR_NWSE_RESIZE: + m_value.ident = CSSValueNwseResize; + break; + case CURSOR_COL_RESIZE: + m_value.ident = CSSValueColResize; + break; + case CURSOR_ROW_RESIZE: + m_value.ident = CSSValueRowResize; + break; + case CURSOR_TEXT: + m_value.ident = CSSValueText; + break; + case CURSOR_WAIT: + m_value.ident = CSSValueWait; + break; + case CURSOR_HELP: + m_value.ident = CSSValueHelp; + break; + case CURSOR_ALL_SCROLL: + m_value.ident = CSSValueAllScroll; + break; + case CURSOR_WEBKIT_GRAB: + m_value.ident = CSSValueWebkitGrab; + break; + case CURSOR_WEBKIT_GRABBING: + m_value.ident = CSSValueWebkitGrabbing; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ECursor() const +{ + if (m_value.ident == CSSValueCopy) + return CURSOR_COPY; + if (m_value.ident == CSSValueNone) + return CURSOR_NONE; + return static_cast<ECursor>(m_value.ident - CSSValueAuto); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EDisplay e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case INLINE: + m_value.ident = CSSValueInline; + break; + case BLOCK: + m_value.ident = CSSValueBlock; + break; + case LIST_ITEM: + m_value.ident = CSSValueListItem; + break; + case RUN_IN: + m_value.ident = CSSValueRunIn; + break; + case COMPACT: + m_value.ident = CSSValueCompact; + break; + case INLINE_BLOCK: + m_value.ident = CSSValueInlineBlock; + break; + case TABLE: + m_value.ident = CSSValueTable; + break; + case INLINE_TABLE: + m_value.ident = CSSValueInlineTable; + break; + case TABLE_ROW_GROUP: + m_value.ident = CSSValueTableRowGroup; + break; + case TABLE_HEADER_GROUP: + m_value.ident = CSSValueTableHeaderGroup; + break; + case TABLE_FOOTER_GROUP: + m_value.ident = CSSValueTableFooterGroup; + break; + case TABLE_ROW: + m_value.ident = CSSValueTableRow; + break; + case TABLE_COLUMN_GROUP: + m_value.ident = CSSValueTableColumnGroup; + break; + case TABLE_COLUMN: + m_value.ident = CSSValueTableColumn; + break; + case TABLE_CELL: + m_value.ident = CSSValueTableCell; + break; + case TABLE_CAPTION: + m_value.ident = CSSValueTableCaption; + break; +#if ENABLE(WCSS) + case WAP_MARQUEE: + m_value.ident = CSSValueWapMarquee; + break; +#endif + case BOX: + m_value.ident = CSSValueWebkitBox; + break; + case INLINE_BOX: + m_value.ident = CSSValueWebkitInlineBox; + break; + case NONE: + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EDisplay() const +{ + if (m_value.ident == CSSValueNone) + return NONE; + return static_cast<EDisplay>(m_value.ident - CSSValueInline); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EEmptyCell e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case SHOW: + m_value.ident = CSSValueShow; + break; + case HIDE: + m_value.ident = CSSValueHide; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EEmptyCell() const +{ + switch (m_value.ident) { + case CSSValueShow: + return SHOW; + case CSSValueHide: + return HIDE; + default: + ASSERT_NOT_REACHED(); + return SHOW; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFloat e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case FNONE: + m_value.ident = CSSValueNone; + break; + case FLEFT: + m_value.ident = CSSValueLeft; + break; + case FRIGHT: + m_value.ident = CSSValueRight; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFloat() const +{ + switch (m_value.ident) { + case CSSValueLeft: + return FLEFT; + case CSSValueRight: + return FRIGHT; + case CSSValueNone: + case CSSValueCenter: // Non-standard CSS value + return FNONE; + default: + ASSERT_NOT_REACHED(); + return FNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EKHTMLLineBreak e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case LBNORMAL: + m_value.ident = CSSValueNormal; + break; + case AFTER_WHITE_SPACE: + m_value.ident = CSSValueAfterWhiteSpace; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EKHTMLLineBreak() const +{ + switch (m_value.ident) { + case CSSValueAfterWhiteSpace: + return AFTER_WHITE_SPACE; + case CSSValueNormal: + return LBNORMAL; + default: + ASSERT_NOT_REACHED(); + return LBNORMAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EListStylePosition e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case OUTSIDE: + m_value.ident = CSSValueOutside; + break; + case INSIDE: + m_value.ident = CSSValueInside; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EListStylePosition() const +{ + return (EListStylePosition)(m_value.ident - CSSValueOutside); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EListStyleType e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case Afar: + m_value.ident = CSSValueAfar; + break; + case Amharic: + m_value.ident = CSSValueAmharic; + break; + case AmharicAbegede: + m_value.ident = CSSValueAmharicAbegede; + break; + case ArabicIndic: + m_value.ident = CSSValueArabicIndic; + break; + case Armenian: + m_value.ident = CSSValueArmenian; + break; + case Asterisks: + m_value.ident = CSSValueAsterisks; + break; + case BinaryListStyle: + m_value.ident = CSSValueBinary; + break; + case Bengali: + m_value.ident = CSSValueBengali; + break; + case Cambodian: + m_value.ident = CSSValueCambodian; + break; + case Circle: + m_value.ident = CSSValueCircle; + break; + case CjkEarthlyBranch: + m_value.ident = CSSValueCjkEarthlyBranch; + break; + case CjkHeavenlyStem: + m_value.ident = CSSValueCjkHeavenlyStem; + break; + case CJKIdeographic: + m_value.ident = CSSValueCjkIdeographic; + break; + case DecimalLeadingZero: + m_value.ident = CSSValueDecimalLeadingZero; + break; + case DecimalListStyle: + m_value.ident = CSSValueDecimal; + break; + case Devanagari: + m_value.ident = CSSValueDevanagari; + break; + case Disc: + m_value.ident = CSSValueDisc; + break; + case Ethiopic: + m_value.ident = CSSValueEthiopic; + break; + case EthiopicAbegede: + m_value.ident = CSSValueEthiopicAbegede; + break; + case EthiopicAbegedeAmEt: + m_value.ident = CSSValueEthiopicAbegedeAmEt; + break; + case EthiopicAbegedeGez: + m_value.ident = CSSValueEthiopicAbegedeGez; + break; + case EthiopicAbegedeTiEr: + m_value.ident = CSSValueEthiopicAbegedeTiEr; + break; + case EthiopicAbegedeTiEt: + m_value.ident = CSSValueEthiopicAbegedeTiEt; + break; + case EthiopicHalehameAaEr: + m_value.ident = CSSValueEthiopicHalehameAaEr; + break; + case EthiopicHalehameAaEt: + m_value.ident = CSSValueEthiopicHalehameAaEt; + break; + case EthiopicHalehameAmEt: + m_value.ident = CSSValueEthiopicHalehameAmEt; + break; + case EthiopicHalehameGez: + m_value.ident = CSSValueEthiopicHalehameGez; + break; + case EthiopicHalehameOmEt: + m_value.ident = CSSValueEthiopicHalehameOmEt; + break; + case EthiopicHalehameSidEt: + m_value.ident = CSSValueEthiopicHalehameSidEt; + break; + case EthiopicHalehameSoEt: + m_value.ident = CSSValueEthiopicHalehameSoEt; + break; + case EthiopicHalehameTiEr: + m_value.ident = CSSValueEthiopicHalehameTiEr; + break; + case EthiopicHalehameTiEt: + m_value.ident = CSSValueEthiopicHalehameTiEt; + break; + case EthiopicHalehameTig: + m_value.ident = CSSValueEthiopicHalehameTig; + break; + case Footnotes: + m_value.ident = CSSValueFootnotes; + break; + case Georgian: + m_value.ident = CSSValueGeorgian; + break; + case Gujarati: + m_value.ident = CSSValueGujarati; + break; + case Gurmukhi: + m_value.ident = CSSValueGurmukhi; + break; + case Hangul: + m_value.ident = CSSValueHangul; + break; + case HangulConsonant: + m_value.ident = CSSValueHangulConsonant; + break; + case Hebrew: + m_value.ident = CSSValueHebrew; + break; + case Hiragana: + m_value.ident = CSSValueHiragana; + break; + case HiraganaIroha: + m_value.ident = CSSValueHiraganaIroha; + break; + case Kannada: + m_value.ident = CSSValueKannada; + break; + case Katakana: + m_value.ident = CSSValueKatakana; + break; + case KatakanaIroha: + m_value.ident = CSSValueKatakanaIroha; + break; + case Khmer: + m_value.ident = CSSValueKhmer; + break; + case Lao: + m_value.ident = CSSValueLao; + break; + case LowerAlpha: + m_value.ident = CSSValueLowerAlpha; + break; + case LowerArmenian: + m_value.ident = CSSValueLowerArmenian; + break; + case LowerGreek: + m_value.ident = CSSValueLowerGreek; + break; + case LowerHexadecimal: + m_value.ident = CSSValueLowerHexadecimal; + break; + case LowerLatin: + m_value.ident = CSSValueLowerLatin; + break; + case LowerNorwegian: + m_value.ident = CSSValueLowerNorwegian; + break; + case LowerRoman: + m_value.ident = CSSValueLowerRoman; + break; + case Malayalam: + m_value.ident = CSSValueMalayalam; + break; + case Mongolian: + m_value.ident = CSSValueMongolian; + break; + case Myanmar: + m_value.ident = CSSValueMyanmar; + break; + case NoneListStyle: + m_value.ident = CSSValueNone; + break; + case Octal: + m_value.ident = CSSValueOctal; + break; + case Oriya: + m_value.ident = CSSValueOriya; + break; + case Oromo: + m_value.ident = CSSValueOromo; + break; + case Persian: + m_value.ident = CSSValuePersian; + break; + case Sidama: + m_value.ident = CSSValueSidama; + break; + case Somali: + m_value.ident = CSSValueSomali; + break; + case Square: + m_value.ident = CSSValueSquare; + break; + case Telugu: + m_value.ident = CSSValueTelugu; + break; + case Thai: + m_value.ident = CSSValueThai; + break; + case Tibetan: + m_value.ident = CSSValueTibetan; + break; + case Tigre: + m_value.ident = CSSValueTigre; + break; + case TigrinyaEr: + m_value.ident = CSSValueTigrinyaEr; + break; + case TigrinyaErAbegede: + m_value.ident = CSSValueTigrinyaErAbegede; + break; + case TigrinyaEt: + m_value.ident = CSSValueTigrinyaEt; + break; + case TigrinyaEtAbegede: + m_value.ident = CSSValueTigrinyaEtAbegede; + break; + case UpperAlpha: + m_value.ident = CSSValueUpperAlpha; + break; + case UpperArmenian: + m_value.ident = CSSValueUpperArmenian; + break; + case UpperGreek: + m_value.ident = CSSValueUpperGreek; + break; + case UpperHexadecimal: + m_value.ident = CSSValueUpperHexadecimal; + break; + case UpperLatin: + m_value.ident = CSSValueUpperLatin; + break; + case UpperNorwegian: + m_value.ident = CSSValueUpperNorwegian; + break; + case UpperRoman: + m_value.ident = CSSValueUpperRoman; + break; + case Urdu: + m_value.ident = CSSValueUrdu; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EListStyleType() const +{ + switch (m_value.ident) { + case CSSValueNone: + return NoneListStyle; + default: + return static_cast<EListStyleType>(m_value.ident - CSSValueDisc); + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMarginCollapse e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case MCOLLAPSE: + m_value.ident = CSSValueCollapse; + break; + case MSEPARATE: + m_value.ident = CSSValueSeparate; + break; + case MDISCARD: + m_value.ident = CSSValueDiscard; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EMarginCollapse() const +{ + switch (m_value.ident) { + case CSSValueCollapse: + return MCOLLAPSE; + case CSSValueSeparate: + return MSEPARATE; + case CSSValueDiscard: + return MDISCARD; + default: + ASSERT_NOT_REACHED(); + return MCOLLAPSE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMarqueeBehavior e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case MNONE: + m_value.ident = CSSValueNone; + break; + case MSCROLL: + m_value.ident = CSSValueScroll; + break; + case MSLIDE: + m_value.ident = CSSValueSlide; + break; + case MALTERNATE: + m_value.ident = CSSValueAlternate; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EMarqueeBehavior() const +{ + switch (m_value.ident) { + case CSSValueNone: + return MNONE; + case CSSValueScroll: + return MSCROLL; + case CSSValueSlide: + return MSLIDE; + case CSSValueAlternate: + return MALTERNATE; + default: + ASSERT_NOT_REACHED(); + return MNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMarqueeDirection e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case MFORWARD: + m_value.ident = CSSValueForwards; + break; + case MBACKWARD: + m_value.ident = CSSValueBackwards; + break; + case MAUTO: + m_value.ident = CSSValueAuto; + break; + case MUP: + m_value.ident = CSSValueUp; + break; + case MDOWN: + m_value.ident = CSSValueDown; + break; + case MLEFT: + m_value.ident = CSSValueLeft; + break; + case MRIGHT: + m_value.ident = CSSValueRight; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EMarqueeDirection() const +{ + switch (m_value.ident) { + case CSSValueForwards: + return MFORWARD; + case CSSValueBackwards: + return MBACKWARD; + case CSSValueAuto: + return MAUTO; + case CSSValueAhead: + case CSSValueUp: // We don't support vertical languages, so AHEAD just maps to UP. + return MUP; + case CSSValueReverse: + case CSSValueDown: // REVERSE just maps to DOWN, since we don't do vertical text. + return MDOWN; + case CSSValueLeft: + return MLEFT; + case CSSValueRight: + return MRIGHT; + default: + ASSERT_NOT_REACHED(); + return MAUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMatchNearestMailBlockquoteColor e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case BCNORMAL: + m_value.ident = CSSValueNormal; + break; + case MATCH: + m_value.ident = CSSValueMatch; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EMatchNearestMailBlockquoteColor() const +{ + switch (m_value.ident) { + case CSSValueNormal: + return BCNORMAL; + case CSSValueMatch: + return MATCH; + default: + ASSERT_NOT_REACHED(); + return BCNORMAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ENBSPMode e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case NBNORMAL: + m_value.ident = CSSValueNormal; + break; + case SPACE: + m_value.ident = CSSValueSpace; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ENBSPMode() const +{ + switch (m_value.ident) { + case CSSValueSpace: + return SPACE; + case CSSValueNormal: + return NBNORMAL; + default: + ASSERT_NOT_REACHED(); + return NBNORMAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EOverflow e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case OVISIBLE: + m_value.ident = CSSValueVisible; + break; + case OHIDDEN: + m_value.ident = CSSValueHidden; + break; + case OSCROLL: + m_value.ident = CSSValueScroll; + break; + case OAUTO: + m_value.ident = CSSValueAuto; + break; + case OMARQUEE: + m_value.ident = CSSValueWebkitMarquee; + break; + case OOVERLAY: + m_value.ident = CSSValueOverlay; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EOverflow() const +{ + switch (m_value.ident) { + case CSSValueVisible: + return OVISIBLE; + case CSSValueHidden: + return OHIDDEN; + case CSSValueScroll: + return OSCROLL; + case CSSValueAuto: + return OAUTO; + case CSSValueWebkitMarquee: + return OMARQUEE; + case CSSValueOverlay: + return OOVERLAY; + default: + ASSERT_NOT_REACHED(); + return OVISIBLE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPageBreak e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case PBAUTO: + m_value.ident = CSSValueAuto; + break; + case PBALWAYS: + m_value.ident = CSSValueAlways; + break; + case PBAVOID: + m_value.ident = CSSValueAvoid; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EPageBreak() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return PBAUTO; + case CSSValueLeft: + case CSSValueRight: + case CSSValueAlways: + return PBALWAYS; // CSS2.1: "Conforming user agents may map left/right to always." + case CSSValueAvoid: + return PBAVOID; + default: + ASSERT_NOT_REACHED(); + return PBAUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPosition e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case StaticPosition: + m_value.ident = CSSValueStatic; + break; + case RelativePosition: + m_value.ident = CSSValueRelative; + break; + case AbsolutePosition: + m_value.ident = CSSValueAbsolute; + break; + case FixedPosition: + m_value.ident = CSSValueFixed; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EPosition() const +{ + switch (m_value.ident) { + case CSSValueStatic: + return StaticPosition; + case CSSValueRelative: + return RelativePosition; + case CSSValueAbsolute: + return AbsolutePosition; + case CSSValueFixed: + return FixedPosition; + default: + ASSERT_NOT_REACHED(); + return StaticPosition; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EResize e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case RESIZE_BOTH: + m_value.ident = CSSValueBoth; + break; + case RESIZE_HORIZONTAL: + m_value.ident = CSSValueHorizontal; + break; + case RESIZE_VERTICAL: + m_value.ident = CSSValueVertical; + break; + case RESIZE_NONE: + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EResize() const +{ + switch (m_value.ident) { + case CSSValueBoth: + return RESIZE_BOTH; + case CSSValueHorizontal: + return RESIZE_HORIZONTAL; + case CSSValueVertical: + return RESIZE_VERTICAL; + case CSSValueAuto: + ASSERT_NOT_REACHED(); // Depends on settings, thus should be handled by the caller. + return RESIZE_NONE; + case CSSValueNone: + return RESIZE_NONE; + default: + ASSERT_NOT_REACHED(); + return RESIZE_NONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETableLayout e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TAUTO: + m_value.ident = CSSValueAuto; + break; + case TFIXED: + m_value.ident = CSSValueFixed; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETableLayout() const +{ + switch (m_value.ident) { + case CSSValueFixed: + return TFIXED; + case CSSValueAuto: + return TAUTO; + default: + ASSERT_NOT_REACHED(); + return TAUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextAlign e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TAAUTO: + m_value.ident = CSSValueWebkitAuto; + break; + case LEFT: + m_value.ident = CSSValueLeft; + break; + case RIGHT: + m_value.ident = CSSValueRight; + break; + case CENTER: + m_value.ident = CSSValueCenter; + break; + case JUSTIFY: + m_value.ident = CSSValueJustify; + break; + case WEBKIT_LEFT: + m_value.ident = CSSValueWebkitLeft; + break; + case WEBKIT_RIGHT: + m_value.ident = CSSValueWebkitRight; + break; + case WEBKIT_CENTER: + m_value.ident = CSSValueWebkitCenter; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETextAlign() const +{ + switch (m_value.ident) { + case CSSValueStart: + case CSSValueEnd: + ASSERT_NOT_REACHED(); // Depends on direction, thus should be handled by the caller. + return LEFT; + default: + return static_cast<ETextAlign>(m_value.ident - CSSValueWebkitAuto); + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextSecurity e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TSNONE: + m_value.ident = CSSValueNone; + break; + case TSDISC: + m_value.ident = CSSValueDisc; + break; + case TSCIRCLE: + m_value.ident = CSSValueCircle; + break; + case TSSQUARE: + m_value.ident = CSSValueSquare; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETextSecurity() const +{ + switch (m_value.ident) { + case CSSValueNone: + return TSNONE; + case CSSValueDisc: + return TSDISC; + case CSSValueCircle: + return TSCIRCLE; + case CSSValueSquare: + return TSSQUARE; + default: + ASSERT_NOT_REACHED(); + return TSNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextTransform e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CAPITALIZE: + m_value.ident = CSSValueCapitalize; + break; + case UPPERCASE: + m_value.ident = CSSValueUppercase; + break; + case LOWERCASE: + m_value.ident = CSSValueLowercase; + break; + case TTNONE: + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETextTransform() const +{ + switch (m_value.ident) { + case CSSValueCapitalize: + return CAPITALIZE; + case CSSValueUppercase: + return UPPERCASE; + case CSSValueLowercase: + return LOWERCASE; + case CSSValueNone: + return TTNONE; + default: + ASSERT_NOT_REACHED(); + return TTNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUnicodeBidi e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case UBNormal: + m_value.ident = CSSValueNormal; + break; + case Embed: + m_value.ident = CSSValueEmbed; + break; + case Override: + m_value.ident = CSSValueBidiOverride; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EUnicodeBidi() const +{ + switch (m_value.ident) { + case CSSValueNormal: + return UBNormal; + case CSSValueEmbed: + return Embed; + case CSSValueBidiOverride: + return Override; + default: + ASSERT_NOT_REACHED(); + return UBNormal; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserDrag e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case DRAG_AUTO: + m_value.ident = CSSValueAuto; + break; + case DRAG_NONE: + m_value.ident = CSSValueNone; + break; + case DRAG_ELEMENT: + m_value.ident = CSSValueElement; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EUserDrag() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return DRAG_AUTO; + case CSSValueNone: + return DRAG_NONE; + case CSSValueElement: + return DRAG_ELEMENT; + default: + ASSERT_NOT_REACHED(); + return DRAG_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserModify e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case READ_ONLY: + m_value.ident = CSSValueReadOnly; + break; + case READ_WRITE: + m_value.ident = CSSValueReadWrite; + break; + case READ_WRITE_PLAINTEXT_ONLY: + m_value.ident = CSSValueReadWritePlaintextOnly; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EUserModify() const +{ + return static_cast<EUserModify>(m_value.ident - CSSValueReadOnly); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserSelect e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case SELECT_NONE: + m_value.ident = CSSValueNone; + break; + case SELECT_TEXT: + m_value.ident = CSSValueText; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EUserSelect() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return SELECT_TEXT; + case CSSValueNone: + return SELECT_NONE; + case CSSValueText: + return SELECT_TEXT; + default: + ASSERT_NOT_REACHED(); + return SELECT_TEXT; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EVisibility e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case VISIBLE: + m_value.ident = CSSValueVisible; + break; + case HIDDEN: + m_value.ident = CSSValueHidden; + break; + case COLLAPSE: + m_value.ident = CSSValueCollapse; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EVisibility() const +{ + switch (m_value.ident) { + case CSSValueHidden: + return HIDDEN; + case CSSValueVisible: + return VISIBLE; + case CSSValueCollapse: + return COLLAPSE; + default: + ASSERT_NOT_REACHED(); + return VISIBLE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWhiteSpace e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case NORMAL: + m_value.ident = CSSValueNormal; + break; + case PRE: + m_value.ident = CSSValuePre; + break; + case PRE_WRAP: + m_value.ident = CSSValuePreWrap; + break; + case PRE_LINE: + m_value.ident = CSSValuePreLine; + break; + case NOWRAP: + m_value.ident = CSSValueNowrap; + break; + case KHTML_NOWRAP: + m_value.ident = CSSValueWebkitNowrap; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EWhiteSpace() const +{ + switch (m_value.ident) { + case CSSValueWebkitNowrap: + return KHTML_NOWRAP; + case CSSValueNowrap: + return NOWRAP; + case CSSValuePre: + return PRE; + case CSSValuePreWrap: + return PRE_WRAP; + case CSSValuePreLine: + return PRE_LINE; + case CSSValueNormal: + return NORMAL; + default: + ASSERT_NOT_REACHED(); + return NORMAL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWordBreak e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case NormalWordBreak: + m_value.ident = CSSValueNormal; + break; + case BreakAllWordBreak: + m_value.ident = CSSValueBreakAll; + break; + case BreakWordBreak: + m_value.ident = CSSValueBreakWord; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EWordBreak() const +{ + switch (m_value.ident) { + case CSSValueBreakAll: + return BreakAllWordBreak; + case CSSValueBreakWord: + return BreakWordBreak; + case CSSValueNormal: + return NormalWordBreak; + default: + ASSERT_NOT_REACHED(); + return NormalWordBreak; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWordWrap e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case NormalWordWrap: + m_value.ident = CSSValueNormal; + break; + case BreakWordWrap: + m_value.ident = CSSValueBreakWord; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EWordWrap() const +{ + switch (m_value.ident) { + case CSSValueBreakWord: + return BreakWordWrap; + case CSSValueNormal: + return NormalWordWrap; + default: + ASSERT_NOT_REACHED(); + return NormalWordWrap; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextDirection e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case LTR: + m_value.ident = CSSValueLtr; + break; + case RTL: + m_value.ident = CSSValueRtl; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextDirection() const +{ + switch (m_value.ident) { + case CSSValueLtr: + return LTR; + case CSSValueRtl: + return RTL; + default: + ASSERT_NOT_REACHED(); + return LTR; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WritingMode e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TopToBottomWritingMode: + m_value.ident = CSSValueHorizontalTb; + break; + case RightToLeftWritingMode: + m_value.ident = CSSValueVerticalRl; + break; + case LeftToRightWritingMode: + m_value.ident = CSSValueVerticalLr; + break; + case BottomToTopWritingMode: + m_value.ident = CSSValueHorizontalBt; + break; + } +} + +template<> inline CSSPrimitiveValue::operator WritingMode() const +{ + switch (m_value.ident) { + case CSSValueHorizontalTb: + return TopToBottomWritingMode; + case CSSValueVerticalRl: + return RightToLeftWritingMode; + case CSSValueVerticalLr: + return LeftToRightWritingMode; + case CSSValueHorizontalBt: + return BottomToTopWritingMode; + default: + ASSERT_NOT_REACHED(); + return TopToBottomWritingMode; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextCombine e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TextCombineNone: + m_value.ident = CSSValueNone; + break; + case TextCombineHorizontal: + m_value.ident = CSSValueHorizontal; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextCombine() const +{ + switch (m_value.ident) { + case CSSValueNone: + return TextCombineNone; + case CSSValueHorizontal: + return TextCombineHorizontal; + default: + ASSERT_NOT_REACHED(); + return TextCombineNone; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisPosition position) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (position) { + case TextEmphasisPositionOver: + m_value.ident = CSSValueOver; + break; + case TextEmphasisPositionUnder: + m_value.ident = CSSValueUnder; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextEmphasisPosition() const +{ + switch (m_value.ident) { + case CSSValueOver: + return TextEmphasisPositionOver; + case CSSValueUnder: + return TextEmphasisPositionUnder; + default: + ASSERT_NOT_REACHED(); + return TextEmphasisPositionOver; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisFill fill) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (fill) { + case TextEmphasisFillFilled: + m_value.ident = CSSValueFilled; + break; + case TextEmphasisFillOpen: + m_value.ident = CSSValueOpen; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextEmphasisFill() const +{ + switch (m_value.ident) { + case CSSValueFilled: + return TextEmphasisFillFilled; + case CSSValueOpen: + return TextEmphasisFillOpen; + default: + ASSERT_NOT_REACHED(); + return TextEmphasisFillFilled; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisMark mark) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (mark) { + case TextEmphasisMarkDot: + m_value.ident = CSSValueDot; + break; + case TextEmphasisMarkCircle: + m_value.ident = CSSValueCircle; + break; + case TextEmphasisMarkDoubleCircle: + m_value.ident = CSSValueDoubleCircle; + break; + case TextEmphasisMarkTriangle: + m_value.ident = CSSValueTriangle; + break; + case TextEmphasisMarkSesame: + m_value.ident = CSSValueSesame; + break; + case TextEmphasisMarkNone: + case TextEmphasisMarkAuto: + case TextEmphasisMarkCustom: + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextEmphasisMark() const +{ + switch (m_value.ident) { + case CSSValueNone: + return TextEmphasisMarkNone; + case CSSValueDot: + return TextEmphasisMarkDot; + case CSSValueCircle: + return TextEmphasisMarkCircle; + case CSSValueDoubleCircle: + return TextEmphasisMarkDoubleCircle; + case CSSValueTriangle: + return TextEmphasisMarkTriangle; + case CSSValueSesame: + return TextEmphasisMarkSesame; + default: + ASSERT_NOT_REACHED(); + return TextEmphasisMarkNone; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPointerEvents e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case PE_NONE: + m_value.ident = CSSValueNone; + break; + case PE_STROKE: + m_value.ident = CSSValueStroke; + break; + case PE_FILL: + m_value.ident = CSSValueFill; + break; + case PE_PAINTED: + m_value.ident = CSSValuePainted; + break; + case PE_VISIBLE: + m_value.ident = CSSValueVisible; + break; + case PE_VISIBLE_STROKE: + m_value.ident = CSSValueVisiblestroke; + break; + case PE_VISIBLE_FILL: + m_value.ident = CSSValueVisiblefill; + break; + case PE_VISIBLE_PAINTED: + m_value.ident = CSSValueVisiblepainted; + break; + case PE_AUTO: + m_value.ident = CSSValueAuto; + break; + case PE_ALL: + m_value.ident = CSSValueAll; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EPointerEvents() const +{ + switch (m_value.ident) { + case CSSValueAll: + return PE_ALL; + case CSSValueAuto: + return PE_AUTO; + case CSSValueNone: + return PE_NONE; + case CSSValueVisiblepainted: + return PE_VISIBLE_PAINTED; + case CSSValueVisiblefill: + return PE_VISIBLE_FILL; + case CSSValueVisiblestroke: + return PE_VISIBLE_STROKE; + case CSSValueVisible: + return PE_VISIBLE; + case CSSValuePainted: + return PE_PAINTED; + case CSSValueFill: + return PE_FILL; + case CSSValueStroke: + return PE_STROKE; + default: + ASSERT_NOT_REACHED(); + return PE_ALL; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontSmoothingMode smoothing) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (smoothing) { + case AutoSmoothing: + m_value.ident = CSSValueAuto; + return; + case NoSmoothing: + m_value.ident = CSSValueNone; + return; + case Antialiased: + m_value.ident = CSSValueAntialiased; + return; + case SubpixelAntialiased: + m_value.ident = CSSValueSubpixelAntialiased; + return; + } + + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueAuto; +} + +template<> inline CSSPrimitiveValue::operator FontSmoothingMode() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return AutoSmoothing; + case CSSValueNone: + return NoSmoothing; + case CSSValueAntialiased: + return Antialiased; + case CSSValueSubpixelAntialiased: + return SubpixelAntialiased; + } + + ASSERT_NOT_REACHED(); + return AutoSmoothing; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextRenderingMode e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case AutoTextRendering: + m_value.ident = CSSValueAuto; + break; + case OptimizeSpeed: + m_value.ident = CSSValueOptimizespeed; + break; + case OptimizeLegibility: + m_value.ident = CSSValueOptimizelegibility; + break; + case GeometricPrecision: + m_value.ident = CSSValueGeometricprecision; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextRenderingMode() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return AutoTextRendering; + case CSSValueOptimizespeed: + return OptimizeSpeed; + case CSSValueOptimizelegibility: + return OptimizeLegibility; + case CSSValueGeometricprecision: + return GeometricPrecision; + default: + ASSERT_NOT_REACHED(); + return AutoTextRendering; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ColorSpace space) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (space) { + case ColorSpaceDeviceRGB: + m_value.ident = CSSValueDefault; + break; + case ColorSpaceSRGB: + m_value.ident = CSSValueSrgb; + break; + case ColorSpaceLinearRGB: + // CSS color correction does not support linearRGB yet. + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueDefault; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ColorSpace() const +{ + switch (m_value.ident) { + case CSSValueDefault: + return ColorSpaceDeviceRGB; + case CSSValueSrgb: + return ColorSpaceSRGB; + default: + ASSERT_NOT_REACHED(); + return ColorSpaceDeviceRGB; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Hyphens hyphens) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (hyphens) { + case HyphensNone: + m_value.ident = CSSValueNone; + break; + case HyphensManual: + m_value.ident = CSSValueManual; + break; + case HyphensAuto: + m_value.ident = CSSValueAuto; + break; + } +} + +template<> inline CSSPrimitiveValue::operator Hyphens() const +{ + switch (m_value.ident) { + case CSSValueNone: + return HyphensNone; + case CSSValueManual: + return HyphensManual; + case CSSValueAuto: + return HyphensAuto; + default: + ASSERT_NOT_REACHED(); + return HyphensAuto; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ESpeak e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case SpeakNone: + m_value.ident = CSSValueNone; + break; + case SpeakNormal: + m_value.ident = CSSValueNormal; + break; + case SpeakSpellOut: + m_value.ident = CSSValueSpellOut; + break; + case SpeakDigits: + m_value.ident = CSSValueDigits; + break; + case SpeakLiteralPunctuation: + m_value.ident = CSSValueLiteralPunctuation; + break; + case SpeakNoPunctuation: + m_value.ident = CSSValueNoPunctuation; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ESpeak() const +{ + switch (m_value.ident) { + case CSSValueNone: + return SpeakNone; + case CSSValueNormal: + return SpeakNormal; + case CSSValueSpellOut: + return SpeakSpellOut; + case CSSValueDigits: + return SpeakDigits; + case CSSValueLiteralPunctuation: + return SpeakLiteralPunctuation; + case CSSValueNoPunctuation: + return SpeakNoPunctuation; + default: + ASSERT_NOT_REACHED(); + return SpeakNormal; + } +} + +#if ENABLE(SVG) + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineCap e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case ButtCap: + m_value.ident = CSSValueButt; + break; + case RoundCap: + m_value.ident = CSSValueRound; + break; + case SquareCap: + m_value.ident = CSSValueSquare; + break; + } +} + +template<> inline CSSPrimitiveValue::operator LineCap() const +{ + switch (m_value.ident) { + case CSSValueButt: + return ButtCap; + case CSSValueRound: + return RoundCap; + case CSSValueSquare: + return SquareCap; + default: + ASSERT_NOT_REACHED(); + return ButtCap; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineJoin e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case MiterJoin: + m_value.ident = CSSValueMiter; + break; + case RoundJoin: + m_value.ident = CSSValueRound; + break; + case BevelJoin: + m_value.ident = CSSValueBevel; + break; + } +} + +template<> inline CSSPrimitiveValue::operator LineJoin() const +{ + switch (m_value.ident) { + case CSSValueMiter: + return MiterJoin; + case CSSValueRound: + return RoundJoin; + case CSSValueBevel: + return BevelJoin; + default: + ASSERT_NOT_REACHED(); + return MiterJoin; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WindRule e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case RULE_NONZERO: + m_value.ident = CSSValueNonzero; + break; + case RULE_EVENODD: + m_value.ident = CSSValueEvenodd; + break; + } +} + +template<> inline CSSPrimitiveValue::operator WindRule() const +{ + switch (m_value.ident) { + case CSSValueNonzero: + return RULE_NONZERO; + case CSSValueEvenodd: + return RULE_EVENODD; + default: + ASSERT_NOT_REACHED(); + return RULE_NONZERO; + } +} + + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EAlignmentBaseline e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case AB_AUTO: + m_value.ident = CSSValueAuto; + break; + case AB_BASELINE: + m_value.ident = CSSValueBaseline; + break; + case AB_BEFORE_EDGE: + m_value.ident = CSSValueBeforeEdge; + break; + case AB_TEXT_BEFORE_EDGE: + m_value.ident = CSSValueTextBeforeEdge; + break; + case AB_MIDDLE: + m_value.ident = CSSValueMiddle; + break; + case AB_CENTRAL: + m_value.ident = CSSValueCentral; + break; + case AB_AFTER_EDGE: + m_value.ident = CSSValueAfterEdge; + break; + case AB_TEXT_AFTER_EDGE: + m_value.ident = CSSValueTextAfterEdge; + break; + case AB_IDEOGRAPHIC: + m_value.ident = CSSValueIdeographic; + break; + case AB_ALPHABETIC: + m_value.ident = CSSValueAlphabetic; + break; + case AB_HANGING: + m_value.ident = CSSValueHanging; + break; + case AB_MATHEMATICAL: + m_value.ident = CSSValueMathematical; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EAlignmentBaseline() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return AB_AUTO; + case CSSValueBaseline: + return AB_BASELINE; + case CSSValueBeforeEdge: + return AB_BEFORE_EDGE; + case CSSValueTextBeforeEdge: + return AB_TEXT_BEFORE_EDGE; + case CSSValueMiddle: + return AB_MIDDLE; + case CSSValueCentral: + return AB_CENTRAL; + case CSSValueAfterEdge: + return AB_AFTER_EDGE; + case CSSValueTextAfterEdge: + return AB_TEXT_AFTER_EDGE; + case CSSValueIdeographic: + return AB_IDEOGRAPHIC; + case CSSValueAlphabetic: + return AB_ALPHABETIC; + case CSSValueHanging: + return AB_HANGING; + case CSSValueMathematical: + return AB_MATHEMATICAL; + default: + ASSERT_NOT_REACHED(); + return AB_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorInterpolation e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CI_AUTO: + m_value.ident = CSSValueAuto; + break; + case CI_SRGB: + m_value.ident = CSSValueSrgb; + break; + case CI_LINEARRGB: + m_value.ident = CSSValueLinearrgb; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EColorInterpolation() const +{ + switch (m_value.ident) { + case CSSValueSrgb: + return CI_SRGB; + case CSSValueLinearrgb: + return CI_LINEARRGB; + case CSSValueAuto: + return CI_AUTO; + default: + ASSERT_NOT_REACHED(); + return CI_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorRendering e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case CR_AUTO: + m_value.ident = CSSValueAuto; + break; + case CR_OPTIMIZESPEED: + m_value.ident = CSSValueOptimizespeed; + break; + case CR_OPTIMIZEQUALITY: + m_value.ident = CSSValueOptimizequality; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EColorRendering() const +{ + switch (m_value.ident) { + case CSSValueOptimizespeed: + return CR_OPTIMIZESPEED; + case CSSValueOptimizequality: + return CR_OPTIMIZEQUALITY; + case CSSValueAuto: + return CR_AUTO; + default: + ASSERT_NOT_REACHED(); + return CR_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EDominantBaseline e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case DB_AUTO: + m_value.ident = CSSValueAuto; + break; + case DB_USE_SCRIPT: + m_value.ident = CSSValueUseScript; + break; + case DB_NO_CHANGE: + m_value.ident = CSSValueNoChange; + break; + case DB_RESET_SIZE: + m_value.ident = CSSValueResetSize; + break; + case DB_CENTRAL: + m_value.ident = CSSValueCentral; + break; + case DB_MIDDLE: + m_value.ident = CSSValueMiddle; + break; + case DB_TEXT_BEFORE_EDGE: + m_value.ident = CSSValueTextBeforeEdge; + break; + case DB_TEXT_AFTER_EDGE: + m_value.ident = CSSValueTextAfterEdge; + break; + case DB_IDEOGRAPHIC: + m_value.ident = CSSValueIdeographic; + break; + case DB_ALPHABETIC: + m_value.ident = CSSValueAlphabetic; + break; + case DB_HANGING: + m_value.ident = CSSValueHanging; + break; + case DB_MATHEMATICAL: + m_value.ident = CSSValueMathematical; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EDominantBaseline() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return DB_AUTO; + case CSSValueUseScript: + return DB_USE_SCRIPT; + case CSSValueNoChange: + return DB_NO_CHANGE; + case CSSValueResetSize: + return DB_RESET_SIZE; + case CSSValueIdeographic: + return DB_IDEOGRAPHIC; + case CSSValueAlphabetic: + return DB_ALPHABETIC; + case CSSValueHanging: + return DB_HANGING; + case CSSValueMathematical: + return DB_MATHEMATICAL; + case CSSValueCentral: + return DB_CENTRAL; + case CSSValueMiddle: + return DB_MIDDLE; + case CSSValueTextAfterEdge: + return DB_TEXT_AFTER_EDGE; + case CSSValueTextBeforeEdge: + return DB_TEXT_BEFORE_EDGE; + default: + ASSERT_NOT_REACHED(); + return DB_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EImageRendering e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case IR_AUTO: + m_value.ident = CSSValueAuto; + break; + case IR_OPTIMIZESPEED: + m_value.ident = CSSValueOptimizespeed; + break; + case IR_OPTIMIZEQUALITY: + m_value.ident = CSSValueOptimizequality; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EImageRendering() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return IR_AUTO; + case CSSValueOptimizespeed: + return IR_OPTIMIZESPEED; + case CSSValueOptimizequality: + return IR_OPTIMIZEQUALITY; + default: + ASSERT_NOT_REACHED(); + return IR_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EShapeRendering e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case IR_AUTO: + m_value.ident = CSSValueAuto; + break; + case IR_OPTIMIZESPEED: + m_value.ident = CSSValueOptimizespeed; + break; + case SR_CRISPEDGES: + m_value.ident = CSSValueCrispedges; + break; + case SR_GEOMETRICPRECISION: + m_value.ident = CSSValueGeometricprecision; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EShapeRendering() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return SR_AUTO; + case CSSValueOptimizespeed: + return SR_OPTIMIZESPEED; + case CSSValueCrispedges: + return SR_CRISPEDGES; + case CSSValueGeometricprecision: + return SR_GEOMETRICPRECISION; + default: + ASSERT_NOT_REACHED(); + return SR_AUTO; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextAnchor e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case TA_START: + m_value.ident = CSSValueStart; + break; + case TA_MIDDLE: + m_value.ident = CSSValueMiddle; + break; + case TA_END: + m_value.ident = CSSValueEnd; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETextAnchor() const +{ + switch (m_value.ident) { + case CSSValueStart: + return TA_START; + case CSSValueMiddle: + return TA_MIDDLE; + case CSSValueEnd: + return TA_END; + default: + ASSERT_NOT_REACHED(); + return TA_START; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(SVGWritingMode e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case WM_LRTB: + m_value.ident = CSSValueLrTb; + break; + case WM_LR: + m_value.ident = CSSValueLr; + break; + case WM_RLTB: + m_value.ident = CSSValueRlTb; + break; + case WM_RL: + m_value.ident = CSSValueRl; + break; + case WM_TBRL: + m_value.ident = CSSValueTbRl; + break; + case WM_TB: + m_value.ident = CSSValueTb; + break; + } +} + +template<> inline CSSPrimitiveValue::operator SVGWritingMode() const +{ + switch (m_value.ident) { + case CSSValueLrTb: + return WM_LRTB; + case CSSValueLr: + return WM_LR; + case CSSValueRlTb: + return WM_RLTB; + case CSSValueRl: + return WM_RL; + case CSSValueTbRl: + return WM_TBRL; + case CSSValueTb: + return WM_TB; + default: + ASSERT_NOT_REACHED(); + return WM_LRTB; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EVectorEffect e) + : m_type(CSS_IDENT) + , m_hasCachedCSSText(false) +{ + switch (e) { + case VE_NONE: + m_value.ident = CSSValueNone; + break; + case VE_NON_SCALING_STROKE: + m_value.ident = CSSValueNonScalingStroke; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EVectorEffect() const +{ + switch (m_value.ident) { + case CSSValueNone: + return VE_NONE; + case CSSValueNonScalingStroke: + return VE_NON_SCALING_STROKE; + default: + ASSERT_NOT_REACHED(); + return VE_NONE; + } +} + +#endif + +} + +#endif diff --git a/Source/WebCore/css/CSSProperty.cpp b/Source/WebCore/css/CSSProperty.cpp new file mode 100644 index 0000000..1e04da7 --- /dev/null +++ b/Source/WebCore/css/CSSProperty.cpp @@ -0,0 +1,285 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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 "CSSProperty.h" + +#include "CSSPropertyNames.h" +#include "PlatformString.h" +#include "RenderStyleConstants.h" + +namespace WebCore { + +String CSSProperty::cssText() const +{ + return String(getPropertyName(static_cast<CSSPropertyID>(id()))) + ": " + m_value->cssText() + (isImportant() ? " !important" : "") + "; "; +} + +bool operator==(const CSSProperty& a, const CSSProperty& b) +{ + return a.m_id == b.m_id && a.m_important == b.m_important && a.m_value == b.m_value; +} + +enum LogicalBoxSide { BeforeSide, EndSide, AfterSide, StartSide }; +enum PhysicalBoxSide { TopSide, RightSide, BottomSide, LeftSide }; + +static int resolveToPhysicalProperty(TextDirection direction, WritingMode writingMode, LogicalBoxSide logicalSide, const int* properties) +{ + if (direction == LTR) { + if (writingMode == TopToBottomWritingMode) { + // The common case. The logical and physical box sides match. + // Left = Start, Right = End, Before = Top, After = Bottom + return properties[logicalSide]; + } + + if (writingMode == BottomToTopWritingMode) { + // Start = Left, End = Right, Before = Bottom, After = Top. + switch (logicalSide) { + case StartSide: + return properties[LeftSide]; + case EndSide: + return properties[RightSide]; + case BeforeSide: + return properties[BottomSide]; + default: + return properties[TopSide]; + } + } + + if (writingMode == LeftToRightWritingMode) { + // Start = Top, End = Bottom, Before = Left, After = Right. + switch (logicalSide) { + case StartSide: + return properties[TopSide]; + case EndSide: + return properties[BottomSide]; + case BeforeSide: + return properties[LeftSide]; + default: + return properties[RightSide]; + } + } + + // Start = Top, End = Bottom, Before = Right, After = Left + switch (logicalSide) { + case StartSide: + return properties[TopSide]; + case EndSide: + return properties[BottomSide]; + case BeforeSide: + return properties[RightSide]; + default: + return properties[LeftSide]; + } + } + + if (writingMode == TopToBottomWritingMode) { + // Start = Right, End = Left, Before = Top, After = Bottom + switch (logicalSide) { + case StartSide: + return properties[RightSide]; + case EndSide: + return properties[LeftSide]; + case BeforeSide: + return properties[TopSide]; + default: + return properties[BottomSide]; + } + } + + if (writingMode == BottomToTopWritingMode) { + // Start = Right, End = Left, Before = Bottom, After = Top + switch (logicalSide) { + case StartSide: + return properties[RightSide]; + case EndSide: + return properties[LeftSide]; + case BeforeSide: + return properties[BottomSide]; + default: + return properties[TopSide]; + } + } + + if (writingMode == LeftToRightWritingMode) { + // Start = Bottom, End = Top, Before = Left, After = Right + switch (logicalSide) { + case StartSide: + return properties[BottomSide]; + case EndSide: + return properties[TopSide]; + case BeforeSide: + return properties[LeftSide]; + default: + return properties[RightSide]; + } + } + + // Start = Bottom, End = Top, Before = Right, After = Left + switch (logicalSide) { + case StartSide: + return properties[BottomSide]; + case EndSide: + return properties[TopSide]; + case BeforeSide: + return properties[RightSide]; + default: + return properties[LeftSide]; + } +} + +enum LogicalExtent { LogicalWidth, LogicalHeight }; + +static int resolveToPhysicalProperty(WritingMode writingMode, LogicalExtent logicalSide, const int* properties) +{ + if (writingMode == TopToBottomWritingMode || writingMode == BottomToTopWritingMode) + return properties[logicalSide]; + return logicalSide == LogicalWidth ? properties[1] : properties[0]; +} + +int CSSProperty::resolveDirectionAwareProperty(int propertyID, TextDirection direction, WritingMode writingMode) +{ + switch (static_cast<CSSPropertyID>(propertyID)) { + case CSSPropertyWebkitMarginEnd: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitMarginStart: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitMarginBefore: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitMarginAfter: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitPaddingEnd: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitPaddingStart: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitPaddingBefore: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitPaddingAfter: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitBorderEnd: { + const int properties[4] = { CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitBorderStart: { + const int properties[4] = { CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitBorderBefore: { + const int properties[4] = { CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitBorderAfter: { + const int properties[4] = { CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitBorderEndColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitBorderStartColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitBorderBeforeColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitBorderAfterColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitBorderEndStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitBorderStartStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitBorderBeforeStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitBorderAfterStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitBorderEndWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return resolveToPhysicalProperty(direction, writingMode, EndSide, properties); + } + case CSSPropertyWebkitBorderStartWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return resolveToPhysicalProperty(direction, writingMode, StartSide, properties); + } + case CSSPropertyWebkitBorderBeforeWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return resolveToPhysicalProperty(direction, writingMode, BeforeSide, properties); + } + case CSSPropertyWebkitBorderAfterWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return resolveToPhysicalProperty(direction, writingMode, AfterSide, properties); + } + case CSSPropertyWebkitLogicalWidth: { + const int properties[2] = { CSSPropertyWidth, CSSPropertyHeight }; + return resolveToPhysicalProperty(writingMode, LogicalWidth, properties); + } + case CSSPropertyWebkitLogicalHeight: { + const int properties[2] = { CSSPropertyWidth, CSSPropertyHeight }; + return resolveToPhysicalProperty(writingMode, LogicalHeight, properties); + } + case CSSPropertyWebkitMinLogicalWidth: { + const int properties[2] = { CSSPropertyMinWidth, CSSPropertyMinHeight }; + return resolveToPhysicalProperty(writingMode, LogicalWidth, properties); + } + case CSSPropertyWebkitMinLogicalHeight: { + const int properties[2] = { CSSPropertyMinWidth, CSSPropertyMinHeight }; + return resolveToPhysicalProperty(writingMode, LogicalHeight, properties); + } + case CSSPropertyWebkitMaxLogicalWidth: { + const int properties[2] = { CSSPropertyMaxWidth, CSSPropertyMaxHeight }; + return resolveToPhysicalProperty(writingMode, LogicalWidth, properties); + } + case CSSPropertyWebkitMaxLogicalHeight: { + const int properties[2] = { CSSPropertyMaxWidth, CSSPropertyMaxHeight }; + return resolveToPhysicalProperty(writingMode, LogicalHeight, properties); + } + default: + return propertyID; + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSProperty.h b/Source/WebCore/css/CSSProperty.h new file mode 100644 index 0000000..106171d --- /dev/null +++ b/Source/WebCore/css/CSSProperty.h @@ -0,0 +1,83 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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. + */ + +#ifndef CSSProperty_h +#define CSSProperty_h + +#include "CSSValue.h" +#include "RenderStyleConstants.h" +#include "TextDirection.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSProperty : public FastAllocBase { +public: + CSSProperty(int propID, PassRefPtr<CSSValue> value, bool important = false, int shorthandID = 0, bool implicit = false) + : m_id(propID) + , m_shorthandID(shorthandID) + , m_important(important) + , m_implicit(implicit) + , m_value(value) + { + } + + CSSProperty& operator=(const CSSProperty& other) + { + m_id = other.m_id; + m_shorthandID = other.m_shorthandID; + m_important = other.m_important; + m_implicit = other.m_implicit; + m_value = other.m_value; + return *this; + } + + int id() const { return m_id; } + int shorthandID() const { return m_shorthandID; } + + bool isImportant() const { return m_important; } + bool isImplicit() const { return m_implicit; } + + CSSValue* value() const { return m_value.get(); } + + String cssText() const; + + static int resolveDirectionAwareProperty(int propertyID, TextDirection, WritingMode); + + friend bool operator==(const CSSProperty&, const CSSProperty&); + + // Make sure the following fits in 4 bytes. Really. + int m_id : 15; + int m_shorthandID : 15; // If this property was set as part of a shorthand, gives the shorthand. + bool m_important : 1; + bool m_implicit : 1; // Whether or not the property was set implicitly as the result of a shorthand. + + RefPtr<CSSValue> m_value; +}; + +} // namespace WebCore + +namespace WTF { + // Properties in Vector can be initialized with memset and moved using memcpy. + template<> struct VectorTraits<WebCore::CSSProperty> : SimpleClassVectorTraits { }; +} + +#endif // CSSProperty_h diff --git a/Source/WebCore/css/CSSPropertyLonghand.cpp b/Source/WebCore/css/CSSPropertyLonghand.cpp new file mode 100644 index 0000000..7372a54 --- /dev/null +++ b/Source/WebCore/css/CSSPropertyLonghand.cpp @@ -0,0 +1,229 @@ +/* + * (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 "CSSPropertyLonghand.h" + +#include "CSSPropertyNames.h" +#include <wtf/HashMap.h> +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +typedef HashMap<int, CSSPropertyLonghand> ShorthandMap; + +static void initShorthandMap(ShorthandMap& shorthandMap) +{ + #define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \ + map.set(propID, CSSPropertyLonghand(array, WTF_ARRAY_LENGTH(array))) + + // FIXME: The 'font' property has "shorthand nature" but is not parsed as a shorthand. + + // Do not change the order of the following four shorthands, and keep them together. + static const int borderProperties[4][3] = { + { CSSPropertyBorderTopColor, CSSPropertyBorderTopStyle, CSSPropertyBorderTopWidth }, + { CSSPropertyBorderRightColor, CSSPropertyBorderRightStyle, CSSPropertyBorderRightWidth }, + { CSSPropertyBorderBottomColor, CSSPropertyBorderBottomStyle, CSSPropertyBorderBottomWidth }, + { CSSPropertyBorderLeftColor, CSSPropertyBorderLeftStyle, CSSPropertyBorderLeftWidth } + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderTop, borderProperties[0]); + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderRight, borderProperties[1]); + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderBottom, borderProperties[2]); + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderLeft, borderProperties[3]); + + shorthandMap.set(CSSPropertyBorder, CSSPropertyLonghand(borderProperties[0], sizeof(borderProperties) / sizeof(borderProperties[0][0]))); + + static const int borderColorProperties[] = { + CSSPropertyBorderTopColor, + CSSPropertyBorderRightColor, + CSSPropertyBorderBottomColor, + CSSPropertyBorderLeftColor + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderColor, borderColorProperties); + + static const int borderStyleProperties[] = { + CSSPropertyBorderTopStyle, + CSSPropertyBorderRightStyle, + CSSPropertyBorderBottomStyle, + CSSPropertyBorderLeftStyle + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderStyle, borderStyleProperties); + + static const int borderWidthProperties[] = { + CSSPropertyBorderTopWidth, + CSSPropertyBorderRightWidth, + CSSPropertyBorderBottomWidth, + CSSPropertyBorderLeftWidth + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderWidth, borderWidthProperties); + + static const int backgroundPositionProperties[] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBackgroundPosition, backgroundPositionProperties); + + static const int backgroundRepeatProperties[] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBackgroundRepeat, backgroundRepeatProperties); + + static const int borderSpacingProperties[] = { CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyWebkitBorderVerticalSpacing }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderSpacing, borderSpacingProperties); + + static const int listStyleProperties[] = { + CSSPropertyListStyleImage, + CSSPropertyListStylePosition, + CSSPropertyListStyleType + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyListStyle, listStyleProperties); + + static const int marginProperties[] = { + CSSPropertyMarginTop, + CSSPropertyMarginRight, + CSSPropertyMarginBottom, + CSSPropertyMarginLeft + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyMargin, marginProperties); + + static const int marginCollapseProperties[] = { CSSPropertyWebkitMarginBeforeCollapse, CSSPropertyWebkitMarginAfterCollapse }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitMarginCollapse, marginCollapseProperties); + + static const int marqueeProperties[] = { + CSSPropertyWebkitMarqueeDirection, + CSSPropertyWebkitMarqueeIncrement, + CSSPropertyWebkitMarqueeRepetition, + CSSPropertyWebkitMarqueeStyle, + CSSPropertyWebkitMarqueeSpeed + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitMarquee, marqueeProperties); + + static const int outlineProperties[] = { + CSSPropertyOutlineColor, + CSSPropertyOutlineOffset, + CSSPropertyOutlineStyle, + CSSPropertyOutlineWidth + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyOutline, outlineProperties); + + static const int paddingProperties[] = { + CSSPropertyPaddingTop, + CSSPropertyPaddingRight, + CSSPropertyPaddingBottom, + CSSPropertyPaddingLeft + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyPadding, paddingProperties); + + static const int textStrokeProperties[] = { CSSPropertyWebkitTextStrokeColor, CSSPropertyWebkitTextStrokeWidth }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitTextStroke, textStrokeProperties); + + static const int backgroundProperties[] = { + CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundClip, + CSSPropertyBackgroundColor, + CSSPropertyBackgroundImage, + CSSPropertyBackgroundOrigin, + CSSPropertyBackgroundPositionX, + CSSPropertyBackgroundPositionY, + CSSPropertyBackgroundRepeatX, + CSSPropertyBackgroundRepeatY + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBackground, backgroundProperties); + + static const int columnsProperties[] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitColumns, columnsProperties); + + static const int columnRuleProperties[] = { + CSSPropertyWebkitColumnRuleColor, + CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleWidth + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitColumnRule, columnRuleProperties); + + static const int overflowProperties[] = { CSSPropertyOverflowX, CSSPropertyOverflowY }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyOverflow, overflowProperties); + + static const int borderRadiusProperties[] = { + CSSPropertyBorderTopRightRadius, + CSSPropertyBorderTopLeftRadius, + CSSPropertyBorderBottomLeftRadius, + CSSPropertyBorderBottomRightRadius + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyBorderRadius, borderRadiusProperties); + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitBorderRadius, borderRadiusProperties); + + static const int maskPositionProperties[] = { CSSPropertyWebkitMaskPositionX, CSSPropertyWebkitMaskPositionY }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitMaskPosition, maskPositionProperties); + + static const int maskRepeatProperties[] = { CSSPropertyWebkitMaskRepeatX, CSSPropertyWebkitMaskRepeatY }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitMaskRepeat, maskRepeatProperties); + + static const int maskProperties[] = { + CSSPropertyWebkitMaskAttachment, + CSSPropertyWebkitMaskClip, + CSSPropertyWebkitMaskImage, + CSSPropertyWebkitMaskOrigin, + CSSPropertyWebkitMaskPositionX, + CSSPropertyWebkitMaskPositionY, + CSSPropertyWebkitMaskRepeatX, + CSSPropertyWebkitMaskRepeatY + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitMask, maskProperties); + + static const int animationProperties[] = { + CSSPropertyWebkitAnimationName, + CSSPropertyWebkitAnimationDuration, + CSSPropertyWebkitAnimationTimingFunction, + CSSPropertyWebkitAnimationDelay, + CSSPropertyWebkitAnimationIterationCount, + CSSPropertyWebkitAnimationDirection, + CSSPropertyWebkitAnimationFillMode + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitAnimation, animationProperties); + + static const int transitionProperties[] = { + CSSPropertyWebkitTransitionProperty, + CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionTimingFunction, + CSSPropertyWebkitTransitionDelay + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitTransition, transitionProperties); + + static const int transformOriginProperties[] = { + CSSPropertyWebkitTransformOriginX, + CSSPropertyWebkitTransformOriginY + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitTransformOrigin, transformOriginProperties); + + static const int textEmphasisProperties[] = { + CSSPropertyWebkitTextEmphasisColor, + CSSPropertyWebkitTextEmphasisStyle + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitTextEmphasis, textEmphasisProperties); + + #undef SET_SHORTHAND_MAP_ENTRY +} + +CSSPropertyLonghand longhandForProperty(int propertyID) +{ + DEFINE_STATIC_LOCAL(ShorthandMap, shorthandMap, ()); + if (shorthandMap.isEmpty()) + initShorthandMap(shorthandMap); + + return shorthandMap.get(propertyID); +} + + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSPropertyLonghand.h b/Source/WebCore/css/CSSPropertyLonghand.h new file mode 100644 index 0000000..9633c02 --- /dev/null +++ b/Source/WebCore/css/CSSPropertyLonghand.h @@ -0,0 +1,53 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSPropertyLonghand_h +#define CSSPropertyLonghand_h + +namespace WebCore { + +class CSSPropertyLonghand { +public: + CSSPropertyLonghand() + : m_properties(0) + , m_length(0) + { + } + + CSSPropertyLonghand(const int* firstProperty, unsigned numProperties) + : m_properties(firstProperty) + , m_length(numProperties) + { + } + + const int* properties() const { return m_properties; } + unsigned length() const { return m_length; } + +private: + const int* m_properties; + unsigned m_length; +}; + +// Returns an empty list if the property is not a shorthand +CSSPropertyLonghand longhandForProperty(int); + +} // namespace WebCore + +#endif // CSSPropertyLonghand_h diff --git a/Source/WebCore/css/CSSPropertyNames.in b/Source/WebCore/css/CSSPropertyNames.in new file mode 100644 index 0000000..b04c6d6 --- /dev/null +++ b/Source/WebCore/css/CSSPropertyNames.in @@ -0,0 +1,304 @@ +# +# CSS property names +# +# Some properties are used internally, but are not part of CSS. They are used to get +# HTML4 compatibility in the rendering engine. +# +# Microsoft extensions are documented here: +# http://msdn.microsoft.com/workshop/author/css/reference/attributes.asp +# + +# high-priority property names have to be listed first, to simplify the check +# for applying them first. +color +direction +display +font +font-family +font-size +font-style +font-variant +font-weight +text-rendering +-webkit-font-smoothing +-webkit-text-size-adjust +-webkit-writing-mode +zoom + +# line height needs to be right after the above high-priority properties +line-height + +# The remaining properties are listed in alphabetical order +background +background-attachment +background-clip +background-color +background-image +background-origin +background-position +background-position-x +background-position-y +background-repeat +background-repeat-x +background-repeat-y +background-size +border +border-bottom +border-bottom-color +border-bottom-left-radius +border-bottom-right-radius +border-bottom-style +border-bottom-width +border-collapse +border-color +border-left +border-left-color +border-left-style +border-left-width +border-radius +border-right +border-right-color +border-right-style +border-right-width +border-spacing +border-style +border-top +border-top-color +border-top-left-radius +border-top-right-radius +border-top-style +border-top-width +border-width +bottom +box-shadow +box-sizing +caption-side +clear +clip +content +counter-increment +counter-reset +cursor +empty-cells +float +font-stretch +height +left +letter-spacing +list-style +list-style-image +list-style-position +list-style-type +margin +margin-bottom +margin-left +margin-right +margin-top +max-height +max-width +min-height +min-width +opacity +orphans +outline +outline-color +outline-offset +outline-style +outline-width +overflow +overflow-x +overflow-y +padding +padding-bottom +padding-left +padding-right +padding-top +page +page-break-after +page-break-before +page-break-inside +pointer-events +position +quotes +resize +right +size +src +speak +table-layout +text-align +text-decoration +text-indent +text-line-through +text-line-through-color +text-line-through-mode +text-line-through-style +text-line-through-width +text-overflow +text-overline +text-overline-color +text-overline-mode +text-overline-style +text-overline-width +text-shadow +text-transform +text-underline +text-underline-color +text-underline-mode +text-underline-style +text-underline-width +top +unicode-bidi +unicode-range +vertical-align +visibility +white-space +widows +width +word-break +word-spacing +word-wrap +z-index +-webkit-animation +-webkit-animation-delay +-webkit-animation-direction +-webkit-animation-duration +-webkit-animation-fill-mode +-webkit-animation-iteration-count +-webkit-animation-name +-webkit-animation-play-state +-webkit-animation-timing-function +-webkit-appearance +-webkit-backface-visibility +-webkit-background-clip +-webkit-background-composite +-webkit-background-origin +# -webkit-background-size differs from background-size only in the interpretation of +# a single value: -webkit-background-size: l; is equivalent to background-size: l l; +# whereas background-size: l; is equivalent to background-size: l auto; +-webkit-background-size +-webkit-border-after +-webkit-border-after-color +-webkit-border-after-style +-webkit-border-after-width +-webkit-border-before +-webkit-border-before-color +-webkit-border-before-style +-webkit-border-before-width +-webkit-border-end +-webkit-border-end-color +-webkit-border-end-style +-webkit-border-end-width +-webkit-border-fit +-webkit-border-horizontal-spacing +-webkit-border-image +# -webkit-border-radius differs from border-radius only in the interpretation of +# a value consisting of two lengths: "-webkit-border-radius: l1 l2;" is equivalent +# to "border-radius: l1 / l2;" +-webkit-border-radius +-webkit-border-start +-webkit-border-start-color +-webkit-border-start-style +-webkit-border-start-width +-webkit-border-vertical-spacing +-webkit-box-align +-webkit-box-direction +-webkit-box-flex +-webkit-box-flex-group +-webkit-box-lines +-webkit-box-ordinal-group +-webkit-box-orient +-webkit-box-pack +-webkit-box-reflect +-webkit-box-shadow +-webkit-color-correction +-webkit-column-break-after +-webkit-column-break-before +-webkit-column-break-inside +-webkit-column-count +-webkit-column-gap +-webkit-column-rule +-webkit-column-rule-color +-webkit-column-rule-style +-webkit-column-rule-width +-webkit-column-span +-webkit-column-width +-webkit-columns +-webkit-font-size-delta +-webkit-highlight +-webkit-hyphenate-character +-webkit-hyphenate-locale +-webkit-hyphens +-webkit-line-break +-webkit-line-clamp +-webkit-logical-width +-webkit-logical-height +-webkit-margin-after-collapse +-webkit-margin-before-collapse +-webkit-margin-bottom-collapse +-webkit-margin-top-collapse +-webkit-margin-collapse +-webkit-margin-after +-webkit-margin-before +-webkit-margin-end +-webkit-margin-start +-webkit-marquee +-webkit-marquee-direction +-webkit-marquee-increment +-webkit-marquee-repetition +-webkit-marquee-speed +-webkit-marquee-style +-webkit-mask +-webkit-mask-attachment +-webkit-mask-box-image +-webkit-mask-clip +-webkit-mask-composite +-webkit-mask-image +-webkit-mask-origin +-webkit-mask-position +-webkit-mask-position-x +-webkit-mask-position-y +-webkit-mask-repeat +-webkit-mask-repeat-x +-webkit-mask-repeat-y +-webkit-mask-size +-webkit-match-nearest-mail-blockquote-color +-webkit-max-logical-width +-webkit-max-logical-height +-webkit-min-logical-width +-webkit-min-logical-height +-webkit-nbsp-mode +-webkit-padding-after +-webkit-padding-before +-webkit-padding-end +-webkit-padding-start +-webkit-perspective +-webkit-perspective-origin +-webkit-perspective-origin-x +-webkit-perspective-origin-y +-webkit-rtl-ordering +-webkit-text-combine +-webkit-text-decorations-in-effect +-webkit-text-emphasis +-webkit-text-emphasis-color +-webkit-text-emphasis-position +-webkit-text-emphasis-style +-webkit-text-fill-color +-webkit-text-security +-webkit-text-stroke +-webkit-text-stroke-color +-webkit-text-stroke-width +-webkit-transform +-webkit-transform-origin +-webkit-transform-origin-x +-webkit-transform-origin-y +-webkit-transform-origin-z +-webkit-transform-style +-webkit-transition +-webkit-transition-delay +-webkit-transition-duration +-webkit-transition-property +-webkit-transition-timing-function +-webkit-user-drag +-webkit-user-modify +-webkit-user-select diff --git a/Source/WebCore/css/CSSPropertySourceData.cpp b/Source/WebCore/css/CSSPropertySourceData.cpp new file mode 100644 index 0000000..eb9c2c1 --- /dev/null +++ b/Source/WebCore/css/CSSPropertySourceData.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC +#define CSSPROPERTYSOURCEDATA_HIDE_GLOBALS 1 +#endif + +#include "CSSPropertySourceData.h" + +#include "PlatformString.h" +#include <wtf/StaticConstructors.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +SourceRange::SourceRange() + : start(0) + , end(0) +{ +} + +SourceRange::SourceRange(unsigned start, unsigned end) + : start(start) + , end(end) +{ +} + +CSSPropertySourceData::CSSPropertySourceData(const String& name, const String& value, bool important, bool parsedOk, const SourceRange& range) + : name(name) + , value(value) + , important(important) + , parsedOk(parsedOk) + , range(range) +{ +} + +CSSPropertySourceData::CSSPropertySourceData(const CSSPropertySourceData& other) + : name(other.name) + , value(other.value) + , important(other.important) + , parsedOk(other.parsedOk) + , range(other.range) +{ +} + +CSSPropertySourceData::CSSPropertySourceData() + : name("") + , value("") + , important(false) + , parsedOk(false) + , range(SourceRange(0, 0)) +{ +} + +String CSSPropertySourceData::toString() const +{ + DEFINE_STATIC_LOCAL(String, emptyValue, ("e")); + DEFINE_STATIC_LOCAL(String, importantSuffix, (" !important")); + if (!name && value == emptyValue) + return String(); + + String result = name; + result += ": "; + result += value; + if (important) + result += importantSuffix; + result += ";"; + return result; +} + +unsigned CSSPropertySourceData::hash() const +{ + return StringHash::hash(name) + 3 * StringHash::hash(value) + 7 * important + 13 * parsedOk + 31; +} + +// Global init routines +DEFINE_GLOBAL(CSSPropertySourceData, emptyCSSPropertySourceData, "", "e", false, false) + +// static +void CSSPropertySourceData::init() +{ + static bool initialized; + if (!initialized) { + new ((void *) &emptyCSSPropertySourceData) CSSPropertySourceData("", "e", false, false, SourceRange(0, 0)); + initialized = true; + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSPropertySourceData.h b/Source/WebCore/css/CSSPropertySourceData.h new file mode 100644 index 0000000..db80d46 --- /dev/null +++ b/Source/WebCore/css/CSSPropertySourceData.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSPropertySourceData_h +#define CSSPropertySourceData_h + +#include "PlatformString.h" +#include <utility> +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSStyleRule; + +struct SourceRange { + SourceRange(); + SourceRange(unsigned start, unsigned end); + + unsigned start; + unsigned end; +}; + +struct CSSPropertySourceData { + static void init(); + + CSSPropertySourceData(const String& name, const String& value, bool important, bool parsedOk, const SourceRange& range); + CSSPropertySourceData(const CSSPropertySourceData& other); + CSSPropertySourceData(); + + String toString() const; + unsigned hash() const; + + String name; + String value; + bool important; + bool parsedOk; + SourceRange range; +}; + +#ifndef CSSPROPERTYSOURCEDATA_HIDE_GLOBALS +extern const CSSPropertySourceData emptyCSSPropertySourceData; +#endif + +struct CSSStyleSourceData : public RefCounted<CSSStyleSourceData> { + static PassRefPtr<CSSStyleSourceData> create() + { + return adoptRef(new CSSStyleSourceData()); + } + + // Range of the style text in the enclosing source. + SourceRange styleBodyRange; + Vector<CSSPropertySourceData> propertyData; +}; + +struct CSSRuleSourceData : public RefCounted<CSSRuleSourceData> { + static PassRefPtr<CSSRuleSourceData> create() + { + return adoptRef(new CSSRuleSourceData()); + } + + // Range of the selector list in the enclosing source. + SourceRange selectorListRange; + RefPtr<CSSStyleSourceData> styleSourceData; +}; +typedef HashMap<CSSStyleRule*, RefPtr<CSSRuleSourceData> > StyleRuleRangeMap; + +} // namespace WebCore + +#endif // CSSPropertySourceData_h diff --git a/Source/WebCore/css/CSSQuirkPrimitiveValue.h b/Source/WebCore/css/CSSQuirkPrimitiveValue.h new file mode 100644 index 0000000..56857b7 --- /dev/null +++ b/Source/WebCore/css/CSSQuirkPrimitiveValue.h @@ -0,0 +1,50 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSQuirkPrimitiveValue_h +#define CSSQuirkPrimitiveValue_h + +#include "CSSPrimitiveValue.h" + +namespace WebCore { + +// This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE. +// The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em. +// When the quirky value is used, if you're in quirks mode, the margin will collapse away +// inside a table cell. +class CSSQuirkPrimitiveValue : public CSSPrimitiveValue { +public: + static PassRefPtr<CSSQuirkPrimitiveValue> create(double value, UnitTypes type) + { + return adoptRef(new CSSQuirkPrimitiveValue(value, type)); + } + +private: + CSSQuirkPrimitiveValue(double num, UnitTypes type) + : CSSPrimitiveValue(num, type) + { + } + + virtual bool isQuirkValue() { return true; } +}; + +} // namespace WebCore + +#endif // CSSQuirkPrimitiveValue_h diff --git a/Source/WebCore/css/CSSReflectValue.cpp b/Source/WebCore/css/CSSReflectValue.cpp new file mode 100644 index 0000000..a8ca59e --- /dev/null +++ b/Source/WebCore/css/CSSReflectValue.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSReflectValue.h" + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +using namespace std; + +namespace WebCore { + +String CSSReflectValue::cssText() const +{ + String result; + switch (m_direction) { + case ReflectionBelow: + result += "below "; + break; + case ReflectionAbove: + result += "above "; + break; + case ReflectionLeft: + result += "left "; + break; + case ReflectionRight: + result += "right "; + break; + default: + break; + } + + result += m_offset->cssText() + " "; + if (m_mask) + result += m_mask->cssText(); + return result; +} + +void CSSReflectValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + if (m_mask) + m_mask->addSubresourceStyleURLs(urls, styleSheet); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSReflectValue.h b/Source/WebCore/css/CSSReflectValue.h new file mode 100644 index 0000000..1dcb1be --- /dev/null +++ b/Source/WebCore/css/CSSReflectValue.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSReflectValue_h +#define CSSReflectValue_h + +#include "CSSReflectionDirection.h" +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSPrimitiveValue; + +class CSSReflectValue : public CSSValue { +public: + static PassRefPtr<CSSReflectValue> create(CSSReflectionDirection direction, + PassRefPtr<CSSPrimitiveValue> offset, PassRefPtr<CSSValue> mask) + { + return adoptRef(new CSSReflectValue(direction, offset, mask)); + } + + CSSReflectionDirection direction() const { return m_direction; } + CSSPrimitiveValue* offset() const { return m_offset.get(); } + CSSValue* mask() const { return m_mask.get(); } + + virtual String cssText() const; + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +private: + CSSReflectValue(CSSReflectionDirection direction, + PassRefPtr<CSSPrimitiveValue> offset, PassRefPtr<CSSValue> mask) + : m_direction(direction) + , m_offset(offset) + , m_mask(mask) + { + } + + virtual bool isReflectValue() const { return true; } + + CSSReflectionDirection m_direction; + RefPtr<CSSPrimitiveValue> m_offset; + RefPtr<CSSValue> m_mask; +}; + +} // namespace WebCore + +#endif // CSSReflectValue_h diff --git a/Source/WebCore/css/CSSReflectionDirection.h b/Source/WebCore/css/CSSReflectionDirection.h new file mode 100644 index 0000000..5a0c203 --- /dev/null +++ b/Source/WebCore/css/CSSReflectionDirection.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSReflectionDirection_h +#define CSSReflectionDirection_h + +namespace WebCore { + +enum CSSReflectionDirection { ReflectionBelow, ReflectionAbove, ReflectionLeft, ReflectionRight }; + +} // namespace WebCore + +#endif // CSSReflectionDirection_h diff --git a/Source/WebCore/css/CSSRule.cpp b/Source/WebCore/css/CSSRule.cpp new file mode 100644 index 0000000..43d8eac --- /dev/null +++ b/Source/WebCore/css/CSSRule.cpp @@ -0,0 +1,47 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006, 2007 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 "CSSRule.h" + +#include "NotImplemented.h" + +namespace WebCore { + +CSSStyleSheet* CSSRule::parentStyleSheet() const +{ + StyleBase* curr = parent(); + while (curr && !curr->isCSSStyleSheet()) + curr = curr->parent(); + return curr ? static_cast<CSSStyleSheet*>(curr) : 0; +} + +CSSRule* CSSRule::parentRule() const +{ + return (parent() && parent()->isRule()) ? static_cast<CSSRule*>(parent()) : 0; +} + +void CSSRule::setCssText(const String& /*cssText*/, ExceptionCode& /*ec*/) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSRule.h b/Source/WebCore/css/CSSRule.h new file mode 100644 index 0000000..4d2de8a --- /dev/null +++ b/Source/WebCore/css/CSSRule.h @@ -0,0 +1,77 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 2007 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. + */ + +#ifndef CSSRule_h +#define CSSRule_h + +#include "CSSStyleSheet.h" +#include "KURLHash.h" +#include <wtf/ListHashSet.h> + +namespace WebCore { + +typedef int ExceptionCode; + +enum CSSRuleFilter { + AllCSSRules, + SameOriginCSSRulesOnly +}; + +class CSSRule : public StyleBase { +public: + // FIXME: Change name to Type. + enum CSSRuleType { + UNKNOWN_RULE, + STYLE_RULE, + CHARSET_RULE, + IMPORT_RULE, + MEDIA_RULE, + FONT_FACE_RULE, + PAGE_RULE, + // 7 used to be VARIABLES_RULE + WEBKIT_KEYFRAMES_RULE = 8, + WEBKIT_KEYFRAME_RULE + }; + + // FIXME: Change to return CSSRuleType. + virtual unsigned short type() const = 0; + + CSSStyleSheet* parentStyleSheet() const; + CSSRule* parentRule() const; + + virtual String cssText() const = 0; + void setCssText(const String&, ExceptionCode&); + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&) { } + +protected: + CSSRule(CSSStyleSheet* parent) + : StyleBase(parent) + { + } + +private: + virtual bool isRule() { return true; } +}; + +} // namespace WebCore + +#endif // CSSRule_h diff --git a/Source/WebCore/css/CSSRule.idl b/Source/WebCore/css/CSSRule.idl new file mode 100644 index 0000000..170a801 --- /dev/null +++ b/Source/WebCore/css/CSSRule.idl @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [ + CustomMarkFunction, + CustomToJS, + Polymorphic + ] CSSRule { + + // RuleType + const unsigned short UNKNOWN_RULE = 0; + const unsigned short STYLE_RULE = 1; + const unsigned short CHARSET_RULE = 2; + const unsigned short IMPORT_RULE = 3; + const unsigned short MEDIA_RULE = 4; + const unsigned short FONT_FACE_RULE = 5; + const unsigned short PAGE_RULE = 6; + const unsigned short WEBKIT_KEYFRAMES_RULE = 8; + const unsigned short WEBKIT_KEYFRAME_RULE = 9; + + readonly attribute unsigned short type; + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString cssText + setter raises (DOMException); + + readonly attribute CSSStyleSheet parentStyleSheet; + readonly attribute CSSRule parentRule; + + }; + +} diff --git a/Source/WebCore/css/CSSRuleList.cpp b/Source/WebCore/css/CSSRuleList.cpp new file mode 100644 index 0000000..0a312af --- /dev/null +++ b/Source/WebCore/css/CSSRuleList.cpp @@ -0,0 +1,111 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006 Apple Computer, Inc. + * + * 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 "CSSRuleList.h" + +#include "CSSRule.h" +#include "StyleList.h" + +namespace WebCore { + +CSSRuleList::CSSRuleList() +{ +} + +CSSRuleList::CSSRuleList(StyleList* list, bool omitCharsetRules) +{ + m_list = list; + if (list && omitCharsetRules) { + m_list = 0; + unsigned len = list->length(); + for (unsigned i = 0; i < len; ++i) { + StyleBase* style = list->item(i); + if (style->isRule() && !style->isCharsetRule()) + append(static_cast<CSSRule*>(style)); + } + } +} + +CSSRuleList::~CSSRuleList() +{ +} + +unsigned CSSRuleList::length() const +{ + return m_list ? m_list->length() : m_lstCSSRules.size(); +} + +CSSRule* CSSRuleList::item(unsigned index) +{ + if (m_list) { + StyleBase* rule = m_list->item(index); + ASSERT(!rule || rule->isRule()); + return static_cast<CSSRule*>(rule); + } + + if (index < m_lstCSSRules.size()) + return m_lstCSSRules[index].get(); + return 0; +} + +void CSSRuleList::deleteRule(unsigned index) +{ + ASSERT(!m_list); + + if (index >= m_lstCSSRules.size()) { + // FIXME: Should we throw an INDEX_SIZE_ERR exception here? + return; + } + + m_lstCSSRules[index]->setParent(0); + m_lstCSSRules.remove(index); +} + +void CSSRuleList::append(CSSRule* rule) +{ + ASSERT(!m_list); + if (!rule) { + // FIXME: Should we throw an exception? + return; + } + + m_lstCSSRules.append(rule); +} + +unsigned CSSRuleList::insertRule(CSSRule* rule, unsigned index) +{ + ASSERT(!m_list); + if (!rule) { + // FIXME: Should we throw an exception? + return 0; + } + + if (index > m_lstCSSRules.size()) { + // FIXME: Should we throw an INDEX_SIZE_ERR exception here? + return 0; + } + + m_lstCSSRules.insert(index, rule); + return index; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSRuleList.h b/Source/WebCore/css/CSSRuleList.h new file mode 100644 index 0000000..a355c4a --- /dev/null +++ b/Source/WebCore/css/CSSRuleList.h @@ -0,0 +1,66 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006 Apple Computer, Inc. + * + * 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. + */ + +#ifndef CSSRuleList_h +#define CSSRuleList_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSRule; +class StyleList; + +class CSSRuleList : public RefCounted<CSSRuleList> { +public: + static PassRefPtr<CSSRuleList> create(StyleList* list, bool omitCharsetRules = false) + { + return adoptRef(new CSSRuleList(list, omitCharsetRules)); + } + static PassRefPtr<CSSRuleList> create() + { + return adoptRef(new CSSRuleList); + } + ~CSSRuleList(); + + unsigned length() const; + CSSRule* item(unsigned index); + + // FIXME: Not part of the DOM. Only used by media rules. We should be able to remove them if we changed media rules to work + // as StyleLists instead. + unsigned insertRule(CSSRule*, unsigned index); + void deleteRule(unsigned index); + void append(CSSRule*); + +private: + CSSRuleList(); + CSSRuleList(StyleList*, bool omitCharsetRules); + + RefPtr<StyleList> m_list; + Vector<RefPtr<CSSRule> > m_lstCSSRules; // FIXME: Want to eliminate, but used by IE rules() extension and still used by media rules. +}; + +} // namespace WebCore + +#endif // CSSRuleList_h diff --git a/Source/WebCore/css/CSSRuleList.idl b/Source/WebCore/css/CSSRuleList.idl new file mode 100644 index 0000000..e253287 --- /dev/null +++ b/Source/WebCore/css/CSSRuleList.idl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + // Introduced in DOM Level 2: + interface [ + CustomMarkFunction, + HasIndexGetter + ] CSSRuleList { + readonly attribute unsigned long length; + CSSRule item(in unsigned long index); + }; + +} diff --git a/Source/WebCore/css/CSSSegmentedFontFace.cpp b/Source/WebCore/css/CSSSegmentedFontFace.cpp new file mode 100644 index 0000000..cdabec1 --- /dev/null +++ b/Source/WebCore/css/CSSSegmentedFontFace.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSSegmentedFontFace.h" + +#include "CSSFontFace.h" +#include "CSSFontSelector.h" +#include "FontDescription.h" +#include "SegmentedFontData.h" +#include "SimpleFontData.h" + +namespace WebCore { + +CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector) + : m_fontSelector(fontSelector) +{ +} + +CSSSegmentedFontFace::~CSSSegmentedFontFace() +{ + pruneTable(); + unsigned size = m_fontFaces.size(); + for (unsigned i = 0; i < size; i++) + m_fontFaces[i]->removedFromSegmentedFontFace(this); +} + +void CSSSegmentedFontFace::pruneTable() +{ + // Make sure the glyph page tree prunes out all uses of this custom font. + if (m_fontDataTable.isEmpty()) + return; + HashMap<unsigned, SegmentedFontData*>::iterator end = m_fontDataTable.end(); + for (HashMap<unsigned, SegmentedFontData*>::iterator it = m_fontDataTable.begin(); it != end; ++it) + GlyphPageTreeNode::pruneTreeCustomFontData(it->second); + deleteAllValues(m_fontDataTable); + m_fontDataTable.clear(); +} + +bool CSSSegmentedFontFace::isValid() const +{ + // Valid if at least one font face is valid. + unsigned size = m_fontFaces.size(); + for (unsigned i = 0; i < size; i++) { + if (m_fontFaces[i]->isValid()) + return true; + } + return false; +} + +void CSSSegmentedFontFace::fontLoaded(CSSFontFace*) +{ + pruneTable(); +} + +void CSSSegmentedFontFace::appendFontFace(PassRefPtr<CSSFontFace> fontFace) +{ + pruneTable(); + fontFace->addedToSegmentedFontFace(this); + m_fontFaces.append(fontFace); +} + +FontData* CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription) +{ + if (!isValid()) + return 0; + + FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); + unsigned hashKey = (fontDescription.computedPixelSize() << (FontTraitsMaskWidth + 1)) | ((fontDescription.orientation() == Vertical ? 1 : 0) << FontTraitsMaskWidth) | desiredTraitsMask; + + SegmentedFontData* fontData = m_fontDataTable.get(hashKey); + if (fontData) + return fontData; + + fontData = new SegmentedFontData(); + + unsigned size = m_fontFaces.size(); + for (unsigned i = 0; i < size; i++) { + if (!m_fontFaces[i]->isValid()) + continue; + FontTraitsMask traitsMask = m_fontFaces[i]->traitsMask(); + bool syntheticBold = !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); + bool syntheticItalic = !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); + if (const SimpleFontData* faceFontData = m_fontFaces[i]->getFontData(fontDescription, syntheticBold, syntheticItalic)) { + ASSERT(!faceFontData->isSegmented()); + const Vector<CSSFontFace::UnicodeRange>& ranges = m_fontFaces[i]->ranges(); + unsigned numRanges = ranges.size(); + if (!numRanges) + fontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData)); + else { + for (unsigned j = 0; j < numRanges; ++j) + fontData->appendRange(FontDataRange(ranges[j].from(), ranges[j].to(), faceFontData)); + } + } + } + if (fontData->numRanges()) + m_fontDataTable.set(hashKey, fontData); + else { + delete fontData; + fontData = 0; + } + + return fontData; +} + +} diff --git a/Source/WebCore/css/CSSSegmentedFontFace.h b/Source/WebCore/css/CSSSegmentedFontFace.h new file mode 100644 index 0000000..03ebe4a --- /dev/null +++ b/Source/WebCore/css/CSSSegmentedFontFace.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSSegmentedFontFace_h +#define CSSSegmentedFontFace_h + +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class CSSFontFace; +class CSSFontSelector; +class FontData; +class FontDescription; +class SegmentedFontData; + +class CSSSegmentedFontFace : public RefCounted<CSSSegmentedFontFace> { +public: + static PassRefPtr<CSSSegmentedFontFace> create(CSSFontSelector* selector) { return adoptRef(new CSSSegmentedFontFace(selector)); } + ~CSSSegmentedFontFace(); + + CSSFontSelector* fontSelector() const { return m_fontSelector; } + + void fontLoaded(CSSFontFace*); + + void appendFontFace(PassRefPtr<CSSFontFace>); + + FontData* getFontData(const FontDescription&); + +private: + CSSSegmentedFontFace(CSSFontSelector*); + + void pruneTable(); + bool isValid() const; + + CSSFontSelector* m_fontSelector; + HashMap<unsigned, SegmentedFontData*> m_fontDataTable; + Vector<RefPtr<CSSFontFace>, 1> m_fontFaces; +}; + +} // namespace WebCore + +#endif // CSSSegmentedFontFace_h diff --git a/Source/WebCore/css/CSSSelector.cpp b/Source/WebCore/css/CSSSelector.cpp new file mode 100644 index 0000000..c139dbf --- /dev/null +++ b/Source/WebCore/css/CSSSelector.cpp @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) + * 2001-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2008 David Smith (catfish.man@gmail.com) + * Copyright (C) 2010 Google 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 "CSSSelector.h" + +#include "CSSOMUtils.h" +#include "HTMLNames.h" +#include <wtf/Assertions.h> +#include <wtf/HashMap.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +namespace WebCore { + +using namespace HTMLNames; + +class CSSSelectorBag : public Noncopyable { +public: + ~CSSSelectorBag() + { + ASSERT(isEmpty()); + } + + bool isEmpty() const + { + return m_stack.isEmpty(); + } + + void add(PassOwnPtr<CSSSelector> selector) + { + if (selector) + m_stack.append(selector.leakPtr()); + } + + PassOwnPtr<CSSSelector> takeAny() + { + ASSERT(!isEmpty()); + OwnPtr<CSSSelector> selector = adoptPtr(m_stack.last()); + m_stack.removeLast(); + return selector.release(); + } + +private: + Vector<CSSSelector*, 16> m_stack; +}; + +unsigned CSSSelector::specificity() const +{ + // make sure the result doesn't overflow + static const unsigned maxValueMask = 0xffffff; + unsigned total = 0; + for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) { + if (selector->m_isForPage) + return (total + selector->specificityForPage()) & maxValueMask; + total = (total + selector->specificityForOneSelector()) & maxValueMask; + } + return total; +} + +inline unsigned CSSSelector::specificityForOneSelector() const +{ + // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function + // isn't quite correct. + unsigned s = (m_tag.localName() == starAtom ? 0 : 1); + switch (m_match) { + case Id: + s += 0x10000; + break; + case Exact: + case Class: + case Set: + case List: + case Hyphen: + case PseudoClass: + case PseudoElement: + case Contain: + case Begin: + case End: + s += 0x100; + case None: + break; + } + return s; +} + +unsigned CSSSelector::specificityForPage() const +{ + // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context + unsigned s = (m_tag.localName() == starAtom ? 0 : 4); + + switch (pseudoType()) { + case PseudoFirstPage: + s += 2; + break; + case PseudoLeftPage: + case PseudoRightPage: + s += 1; + break; + case PseudoNotParsed: + break; + default: + ASSERT_NOT_REACHED(); + } + return s; +} + +PseudoId CSSSelector::pseudoId(PseudoType type) +{ + switch (type) { + case PseudoFirstLine: + return FIRST_LINE; + case PseudoFirstLetter: + return FIRST_LETTER; + case PseudoSelection: + return SELECTION; + case PseudoBefore: + return BEFORE; + case PseudoAfter: + return AFTER; + case PseudoFileUploadButton: + return FILE_UPLOAD_BUTTON; + case PseudoInputPlaceholder: + return INPUT_PLACEHOLDER; +#if ENABLE(INPUT_SPEECH) + case PseudoInputSpeechButton: + return INPUT_SPEECH_BUTTON; +#endif + case PseudoSliderThumb: + return SLIDER_THUMB; + case PseudoSearchCancelButton: + return SEARCH_CANCEL_BUTTON; + case PseudoSearchDecoration: + return SEARCH_DECORATION; + case PseudoSearchResultsDecoration: + return SEARCH_RESULTS_DECORATION; + case PseudoSearchResultsButton: + return SEARCH_RESULTS_BUTTON; + case PseudoMediaControlsPanel: + return MEDIA_CONTROLS_PANEL; + case PseudoMediaControlsMuteButton: + return MEDIA_CONTROLS_MUTE_BUTTON; + case PseudoMediaControlsPlayButton: + return MEDIA_CONTROLS_PLAY_BUTTON; + case PseudoMediaControlsTimelineContainer: + return MEDIA_CONTROLS_TIMELINE_CONTAINER; + case PseudoMediaControlsVolumeSliderContainer: + return MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER; + case PseudoMediaControlsCurrentTimeDisplay: + return MEDIA_CONTROLS_CURRENT_TIME_DISPLAY; + case PseudoMediaControlsTimeRemainingDisplay: + return MEDIA_CONTROLS_TIME_REMAINING_DISPLAY; + case PseudoMediaControlsTimeline: + return MEDIA_CONTROLS_TIMELINE; + case PseudoMediaControlsVolumeSlider: + return MEDIA_CONTROLS_VOLUME_SLIDER; + case PseudoMediaControlsVolumeSliderMuteButton: + return MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON; + case PseudoMediaControlsSeekBackButton: + return MEDIA_CONTROLS_SEEK_BACK_BUTTON; + case PseudoMediaControlsSeekForwardButton: + return MEDIA_CONTROLS_SEEK_FORWARD_BUTTON; + case PseudoMediaControlsRewindButton: + return MEDIA_CONTROLS_REWIND_BUTTON; + case PseudoMediaControlsReturnToRealtimeButton: + return MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON; + case PseudoMediaControlsToggleClosedCaptions: + return MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON; + case PseudoMediaControlsStatusDisplay: + return MEDIA_CONTROLS_STATUS_DISPLAY; + case PseudoMediaControlsFullscreenButton: + return MEDIA_CONTROLS_FULLSCREEN_BUTTON; + case PseudoScrollbar: + return SCROLLBAR; + case PseudoScrollbarButton: + return SCROLLBAR_BUTTON; + case PseudoScrollbarCorner: + return SCROLLBAR_CORNER; + case PseudoScrollbarThumb: + return SCROLLBAR_THUMB; + case PseudoScrollbarTrack: + return SCROLLBAR_TRACK; + case PseudoScrollbarTrackPiece: + return SCROLLBAR_TRACK_PIECE; + case PseudoResizer: + return RESIZER; + case PseudoInnerSpinButton: + return INNER_SPIN_BUTTON; + case PseudoOuterSpinButton: + return OUTER_SPIN_BUTTON; + case PseudoProgressBarValue: +#if ENABLE(PROGRESS_TAG) + return PROGRESS_BAR_VALUE; +#else + ASSERT_NOT_REACHED(); + return NOPSEUDO; +#endif + +#if ENABLE(METER_TAG) + case PseudoMeterHorizontalBar: + return METER_HORIZONTAL_BAR; + case PseudoMeterHorizontalOptimum: + return METER_HORIZONTAL_OPTIMUM; + case PseudoMeterHorizontalSuboptimal: + return METER_HORIZONTAL_SUBOPTIMAL; + case PseudoMeterHorizontalEvenLessGood: + return METER_HORIZONTAL_EVEN_LESS_GOOD; + case PseudoMeterVerticalBar: + return METER_VERTICAL_BAR; + case PseudoMeterVerticalOptimum: + return METER_VERTICAL_OPTIMUM; + case PseudoMeterVerticalSuboptimal: + return METER_VERTICAL_SUBOPTIMAL; + case PseudoMeterVerticalEvenLessGood: + return METER_VERTICAL_EVEN_LESS_GOOD; +#else + case PseudoMeterHorizontalBar: + case PseudoMeterHorizontalOptimum: + case PseudoMeterHorizontalSuboptimal: + case PseudoMeterHorizontalEvenLessGood: + case PseudoMeterVerticalBar: + case PseudoMeterVerticalOptimum: + case PseudoMeterVerticalSuboptimal: + case PseudoMeterVerticalEvenLessGood: + ASSERT_NOT_REACHED(); + return NOPSEUDO; +#endif + +#if ENABLE(FULLSCREEN_API) + case PseudoFullScreen: + return FULL_SCREEN; + case PseudoFullScreenDocument: + return FULL_SCREEN_DOCUMENT; +#endif + + case PseudoInputListButton: +#if ENABLE(DATALIST) + return INPUT_LIST_BUTTON; +#endif + case PseudoUnknown: + case PseudoEmpty: + case PseudoFirstChild: + case PseudoFirstOfType: + case PseudoLastChild: + case PseudoLastOfType: + case PseudoOnlyChild: + case PseudoOnlyOfType: + case PseudoNthChild: + case PseudoNthOfType: + case PseudoNthLastChild: + case PseudoNthLastOfType: + case PseudoLink: + case PseudoVisited: + case PseudoAnyLink: + case PseudoAutofill: + case PseudoHover: + case PseudoDrag: + case PseudoFocus: + case PseudoActive: + case PseudoChecked: + case PseudoEnabled: + case PseudoFullPageMedia: + case PseudoDefault: + case PseudoDisabled: + case PseudoOptional: + case PseudoRequired: + case PseudoReadOnly: + case PseudoReadWrite: + case PseudoValid: + case PseudoInvalid: + case PseudoIndeterminate: + case PseudoTarget: + case PseudoLang: + case PseudoNot: + case PseudoRoot: + case PseudoScrollbarBack: + case PseudoScrollbarForward: + case PseudoWindowInactive: + case PseudoCornerPresent: + case PseudoDecrement: + case PseudoIncrement: + case PseudoHorizontal: + case PseudoVertical: + case PseudoStart: + case PseudoEnd: + case PseudoDoubleButton: + case PseudoSingleButton: + case PseudoNoButton: + case PseudoFirstPage: + case PseudoLeftPage: + case PseudoRightPage: + case PseudoInRange: + case PseudoOutOfRange: + return NOPSEUDO; + case PseudoNotParsed: + ASSERT_NOT_REACHED(); + return NOPSEUDO; + } + + ASSERT_NOT_REACHED(); + return NOPSEUDO; +} + +static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap() +{ + DEFINE_STATIC_LOCAL(AtomicString, active, ("active")); + DEFINE_STATIC_LOCAL(AtomicString, after, ("after")); + DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link")); + DEFINE_STATIC_LOCAL(AtomicString, autofill, ("-webkit-autofill")); + DEFINE_STATIC_LOCAL(AtomicString, before, ("before")); + DEFINE_STATIC_LOCAL(AtomicString, checked, ("checked")); + DEFINE_STATIC_LOCAL(AtomicString, fileUploadButton, ("-webkit-file-upload-button")); +#if ENABLE(INPUT_SPEECH) + DEFINE_STATIC_LOCAL(AtomicString, inputSpeechButton, ("-webkit-input-speech-button")); +#endif + DEFINE_STATIC_LOCAL(AtomicString, defaultString, ("default")); + DEFINE_STATIC_LOCAL(AtomicString, disabled, ("disabled")); + DEFINE_STATIC_LOCAL(AtomicString, readOnly, ("read-only")); + DEFINE_STATIC_LOCAL(AtomicString, readWrite, ("read-write")); + DEFINE_STATIC_LOCAL(AtomicString, valid, ("valid")); + DEFINE_STATIC_LOCAL(AtomicString, invalid, ("invalid")); + DEFINE_STATIC_LOCAL(AtomicString, drag, ("-webkit-drag")); + DEFINE_STATIC_LOCAL(AtomicString, dragAlias, ("-khtml-drag")); // was documented with this name in Apple documentation, so keep an alia + DEFINE_STATIC_LOCAL(AtomicString, empty, ("empty")); + DEFINE_STATIC_LOCAL(AtomicString, enabled, ("enabled")); + DEFINE_STATIC_LOCAL(AtomicString, firstChild, ("first-child")); + DEFINE_STATIC_LOCAL(AtomicString, firstLetter, ("first-letter")); + DEFINE_STATIC_LOCAL(AtomicString, firstLine, ("first-line")); + DEFINE_STATIC_LOCAL(AtomicString, firstOfType, ("first-of-type")); + DEFINE_STATIC_LOCAL(AtomicString, fullPageMedia, ("-webkit-full-page-media")); + DEFINE_STATIC_LOCAL(AtomicString, nthChild, ("nth-child(")); + DEFINE_STATIC_LOCAL(AtomicString, nthOfType, ("nth-of-type(")); + DEFINE_STATIC_LOCAL(AtomicString, nthLastChild, ("nth-last-child(")); + DEFINE_STATIC_LOCAL(AtomicString, nthLastOfType, ("nth-last-of-type(")); + DEFINE_STATIC_LOCAL(AtomicString, focus, ("focus")); + DEFINE_STATIC_LOCAL(AtomicString, hover, ("hover")); + DEFINE_STATIC_LOCAL(AtomicString, indeterminate, ("indeterminate")); + DEFINE_STATIC_LOCAL(AtomicString, innerSpinButton, ("-webkit-inner-spin-button")); +#if ENABLE(DATALIST) + DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button")); +#endif + DEFINE_STATIC_LOCAL(AtomicString, inputPlaceholder, ("-webkit-input-placeholder")); + DEFINE_STATIC_LOCAL(AtomicString, lastChild, ("last-child")); + DEFINE_STATIC_LOCAL(AtomicString, lastOfType, ("last-of-type")); + DEFINE_STATIC_LOCAL(AtomicString, link, ("link")); + DEFINE_STATIC_LOCAL(AtomicString, lang, ("lang(")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPanel, ("-webkit-media-controls-panel")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsMuteButton, ("-webkit-media-controls-mute-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsPlayButton, ("-webkit-media-controls-play-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeline, ("-webkit-media-controls-timeline")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSlider, ("-webkit-media-controls-volume-slider")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderMuteButton, ("-webkit-media-controls-volume-slider-mute-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekBackButton, ("-webkit-media-controls-seek-back-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsSeekForwardButton, ("-webkit-media-controls-seek-forward-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsRewindButton, ("-webkit-media-controls-rewind-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsReturnToRealtimeButton, ("-webkit-media-controls-return-to-realtime-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsToggleClosedCaptionsButton, ("-webkit-media-controls-toggle-closed-captions-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsStatusDisplay, ("-webkit-media-controls-status-display")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsFullscreenButton, ("-webkit-media-controls-fullscreen-button")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimelineContainer, ("-webkit-media-controls-timeline-container")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsVolumeSliderContainer, ("-webkit-media-controls-volume-slider-container")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsCurrentTimeDisplay, ("-webkit-media-controls-current-time-display")); + DEFINE_STATIC_LOCAL(AtomicString, mediaControlsTimeRemainingDisplay, ("-webkit-media-controls-time-remaining-display")); + DEFINE_STATIC_LOCAL(AtomicString, notStr, ("not(")); + DEFINE_STATIC_LOCAL(AtomicString, onlyChild, ("only-child")); + DEFINE_STATIC_LOCAL(AtomicString, onlyOfType, ("only-of-type")); + DEFINE_STATIC_LOCAL(AtomicString, optional, ("optional")); + DEFINE_STATIC_LOCAL(AtomicString, outerSpinButton, ("-webkit-outer-spin-button")); +#if ENABLE(PROGRESS_TAG) + DEFINE_STATIC_LOCAL(AtomicString, progressBarValue, ("-webkit-progress-bar-value")); +#endif + +#if ENABLE(METER_TAG) + DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalBar, ("-webkit-meter-horizontal-bar")); + DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalOptimumValue, ("-webkit-meter-horizontal-optimum-value")); + DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalSuboptimalValue, ("-webkit-meter-horizontal-suboptimal-value")); + DEFINE_STATIC_LOCAL(AtomicString, meterHorizontalEvenLessGoodValue, ("-webkit-meter-horizontal-even-less-good-value")); + DEFINE_STATIC_LOCAL(AtomicString, meterVerticalBar, ("-webkit-meter-vertical-bar")); + DEFINE_STATIC_LOCAL(AtomicString, meterVerticalOptimumValue, ("-webkit-meter-vertical-optimum-value")); + DEFINE_STATIC_LOCAL(AtomicString, meterVerticalSuboptimalValue, ("-webkit-meter-vertical-suboptimal-value")); + DEFINE_STATIC_LOCAL(AtomicString, meterVerticalEvenLessGoodValue, ("-webkit-meter-vertical-even-less-good-value")); +#endif + + DEFINE_STATIC_LOCAL(AtomicString, required, ("required")); + DEFINE_STATIC_LOCAL(AtomicString, resizer, ("-webkit-resizer")); + DEFINE_STATIC_LOCAL(AtomicString, root, ("root")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbar, ("-webkit-scrollbar")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbarButton, ("-webkit-scrollbar-button")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbarCorner, ("-webkit-scrollbar-corner")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbarThumb, ("-webkit-scrollbar-thumb")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrack, ("-webkit-scrollbar-track")); + DEFINE_STATIC_LOCAL(AtomicString, scrollbarTrackPiece, ("-webkit-scrollbar-track-piece")); + DEFINE_STATIC_LOCAL(AtomicString, searchCancelButton, ("-webkit-search-cancel-button")); + DEFINE_STATIC_LOCAL(AtomicString, searchDecoration, ("-webkit-search-decoration")); + DEFINE_STATIC_LOCAL(AtomicString, searchResultsDecoration, ("-webkit-search-results-decoration")); + DEFINE_STATIC_LOCAL(AtomicString, searchResultsButton, ("-webkit-search-results-button")); + DEFINE_STATIC_LOCAL(AtomicString, selection, ("selection")); + DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb")); + DEFINE_STATIC_LOCAL(AtomicString, target, ("target")); + DEFINE_STATIC_LOCAL(AtomicString, visited, ("visited")); + DEFINE_STATIC_LOCAL(AtomicString, windowInactive, ("window-inactive")); + DEFINE_STATIC_LOCAL(AtomicString, decrement, ("decrement")); + DEFINE_STATIC_LOCAL(AtomicString, increment, ("increment")); + DEFINE_STATIC_LOCAL(AtomicString, start, ("start")); + DEFINE_STATIC_LOCAL(AtomicString, end, ("end")); + DEFINE_STATIC_LOCAL(AtomicString, horizontal, ("horizontal")); + DEFINE_STATIC_LOCAL(AtomicString, vertical, ("vertical")); + DEFINE_STATIC_LOCAL(AtomicString, doubleButton, ("double-button")); + DEFINE_STATIC_LOCAL(AtomicString, singleButton, ("single-button")); + DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button")); + DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present")); + // Paged Media pseudo-classes + DEFINE_STATIC_LOCAL(AtomicString, firstPage, ("first")); + DEFINE_STATIC_LOCAL(AtomicString, leftPage, ("left")); + DEFINE_STATIC_LOCAL(AtomicString, rightPage, ("right")); +#if ENABLE(FULLSCREEN_API) + DEFINE_STATIC_LOCAL(AtomicString, fullScreen, ("-webkit-full-screen")); + DEFINE_STATIC_LOCAL(AtomicString, fullScreenDocument, ("-webkit-full-screen-document")); +#endif + DEFINE_STATIC_LOCAL(AtomicString, inRange, ("in-range")); + DEFINE_STATIC_LOCAL(AtomicString, outOfRange, ("out-of-range")); + + static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0; + if (!nameToPseudoType) { + nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>; + nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive); + nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter); + nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink); + nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill); + nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore); + nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked); + nameToPseudoType->set(fileUploadButton.impl(), CSSSelector::PseudoFileUploadButton); +#if ENABLE(INPUT_SPEECH) + nameToPseudoType->set(inputSpeechButton.impl(), CSSSelector::PseudoInputSpeechButton); +#endif + nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault); + nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled); + nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly); + nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite); + nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid); + nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid); + nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag); + nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag); + nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled); + nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty); + nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild); + nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia); +#if ENABLE(DATALIST) + nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton); +#endif + nameToPseudoType->set(inputPlaceholder.impl(), CSSSelector::PseudoInputPlaceholder); + nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild); + nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType); + nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild); + nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType); + nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter); + nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine); + nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType); + nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus); + nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover); + nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate); + nameToPseudoType->set(innerSpinButton.impl(), CSSSelector::PseudoInnerSpinButton); + nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink); + nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang); + nameToPseudoType->set(mediaControlsPanel.impl(), CSSSelector::PseudoMediaControlsPanel); + nameToPseudoType->set(mediaControlsMuteButton.impl(), CSSSelector::PseudoMediaControlsMuteButton); + nameToPseudoType->set(mediaControlsPlayButton.impl(), CSSSelector::PseudoMediaControlsPlayButton); + nameToPseudoType->set(mediaControlsCurrentTimeDisplay.impl(), CSSSelector::PseudoMediaControlsCurrentTimeDisplay); + nameToPseudoType->set(mediaControlsTimeRemainingDisplay.impl(), CSSSelector::PseudoMediaControlsTimeRemainingDisplay); + nameToPseudoType->set(mediaControlsTimeline.impl(), CSSSelector::PseudoMediaControlsTimeline); + nameToPseudoType->set(mediaControlsVolumeSlider.impl(), CSSSelector::PseudoMediaControlsVolumeSlider); + nameToPseudoType->set(mediaControlsVolumeSliderMuteButton.impl(), CSSSelector::PseudoMediaControlsVolumeSliderMuteButton); + nameToPseudoType->set(mediaControlsSeekBackButton.impl(), CSSSelector::PseudoMediaControlsSeekBackButton); + nameToPseudoType->set(mediaControlsSeekForwardButton.impl(), CSSSelector::PseudoMediaControlsSeekForwardButton); + nameToPseudoType->set(mediaControlsRewindButton.impl(), CSSSelector::PseudoMediaControlsRewindButton); + nameToPseudoType->set(mediaControlsReturnToRealtimeButton.impl(), CSSSelector::PseudoMediaControlsReturnToRealtimeButton); + nameToPseudoType->set(mediaControlsToggleClosedCaptionsButton.impl(), CSSSelector::PseudoMediaControlsToggleClosedCaptions); + nameToPseudoType->set(mediaControlsStatusDisplay.impl(), CSSSelector::PseudoMediaControlsStatusDisplay); + nameToPseudoType->set(mediaControlsFullscreenButton.impl(), CSSSelector::PseudoMediaControlsFullscreenButton); + nameToPseudoType->set(mediaControlsTimelineContainer.impl(), CSSSelector::PseudoMediaControlsTimelineContainer); + nameToPseudoType->set(mediaControlsVolumeSliderContainer.impl(), CSSSelector::PseudoMediaControlsVolumeSliderContainer); + nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot); + nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild); + nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType); + nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild); + nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType); + nameToPseudoType->set(outerSpinButton.impl(), CSSSelector::PseudoOuterSpinButton); +#if ENABLE(PROGRESS_TAG) + nameToPseudoType->set(progressBarValue.impl(), CSSSelector::PseudoProgressBarValue); +#endif +#if ENABLE(METER_TAG) + nameToPseudoType->set(meterHorizontalBar.impl(), CSSSelector::PseudoMeterHorizontalBar); + nameToPseudoType->set(meterHorizontalOptimumValue.impl(), CSSSelector::PseudoMeterHorizontalOptimum); + nameToPseudoType->set(meterHorizontalSuboptimalValue.impl(), CSSSelector::PseudoMeterHorizontalSuboptimal); + nameToPseudoType->set(meterHorizontalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterHorizontalEvenLessGood); + nameToPseudoType->set(meterVerticalBar.impl(), CSSSelector::PseudoMeterVerticalBar); + nameToPseudoType->set(meterVerticalOptimumValue.impl(), CSSSelector::PseudoMeterVerticalOptimum); + nameToPseudoType->set(meterVerticalSuboptimalValue.impl(), CSSSelector::PseudoMeterVerticalSuboptimal); + nameToPseudoType->set(meterVerticalEvenLessGoodValue.impl(), CSSSelector::PseudoMeterVerticalEvenLessGood); +#endif + nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot); + nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive); + nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement); + nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement); + nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart); + nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd); + nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal); + nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical); + nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton); + nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton); + nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton); + nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional); + nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired); + nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer); + nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar); + nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton); + nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner); + nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb); + nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack); + nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece); + nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent); + nameToPseudoType->set(searchCancelButton.impl(), CSSSelector::PseudoSearchCancelButton); + nameToPseudoType->set(searchDecoration.impl(), CSSSelector::PseudoSearchDecoration); + nameToPseudoType->set(searchResultsDecoration.impl(), CSSSelector::PseudoSearchResultsDecoration); + nameToPseudoType->set(searchResultsButton.impl(), CSSSelector::PseudoSearchResultsButton); + nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection); + nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb); + nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget); + nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited); + nameToPseudoType->set(firstPage.impl(), CSSSelector::PseudoFirstPage); + nameToPseudoType->set(leftPage.impl(), CSSSelector::PseudoLeftPage); + nameToPseudoType->set(rightPage.impl(), CSSSelector::PseudoRightPage); +#if ENABLE(FULLSCREEN_API) + nameToPseudoType->set(fullScreen.impl(), CSSSelector::PseudoFullScreen); + nameToPseudoType->set(fullScreenDocument.impl(), CSSSelector::PseudoFullScreenDocument); +#endif + nameToPseudoType->set(inRange.impl(), CSSSelector::PseudoInRange); + nameToPseudoType->set(outOfRange.impl(), CSSSelector::PseudoOutOfRange); + } + return nameToPseudoType; +} + +CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) +{ + if (name.isNull()) + return PseudoUnknown; + HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap(); + HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl()); + return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second; +} + +void CSSSelector::extractPseudoType() const +{ + if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass) + return; + + m_pseudoType = parsePseudoType(m_value); + + bool element = false; // pseudo-element + bool compat = false; // single colon compatbility mode + bool isPagePseudoClass = false; // Page pseudo-class + + switch (m_pseudoType) { + case PseudoAfter: + case PseudoBefore: + case PseudoFirstLetter: + case PseudoFirstLine: + compat = true; + case PseudoFileUploadButton: + case PseudoInputListButton: + case PseudoInputPlaceholder: +#if ENABLE(INPUT_SPEECH) + case PseudoInputSpeechButton: +#endif + case PseudoInnerSpinButton: + case PseudoMediaControlsPanel: + case PseudoMediaControlsMuteButton: + case PseudoMediaControlsPlayButton: + case PseudoMediaControlsCurrentTimeDisplay: + case PseudoMediaControlsTimeRemainingDisplay: + case PseudoMediaControlsTimeline: + case PseudoMediaControlsVolumeSlider: + case PseudoMediaControlsVolumeSliderMuteButton: + case PseudoMediaControlsSeekBackButton: + case PseudoMediaControlsSeekForwardButton: + case PseudoMediaControlsRewindButton: + case PseudoMediaControlsReturnToRealtimeButton: + case PseudoMediaControlsToggleClosedCaptions: + case PseudoMediaControlsStatusDisplay: + case PseudoMediaControlsFullscreenButton: + case PseudoMediaControlsTimelineContainer: + case PseudoMediaControlsVolumeSliderContainer: + case PseudoMeterHorizontalBar: + case PseudoMeterHorizontalOptimum: + case PseudoMeterHorizontalSuboptimal: + case PseudoMeterHorizontalEvenLessGood: + case PseudoMeterVerticalBar: + case PseudoMeterVerticalOptimum: + case PseudoMeterVerticalSuboptimal: + case PseudoMeterVerticalEvenLessGood: + case PseudoOuterSpinButton: + case PseudoProgressBarValue: + case PseudoResizer: + case PseudoScrollbar: + case PseudoScrollbarCorner: + case PseudoScrollbarButton: + case PseudoScrollbarThumb: + case PseudoScrollbarTrack: + case PseudoScrollbarTrackPiece: + case PseudoSearchCancelButton: + case PseudoSearchDecoration: + case PseudoSearchResultsDecoration: + case PseudoSearchResultsButton: + case PseudoSelection: + case PseudoSliderThumb: + element = true; + break; + case PseudoUnknown: + case PseudoEmpty: + case PseudoFirstChild: + case PseudoFirstOfType: + case PseudoLastChild: + case PseudoLastOfType: + case PseudoOnlyChild: + case PseudoOnlyOfType: + case PseudoNthChild: + case PseudoNthOfType: + case PseudoNthLastChild: + case PseudoNthLastOfType: + case PseudoLink: + case PseudoVisited: + case PseudoAnyLink: + case PseudoAutofill: + case PseudoHover: + case PseudoDrag: + case PseudoFocus: + case PseudoActive: + case PseudoChecked: + case PseudoEnabled: + case PseudoFullPageMedia: + case PseudoDefault: + case PseudoDisabled: + case PseudoOptional: + case PseudoRequired: + case PseudoReadOnly: + case PseudoReadWrite: + case PseudoValid: + case PseudoInvalid: + case PseudoIndeterminate: + case PseudoTarget: + case PseudoLang: + case PseudoNot: + case PseudoRoot: + case PseudoScrollbarBack: + case PseudoScrollbarForward: + case PseudoWindowInactive: + case PseudoCornerPresent: + case PseudoDecrement: + case PseudoIncrement: + case PseudoHorizontal: + case PseudoVertical: + case PseudoStart: + case PseudoEnd: + case PseudoDoubleButton: + case PseudoSingleButton: + case PseudoNoButton: + case PseudoNotParsed: +#if ENABLE(FULLSCREEN_API) + case PseudoFullScreen: + case PseudoFullScreenDocument: +#endif + case PseudoInRange: + case PseudoOutOfRange: + break; + case PseudoFirstPage: + case PseudoLeftPage: + case PseudoRightPage: + isPagePseudoClass = true; + break; + } + + bool matchPagePseudoClass = (m_match == PagePseudoClass); + if (matchPagePseudoClass != isPagePseudoClass) + m_pseudoType = PseudoUnknown; + else if (m_match == PseudoClass && element) { + if (!compat) + m_pseudoType = PseudoUnknown; + else + m_match = PseudoElement; + } else if (m_match == PseudoElement && !element) + m_pseudoType = PseudoUnknown; +} + +bool CSSSelector::operator==(const CSSSelector& other) +{ + const CSSSelector* sel1 = this; + const CSSSelector* sel2 = &other; + + while (sel1 && sel2) { + if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() || + sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match || + sel1->m_value != sel2->m_value || + sel1->pseudoType() != sel2->pseudoType() || + sel1->argument() != sel2->argument()) + return false; + sel1 = sel1->tagHistory(); + sel2 = sel2->tagHistory(); + } + + if (sel1 || sel2) + return false; + + return true; +} + +String CSSSelector::selectorText() const +{ + String str = ""; + + const AtomicString& prefix = m_tag.prefix(); + const AtomicString& localName = m_tag.localName(); + if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) { + if (prefix.isNull()) + str = localName; + else { + str = prefix.string(); + str.append("|"); + str.append(localName); + } + } + + const CSSSelector* cs = this; + while (true) { + if (cs->m_match == CSSSelector::Id) { + str += "#"; + serializeIdentifier(cs->m_value, str); + } else if (cs->m_match == CSSSelector::Class) { + str += "."; + serializeIdentifier(cs->m_value, str); + } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) { + str += ":"; + str += cs->m_value; + if (cs->pseudoType() == PseudoNot) { + if (CSSSelector* subSel = cs->simpleSelector()) + str += subSel->selectorText(); + str += ")"; + } else if (cs->pseudoType() == PseudoLang + || cs->pseudoType() == PseudoNthChild + || cs->pseudoType() == PseudoNthLastChild + || cs->pseudoType() == PseudoNthOfType + || cs->pseudoType() == PseudoNthLastOfType) { + str += cs->argument(); + str += ")"; + } + } else if (cs->m_match == CSSSelector::PseudoElement) { + str += "::"; + str += cs->m_value; + } else if (cs->hasAttribute()) { + str += "["; + const AtomicString& prefix = cs->attribute().prefix(); + if (!prefix.isNull()) { + str.append(prefix); + str.append("|"); + } + str += cs->attribute().localName(); + switch (cs->m_match) { + case CSSSelector::Exact: + str += "="; + break; + case CSSSelector::Set: + // set has no operator or value, just the attrName + str += "]"; + break; + case CSSSelector::List: + str += "~="; + break; + case CSSSelector::Hyphen: + str += "|="; + break; + case CSSSelector::Begin: + str += "^="; + break; + case CSSSelector::End: + str += "$="; + break; + case CSSSelector::Contain: + str += "*="; + break; + default: + break; + } + if (cs->m_match != CSSSelector::Set) { + serializeString(cs->m_value, str); + str += "]"; + } + } + if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory()) + break; + cs = cs->tagHistory(); + } + + if (CSSSelector* tagHistory = cs->tagHistory()) { + String tagHistoryText = tagHistory->selectorText(); + if (cs->relation() == CSSSelector::DirectAdjacent) + str = tagHistoryText + " + " + str; + else if (cs->relation() == CSSSelector::IndirectAdjacent) + str = tagHistoryText + " ~ " + str; + else if (cs->relation() == CSSSelector::Child) + str = tagHistoryText + " > " + str; + else + // Descendant + str = tagHistoryText + " " + str; + } + + return str; +} + +void CSSSelector::setTagHistory(CSSSelector* tagHistory) +{ + if (m_hasRareData) + m_data.m_rareData->m_tagHistory.set(tagHistory); + else + m_data.m_tagHistory = tagHistory; +} + +const QualifiedName& CSSSelector::attribute() const +{ + switch (m_match) { + case Id: + return idAttr; + case Class: + return classAttr; + default: + return m_hasRareData ? m_data.m_rareData->m_attribute : anyQName(); + } +} + +void CSSSelector::setAttribute(const QualifiedName& value) +{ + createRareData(); + m_data.m_rareData->m_attribute = value; +} + +void CSSSelector::setArgument(const AtomicString& value) +{ + createRareData(); + m_data.m_rareData->m_argument = value; +} + +void CSSSelector::setSimpleSelector(CSSSelector* value) +{ + createRareData(); + m_data.m_rareData->m_simpleSelector.set(value); +} + +bool CSSSelector::parseNth() +{ + if (!m_hasRareData) + return false; + if (m_parsedNth) + return true; + m_parsedNth = m_data.m_rareData->parseNth(); + return m_parsedNth; +} + +bool CSSSelector::matchNth(int count) +{ + ASSERT(m_hasRareData); + return m_data.m_rareData->matchNth(count); +} + +bool CSSSelector::isSimple() const +{ + if (simpleSelector() || tagHistory() || matchesPseudoElement()) + return false; + + int numConditions = 0; + + // hasTag() cannot be be used here because namespace may not be nullAtom. + // Example: + // @namespace "http://www.w3.org/2000/svg"; + // svg:not(:root) { ... + if (m_tag != starAtom) + numConditions++; + + if (m_match == Id || m_match == Class || m_match == PseudoClass) + numConditions++; + + if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()) + numConditions++; + + // numConditions is 0 for a universal selector. + // numConditions is 1 for other simple selectors. + return numConditions <= 1; +} + +// a helper function for parsing nth-arguments +bool CSSSelector::RareData::parseNth() +{ + String argument = m_argument.lower(); + + if (argument.isEmpty()) + return false; + + m_a = 0; + m_b = 0; + if (argument == "odd") { + m_a = 2; + m_b = 1; + } else if (argument == "even") { + m_a = 2; + m_b = 0; + } else { + size_t n = argument.find('n'); + if (n != notFound) { + if (argument[0] == '-') { + if (n == 1) + m_a = -1; // -n == -1n + else + m_a = argument.substring(0, n).toInt(); + } else if (!n) + m_a = 1; // n == 1n + else + m_a = argument.substring(0, n).toInt(); + + size_t p = argument.find('+', n); + if (p != notFound) + m_b = argument.substring(p + 1, argument.length() - p - 1).toInt(); + else { + p = argument.find('-', n); + if (p != notFound) + m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt(); + } + } else + m_b = argument.toInt(); + } + return true; +} + +// a helper function for checking nth-arguments +bool CSSSelector::RareData::matchNth(int count) +{ + if (!m_a) + return count == m_b; + else if (m_a > 0) { + if (count < m_b) + return false; + return (count - m_b) % m_a == 0; + } else { + if (count > m_b) + return false; + return (m_b - count) % (-m_a) == 0; + } +} + +inline void CSSSelector::releaseOwnedSelectorsToBag(CSSSelectorBag& bag) +{ + if (m_hasRareData) { + ASSERT(m_data.m_rareData); + bag.add(m_data.m_rareData->m_tagHistory.release()); + bag.add(m_data.m_rareData->m_simpleSelector.release()); + delete m_data.m_rareData; + // Clear the pointer so that a destructor of this selector will not + // traverse this chain. + m_data.m_rareData = 0; + } else { + bag.add(adoptPtr(m_data.m_tagHistory)); + // Clear the pointer for the same reason. + m_data.m_tagHistory = 0; + } +} + +void CSSSelector::deleteReachableSelectors() +{ + // Traverse the chain of selectors and delete each iteratively. + CSSSelectorBag selectorsToBeDeleted; + releaseOwnedSelectorsToBag(selectorsToBeDeleted); + while (!selectorsToBeDeleted.isEmpty()) { + OwnPtr<CSSSelector> selector(selectorsToBeDeleted.takeAny()); + ASSERT(selector); + selector->releaseOwnedSelectorsToBag(selectorsToBeDeleted); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSSelector.h b/Source/WebCore/css/CSSSelector.h new file mode 100644 index 0000000..353fb5e --- /dev/null +++ b/Source/WebCore/css/CSSSelector.h @@ -0,0 +1,349 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 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. + */ + +#ifndef CSSSelector_h +#define CSSSelector_h + +#include "QualifiedName.h" +#include "RenderStyleConstants.h" +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + + class CSSSelectorBag; + + // this class represents a selector for a StyleRule + class CSSSelector : public Noncopyable { + public: + CSSSelector() + : m_relation(Descendant) + , m_match(None) + , m_pseudoType(PseudoNotParsed) + , m_parsedNth(false) + , m_isLastInSelectorList(false) + , m_hasRareData(false) + , m_isForPage(false) + , m_tag(anyQName()) + { + } + + CSSSelector(const QualifiedName& qName) + : m_relation(Descendant) + , m_match(None) + , m_pseudoType(PseudoNotParsed) + , m_parsedNth(false) + , m_isLastInSelectorList(false) + , m_hasRareData(false) + , m_isForPage(false) + , m_tag(qName) + { + } + + ~CSSSelector() + { + // Exit if this selector does not own any objects to be deleted. + if (m_hasRareData) { + if (!m_data.m_rareData) + return; + } else if (!m_data.m_tagHistory) + return; + + // We can not delete the owned object(s) by simply calling delete + // directly on them. That would lead to recursive destructor calls + // which might cause stack overflow. We have to delete them + // iteratively. + deleteReachableSelectors(); + } + + /** + * Re-create selector text from selector's data + */ + String selectorText() const; + + // checks if the 2 selectors (including sub selectors) agree. + bool operator==(const CSSSelector&); + + // tag == -1 means apply to all elements (Selector = *) + + unsigned specificity() const; + + /* how the attribute value has to match.... Default is Exact */ + enum Match { + None = 0, + Id, + Class, + Exact, + Set, + List, + Hyphen, + PseudoClass, + PseudoElement, + Contain, // css3: E[foo*="bar"] + Begin, // css3: E[foo^="bar"] + End, // css3: E[foo$="bar"] + PagePseudoClass + }; + + enum Relation { + Descendant = 0, + Child, + DirectAdjacent, + IndirectAdjacent, + SubSelector + }; + + enum PseudoType { + PseudoNotParsed = 0, + PseudoUnknown, + PseudoEmpty, + PseudoFirstChild, + PseudoFirstOfType, + PseudoLastChild, + PseudoLastOfType, + PseudoOnlyChild, + PseudoOnlyOfType, + PseudoFirstLine, + PseudoFirstLetter, + PseudoNthChild, + PseudoNthOfType, + PseudoNthLastChild, + PseudoNthLastOfType, + PseudoLink, + PseudoVisited, + PseudoAnyLink, + PseudoAutofill, + PseudoHover, + PseudoDrag, + PseudoFocus, + PseudoActive, + PseudoChecked, + PseudoEnabled, + PseudoFullPageMedia, + PseudoDefault, + PseudoDisabled, + PseudoInputPlaceholder, + PseudoOptional, + PseudoRequired, + PseudoReadOnly, + PseudoReadWrite, + PseudoValid, + PseudoInvalid, + PseudoIndeterminate, + PseudoTarget, + PseudoBefore, + PseudoAfter, + PseudoLang, + PseudoNot, + PseudoResizer, + PseudoRoot, + PseudoScrollbar, + PseudoScrollbarBack, + PseudoScrollbarButton, + PseudoScrollbarCorner, + PseudoScrollbarForward, + PseudoScrollbarThumb, + PseudoScrollbarTrack, + PseudoScrollbarTrackPiece, + PseudoWindowInactive, + PseudoCornerPresent, + PseudoDecrement, + PseudoIncrement, + PseudoHorizontal, + PseudoVertical, + PseudoStart, + PseudoEnd, + PseudoDoubleButton, + PseudoSingleButton, + PseudoNoButton, + PseudoSelection, + PseudoFileUploadButton, + PseudoSliderThumb, + PseudoSearchCancelButton, + PseudoSearchDecoration, + PseudoSearchResultsDecoration, + PseudoSearchResultsButton, + PseudoMediaControlsPanel, + PseudoMediaControlsMuteButton, + PseudoMediaControlsPlayButton, + PseudoMediaControlsTimelineContainer, + PseudoMediaControlsVolumeSliderContainer, + PseudoMediaControlsVolumeSliderMuteButton, + PseudoMediaControlsCurrentTimeDisplay, + PseudoMediaControlsTimeRemainingDisplay, + PseudoMediaControlsToggleClosedCaptions, + PseudoMediaControlsTimeline, + PseudoMediaControlsVolumeSlider, + PseudoMediaControlsSeekBackButton, + PseudoMediaControlsSeekForwardButton, + PseudoMediaControlsRewindButton, + PseudoMediaControlsReturnToRealtimeButton, + PseudoMediaControlsStatusDisplay, + PseudoMediaControlsFullscreenButton, + PseudoMeterHorizontalBar, + PseudoMeterVerticalBar, + PseudoMeterHorizontalOptimum, + PseudoMeterHorizontalSuboptimal, + PseudoMeterHorizontalEvenLessGood, + PseudoMeterVerticalOptimum, + PseudoMeterVerticalSuboptimal, + PseudoMeterVerticalEvenLessGood, + PseudoInputListButton, +#if ENABLE(INPUT_SPEECH) + PseudoInputSpeechButton, +#endif + PseudoInnerSpinButton, + PseudoOuterSpinButton, + PseudoProgressBarValue, + PseudoLeftPage, + PseudoRightPage, + PseudoFirstPage, +#if ENABLE(FULLSCREEN_API) + PseudoFullScreen, + PseudoFullScreenDocument, +#endif + PseudoInRange, + PseudoOutOfRange, + }; + + enum MarginBoxType { + TopLeftCornerMarginBox, + TopLeftMarginBox, + TopCenterMarginBox, + TopRightMarginBox, + TopRightCornerMarginBox, + BottomLeftCornerMarginBox, + BottomLeftMarginBox, + BottomCenterMarginBox, + BottomRightMarginBox, + BottomRightCornerMarginBox, + LeftTopMarginBox, + LeftMiddleMarginBox, + LeftBottomMarginBox, + RightTopMarginBox, + RightMiddleMarginBox, + RightBottomMarginBox, + }; + + PseudoType pseudoType() const + { + if (m_pseudoType == PseudoNotParsed) + extractPseudoType(); + return static_cast<PseudoType>(m_pseudoType); + } + + static PseudoType parsePseudoType(const AtomicString&); + static PseudoId pseudoId(PseudoType); + + CSSSelector* tagHistory() const { return m_hasRareData ? m_data.m_rareData->m_tagHistory.get() : m_data.m_tagHistory; } + void setTagHistory(CSSSelector* tagHistory); + + bool hasTag() const { return m_tag != anyQName(); } + bool hasAttribute() const { return m_match == Id || m_match == Class || (m_hasRareData && m_data.m_rareData->m_attribute != anyQName()); } + + const QualifiedName& attribute() const; + const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; } + CSSSelector* simpleSelector() const { return m_hasRareData ? m_data.m_rareData->m_simpleSelector.get() : 0; } + + void setAttribute(const QualifiedName& value); + void setArgument(const AtomicString& value); + void setSimpleSelector(CSSSelector* value); + + bool parseNth(); + bool matchNth(int count); + + bool matchesPseudoElement() const + { + if (m_pseudoType == PseudoUnknown) + extractPseudoType(); + return m_match == PseudoElement; + } + + Relation relation() const { return static_cast<Relation>(m_relation); } + + bool isLastInSelectorList() const { return m_isLastInSelectorList; } + void setLastInSelectorList() { m_isLastInSelectorList = true; } + bool isSimple() const; + + bool isForPage() const { return m_isForPage; } + void setForPage() { m_isForPage = true; } + + unsigned m_relation : 3; // enum Relation + mutable unsigned m_match : 4; // enum Match + mutable unsigned m_pseudoType : 8; // PseudoType + + private: + bool m_parsedNth : 1; // Used for :nth-* + bool m_isLastInSelectorList : 1; + bool m_hasRareData : 1; + bool m_isForPage : 1; + + void releaseOwnedSelectorsToBag(CSSSelectorBag&); + void deleteReachableSelectors(); + + unsigned specificityForOneSelector() const; + unsigned specificityForPage() const; + void extractPseudoType() const; + + struct RareData : Noncopyable { + RareData(PassOwnPtr<CSSSelector> tagHistory) + : m_a(0) + , m_b(0) + , m_tagHistory(tagHistory) + , m_attribute(anyQName()) + , m_argument(nullAtom) + { + } + + bool parseNth(); + bool matchNth(int count); + + int m_a; // Used for :nth-* + int m_b; // Used for :nth-* + OwnPtr<CSSSelector> m_tagHistory; + OwnPtr<CSSSelector> m_simpleSelector; // Used for :not. + QualifiedName m_attribute; // used for attribute selector + AtomicString m_argument; // Used for :contains, :lang and :nth-* + }; + + void createRareData() + { + if (m_hasRareData) + return; + m_data.m_rareData = new RareData(adoptPtr(m_data.m_tagHistory)); + m_hasRareData = true; + } + + union DataUnion { + DataUnion() : m_tagHistory(0) { } + CSSSelector* m_tagHistory; + RareData* m_rareData; + } m_data; + + public: + mutable AtomicString m_value; + QualifiedName m_tag; + }; + +} // namespace WebCore + +#endif // CSSSelector_h diff --git a/Source/WebCore/css/CSSSelectorList.cpp b/Source/WebCore/css/CSSSelectorList.cpp new file mode 100644 index 0000000..7f82ca4 --- /dev/null +++ b/Source/WebCore/css/CSSSelectorList.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSSelectorList.h" + +namespace WebCore { + +CSSSelectorList::~CSSSelectorList() +{ + deleteSelectors(); +} + +void CSSSelectorList::adopt(CSSSelectorList& list) +{ + deleteSelectors(); + m_selectorArray = list.m_selectorArray; + list.m_selectorArray = 0; +} + +void CSSSelectorList::adoptSelectorVector(Vector<CSSSelector*>& selectorVector) +{ + deleteSelectors(); + const size_t size = selectorVector.size(); + ASSERT(size); + if (size == 1) { + m_selectorArray = selectorVector[0]; + m_selectorArray->setLastInSelectorList(); + selectorVector.shrink(0); + return; + } + m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * selectorVector.size())); + for (size_t i = 0; i < size; ++i) { + memcpy(&m_selectorArray[i], selectorVector[i], sizeof(CSSSelector)); + // We want to free the memory (which was allocated with fastNew), but we + // don't want the destructor to run since it will affect the copy we've just made. + fastDeleteSkippingDestructor(selectorVector[i]); + ASSERT(!m_selectorArray[i].isLastInSelectorList()); + } + m_selectorArray[size - 1].setLastInSelectorList(); + selectorVector.shrink(0); +} + +void CSSSelectorList::deleteSelectors() +{ + if (!m_selectorArray) + return; + + // We had two cases in adoptSelectVector. The fast case of a 1 element + // vector took the CSSSelector directly, which was allocated with new. + // The second case we allocated a new fastMalloc buffer, which should be + // freed with fastFree, and the destructors called manually. + CSSSelector* s = m_selectorArray; + bool done = s->isLastInSelectorList(); + if (done) + delete s; + else { + while (1) { + s->~CSSSelector(); + if (done) + break; + ++s; + done = s->isLastInSelectorList(); + } + fastFree(m_selectorArray); + } +} + + +template <typename Functor> +static bool forEachTagSelector(Functor& functor, CSSSelector* selector) +{ + ASSERT(selector); + + do { + if (functor(selector)) + return true; + if (CSSSelector* simpleSelector = selector->simpleSelector()) { + if (forEachTagSelector(functor, simpleSelector)) + return true; + } + } while ((selector = selector->tagHistory())); + + return false; +} + +template <typename Functor> +static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList) +{ + for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) { + if (forEachTagSelector(functor, selector)) + return true; + } + + return false; +} + +class SelectorNeedsNamespaceResolutionFunctor { +public: + bool operator()(CSSSelector* selector) + { + if (selector->hasTag() && selector->m_tag.prefix() != nullAtom && selector->m_tag.prefix() != starAtom) + return true; + if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) + return true; + return false; + } +}; + +bool CSSSelectorList::selectorsNeedNamespaceResolution() +{ + SelectorNeedsNamespaceResolutionFunctor functor; + return forEachSelector(functor, this); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSSelectorList.h b/Source/WebCore/css/CSSSelectorList.h new file mode 100644 index 0000000..9e40ef8 --- /dev/null +++ b/Source/WebCore/css/CSSSelectorList.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSSelectorList_h +#define CSSSelectorList_h + +#include "CSSSelector.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class CSSSelectorList : public Noncopyable { +public: + CSSSelectorList() : m_selectorArray(0) { } + ~CSSSelectorList(); + + void adopt(CSSSelectorList& list); + void adoptSelectorVector(Vector<CSSSelector*>& selectorVector); + + CSSSelector* first() const { return m_selectorArray ? m_selectorArray : 0; } + static CSSSelector* next(CSSSelector* previous) { return previous->isLastInSelectorList() ? 0 : previous + 1; } + bool hasOneSelector() const { return m_selectorArray ? m_selectorArray->isLastInSelectorList() : false; } + + bool selectorsNeedNamespaceResolution(); + +private: + void deleteSelectors(); + + // End of the array is indicated by m_isLastInSelectorList bit in the last item. + CSSSelector* m_selectorArray; +}; + +} // namespace WebCore + +#endif // CSSSelectorList_h diff --git a/Source/WebCore/css/CSSStyleDeclaration.cpp b/Source/WebCore/css/CSSStyleDeclaration.cpp new file mode 100644 index 0000000..422dd0d --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.cpp @@ -0,0 +1,159 @@ +/* + * (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 "CSSStyleDeclaration.h" + +#include "CSSMutableStyleDeclaration.h" +#include "CSSParser.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSRule.h" +#include <wtf/ASCIICType.h> + +using namespace WTF; + +namespace WebCore { + +CSSStyleDeclaration::CSSStyleDeclaration(CSSRule* parent) + : StyleBase(parent) +{ +} + +PassRefPtr<CSSValue> CSSStyleDeclaration::getPropertyCSSValue(const String& propertyName) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return 0; + return getPropertyCSSValue(propID); +} + +String CSSStyleDeclaration::getPropertyValue(const String &propertyName) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return String(); + return getPropertyValue(propID); +} + +String CSSStyleDeclaration::getPropertyPriority(const String& propertyName) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return String(); + return getPropertyPriority(propID) ? "important" : ""; +} + +String CSSStyleDeclaration::getPropertyShorthand(const String& propertyName) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return String(); + int shorthandID = getPropertyShorthand(propID); + if (!shorthandID) + return String(); + return getPropertyName(static_cast<CSSPropertyID>(shorthandID)); +} + +bool CSSStyleDeclaration::isPropertyImplicit(const String& propertyName) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return false; + return isPropertyImplicit(propID); +} + +void CSSStyleDeclaration::setProperty(const String& propertyName, const String& value, ExceptionCode& ec) +{ + size_t important = value.find("!important", 0, false); + if (important == notFound) + setProperty(propertyName, value, "", ec); + else + setProperty(propertyName, value.left(important - 1), "important", ec); +} + +void CSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode& ec) +{ + int propID = cssPropertyID(propertyName); + if (!propID) { + // FIXME: Should we raise an exception here? + return; + } + bool important = priority.find("important", 0, false) != notFound; + setProperty(propID, value, important, ec); +} + +String CSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionCode& ec) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + return String(); + return removeProperty(propID, ec); +} + +bool CSSStyleDeclaration::isPropertyName(const String& propertyName) +{ + return cssPropertyID(propertyName); +} + +CSSRule* CSSStyleDeclaration::parentRule() const +{ + return (parent() && parent()->isRule()) ? static_cast<CSSRule*>(parent()) : 0; +} + +bool CSSStyleDeclaration::cssPropertyMatches(const CSSProperty* property) const +{ + RefPtr<CSSValue> value = getPropertyCSSValue(property->id()); + return value && value->cssText() == property->value()->cssText(); +} + +void CSSStyleDeclaration::diff(CSSMutableStyleDeclaration* style) const +{ + if (!style) + return; + + Vector<int> propertiesToRemove; + { + CSSMutableStyleDeclaration::const_iterator end = style->end(); + for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { + const CSSProperty& property = *it; + if (cssPropertyMatches(&property)) + propertiesToRemove.append(property.id()); + } + } + + // FIXME: This should use mass removal. + for (unsigned i = 0; i < propertiesToRemove.size(); i++) + style->removeProperty(propertiesToRemove[i]); +} + +PassRefPtr<CSSMutableStyleDeclaration> CSSStyleDeclaration::copyPropertiesInSet(const int* set, unsigned length) const +{ + Vector<CSSProperty> list; + list.reserveInitialCapacity(length); + for (unsigned i = 0; i < length; i++) { + RefPtr<CSSValue> value = getPropertyCSSValue(set[i]); + if (value) + list.append(CSSProperty(set[i], value.release(), false)); + } + return CSSMutableStyleDeclaration::create(list); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSStyleDeclaration.h b/Source/WebCore/css/CSSStyleDeclaration.h new file mode 100644 index 0000000..08b3bf0 --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.h @@ -0,0 +1,84 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef CSSStyleDeclaration_h +#define CSSStyleDeclaration_h + +#include "StyleBase.h" +#include <wtf/Forward.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; +class CSSProperty; +class CSSRule; +class CSSValue; + +typedef int ExceptionCode; + +class CSSStyleDeclaration : public StyleBase { +public: + static bool isPropertyName(const String&); + + CSSRule* parentRule() const; + + virtual String cssText() const = 0; + virtual void setCssText(const String&, ExceptionCode&) = 0; + + unsigned length() const { return virtualLength(); } + virtual unsigned virtualLength() const = 0; + bool isEmpty() const { return !length(); } + virtual String item(unsigned index) const = 0; + + PassRefPtr<CSSValue> getPropertyCSSValue(const String& propertyName); + String getPropertyValue(const String& propertyName); + String getPropertyPriority(const String& propertyName); + String getPropertyShorthand(const String& propertyName); + bool isPropertyImplicit(const String& propertyName); + + virtual PassRefPtr<CSSValue> getPropertyCSSValue(int propertyID) const = 0; + virtual String getPropertyValue(int propertyID) const = 0; + virtual bool getPropertyPriority(int propertyID) const = 0; + virtual int getPropertyShorthand(int propertyID) const = 0; + virtual bool isPropertyImplicit(int propertyID) const = 0; + + void setProperty(const String& propertyName, const String& value, ExceptionCode&); + void setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode&); + String removeProperty(const String& propertyName, ExceptionCode&); + virtual void setProperty(int propertyId, const String& value, bool important, ExceptionCode&) = 0; + virtual String removeProperty(int propertyID, ExceptionCode&) = 0; + + virtual PassRefPtr<CSSMutableStyleDeclaration> copy() const = 0; + virtual PassRefPtr<CSSMutableStyleDeclaration> makeMutable() = 0; + + void diff(CSSMutableStyleDeclaration*) const; + + PassRefPtr<CSSMutableStyleDeclaration> copyPropertiesInSet(const int* set, unsigned length) const; + +protected: + CSSStyleDeclaration(CSSRule* parentRule = 0); + + virtual bool cssPropertyMatches(const CSSProperty*) const; + +}; + +} // namespace WebCore + +#endif // CSSStyleDeclaration_h diff --git a/Source/WebCore/css/CSSStyleDeclaration.idl b/Source/WebCore/css/CSSStyleDeclaration.idl new file mode 100644 index 0000000..297b732 --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.idl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [ + CustomMarkFunction, + DelegatingPutFunction, + HasNameGetter, + HasIndexGetter + ] CSSStyleDeclaration { + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString cssText + setter raises(DOMException); + + [ConvertNullStringTo=Null] DOMString getPropertyValue(in DOMString propertyName); + CSSValue getPropertyCSSValue(in DOMString propertyName); + [ConvertNullStringTo=Null] DOMString removeProperty(in DOMString propertyName) + raises(DOMException); + [ConvertNullStringTo=Null] DOMString getPropertyPriority(in DOMString propertyName); + [OldStyleObjC] void setProperty(in DOMString propertyName, + in [ConvertNullToNullString] DOMString value, + in DOMString priority) + raises(DOMException); + + readonly attribute unsigned long length; + DOMString item(in unsigned long index); + readonly attribute CSSRule parentRule; + + // Extensions + [ConvertNullStringTo=Null] DOMString getPropertyShorthand(in DOMString propertyName); + boolean isPropertyImplicit(in DOMString propertyName); + }; + +} diff --git a/Source/WebCore/css/CSSStyleRule.cpp b/Source/WebCore/css/CSSStyleRule.cpp new file mode 100644 index 0000000..faf60b0 --- /dev/null +++ b/Source/WebCore/css/CSSStyleRule.cpp @@ -0,0 +1,115 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2005, 2006, 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 "CSSStyleRule.h" + +#include "CSSMutableStyleDeclaration.h" +#include "CSSParser.h" +#include "CSSSelector.h" +#include "CSSStyleSheet.h" +#include "Document.h" +#include "StyleSheet.h" + +namespace WebCore { + +CSSStyleRule::CSSStyleRule(CSSStyleSheet* parent, int sourceLine) + : CSSRule(parent) + , m_sourceLine(sourceLine) +{ +} + +CSSStyleRule::~CSSStyleRule() +{ + if (m_style) + m_style->setParent(0); +} + +String CSSStyleRule::selectorText() const +{ + String str; + for (CSSSelector* s = selectorList().first(); s; s = CSSSelectorList::next(s)) { + if (s != selectorList().first()) + str += ", "; + str += s->selectorText(); + } + return str; +} + +void CSSStyleRule::setSelectorText(const String& selectorText) +{ + Document* doc = 0; + StyleSheet* ownerStyleSheet = m_style->stylesheet(); + if (ownerStyleSheet) { + if (ownerStyleSheet->isCSSStyleSheet()) + doc = static_cast<CSSStyleSheet*>(ownerStyleSheet)->document(); + if (!doc) + doc = ownerStyleSheet->ownerNode() ? ownerStyleSheet->ownerNode()->document() : 0; + } + if (!doc) + doc = m_style->node() ? m_style->node()->document() : 0; + + if (!doc) + return; + + CSSParser p; + CSSSelectorList selectorList; + p.parseSelector(selectorText, doc, selectorList); + if (!selectorList.first()) + return; + + String oldSelectorText = this->selectorText(); + m_selectorList.adopt(selectorList); + if (this->selectorText() == oldSelectorText) + return; + + doc->styleSelectorChanged(DeferRecalcStyle); +} + +String CSSStyleRule::cssText() const +{ + String result = selectorText(); + + result += " { "; + result += m_style->cssText(); + result += "}"; + + return result; +} + +bool CSSStyleRule::parseString(const String& /*string*/, bool /*strict*/) +{ + // FIXME + return false; +} + +void CSSStyleRule::setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) +{ + m_style = style; +} + +void CSSStyleRule::addSubresourceStyleURLs(ListHashSet<KURL>& urls) +{ + if (m_style) + m_style->addSubresourceStyleURLs(urls); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSStyleRule.h b/Source/WebCore/css/CSSStyleRule.h new file mode 100644 index 0000000..171b636 --- /dev/null +++ b/Source/WebCore/css/CSSStyleRule.h @@ -0,0 +1,79 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSStyleRule_h +#define CSSStyleRule_h + +#include "CSSRule.h" +#include "CSSSelectorList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; +class CSSSelector; + +class CSSStyleRule : public CSSRule { +public: + static PassRefPtr<CSSStyleRule> create(CSSStyleSheet* parent, int sourceLine) + { + return adoptRef(new CSSStyleRule(parent, sourceLine)); + } + virtual ~CSSStyleRule(); + + virtual String selectorText() const; + void setSelectorText(const String&); + + CSSMutableStyleDeclaration* style() const { return m_style.get(); } + + virtual String cssText() const; + + // Not part of the CSSOM + virtual bool parseString(const String&, bool = false); + + void adoptSelectorVector(Vector<CSSSelector*>& selectors) { m_selectorList.adoptSelectorVector(selectors); } + void setDeclaration(PassRefPtr<CSSMutableStyleDeclaration>); + + const CSSSelectorList& selectorList() const { return m_selectorList; } + CSSMutableStyleDeclaration* declaration() { return m_style.get(); } + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + + int sourceLine() { return m_sourceLine; } + +protected: + CSSStyleRule(CSSStyleSheet* parent, int sourceLine); + +private: + virtual bool isStyleRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return STYLE_RULE; } + + RefPtr<CSSMutableStyleDeclaration> m_style; + CSSSelectorList m_selectorList; + int m_sourceLine; +}; + +} // namespace WebCore + +#endif // CSSStyleRule_h diff --git a/Source/WebCore/css/CSSStyleRule.idl b/Source/WebCore/css/CSSStyleRule.idl new file mode 100644 index 0000000..342aedd --- /dev/null +++ b/Source/WebCore/css/CSSStyleRule.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [CustomMarkFunction] CSSStyleRule : CSSRule { + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString selectorText; + + readonly attribute CSSStyleDeclaration style; + + }; + +} diff --git a/Source/WebCore/css/CSSStyleSelector.cpp b/Source/WebCore/css/CSSStyleSelector.cpp new file mode 100644 index 0000000..986591d --- /dev/null +++ b/Source/WebCore/css/CSSStyleSelector.cpp @@ -0,0 +1,7188 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) + * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * 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 "CSSStyleSelector.h" + +#include "Attribute.h" +#include "CSSBorderImageValue.h" +#include "CSSCursorImageValue.h" +#include "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSMediaRule.h" +#include "CSSPageRule.h" +#include "CSSParser.h" +#include "CSSPrimitiveValueMappings.h" +#include "CSSPropertyNames.h" +#include "CSSReflectValue.h" +#include "CSSRuleList.h" +#include "CSSSelector.h" +#include "CSSSelectorList.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSTimingFunctionValue.h" +#include "CSSValueList.h" +#include "CachedImage.h" +#include "Counter.h" +#include "FocusController.h" +#include "FontFamilyValue.h" +#include "FontValue.h" +#include "Frame.h" +#include "FrameView.h" +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLTextAreaElement.h" +#include "KeyframeList.h" +#include "LinkHash.h" +#include "Matrix3DTransformOperation.h" +#include "MatrixTransformOperation.h" +#include "MediaList.h" +#include "MediaQueryEvaluator.h" +#include "NodeRenderStyle.h" +#include "Page.h" +#include "PageGroup.h" +#include "Pair.h" +#include "PerspectiveTransformOperation.h" +#include "Rect.h" +#include "RenderScrollbar.h" +#include "RenderScrollbarTheme.h" +#include "RenderStyleConstants.h" +#include "RenderTheme.h" +#include "RotateTransformOperation.h" +#include "ScaleTransformOperation.h" +#include "SelectionController.h" +#include "Settings.h" +#include "ShadowValue.h" +#include "SkewTransformOperation.h" +#include "StyleCachedImage.h" +#include "StylePendingImage.h" +#include "StyleGeneratedImage.h" +#include "StyleSheetList.h" +#include "Text.h" +#include "TransformationMatrix.h" +#include "TranslateTransformOperation.h" +#include "UserAgentStyleSheets.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSTransformValue.h" +#include "XMLNames.h" +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +#if USE(PLATFORM_STRATEGIES) +#include "PlatformStrategies.h" +#include "VisitedLinkStrategy.h" +#endif + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +#if ENABLE(SVG) +#include "XLinkNames.h" +#include "SVGNames.h" +#endif + +#if ENABLE(WML) +#include "WMLNames.h" +#endif + +#if PLATFORM(QT) +#include <qwebhistoryinterface.h> +#endif + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +#define HANDLE_INHERIT(prop, Prop) \ +if (isInherit) { \ + m_style->set##Prop(m_parentStyle->prop()); \ + return; \ +} + +#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ +HANDLE_INHERIT(prop, Prop) \ +if (isInitial) { \ + m_style->set##Prop(RenderStyle::initial##Prop()); \ + return; \ +} + +#define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ +HANDLE_INHERIT(prop, Prop) \ +if (isInitial) { \ + m_style->set##Prop(RenderStyle::initial##Value());\ + return;\ +} + +#define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(prop, Prop) \ +HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ +if (primitiveValue) \ + m_style->set##Prop(*primitiveValue); + +#define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(prop, Prop, Value) \ +HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ +if (primitiveValue) \ + m_style->set##Prop(*primitiveValue); + +#define HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \ +if (isInherit) { \ + FillLayer* currChild = m_style->access##LayerType##Layers(); \ + FillLayer* prevChild = 0; \ + const FillLayer* currParent = m_parentStyle->layerType##Layers(); \ + while (currParent && currParent->is##Prop##Set()) { \ + if (!currChild) { \ + /* Need to make a new layer.*/ \ + currChild = new FillLayer(LayerType##FillLayer); \ + prevChild->setNext(currChild); \ + } \ + currChild->set##Prop(currParent->prop()); \ + prevChild = currChild; \ + currChild = prevChild->next(); \ + currParent = currParent->next(); \ + } \ + \ + while (currChild) { \ + /* Reset any remaining layers to not have the property set. */ \ + currChild->clear##Prop(); \ + currChild = currChild->next(); \ + } \ +} else if (isInitial) { \ + FillLayer* currChild = m_style->access##LayerType##Layers(); \ + currChild->set##Prop(FillLayer::initialFill##Prop(LayerType##FillLayer)); \ + for (currChild = currChild->next(); currChild; currChild = currChild->next()) \ + currChild->clear##Prop(); \ +} + +#define HANDLE_FILL_LAYER_VALUE(layerType, LayerType, prop, Prop, value) { \ +HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \ +if (isInherit || isInitial) \ + return; \ +FillLayer* currChild = m_style->access##LayerType##Layers(); \ +FillLayer* prevChild = 0; \ +if (value->isValueList()) { \ + /* Walk each value and put it into a layer, creating new layers as needed. */ \ + CSSValueList* valueList = static_cast<CSSValueList*>(value); \ + for (unsigned int i = 0; i < valueList->length(); i++) { \ + if (!currChild) { \ + /* Need to make a new layer to hold this value */ \ + currChild = new FillLayer(LayerType##FillLayer); \ + prevChild->setNext(currChild); \ + } \ + mapFill##Prop(property, currChild, valueList->itemWithoutBoundsCheck(i)); \ + prevChild = currChild; \ + currChild = currChild->next(); \ + } \ +} else { \ + mapFill##Prop(property, currChild, value); \ + currChild = currChild->next(); \ +} \ +while (currChild) { \ + /* Reset all remaining layers to not have the property set. */ \ + currChild->clear##Prop(); \ + currChild = currChild->next(); \ +} } + +#define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \ +HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(background, Background, prop, Prop) + +#define HANDLE_BACKGROUND_VALUE(prop, Prop, value) \ +HANDLE_FILL_LAYER_VALUE(background, Background, prop, Prop, value) + +#define HANDLE_MASK_INHERIT_AND_INITIAL(prop, Prop) \ +HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(mask, Mask, prop, Prop) + +#define HANDLE_MASK_VALUE(prop, Prop, value) \ +HANDLE_FILL_LAYER_VALUE(mask, Mask, prop, Prop, value) + +#define HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ +if (isInherit) { \ + AnimationList* list = m_style->accessAnimations(); \ + const AnimationList* parentList = m_parentStyle->animations(); \ + size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ + for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \ + if (list->size() <= i) \ + list->append(Animation::create()); \ + list->animation(i)->set##Prop(parentList->animation(i)->prop()); \ + } \ + \ + /* Reset any remaining animations to not have the property set. */ \ + for ( ; i < list->size(); ++i) \ + list->animation(i)->clear##Prop(); \ +} else if (isInitial) { \ + AnimationList* list = m_style->accessAnimations(); \ + if (list->isEmpty()) \ + list->append(Animation::create()); \ + list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \ + for (size_t i = 1; i < list->size(); ++i) \ + list->animation(0)->clear##Prop(); \ +} + +#define HANDLE_ANIMATION_VALUE(prop, Prop, value) { \ +HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ +if (isInherit || isInitial) \ + return; \ +AnimationList* list = m_style->accessAnimations(); \ +size_t childIndex = 0; \ +if (value->isValueList()) { \ + /* Walk each value and put it into an animation, creating new animations as needed. */ \ + CSSValueList* valueList = static_cast<CSSValueList*>(value); \ + for (unsigned int i = 0; i < valueList->length(); i++) { \ + if (childIndex <= list->size()) \ + list->append(Animation::create()); \ + mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \ + ++childIndex; \ + } \ +} else { \ + if (list->isEmpty()) \ + list->append(Animation::create()); \ + mapAnimation##Prop(list->animation(childIndex), value); \ + childIndex = 1; \ +} \ +for ( ; childIndex < list->size(); ++childIndex) { \ + /* Reset all remaining animations to not have the property set. */ \ + list->animation(childIndex)->clear##Prop(); \ +} \ +} + +#define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ +if (isInherit) { \ + AnimationList* list = m_style->accessTransitions(); \ + const AnimationList* parentList = m_parentStyle->transitions(); \ + size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ + for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \ + if (list->size() <= i) \ + list->append(Animation::create()); \ + list->animation(i)->set##Prop(parentList->animation(i)->prop()); \ + } \ + \ + /* Reset any remaining transitions to not have the property set. */ \ + for ( ; i < list->size(); ++i) \ + list->animation(i)->clear##Prop(); \ +} else if (isInitial) { \ + AnimationList* list = m_style->accessTransitions(); \ + if (list->isEmpty()) \ + list->append(Animation::create()); \ + list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \ + for (size_t i = 1; i < list->size(); ++i) \ + list->animation(0)->clear##Prop(); \ +} + +#define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \ +HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ +if (isInherit || isInitial) \ + return; \ +AnimationList* list = m_style->accessTransitions(); \ +size_t childIndex = 0; \ +if (value->isValueList()) { \ + /* Walk each value and put it into a transition, creating new animations as needed. */ \ + CSSValueList* valueList = static_cast<CSSValueList*>(value); \ + for (unsigned int i = 0; i < valueList->length(); i++) { \ + if (childIndex <= list->size()) \ + list->append(Animation::create()); \ + mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \ + ++childIndex; \ + } \ +} else { \ + if (list->isEmpty()) \ + list->append(Animation::create()); \ + mapAnimation##Prop(list->animation(childIndex), value); \ + childIndex = 1; \ +} \ +for ( ; childIndex < list->size(); ++childIndex) { \ + /* Reset all remaining transitions to not have the property set. */ \ + list->animation(childIndex)->clear##Prop(); \ +} \ +} + +#define HANDLE_INHERIT_COND(propID, prop, Prop) \ +if (id == propID) { \ + m_style->set##Prop(m_parentStyle->prop()); \ + return; \ +} + +#define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \ +if (id == propID) { \ + if (m_parentStyle->prop().isValid()) \ + m_style->set##Prop(m_parentStyle->prop()); \ + else \ + m_style->set##Prop(m_parentStyle->propAlt()); \ + return; \ +} + +#define HANDLE_INITIAL_COND(propID, Prop) \ +if (id == propID) { \ + m_style->set##Prop(RenderStyle::initial##Prop()); \ + return; \ +} + +#define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \ +if (id == propID) { \ + m_style->set##Prop(RenderStyle::initial##Value()); \ + return; \ +} + +class CSSRuleData : public Noncopyable { +public: + CSSRuleData(unsigned pos, CSSStyleRule* r, CSSSelector* sel, CSSRuleData* prev = 0) + : m_position(pos) + , m_rule(r) + , m_selector(sel) + , m_next(0) + { + if (prev) + prev->m_next = this; + } + + ~CSSRuleData() + { + } + + unsigned position() { return m_position; } + CSSStyleRule* rule() { return m_rule; } + CSSSelector* selector() { return m_selector; } + CSSRuleData* next() { return m_next; } + +private: + unsigned m_position; + CSSStyleRule* m_rule; + CSSSelector* m_selector; + CSSRuleData* m_next; +}; + +class CSSRuleDataList : public Noncopyable { +public: + CSSRuleDataList(unsigned pos, CSSStyleRule* rule, CSSSelector* sel) + : m_first(new CSSRuleData(pos, rule, sel)) + , m_last(m_first) + { + } + + ~CSSRuleDataList() + { + CSSRuleData* ptr; + CSSRuleData* next; + ptr = m_first; + while (ptr) { + next = ptr->next(); + delete ptr; + ptr = next; + } + } + + CSSRuleData* first() { return m_first; } + CSSRuleData* last() { return m_last; } + + void append(unsigned pos, CSSStyleRule* rule, CSSSelector* sel) { m_last = new CSSRuleData(pos, rule, sel, m_last); } + +private: + CSSRuleData* m_first; + CSSRuleData* m_last; +}; + +class CSSRuleSet : public Noncopyable { +public: + CSSRuleSet(); + ~CSSRuleSet(); + + typedef HashMap<AtomicStringImpl*, CSSRuleDataList*> AtomRuleMap; + + void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0); + + void addStyleRule(CSSStyleRule* item); + void addRule(CSSStyleRule* rule, CSSSelector* sel); + void addPageRule(CSSStyleRule* rule, CSSSelector* sel); + void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, + CSSStyleRule* rule, CSSSelector* sel); + + CSSRuleDataList* getIDRules(AtomicStringImpl* key) { return m_idRules.get(key); } + CSSRuleDataList* getClassRules(AtomicStringImpl* key) { return m_classRules.get(key); } + CSSRuleDataList* getTagRules(AtomicStringImpl* key) { return m_tagRules.get(key); } + CSSRuleDataList* getUniversalRules() { return m_universalRules.get(); } + CSSRuleDataList* getPageRules() { return m_pageRules.get(); } + +public: + AtomRuleMap m_idRules; + AtomRuleMap m_classRules; + AtomRuleMap m_tagRules; + OwnPtr<CSSRuleDataList> m_universalRules; + OwnPtr<CSSRuleDataList> m_pageRules; + unsigned m_ruleCount; + unsigned m_pageRuleCount; +}; + +static CSSRuleSet* defaultStyle; +static CSSRuleSet* defaultQuirksStyle; +static CSSRuleSet* defaultPrintStyle; +static CSSRuleSet* defaultViewSourceStyle; +static CSSStyleSheet* simpleDefaultStyleSheet; + +RenderStyle* CSSStyleSelector::s_styleNotYetAvailable; + +static void loadFullDefaultStyle(); +#if ENABLE(FULLSCREEN_API) +static void loadFullScreenRulesIfNeeded(Document*); +#endif +static void loadSimpleDefaultStyle(); +// FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet. +static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}body{margin:8px}div:focus,span:focus{outline:auto 5px -webkit-focus-ring-color}a:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}"; + +static bool elementCanUseSimpleDefaultStyle(Element* e) +{ + return e->hasTagName(htmlTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || e->hasTagName(aTag); +} + +static const MediaQueryEvaluator& screenEval() +{ + DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen")); + return staticScreenEval; +} + +static const MediaQueryEvaluator& printEval() +{ + DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print")); + return staticPrintEval; +} + +CSSStyleSelector::CSSStyleSelector(Document* document, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, + CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets, + bool strictParsing, bool matchAuthorAndUserStyles) + : m_backgroundData(BackgroundFillLayer) + , m_checker(document, strictParsing) + , m_element(0) + , m_styledElement(0) + , m_elementLinkState(NotInsideLink) + , m_fontSelector(CSSFontSelector::create(document)) +{ + m_matchAuthorAndUserStyles = matchAuthorAndUserStyles; + + Element* root = document->documentElement(); + + if (!defaultStyle) { + if (!root || elementCanUseSimpleDefaultStyle(root)) + loadSimpleDefaultStyle(); + else { + loadFullDefaultStyle(); +#if ENABLE(FULLSCREEN_API) + loadFullScreenRulesIfNeeded(document); +#endif + } + } + + // construct document root element default style. this is needed + // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)" + // This is here instead of constructor, because when constructor is run, + // document doesn't have documentElement + // NOTE: this assumes that element that gets passed to styleForElement -call + // is always from the document that owns the style selector + FrameView* view = document->view(); + if (view) + m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType())); + else + m_medium = adoptPtr(new MediaQueryEvaluator("all")); + + if (root) + m_rootDefaultStyle = styleForElement(root, 0, false, true); // don't ref, because the RenderStyle is allocated from global heap + + if (m_rootDefaultStyle && view) + m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get())); + + m_authorStyle = adoptPtr(new CSSRuleSet); + + // FIXME: This sucks! The user sheet is reparsed every time! + OwnPtr<CSSRuleSet> tempUserStyle = adoptPtr(new CSSRuleSet); + if (pageUserSheet) + tempUserStyle->addRulesFromSheet(pageUserSheet, *m_medium, this); + if (pageGroupUserSheets) { + unsigned length = pageGroupUserSheets->size(); + for (unsigned i = 0; i < length; i++) { + if (pageGroupUserSheets->at(i)->isUserStyleSheet()) + tempUserStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this); + else + m_authorStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this); + } + } + + if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRuleCount > 0) + m_userStyle = tempUserStyle.release(); + + // Add rules from elements like SVG's <font-face> + if (mappedElementSheet) + m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this); + + // add stylesheets from document + unsigned length = styleSheets->length(); + for (unsigned i = 0; i < length; i++) { + StyleSheet* sheet = styleSheets->item(i); + if (sheet->isCSSStyleSheet() && !sheet->disabled()) + m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(sheet), *m_medium, this); + } + + if (document->renderer() && document->renderer()->style()) + document->renderer()->style()->font().update(fontSelector()); +} + +// This is a simplified style setting function for keyframe styles +void CSSStyleSelector::addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule) +{ + AtomicString s(rule->name()); + m_keyframesRuleMap.add(s.impl(), rule); +} + +CSSStyleSelector::~CSSStyleSelector() +{ + m_fontSelector->clearDocument(); + deleteAllValues(m_viewportDependentMediaQueryResults); +} + +static CSSStyleSheet* parseUASheet(const String& str) +{ + CSSStyleSheet* sheet = CSSStyleSheet::create().releaseRef(); // leak the sheet on purpose + sheet->parseString(str); + return sheet; +} + +static CSSStyleSheet* parseUASheet(const char* characters, unsigned size) +{ + return parseUASheet(String(characters, size)); +} + +static void loadFullDefaultStyle() +{ + if (simpleDefaultStyleSheet) { + ASSERT(defaultStyle); + delete defaultStyle; + simpleDefaultStyleSheet->deref(); + defaultStyle = new CSSRuleSet; + simpleDefaultStyleSheet = 0; + } else { + ASSERT(!defaultStyle); + defaultStyle = new CSSRuleSet; + defaultPrintStyle = new CSSRuleSet; + defaultQuirksStyle = new CSSRuleSet; + } + + // Strict-mode rules. + String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet(); + CSSStyleSheet* defaultSheet = parseUASheet(defaultRules); + defaultStyle->addRulesFromSheet(defaultSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval()); + + // Quirks-mode rules. + String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet(); + CSSStyleSheet* quirksSheet = parseUASheet(quirksRules); + defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval()); +} + +#if ENABLE(FULLSCREEN_API) +static void loadFullScreenRulesIfNeeded(Document* document) +{ + if (!document->webkitIsFullScreen()) + return; + // Full-screen rules. + String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet(); + CSSStyleSheet* fullscreenSheet = parseUASheet(fullscreenRules); + defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval()); + defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval()); +} +#endif + +static void loadSimpleDefaultStyle() +{ + ASSERT(!defaultStyle); + ASSERT(!simpleDefaultStyleSheet); + + defaultStyle = new CSSRuleSet; + defaultPrintStyle = new CSSRuleSet; + defaultQuirksStyle = new CSSRuleSet; + + simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval()); + + // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style. +} + +static void loadViewSourceStyle() +{ + ASSERT(!defaultViewSourceStyle); + defaultViewSourceStyle = new CSSRuleSet; + defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval()); +} + +void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* decl) +{ + m_matchedDecls.append(decl); +} + +void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) +{ + m_matchedRules.clear(); + + if (!rules || !m_element) + return; + + // We need to collect the rules for id, class, tag, and everything else into a buffer and + // then sort the buffer. + if (m_element->hasID()) + matchRulesForList(rules->getIDRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + if (m_element->hasClass()) { + ASSERT(m_styledElement); + const SpaceSplitString& classNames = m_styledElement->classNames(); + size_t size = classNames.size(); + for (size_t i = 0; i < size; ++i) + matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + } + matchRulesForList(rules->getTagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules); + + // If we didn't match any rules, we're done. + if (m_matchedRules.isEmpty()) + return; + + // Sort the set of matched rules. + sortMatchedRules(0, m_matchedRules.size()); + + // Now transfer the set of matched rules over to our list of decls. + if (!m_checker.m_collectRulesOnly) { + for (unsigned i = 0; i < m_matchedRules.size(); i++) + addMatchedDeclaration(m_matchedRules[i]->rule()->declaration()); + } else { + for (unsigned i = 0; i < m_matchedRules.size(); i++) { + if (!m_ruleList) + m_ruleList = CSSRuleList::create(); + m_ruleList->append(m_matchedRules[i]->rule()); + } + } +} + +void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) +{ + if (!rules) + return; + + for (CSSRuleData* d = rules->first(); d; d = d->next()) { + CSSStyleRule* rule = d->rule(); + if (m_checker.m_sameOriginOnly && !m_checker.m_document->securityOrigin()->canRequest(rule->baseURL())) + continue; + if (checkSelector(d->selector())) { + // If the rule has no properties to apply, then ignore it in the non-debug mode. + CSSMutableStyleDeclaration* decl = rule->declaration(); + if (!decl || (!decl->length() && !includeEmptyRules)) + continue; + + // If we're matching normal rules, set a pseudo bit if + // we really just matched a pseudo-element. + if (m_dynamicPseudo != NOPSEUDO && m_checker.m_pseudoStyle == NOPSEUDO) { + if (m_checker.m_collectRulesOnly) + continue; + if (m_dynamicPseudo < FIRST_INTERNAL_PSEUDOID) + m_style->setHasPseudoStyle(m_dynamicPseudo); + } else { + // Update our first/last rule indices in the matched rules array. + lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size(); + if (firstRuleIndex == -1) + firstRuleIndex = lastRuleIndex; + + // Add this rule to our list of matched rules. + addMatchedRule(d); + } + } + } +} + +static bool operator >(CSSRuleData& r1, CSSRuleData& r2) +{ + int spec1 = r1.selector()->specificity(); + int spec2 = r2.selector()->specificity(); + return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2; +} + +static bool operator <=(CSSRuleData& r1, CSSRuleData& r2) +{ + return !(r1 > r2); +} + +void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end) +{ + if (start >= end || (end - start == 1)) + return; // Sanity check. + + if (end - start <= 6) { + // Apply a bubble sort for smaller lists. + for (unsigned i = end - 1; i > start; i--) { + bool sorted = true; + for (unsigned j = start; j < i; j++) { + CSSRuleData* elt = m_matchedRules[j]; + CSSRuleData* elt2 = m_matchedRules[j + 1]; + if (*elt > *elt2) { + sorted = false; + m_matchedRules[j] = elt2; + m_matchedRules[j + 1] = elt; + } + } + if (sorted) + return; + } + return; + } + + // Perform a merge sort for larger lists. + unsigned mid = (start + end) / 2; + sortMatchedRules(start, mid); + sortMatchedRules(mid, end); + + CSSRuleData* elt = m_matchedRules[mid - 1]; + CSSRuleData* elt2 = m_matchedRules[mid]; + + // Handle the fast common case (of equal specificity). The list may already + // be completely sorted. + if (*elt <= *elt2) + return; + + // We have to merge sort. Ensure our merge buffer is big enough to hold + // all the items. + Vector<CSSRuleData*> rulesMergeBuffer; + rulesMergeBuffer.reserveInitialCapacity(end - start); + + unsigned i1 = start; + unsigned i2 = mid; + + elt = m_matchedRules[i1]; + elt2 = m_matchedRules[i2]; + + while (i1 < mid || i2 < end) { + if (i1 < mid && (i2 == end || *elt <= *elt2)) { + rulesMergeBuffer.append(elt); + if (++i1 < mid) + elt = m_matchedRules[i1]; + } else { + rulesMergeBuffer.append(elt2); + if (++i2 < end) + elt2 = m_matchedRules[i2]; + } + } + + for (unsigned i = start; i < end; i++) + m_matchedRules[i] = rulesMergeBuffer[i - start]; +} + +inline EInsideLink CSSStyleSelector::SelectorChecker::determineLinkState(Element* element) const +{ + if (!element || !element->isLink()) + return NotInsideLink; + return determineLinkStateSlowCase(element); +} + +inline void CSSStyleSelector::initElement(Element* e) +{ + if (m_element != e) { + m_element = e; + m_styledElement = m_element && m_element->isStyledElement() ? static_cast<StyledElement*>(m_element) : 0; + m_elementLinkState = m_checker.determineLinkState(m_element); + if (e && e == e->document()->documentElement()) { + e->document()->setDirectionSetOnDocumentElement(false); + e->document()->setWritingModeSetOnDocumentElement(false); + } + } +} + +inline void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* parentStyle, PseudoId pseudoID) +{ + m_checker.m_pseudoStyle = pseudoID; + + m_parentNode = e ? e->parentNode() : 0; + +#if ENABLE(SVG) + if (!m_parentNode && e && e->isSVGElement() && e->isShadowRoot()) + m_parentNode = e->shadowHost(); +#endif + + if (parentStyle) + m_parentStyle = parentStyle; + else + m_parentStyle = m_parentNode ? m_parentNode->renderStyle() : 0; + + Node* docElement = e ? e->document()->documentElement() : 0; + RenderStyle* docStyle = m_checker.m_document->renderStyle(); + m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle; + + m_style = 0; + + m_matchedDecls.clear(); + + m_pendingImageProperties.clear(); + + m_ruleList = 0; + + m_fontDirty = false; +} + +static inline const AtomicString* linkAttribute(Node* node) +{ + if (!node->isLink()) + return 0; + + ASSERT(node->isElementNode()); + Element* element = static_cast<Element*>(node); + if (element->isHTMLElement()) + return &element->fastGetAttribute(hrefAttr); + +#if ENABLE(WML) + if (element->isWMLElement()) { + // <anchor> elements don't have href attributes, but we still want to + // appear as link, so linkAttribute() has to return a non-null value! + if (element->hasTagName(WMLNames::anchorTag)) + return &emptyAtom; + + return &element->fastGetAttribute(hrefAttr); + } +#endif + +#if ENABLE(SVG) + if (element->isSVGElement()) + return &element->fastGetAttribute(XLinkNames::hrefAttr); +#endif + + return 0; +} + +CSSStyleSelector::SelectorChecker::SelectorChecker(Document* document, bool strictParsing) + : m_document(document) + , m_strictParsing(strictParsing) + , m_collectRulesOnly(false) + , m_sameOriginOnly(false) + , m_pseudoStyle(NOPSEUDO) + , m_documentIsHTML(document->isHTMLDocument()) + , m_matchVisitedPseudoClass(false) +{ +} + +EInsideLink CSSStyleSelector::SelectorChecker::determineLinkStateSlowCase(Element* element) const +{ + ASSERT(element->isLink()); + + const AtomicString* attr = linkAttribute(element); + if (!attr || attr->isNull()) + return NotInsideLink; + +#if PLATFORM(QT) + Vector<UChar, 512> url; + visitedURL(m_document->baseURL(), *attr, url); + if (url.isEmpty()) + return InsideUnvisitedLink; + + // If the Qt4.4 interface for the history is used, we will have to fallback + // to the old global history. + QWebHistoryInterface* iface = QWebHistoryInterface::defaultInterface(); + if (iface) + return iface->historyContains(QString(reinterpret_cast<QChar*>(url.data()), url.size())) ? InsideVisitedLink : InsideUnvisitedLink; + + LinkHash hash = visitedLinkHash(url.data(), url.size()); + if (!hash) + return InsideUnvisitedLink; +#else + LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr); + if (!hash) + return InsideUnvisitedLink; +#endif + + Frame* frame = m_document->frame(); + if (!frame) + return InsideUnvisitedLink; + + Page* page = frame->page(); + if (!page) + return InsideUnvisitedLink; + + m_linksCheckedForVisitedState.add(hash); + +#if USE(PLATFORM_STRATEGIES) + return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash) ? InsideVisitedLink : InsideUnvisitedLink; +#else + return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink; +#endif +} + +bool CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* element) const +{ + PseudoId dynamicPseudo = NOPSEUDO; + return checkSelector(sel, element, 0, dynamicPseudo, false, false) == SelectorMatches; +} + +static const unsigned cStyleSearchThreshold = 10; + +Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned depth) const +{ + if (parent && parent->isStyledElement()) { + StyledElement* p = static_cast<StyledElement*>(parent); + if (!p->inlineStyleDecl() && !p->hasID()) { + Node* r = p->previousSibling(); + unsigned subcount = 0; + RenderStyle* st = p->renderStyle(); + while (r) { + if (r->renderStyle() == st) + return r->lastChild(); + if (subcount++ == cStyleSearchThreshold) + return 0; + r = r->previousSibling(); + } + if (!r && depth < cStyleSearchThreshold) + r = locateCousinList(parent->parentElement(), depth + 1); + while (r) { + if (r->renderStyle() == st) + return r->lastChild(); + if (subcount++ == cStyleSearchThreshold) + return 0; + r = r->previousSibling(); + } + } + } + return 0; +} + +bool CSSStyleSelector::canShareStyleWithElement(Node* n) const +{ + if (n->isStyledElement()) { + StyledElement* s = static_cast<StyledElement*>(n); + RenderStyle* style = s->renderStyle(); + if (style && !style->unique() && + (s->tagQName() == m_element->tagQName()) && !s->hasID() && + (s->hasClass() == m_element->hasClass()) && !s->inlineStyleDecl() && + (s->hasMappedAttributes() == m_styledElement->hasMappedAttributes()) && + (s->isLink() == m_element->isLink()) && + !style->affectedByAttributeSelectors() && + (s->hovered() == m_element->hovered()) && + (s->active() == m_element->active()) && + (s->focused() == m_element->focused()) && + (s != s->document()->cssTarget() && m_element != m_element->document()->cssTarget()) && + (s->fastGetAttribute(typeAttr) == m_element->fastGetAttribute(typeAttr)) && + (s->fastGetAttribute(XMLNames::langAttr) == m_element->fastGetAttribute(XMLNames::langAttr)) && + (s->fastGetAttribute(langAttr) == m_element->fastGetAttribute(langAttr)) && + (s->fastGetAttribute(readonlyAttr) == m_element->fastGetAttribute(readonlyAttr)) && + (s->fastGetAttribute(cellpaddingAttr) == m_element->fastGetAttribute(cellpaddingAttr))) { + bool isControl = s->isFormControlElement(); + if (isControl != m_element->isFormControlElement()) + return false; + if (isControl) { + InputElement* thisInputElement = toInputElement(s); + InputElement* otherInputElement = toInputElement(m_element); + if (thisInputElement && otherInputElement) { + if ((thisInputElement->isAutofilled() != otherInputElement->isAutofilled()) || + (thisInputElement->isChecked() != otherInputElement->isChecked()) || + (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate())) + return false; + } else + return false; + + if (s->isEnabledFormControl() != m_element->isEnabledFormControl()) + return false; + + if (s->isDefaultButtonForForm() != m_element->isDefaultButtonForForm()) + return false; + + if (!m_element->document()->containsValidityStyleRules()) + return false; + + bool willValidate = s->willValidate(); + if (willValidate != m_element->willValidate()) + return false; + + if (willValidate && (s->isValidFormControlElement() != m_element->isValidFormControlElement())) + return false; + + if (s->isInRange() != m_element->isInRange()) + return false; + + if (s->isOutOfRange() != m_element->isOutOfRange()) + return false; + } + + if (style->transitions() || style->animations()) + return false; + +#if USE(ACCELERATED_COMPOSITING) + // Turn off style sharing for elements that can gain layers for reasons outside of the style system. + // See comments in RenderObject::setStyle(). + if (s->hasTagName(iframeTag) || s->hasTagName(embedTag) || s->hasTagName(objectTag) || s->hasTagName(appletTag)) + return false; +#endif + + bool classesMatch = true; + if (s->hasClass()) { + const AtomicString& class1 = m_element->fastGetAttribute(classAttr); + const AtomicString& class2 = s->fastGetAttribute(classAttr); + classesMatch = (class1 == class2); + } + + if (classesMatch) { + bool mappedAttrsMatch = true; + if (s->hasMappedAttributes()) + mappedAttrsMatch = s->attributeMap()->mappedMapsEquivalent(m_styledElement->attributeMap()); + if (mappedAttrsMatch) { + if (s->isLink()) { + if (m_elementLinkState != style->insideLink()) + return false; + } + return true; + } + } + } + } + return false; +} + +ALWAYS_INLINE RenderStyle* CSSStyleSelector::locateSharedStyle() const +{ + if (m_styledElement && !m_styledElement->inlineStyleDecl() && !m_styledElement->hasID() && !m_styledElement->document()->usesSiblingRules()) { + // Check previous siblings. + unsigned count = 0; + Node* n; + for (n = m_element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } + while (n) { + if (canShareStyleWithElement(n)) + return n->renderStyle(); + if (count++ == cStyleSearchThreshold) + return 0; + for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } + } + if (!n) + n = locateCousinList(m_element->parentElement()); + while (n) { + if (canShareStyleWithElement(n)) + return n->renderStyle(); + if (count++ == cStyleSearchThreshold) + return 0; + for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } + } + } + return 0; +} + +void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule) +{ + // First we match rules from the user agent sheet. + CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") + ? defaultPrintStyle : defaultStyle; + matchRules(userAgentStyleSheet, firstUARule, lastUARule, false); + + // In quirks mode, we match rules from the quirks user agent sheet. + if (!m_checker.m_strictParsing) + matchRules(defaultQuirksStyle, firstUARule, lastUARule, false); + + // If we're in view source mode, then we match rules from the view source style sheet. + if (m_checker.m_document->frame() && m_checker.m_document->frame()->inViewSourceMode()) { + if (!defaultViewSourceStyle) + loadViewSourceStyle(); + matchRules(defaultViewSourceStyle, firstUARule, lastUARule, false); + } +} + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForDocument(Document* document) +{ + Frame* frame = document->frame(); + + RefPtr<RenderStyle> documentStyle = RenderStyle::create(); + documentStyle->setDisplay(BLOCK); + documentStyle->setVisuallyOrdered(document->visuallyOrdered()); + documentStyle->setZoom(frame ? frame->pageZoomFactor() : 1); + documentStyle->setPageScaleTransform(frame ? frame->pageScaleFactor() : 1); + + Element* docElement = document->documentElement(); + RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0; + if (docElementRenderer) { + // Use the direction and writing-mode of the body to set the + // viewport's direction and writing-mode unless the property is set on the document element. + // If there is no body, then use the document element. + RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0; + if (bodyRenderer && !document->writingModeSetOnDocumentElement()) + documentStyle->setWritingMode(bodyRenderer->style()->writingMode()); + else + documentStyle->setWritingMode(docElementRenderer->style()->writingMode()); + if (bodyRenderer && !document->directionSetOnDocumentElement()) + documentStyle->setDirection(bodyRenderer->style()->direction()); + else + documentStyle->setDirection(docElementRenderer->style()->direction()); + } + + FontDescription fontDescription; + fontDescription.setUsePrinterFont(document->printing()); + if (Settings* settings = document->settings()) { + fontDescription.setRenderingMode(settings->fontRenderingMode()); + if (document->printing() && !settings->shouldPrintBackgrounds()) + documentStyle->setForceBackgroundsToWhite(true); + const AtomicString& stdfont = settings->standardFontFamily(); + if (!stdfont.isEmpty()) { + fontDescription.firstFamily().setFamily(stdfont); + fontDescription.firstFamily().appendFamily(0); + } + fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); + int size = CSSStyleSelector::fontSizeForKeyword(document, CSSValueMedium, false); + fontDescription.setSpecifiedSize(size); + bool useSVGZoomRules = document->isSVGDocument(); + fontDescription.setComputedSize(CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules)); + } + + documentStyle->setFontDescription(fontDescription); + documentStyle->font().update(0); + + return documentStyle.release(); +} + +// If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where +// relative units are interpreted according to document root element style, styled only with UA stylesheet + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault, bool matchVisitedPseudoClass) +{ + // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer + // will vanish if a style recalc happens during loading. + if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) { + if (!s_styleNotYetAvailable) { + s_styleNotYetAvailable = RenderStyle::create().releaseRef(); + s_styleNotYetAvailable->ref(); + s_styleNotYetAvailable->setDisplay(NONE); + s_styleNotYetAvailable->font().update(m_fontSelector); + } + s_styleNotYetAvailable->ref(); + e->document()->setHasNodesWithPlaceholderStyle(); + return s_styleNotYetAvailable; + } + + initElement(e); + if (allowSharing) { + RenderStyle* sharedStyle = locateSharedStyle(); + if (sharedStyle) + return sharedStyle; + } + initForStyleResolve(e, defaultParent); + + // Compute our style allowing :visited to match first. + RefPtr<RenderStyle> visitedStyle; + if (!matchVisitedPseudoClass && m_parentStyle && (m_parentStyle->insideLink() || e->isLink()) && e->document()->usesLinkRules()) { + // Fetch our parent style. + RenderStyle* parentStyle = m_parentStyle; + if (!e->isLink()) { + // Use the parent's visited style if one exists. + RenderStyle* parentVisitedStyle = m_parentStyle->getCachedPseudoStyle(VISITED_LINK); + if (parentVisitedStyle) + parentStyle = parentVisitedStyle; + } + visitedStyle = styleForElement(e, parentStyle, false, false, true); + if (visitedStyle) { + if (m_elementLinkState == InsideUnvisitedLink) + visitedStyle = 0; // We made the style to avoid timing attacks. Just throw it away now that we did that, since we don't need it. + else + visitedStyle->setStyleType(VISITED_LINK); + } + initForStyleResolve(e, defaultParent); + } + + m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; + + m_style = RenderStyle::create(); + + if (m_parentStyle) + m_style->inheritFrom(m_parentStyle); + else + m_parentStyle = style(); + + if (e->isLink()) { + m_style->setIsLink(true); + m_style->setInsideLink(m_elementLinkState); + } + + if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(e)) { + loadFullDefaultStyle(); +#if ENABLE(FULLSCREEN_API) + loadFullScreenRulesIfNeeded(e->document()); +#endif + } + +#if ENABLE(SVG) + static bool loadedSVGUserAgentSheet; + if (e->isSVGElement() && !loadedSVGUserAgentSheet) { + // SVG rules. + loadedSVGUserAgentSheet = true; + CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(svgSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(svgSheet, printEval()); + } +#endif + +#if ENABLE(MATHML) + static bool loadedMathMLUserAgentSheet; + if (e->isMathMLElement() && !loadedMathMLUserAgentSheet) { + // MathML rules. + loadedMathMLUserAgentSheet = true; + CSSStyleSheet* mathMLSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(mathMLSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval()); + } +#endif + +#if ENABLE(WML) + static bool loadedWMLUserAgentSheet; + if (e->isWMLElement() && !loadedWMLUserAgentSheet) { + // WML rules. + loadedWMLUserAgentSheet = true; + CSSStyleSheet* wmlSheet = parseUASheet(wmlUserAgentStyleSheet, sizeof(wmlUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(wmlSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(wmlSheet, printEval()); + } +#endif + +#if ENABLE(VIDEO) + static bool loadedMediaStyleSheet; + if (!loadedMediaStyleSheet && (e->hasTagName(videoTag) || e->hasTagName(audioTag))) { + loadedMediaStyleSheet = true; + String mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(e->document()->page())->extraMediaControlsStyleSheet(); + CSSStyleSheet* mediaControlsSheet = parseUASheet(mediaRules); + defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval()); + } +#endif + + int firstUARule = -1, lastUARule = -1; + int firstUserRule = -1, lastUserRule = -1; + int firstAuthorRule = -1, lastAuthorRule = -1; + matchUARules(firstUARule, lastUARule); + + if (!resolveForRootDefault) { + // 4. Now we check user sheet rules. + if (m_matchAuthorAndUserStyles) + matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false); + + // 5. Now check author rules, beginning first with presentational attributes + // mapped from HTML. + if (m_styledElement) { + // Ask if the HTML element has mapped attributes. + if (m_styledElement->hasMappedAttributes()) { + // Walk our attribute list and add in each decl. + const NamedNodeMap* map = m_styledElement->attributeMap(); + for (unsigned i = 0; i < map->length(); i++) { + Attribute* attr = map->attributeItem(i); + if (attr->isMappedAttribute() && attr->decl()) { + lastAuthorRule = m_matchedDecls.size(); + if (firstAuthorRule == -1) + firstAuthorRule = lastAuthorRule; + addMatchedDeclaration(attr->decl()); + } + } + } + + // Now we check additional mapped declarations. + // Tables and table cells share an additional mapped rule that must be applied + // after all attributes, since their mapped style depends on the values of multiple attributes. + if (m_styledElement->canHaveAdditionalAttributeStyleDecls()) { + m_additionalAttributeStyleDecls.clear(); + m_styledElement->additionalAttributeStyleDecls(m_additionalAttributeStyleDecls); + if (!m_additionalAttributeStyleDecls.isEmpty()) { + unsigned additionalDeclsSize = m_additionalAttributeStyleDecls.size(); + if (firstAuthorRule == -1) + firstAuthorRule = m_matchedDecls.size(); + lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1; + for (unsigned i = 0; i < additionalDeclsSize; i++) + addMatchedDeclaration(m_additionalAttributeStyleDecls[i]); + } + } + } + + // 6. Check the rules in author sheets next. + if (m_matchAuthorAndUserStyles) + matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false); + + // 7. Now check our inline style attribute. + if (m_matchAuthorAndUserStyles && m_styledElement) { + CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl(); + if (inlineDecl) { + lastAuthorRule = m_matchedDecls.size(); + if (firstAuthorRule == -1) + firstAuthorRule = lastAuthorRule; + addMatchedDeclaration(inlineDecl); + } + } + } + + // Reset the value back before applying properties, so that -webkit-link knows what color to use. + m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; + + // Now we have all of the matched rules in the appropriate order. Walk the rules and apply + // high-priority properties first, i.e., those properties that other properties depend on. + // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important + // and (4) normal important. + m_lineHeightValue = 0; + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); + if (!resolveForRootDefault) { + applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule); + applyDeclarations<true>(true, firstUserRule, lastUserRule); + } + applyDeclarations<true>(true, firstUARule, lastUARule); + + // If our font got dirtied, go ahead and update it now. + if (m_fontDirty) + updateFont(); + + // Line-height is set when we are sure we decided on the font-size + if (m_lineHeightValue) + applyProperty(CSSPropertyLineHeight, m_lineHeightValue); + + // Now do the normal priority UA properties. + applyDeclarations<false>(false, firstUARule, lastUARule); + + // Cache our border and background so that we can examine them later. + cacheBorderAndBackground(); + + // Now do the author and user normal priority properties and all the !important properties. + if (!resolveForRootDefault) { + applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1); + applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule); + applyDeclarations<false>(true, firstUserRule, lastUserRule); + } + applyDeclarations<false>(true, firstUARule, lastUARule); + + ASSERT(!m_fontDirty); + // If our font got dirtied by one of the non-essential font props, + // go ahead and update it a second time. + if (m_fontDirty) + updateFont(); + + // Clean up our style object's display and text decorations (among other fixups). + adjustRenderStyle(style(), m_parentStyle, e); + + // Start loading images referenced by this style. + loadPendingImages(); + + // If we have first-letter pseudo style, do not share this style + if (m_style->hasPseudoStyle(FIRST_LETTER)) + m_style->setUnique(); + + if (visitedStyle) { + // Copy any pseudo bits that the visited style has to the primary style so that + // pseudo element styles will continue to work for pseudo elements inside :visited + // links. + for (unsigned pseudo = FIRST_PUBLIC_PSEUDOID; pseudo < FIRST_INTERNAL_PSEUDOID; ++pseudo) { + if (visitedStyle->hasPseudoStyle(static_cast<PseudoId>(pseudo))) + m_style->setHasPseudoStyle(static_cast<PseudoId>(pseudo)); + } + + // Add the visited style off the main style. + m_style->addCachedPseudoStyle(visitedStyle.release()); + } + + if (!matchVisitedPseudoClass) + initElement(0); // Clear out for the next resolve. + + // Now return the style. + return m_style.release(); +} + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeValue& keyframe) +{ + if (keyframeRule->style()) + addMatchedDeclaration(keyframeRule->style()); + + ASSERT(!m_style); + + // Create the style + m_style = RenderStyle::clone(elementStyle); + + m_lineHeightValue = 0; + + // We don't need to bother with !important. Since there is only ever one + // decl, there's nothing to override. So just add the first properties. + if (keyframeRule->style()) + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); + + // If our font got dirtied, go ahead and update it now. + if (m_fontDirty) + updateFont(); + + // Line-height is set when we are sure we decided on the font-size + if (m_lineHeightValue) + applyProperty(CSSPropertyLineHeight, m_lineHeightValue); + + // Now do rest of the properties. + if (keyframeRule->style()) + applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1); + + // If our font got dirtied by one of the non-essential font props, + // go ahead and update it a second time. + if (m_fontDirty) + updateFont(); + + // Start loading images referenced by this style. + loadPendingImages(); + + // Add all the animating properties to the keyframe. + if (keyframeRule->style()) { + CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end(); + for (CSSMutableStyleDeclaration::const_iterator it = keyframeRule->style()->begin(); it != end; ++it) { + int property = (*it).id(); + // Timing-function within keyframes is special, because it is not animated; it just + // describes the timing function between this keyframe and the next. + if (property != CSSPropertyWebkitAnimationTimingFunction) + keyframe.addProperty(property); + } + } + + return m_style.release(); +} + +void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list) +{ + list.clear(); + + // Get the keyframesRule for this name + if (!e || list.animationName().isEmpty()) + return; + + m_keyframesRuleMap.checkConsistency(); + + if (!m_keyframesRuleMap.contains(list.animationName().impl())) + return; + + const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get(); + + // Construct and populate the style for each keyframe + for (unsigned i = 0; i < rule->length(); ++i) { + // Apply the declaration to the style. This is a simplified version of the logic in styleForElement + initElement(e); + initForStyleResolve(e); + + const WebKitCSSKeyframeRule* keyframeRule = rule->item(i); + + KeyframeValue keyframe(0, 0); + keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule, keyframe)); + + // Add this keyframe style to all the indicated key times + Vector<float> keys; + keyframeRule->getKeys(keys); + for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) { + keyframe.setKey(keys[keyIndex]); + list.insert(keyframe); + } + } + + // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe) + int initialListSize = list.size(); + if (initialListSize > 0 && list[0].key() != 0) { + RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); + keyframeRule->setKeyText("0%"); + KeyframeValue keyframe(0, 0); + keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); + list.insert(keyframe); + } + + // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe) + if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) { + RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); + keyframeRule->setKeyText("100%"); + KeyframeValue keyframe(1, 0); + keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); + list.insert(keyframe); + } +} + +PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle, bool matchVisitedPseudoClass) +{ + if (!e) + return 0; + + initElement(e); + + // Compute our :visited style first, so that we know whether or not we'll need to create a normal style just to hang it + // off of. + RefPtr<RenderStyle> visitedStyle; + if (!matchVisitedPseudoClass && parentStyle && parentStyle->insideLink()) { + // Fetch our parent style with :visited in effect. + RenderStyle* parentVisitedStyle = parentStyle->getCachedPseudoStyle(VISITED_LINK); + visitedStyle = pseudoStyleForElement(pseudo, e, parentVisitedStyle ? parentVisitedStyle : parentStyle, true); + if (visitedStyle) { + if (m_elementLinkState == InsideUnvisitedLink) + visitedStyle = 0; // We made the style to avoid timing attacks. Just throw it away now that we did that. + else + visitedStyle->setStyleType(VISITED_LINK); + } + } + + initForStyleResolve(e, parentStyle, pseudo); + m_style = RenderStyle::create(); + if (parentStyle) + m_style->inheritFrom(parentStyle); + + m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; + + // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking + // those rules. + + // Check UA, user and author rules. + int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1; + matchUARules(firstUARule, lastUARule); + + if (m_matchAuthorAndUserStyles) { + matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false); + matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false); + } + + if (m_matchedDecls.isEmpty() && !visitedStyle) + return 0; + + m_style->setStyleType(pseudo); + + m_lineHeightValue = 0; + + // Reset the value back before applying properties, so that -webkit-link knows what color to use. + m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass; + + // High-priority properties. + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); + applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule); + applyDeclarations<true>(true, firstUserRule, lastUserRule); + applyDeclarations<true>(true, firstUARule, lastUARule); + + // If our font got dirtied, go ahead and update it now. + if (m_fontDirty) + updateFont(); + + // Line-height is set when we are sure we decided on the font-size + if (m_lineHeightValue) + applyProperty(CSSPropertyLineHeight, m_lineHeightValue); + + // Now do the normal priority properties. + applyDeclarations<false>(false, firstUARule, lastUARule); + + // Cache our border and background so that we can examine them later. + cacheBorderAndBackground(); + + applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1); + applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule); + applyDeclarations<false>(true, firstUserRule, lastUserRule); + applyDeclarations<false>(true, firstUARule, lastUARule); + + // If our font got dirtied by one of the non-essential font props, + // go ahead and update it a second time. + if (m_fontDirty) + updateFont(); + + // Clean up our style object's display and text decorations (among other fixups). + adjustRenderStyle(style(), parentStyle, 0); + + // Start loading images referenced by this style. + loadPendingImages(); + + // Hang our visited style off m_style. + if (visitedStyle) + m_style->addCachedPseudoStyle(visitedStyle.release()); + + // Now return the style. + return m_style.release(); +} + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForPage(int pageIndex) +{ + initForStyleResolve(m_checker.m_document->documentElement()); // m_rootElementStyle will be set to the document style. + + m_style = RenderStyle::create(); + m_style->inheritFrom(m_rootElementStyle); + + const bool isLeft = isLeftPage(pageIndex); + const bool isFirst = isFirstPage(pageIndex); + const String page = pageName(pageIndex); + matchPageRules(defaultPrintStyle, isLeft, isFirst, page); + matchPageRules(m_userStyle.get(), isLeft, isFirst, page); + matchPageRules(m_authorStyle.get(), isLeft, isFirst, page); + m_lineHeightValue = 0; + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1); + + // If our font got dirtied, go ahead and update it now. + if (m_fontDirty) + updateFont(); + + // Line-height is set when we are sure we decided on the font-size + if (m_lineHeightValue) + applyProperty(CSSPropertyLineHeight, m_lineHeightValue); + + applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1); + + // Start loading images referenced by this style. + loadPendingImages(); + + // Now return the style. + return m_style.release(); +} + +#if ENABLE(DATAGRID) + +PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumn(DataGridColumn*, RenderStyle*) +{ + // FIXME: Implement + return 0; +} + +PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumnHeader(DataGridColumn*, RenderStyle*) +{ + // FIXME: Implement + return 0; +} + +#endif + +static void addIntrinsicMargins(RenderStyle* style) +{ + // Intrinsic margin value. + const int intrinsicMargin = 2 * style->effectiveZoom(); + + // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. + // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame. + if (style->width().isIntrinsicOrAuto()) { + if (style->marginLeft().quirk()) + style->setMarginLeft(Length(intrinsicMargin, Fixed)); + if (style->marginRight().quirk()) + style->setMarginRight(Length(intrinsicMargin, Fixed)); + } + + if (style->height().isAuto()) { + if (style->marginTop().quirk()) + style->setMarginTop(Length(intrinsicMargin, Fixed)); + if (style->marginBottom().quirk()) + style->setMarginBottom(Length(intrinsicMargin, Fixed)); + } +} + +void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e) +{ + // Cache our original display. + style->setOriginalDisplay(style->display()); + + if (style->display() != NONE) { + // If we have a <td> that specifies a float property, in quirks mode we just drop the float + // property. + // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force + // these tags to retain their display types. + if (!m_checker.m_strictParsing && e) { + if (e->hasTagName(tdTag)) { + style->setDisplay(TABLE_CELL); + style->setFloating(FNONE); + } + else if (e->hasTagName(tableTag)) + style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE); + } + + if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) { + if (style->whiteSpace() == KHTML_NOWRAP) { + // Figure out if we are really nowrapping or if we should just + // use normal instead. If the width of the cell is fixed, then + // we don't actually use NOWRAP. + if (style->width().isFixed()) + style->setWhiteSpace(NORMAL); + else + style->setWhiteSpace(NOWRAP); + } + } + + // Tables never support the -webkit-* values for text-align and will reset back to the default. + if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT)) + style->setTextAlign(TAAUTO); + + // Frames and framesets never honor position:relative or position:absolute. This is necessary to + // fix a crash where a site tries to position these objects. They also never honor display. + if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) { + style->setPosition(StaticPosition); + style->setDisplay(BLOCK); + } + + // Table headers with a text-align of auto will change the text-align to center. + if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO) + style->setTextAlign(CENTER); + + if (e && e->hasTagName(legendTag)) + style->setDisplay(BLOCK); + + // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to + // position or float an inline, compact, or run-in. Cache the original display, since it + // may be needed for positioned elements that have to compute their static normal flow + // positions. We also force inline-level roots to be block-level. + if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX && + (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE || + (e && e->document()->documentElement() == e))) { + if (style->display() == INLINE_TABLE) + style->setDisplay(TABLE); + else if (style->display() == INLINE_BOX) + style->setDisplay(BOX); + else if (style->display() == LIST_ITEM) { + // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, + // but only in quirks mode. + if (!m_checker.m_strictParsing && style->floating() != FNONE) + style->setDisplay(BLOCK); + } + else + style->setDisplay(BLOCK); + } + + // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely + // clear how that should work. + if (style->display() == INLINE && style->styleType() == NOPSEUDO && parentStyle && style->writingMode() != parentStyle->writingMode()) + style->setDisplay(INLINE_BLOCK); + + // After performing the display mutation, check table rows. We do not honor position:relative on + // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock() + // on some sites). + if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP || + style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) && + style->position() == RelativePosition) + style->setPosition(StaticPosition); + + // writing-mode does not apply to table row groups, table column groups, table rows, and table columns. + // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though. + if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP + || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP + || style->display() == TABLE_CELL) + style->setWritingMode(parentStyle->writingMode()); + + // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting + // of block-flow to anything other than TopToBottomWritingMode. + // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support. + if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX)) + style->setWritingMode(TopToBottomWritingMode); + } + + // Make sure our z-index value is only applied if the object is positioned. + if (style->position() == StaticPosition) + style->setHasAutoZIndex(); + + // Auto z-index becomes 0 for the root element and transparent objects. This prevents + // cases where objects that should be blended as a single unit end up with a non-transparent + // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections. + if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f || + style->hasTransformRelatedProperty() || style->hasMask() || style->boxReflect())) + style->setZIndex(0); + +#if ENABLE(WML) + if (e && (e->hasTagName(WMLNames::insertedLegendTag) + || e->hasTagName(WMLNames::inputTag)) + && style->width().isAuto()) + style->setWidth(Length(Intrinsic)); +#endif + + // Textarea considers overflow visible as auto. + if (e && e->hasTagName(textareaTag)) { + style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX()); + style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY()); + } + + // Finally update our text decorations in effect, but don't allow text-decoration to percolate through + // tables, inline blocks, inline tables, or run-ins. + if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN + || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX) + style->setTextDecorationsInEffect(style->textDecoration()); + else + style->addToTextDecorationsInEffect(style->textDecoration()); + + // If either overflow value is not visible, change to auto. + if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE) + style->setOverflowY(OMARQUEE); + else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE) + style->setOverflowX(OMARQUEE); + else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) + style->setOverflowX(OAUTO); + else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) + style->setOverflowY(OAUTO); + + // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto. + // FIXME: Eventually table sections will support auto and scroll. + if (style->display() == TABLE || style->display() == INLINE_TABLE || + style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) { + if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) + style->setOverflowX(OVISIBLE); + if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) + style->setOverflowY(OVISIBLE); + } + + // Menulists should have visible overflow + if (style->appearance() == MenulistPart) { + style->setOverflowX(OVISIBLE); + style->setOverflowY(OVISIBLE); + } + + // Cull out any useless layers and also repeat patterns into additional layers. + style->adjustBackgroundLayers(); + style->adjustMaskLayers(); + + // Do the same for animations and transitions. + style->adjustAnimations(); + style->adjustTransitions(); + + // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will + // alter fonts and heights/widths. + if (e && e->isFormControlElement() && style->fontSize() >= 11) { + // Don't apply intrinsic margins to image buttons. The designer knows how big the images are, + // so we have to treat all image buttons as though they were explicitly sized. + if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton()) + addIntrinsicMargins(style); + } + + // Let the theme also have a crack at adjusting the style. + if (style->hasAppearance()) + RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor); + +#if ENABLE(SVG) + if (e && e->isSVGElement()) { + // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty + if (style->overflowY() == OSCROLL) + style->setOverflowY(OHIDDEN); + else if (style->overflowY() == OAUTO) + style->setOverflowY(OVISIBLE); + + if (style->overflowX() == OSCROLL) + style->setOverflowX(OHIDDEN); + else if (style->overflowX() == OAUTO) + style->setOverflowX(OVISIBLE); + + // Only the root <svg> element in an SVG document fragment tree honors css position + if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement())) + style->setPosition(RenderStyle::initialPosition()); + } +#endif +} + +void CSSStyleSelector::updateFont() +{ + checkForTextSizeAdjust(); + checkForGenericFamilyChange(style(), m_parentStyle); + checkForZoomChange(style(), m_parentStyle); + m_style->font().update(m_fontSelector); + m_fontDirty = false; +} + +void CSSStyleSelector::cacheBorderAndBackground() +{ + m_hasUAAppearance = m_style->hasAppearance(); + if (m_hasUAAppearance) { + m_borderData = m_style->border(); + m_backgroundData = *m_style->backgroundLayers(); + m_backgroundColor = m_style->backgroundColor(); + } +} + +PassRefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter) +{ + return pseudoStyleRulesForElement(e, NOPSEUDO, authorOnly, includeEmptyRules, filter); +} + +PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter) +{ + if (!e || !e->document()->haveStylesheetsLoaded()) + return 0; + + m_checker.m_collectRulesOnly = true; + + initElement(e); + initForStyleResolve(e, 0, pseudoId); + + if (!authorOnly) { + int firstUARule = -1, lastUARule = -1; + // First we match rules from the user agent sheet. + matchUARules(firstUARule, lastUARule); + + // Now we check user sheet rules. + if (m_matchAuthorAndUserStyles) { + int firstUserRule = -1, lastUserRule = -1; + matchRules(m_userStyle.get(), firstUserRule, lastUserRule, includeEmptyRules); + } + } + + if (m_matchAuthorAndUserStyles) { + m_checker.m_sameOriginOnly = (filter == SameOriginCSSRulesOnly); + + // Check the rules in author sheets. + int firstAuthorRule = -1, lastAuthorRule = -1; + matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, includeEmptyRules); + + m_checker.m_sameOriginOnly = false; + } + + m_checker.m_collectRulesOnly = false; + + return m_ruleList.release(); +} + +bool CSSStyleSelector::checkSelector(CSSSelector* sel) +{ + m_dynamicPseudo = NOPSEUDO; + + // Check the selector + SelectorMatch match = m_checker.checkSelector(sel, m_element, &m_selectorAttrs, m_dynamicPseudo, false, false, style(), m_parentNode ? m_parentNode->renderStyle() : 0); + if (match != SelectorMatches) + return false; + + if (m_checker.m_pseudoStyle != NOPSEUDO && m_checker.m_pseudoStyle != m_dynamicPseudo) + return false; + + return true; +} + +// Recursive check of selectors and combinators +// It can return 3 different values: +// * SelectorMatches - the selector matches the element e +// * SelectorFailsLocally - the selector fails for the element e +// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e +CSSStyleSelector::SelectorMatch CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const +{ +#if ENABLE(SVG) + // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree + // because its contents are not part of the formal document structure. + if (e->isSVGElement() && e->isShadowRoot()) + return SelectorFailsCompletely; +#endif + + // first selector has to match + if (!checkOneSelector(sel, e, selectorAttrs, dynamicPseudo, isSubSelector, elementStyle, elementParentStyle)) + return SelectorFailsLocally; + + // The rest of the selectors has to match + CSSSelector::Relation relation = sel->relation(); + + // Prepare next sel + sel = sel->tagHistory(); + if (!sel) + return SelectorMatches; + + if (relation != CSSSelector::SubSelector) + // Bail-out if this selector is irrelevant for the pseudoStyle + if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo) + return SelectorFailsCompletely; + + // Check for nested links. + if (m_matchVisitedPseudoClass && !isSubSelector) { + RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle(); + if (currentStyle && currentStyle->insideLink() && e->isLink()) { + if (encounteredLink) + m_matchVisitedPseudoClass = false; // This link is not relevant to the style being resolved, so disable matching. + else + encounteredLink = true; + } + } + + switch (relation) { + case CSSSelector::Descendant: + while (true) { + ContainerNode* n = e->parentNode(); + if (!n || !n->isElementNode()) + return SelectorFailsCompletely; + e = static_cast<Element*>(n); + SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); + if (match != SelectorFailsLocally) + return match; + } + break; + case CSSSelector::Child: + { + ContainerNode* n = e->parentNode(); + if (!n || !n->isElementNode()) + return SelectorFailsCompletely; + e = static_cast<Element*>(n); + return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); + } + case CSSSelector::DirectAdjacent: + { + if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByDirectAdjacentRules(); + } + Node* n = e->previousSibling(); + while (n && !n->isElementNode()) + n = n->previousSibling(); + if (!n) + return SelectorFailsLocally; + e = static_cast<Element*>(n); + m_matchVisitedPseudoClass = false; + return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); + } + case CSSSelector::IndirectAdjacent: + if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByForwardPositionalRules(); + } + while (true) { + Node* n = e->previousSibling(); + while (n && !n->isElementNode()) + n = n->previousSibling(); + if (!n) + return SelectorFailsLocally; + e = static_cast<Element*>(n); + m_matchVisitedPseudoClass = false; + SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink); + if (match != SelectorFailsLocally) + return match; + }; + break; + case CSSSelector::SubSelector: + // a selector is invalid if something follows a pseudo-element + // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else) + // to follow the pseudo elements. + if ((elementStyle || m_collectRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION && + !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass)) + return SelectorFailsCompletely; + return checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle); + } + + return SelectorFailsCompletely; +} + +static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName) +{ + set->add(qName.localName().impl()); +} + +static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet() +{ + // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive + // Mozilla treats all other values as case-sensitive, thus so do we. + HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>; + + addLocalNameToSet(attrSet, accept_charsetAttr); + addLocalNameToSet(attrSet, acceptAttr); + addLocalNameToSet(attrSet, alignAttr); + addLocalNameToSet(attrSet, alinkAttr); + addLocalNameToSet(attrSet, axisAttr); + addLocalNameToSet(attrSet, bgcolorAttr); + addLocalNameToSet(attrSet, charsetAttr); + addLocalNameToSet(attrSet, checkedAttr); + addLocalNameToSet(attrSet, clearAttr); + addLocalNameToSet(attrSet, codetypeAttr); + addLocalNameToSet(attrSet, colorAttr); + addLocalNameToSet(attrSet, compactAttr); + addLocalNameToSet(attrSet, declareAttr); + addLocalNameToSet(attrSet, deferAttr); + addLocalNameToSet(attrSet, dirAttr); + addLocalNameToSet(attrSet, disabledAttr); + addLocalNameToSet(attrSet, enctypeAttr); + addLocalNameToSet(attrSet, faceAttr); + addLocalNameToSet(attrSet, frameAttr); + addLocalNameToSet(attrSet, hreflangAttr); + addLocalNameToSet(attrSet, http_equivAttr); + addLocalNameToSet(attrSet, langAttr); + addLocalNameToSet(attrSet, languageAttr); + addLocalNameToSet(attrSet, linkAttr); + addLocalNameToSet(attrSet, mediaAttr); + addLocalNameToSet(attrSet, methodAttr); + addLocalNameToSet(attrSet, multipleAttr); + addLocalNameToSet(attrSet, nohrefAttr); + addLocalNameToSet(attrSet, noresizeAttr); + addLocalNameToSet(attrSet, noshadeAttr); + addLocalNameToSet(attrSet, nowrapAttr); + addLocalNameToSet(attrSet, readonlyAttr); + addLocalNameToSet(attrSet, relAttr); + addLocalNameToSet(attrSet, revAttr); + addLocalNameToSet(attrSet, rulesAttr); + addLocalNameToSet(attrSet, scopeAttr); + addLocalNameToSet(attrSet, scrollingAttr); + addLocalNameToSet(attrSet, selectedAttr); + addLocalNameToSet(attrSet, shapeAttr); + addLocalNameToSet(attrSet, targetAttr); + addLocalNameToSet(attrSet, textAttr); + addLocalNameToSet(attrSet, typeAttr); + addLocalNameToSet(attrSet, valignAttr); + addLocalNameToSet(attrSet, valuetypeAttr); + addLocalNameToSet(attrSet, vlinkAttr); + + return attrSet; +} + +static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr) +{ + static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); + bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom); + return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl()); +} + +bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const +{ + ASSERT(e); + if (!e) + return false; + + if (sel->hasTag()) { + const AtomicString& selLocalName = sel->m_tag.localName(); + if (selLocalName != starAtom && selLocalName != e->localName()) + return false; + const AtomicString& selNS = sel->m_tag.namespaceURI(); + if (selNS != starAtom && selNS != e->namespaceURI()) + return false; + } + + if (sel->hasAttribute()) { + if (sel->m_match == CSSSelector::Class) + return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->m_value); + + if (sel->m_match == CSSSelector::Id) + return e->hasID() && e->idForStyleResolution() == sel->m_value; + + const QualifiedName& attr = sel->attribute(); + + // FIXME: Handle the case were elementStyle is 0. + if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr))) { + elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style. + if (selectorAttrs) + selectorAttrs->add(attr.localName().impl()); + } + + const AtomicString& value = e->getAttribute(attr); + if (value.isNull()) + return false; // attribute is not set + + bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr); + + switch (sel->m_match) { + case CSSSelector::Exact: + if (caseSensitive ? sel->m_value != value : !equalIgnoringCase(sel->m_value, value)) + return false; + break; + case CSSSelector::List: + { + // Ignore empty selectors or selectors containing spaces + if (sel->m_value.contains(' ') || sel->m_value.isEmpty()) + return false; + + unsigned startSearchAt = 0; + while (true) { + size_t foundPos = value.find(sel->m_value, startSearchAt, caseSensitive); + if (foundPos == notFound) + return false; + if (foundPos == 0 || value[foundPos - 1] == ' ') { + unsigned endStr = foundPos + sel->m_value.length(); + if (endStr == value.length() || value[endStr] == ' ') + break; // We found a match. + } + + // No match. Keep looking. + startSearchAt = foundPos + 1; + } + break; + } + case CSSSelector::Contain: + if (!value.contains(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) + return false; + break; + case CSSSelector::Begin: + if (!value.startsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) + return false; + break; + case CSSSelector::End: + if (!value.endsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) + return false; + break; + case CSSSelector::Hyphen: + if (value.length() < sel->m_value.length()) + return false; + if (!value.startsWith(sel->m_value, caseSensitive)) + return false; + // It they start the same, check for exact match or following '-': + if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-') + return false; + break; + case CSSSelector::PseudoClass: + case CSSSelector::PseudoElement: + default: + break; + } + } + + if (sel->m_match == CSSSelector::PseudoClass) { + // Handle :not up front. + if (sel->pseudoType() == CSSSelector::PseudoNot) { + // check the simple selector + for (CSSSelector* subSel = sel->simpleSelector(); subSel; subSel = subSel->tagHistory()) { + // :not cannot nest. I don't really know why this is a + // restriction in CSS3, but it is, so let's honor it. + // the parser enforces that this never occurs + ASSERT(!subSel->simpleSelector()); + + if (!checkOneSelector(subSel, e, selectorAttrs, dynamicPseudo, true, elementStyle, elementParentStyle)) + return true; + } + } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) { + // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each + // (since there are no elements involved). + return checkScrollbarPseudoClass(sel, dynamicPseudo); + } else if (dynamicPseudo == SELECTION) { + if (sel->pseudoType() == CSSSelector::PseudoWindowInactive) + return !m_document->page()->focusController()->isActive(); + } + + // Normal element pseudo class checking. + switch (sel->pseudoType()) { + // Pseudo classes: + case CSSSelector::PseudoNot: + break; // Already handled up above. + case CSSSelector::PseudoEmpty: { + bool result = true; + for (Node* n = e->firstChild(); n; n = n->nextSibling()) { + if (n->isElementNode()) { + result = false; + break; + } else if (n->isTextNode()) { + Text* textNode = static_cast<Text*>(n); + if (!textNode->data().isEmpty()) { + result = false; + break; + } + } + } + if (!m_collectRulesOnly) { + if (elementStyle) + elementStyle->setEmptyState(result); + else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique())) + e->renderStyle()->setEmptyState(result); + } + return result; + } + case CSSSelector::PseudoFirstChild: { + // first-child matches the first child that is an element + if (e->parentNode() && e->parentNode()->isElementNode()) { + bool result = false; + Node* n = e->previousSibling(); + while (n && !n->isElementNode()) + n = n->previousSibling(); + if (!n) + result = true; + if (!m_collectRulesOnly) { + RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); + RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByFirstChildRules(); + if (result && childStyle) + childStyle->setFirstChildState(); + } + return result; + } + break; + } + case CSSSelector::PseudoFirstOfType: { + // first-of-type matches the first element of its type + if (e->parentNode() && e->parentNode()->isElementNode()) { + bool result = false; + const QualifiedName& type = e->tagQName(); + Node* n = e->previousSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + break; + n = n->previousSibling(); + } + if (!n) + result = true; + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByForwardPositionalRules(); + } + return result; + } + break; + } + case CSSSelector::PseudoLastChild: { + // last-child matches the last child that is an element + if (Element* parentElement = e->parentElement()) { + bool result = false; + if (parentElement->isFinishedParsingChildren()) { + Node* n = e->nextSibling(); + while (n && !n->isElementNode()) + n = n->nextSibling(); + if (!n) + result = true; + } + if (!m_collectRulesOnly) { + RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByLastChildRules(); + if (result && childStyle) + childStyle->setLastChildState(); + } + return result; + } + break; + } + case CSSSelector::PseudoLastOfType: { + // last-of-type matches the last element of its type + if (Element* parentElement = e->parentElement()) { + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByBackwardPositionalRules(); + } + if (!parentElement->isFinishedParsingChildren()) + return false; + bool result = false; + const QualifiedName& type = e->tagQName(); + Node* n = e->nextSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + break; + n = n->nextSibling(); + } + if (!n) + result = true; + return result; + } + break; + } + case CSSSelector::PseudoOnlyChild: { + if (Element* parentElement = e->parentElement()) { + bool firstChild = false; + bool lastChild = false; + + Node* n = e->previousSibling(); + while (n && !n->isElementNode()) + n = n->previousSibling(); + if (!n) + firstChild = true; + if (firstChild && parentElement->isFinishedParsingChildren()) { + n = e->nextSibling(); + while (n && !n->isElementNode()) + n = n->nextSibling(); + if (!n) + lastChild = true; + } + if (!m_collectRulesOnly) { + RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) { + parentStyle->setChildrenAffectedByFirstChildRules(); + parentStyle->setChildrenAffectedByLastChildRules(); + } + if (firstChild && childStyle) + childStyle->setFirstChildState(); + if (lastChild && childStyle) + childStyle->setLastChildState(); + } + return firstChild && lastChild; + } + break; + } + case CSSSelector::PseudoOnlyOfType: { + // FIXME: This selector is very slow. + if (Element* parentElement = e->parentElement()) { + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) { + parentStyle->setChildrenAffectedByForwardPositionalRules(); + parentStyle->setChildrenAffectedByBackwardPositionalRules(); + } + } + if (!parentElement->isFinishedParsingChildren()) + return false; + bool firstChild = false; + bool lastChild = false; + const QualifiedName& type = e->tagQName(); + Node* n = e->previousSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + break; + n = n->previousSibling(); + } + if (!n) + firstChild = true; + if (firstChild) { + n = e->nextSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + break; + n = n->nextSibling(); + } + if (!n) + lastChild = true; + } + return firstChild && lastChild; + } + break; + } + case CSSSelector::PseudoNthChild: { + if (!sel->parseNth()) + break; + if (Element* parentElement = e->parentElement()) { + int count = 1; + Node* n = e->previousSibling(); + while (n) { + if (n->isElementNode()) { + RenderStyle* s = n->renderStyle(); + unsigned index = s ? s->childIndex() : 0; + if (index) { + count += index; + break; + } + count++; + } + n = n->previousSibling(); + } + + if (!m_collectRulesOnly) { + RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (childStyle) + childStyle->setChildIndex(count); + if (parentStyle) + parentStyle->setChildrenAffectedByForwardPositionalRules(); + } + + if (sel->matchNth(count)) + return true; + } + break; + } + case CSSSelector::PseudoNthOfType: { + if (!sel->parseNth()) + break; + if (Element* parentElement = e->parentElement()) { + int count = 1; + const QualifiedName& type = e->tagQName(); + Node* n = e->previousSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + count++; + n = n->previousSibling(); + } + + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByForwardPositionalRules(); + } + + if (sel->matchNth(count)) + return true; + } + break; + } + case CSSSelector::PseudoNthLastChild: { + if (!sel->parseNth()) + break; + if (Element* parentElement = e->parentElement()) { + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByBackwardPositionalRules(); + } + if (!parentElement->isFinishedParsingChildren()) + return false; + int count = 1; + Node* n = e->nextSibling(); + while (n) { + if (n->isElementNode()) + count++; + n = n->nextSibling(); + } + if (sel->matchNth(count)) + return true; + } + break; + } + case CSSSelector::PseudoNthLastOfType: { + if (!sel->parseNth()) + break; + if (Element* parentElement = e->parentElement()) { + if (!m_collectRulesOnly) { + RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle(); + if (parentStyle) + parentStyle->setChildrenAffectedByBackwardPositionalRules(); + } + if (!parentElement->isFinishedParsingChildren()) + return false; + int count = 1; + const QualifiedName& type = e->tagQName(); + Node* n = e->nextSibling(); + while (n) { + if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) + count++; + n = n->nextSibling(); + } + if (sel->matchNth(count)) + return true; + } + break; + } + case CSSSelector::PseudoTarget: + if (e == e->document()->cssTarget()) + return true; + break; + case CSSSelector::PseudoAnyLink: + if (e && e->isLink()) + return true; + break; + case CSSSelector::PseudoAutofill: { + if (!e || !e->isFormControlElement()) + break; + if (InputElement* inputElement = toInputElement(e)) + return inputElement->isAutofilled(); + break; + } + case CSSSelector::PseudoLink: + if (e && e->isLink()) + return !m_matchVisitedPseudoClass; + break; + case CSSSelector::PseudoVisited: + if (e && e->isLink()) + return m_matchVisitedPseudoClass; + break; + case CSSSelector::PseudoDrag: { + if (elementStyle) + elementStyle->setAffectedByDragRules(true); + else if (e->renderStyle()) + e->renderStyle()->setAffectedByDragRules(true); + if (e->renderer() && e->renderer()->isDragging()) + return true; + break; + } + case CSSSelector::PseudoFocus: + if (e && e->focused() && e->document()->frame() && e->document()->frame()->selection()->isFocusedAndActive()) + return true; + break; + case CSSSelector::PseudoHover: { + // If we're in quirks mode, then hover should never match anchors with no + // href and *:hover should not match anything. This is important for sites like wsj.com. + if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { + if (elementStyle) + elementStyle->setAffectedByHoverRules(true); + else if (e->renderStyle()) + e->renderStyle()->setAffectedByHoverRules(true); + if (e->hovered()) + return true; + } + break; + } + case CSSSelector::PseudoActive: + // If we're in quirks mode, then :active should never match anchors with no + // href and *:active should not match anything. + if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { + if (elementStyle) + elementStyle->setAffectedByActiveRules(true); + else if (e->renderStyle()) + e->renderStyle()->setAffectedByActiveRules(true); + if (e->active()) + return true; + } + break; + case CSSSelector::PseudoEnabled: + if (e && e->isFormControlElement()) + return e->isEnabledFormControl(); + break; + case CSSSelector::PseudoFullPageMedia: + return e && e->document() && e->document()->isMediaDocument(); + break; + case CSSSelector::PseudoDefault: + return e && e->isDefaultButtonForForm(); + case CSSSelector::PseudoDisabled: + if (e && e->isFormControlElement()) + return !e->isEnabledFormControl(); + break; + case CSSSelector::PseudoReadOnly: { + if (!e || !e->isFormControlElement()) + return false; + return e->isTextFormControl() && e->isReadOnlyFormControl(); + } + case CSSSelector::PseudoReadWrite: { + if (!e || !e->isFormControlElement()) + return false; + return e->isTextFormControl() && !e->isReadOnlyFormControl(); + } + case CSSSelector::PseudoOptional: + return e && e->isOptionalFormControl(); + case CSSSelector::PseudoRequired: + return e && e->isRequiredFormControl(); + case CSSSelector::PseudoValid: { + if (!e) + return false; + e->document()->setContainsValidityStyleRules(); + return e->willValidate() && e->isValidFormControlElement(); + } case CSSSelector::PseudoInvalid: { + if (!e) + return false; + e->document()->setContainsValidityStyleRules(); + return (e->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue(); + } case CSSSelector::PseudoChecked: { + if (!e || !e->isFormControlElement()) + break; + // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that + // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just + // obey the CSS spec here in the test for matching the pseudo. + InputElement* inputElement = toInputElement(e); + if (inputElement && inputElement->isChecked() && !inputElement->isIndeterminate()) + return true; + break; + } + case CSSSelector::PseudoIndeterminate: { + if (!e || !e->isFormControlElement()) + break; + InputElement* inputElement = toInputElement(e); + if (inputElement && inputElement->isIndeterminate()) + return true; + break; + } + case CSSSelector::PseudoRoot: + if (e == e->document()->documentElement()) + return true; + break; + case CSSSelector::PseudoLang: { + AtomicString value = e->computeInheritedLanguage(); + const AtomicString& argument = sel->argument(); + if (value.isEmpty() || !value.startsWith(argument, false)) + break; + if (value.length() != argument.length() && value[argument.length()] != '-') + break; + return true; + } +#if ENABLE(FULLSCREEN_API) + case CSSSelector::PseudoFullScreen: + // While a Document is in the fullscreen state, and the document's current fullscreen + // element is an element in the document, the 'full-screen' pseudoclass applies to + // that element. Also, an <iframe>, <object> or <embed> element whose child browsing + // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied. + if (!e->document()->webkitIsFullScreen()) + return false; + if (e != e->document()->webkitCurrentFullScreenElement()) + return false; + return true; + case CSSSelector::PseudoFullScreenDocument: + // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies + // to all elements of that Document. + if (!e->document()->webkitIsFullScreen()) + return false; + return true; +#endif + case CSSSelector::PseudoInRange: + if (!e) + return false; + e->document()->setContainsValidityStyleRules(); + return e->isInRange(); + case CSSSelector::PseudoOutOfRange: + if (!e) + return false; + e->document()->setContainsValidityStyleRules(); + return e->isOutOfRange(); + case CSSSelector::PseudoUnknown: + case CSSSelector::PseudoNotParsed: + default: + ASSERT_NOT_REACHED(); + break; + } + return false; + } + if (sel->m_match == CSSSelector::PseudoElement) { + if (!elementStyle && !m_collectRulesOnly) + return false; + + PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType()); + if (pseudoId == FIRST_LETTER) { + if (Document* document = e->document()) + document->setUsesFirstLetterRules(true); + } + if (pseudoId != NOPSEUDO) { + dynamicPseudo = pseudoId; + return true; + } + ASSERT_NOT_REACHED(); + return false; + } + // ### add the rest of the checks... + return true; +} + +bool CSSStyleSelector::SelectorChecker::checkScrollbarPseudoClass(CSSSelector* sel, PseudoId&) const +{ + RenderScrollbar* scrollbar = RenderScrollbar::scrollbarForStyleResolve(); + ScrollbarPart part = RenderScrollbar::partForStyleResolve(); + + // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real + // pseudo class and just apply to everything. + if (sel->pseudoType() == CSSSelector::PseudoWindowInactive) + return !m_document->page()->focusController()->isActive(); + + if (!scrollbar) + return false; + + ASSERT(sel->m_match == CSSSelector::PseudoClass); + switch (sel->pseudoType()) { + case CSSSelector::PseudoEnabled: + return scrollbar->enabled(); + case CSSSelector::PseudoDisabled: + return !scrollbar->enabled(); + case CSSSelector::PseudoHover: { + ScrollbarPart hoveredPart = scrollbar->hoveredPart(); + if (part == ScrollbarBGPart) + return hoveredPart != NoPart; + if (part == TrackBGPart) + return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart; + return part == hoveredPart; + } + case CSSSelector::PseudoActive: { + ScrollbarPart pressedPart = scrollbar->pressedPart(); + if (part == ScrollbarBGPart) + return pressedPart != NoPart; + if (part == TrackBGPart) + return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart; + return part == pressedPart; + } + case CSSSelector::PseudoHorizontal: + return scrollbar->orientation() == HorizontalScrollbar; + case CSSSelector::PseudoVertical: + return scrollbar->orientation() == VerticalScrollbar; + case CSSSelector::PseudoDecrement: + return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart; + case CSSSelector::PseudoIncrement: + return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart; + case CSSSelector::PseudoStart: + return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart; + case CSSSelector::PseudoEnd: + return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart; + case CSSSelector::PseudoDoubleButton: { + ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement(); + if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart) + return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth; + if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth; + return false; + } + case CSSSelector::PseudoSingleButton: { + ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement(); + if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsSingle; + return false; + } + case CSSSelector::PseudoNoButton: { + ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement(); + if (part == BackTrackPart) + return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd; + if (part == ForwardTrackPart) + return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart; + return false; + } + case CSSSelector::PseudoCornerPresent: + return scrollbar->client()->scrollbarCornerPresent(); + default: + return false; + } +} + +// ----------------------------------------------------------------- + +CSSRuleSet::CSSRuleSet() + : m_ruleCount(0) + , m_pageRuleCount(0) +{ +} + +CSSRuleSet::~CSSRuleSet() +{ + deleteAllValues(m_idRules); + deleteAllValues(m_classRules); + deleteAllValues(m_tagRules); +} + + +void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, + CSSStyleRule* rule, CSSSelector* sel) +{ + if (!key) return; + CSSRuleDataList* rules = map.get(key); + if (!rules) { + rules = new CSSRuleDataList(m_ruleCount++, rule, sel); + map.set(key, rules); + } else + rules->append(m_ruleCount++, rule, sel); +} + +void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel) +{ + if (sel->m_match == CSSSelector::Id) { + addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel); + return; + } + if (sel->m_match == CSSSelector::Class) { + addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel); + return; + } + + const AtomicString& localName = sel->m_tag.localName(); + if (localName != starAtom) { + addToRuleSet(localName.impl(), m_tagRules, rule, sel); + return; + } + + // Just put it in the universal rule set. + if (!m_universalRules) + m_universalRules = adoptPtr(new CSSRuleDataList(m_ruleCount++, rule, sel)); + else + m_universalRules->append(m_ruleCount++, rule, sel); +} + +void CSSRuleSet::addPageRule(CSSStyleRule* rule, CSSSelector* sel) +{ + if (!m_pageRules) + m_pageRules = adoptPtr(new CSSRuleDataList(m_pageRuleCount++, rule, sel)); + else + m_pageRules->append(m_pageRuleCount++, rule, sel); +} + +void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector) +{ + if (!sheet) + return; + + // No media implies "all", but if a media list exists it must + // contain our current medium + if (sheet->media() && !medium.eval(sheet->media(), styleSelector)) + return; // the style sheet doesn't apply + + int len = sheet->length(); + + for (int i = 0; i < len; i++) { + StyleBase* item = sheet->item(i); + if (item->isStyleRule()) + addStyleRule(static_cast<CSSStyleRule*>(item)); + else if (item->isImportRule()) { + CSSImportRule* import = static_cast<CSSImportRule*>(item); + if (!import->media() || medium.eval(import->media(), styleSelector)) + addRulesFromSheet(import->styleSheet(), medium, styleSelector); + } + else if (item->isMediaRule()) { + CSSMediaRule* r = static_cast<CSSMediaRule*>(item); + CSSRuleList* rules = r->cssRules(); + + if ((!r->media() || medium.eval(r->media(), styleSelector)) && rules) { + // Traverse child elements of the @media rule. + for (unsigned j = 0; j < rules->length(); j++) { + CSSRule *childItem = rules->item(j); + if (childItem->isStyleRule()) { + // It is a StyleRule, so append it to our list + addStyleRule(static_cast<CSSStyleRule*>(childItem)); + } else if (childItem->isFontFaceRule() && styleSelector) { + // Add this font face to our set. + const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(childItem); + styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); + } else if (childItem->isKeyframesRule() && styleSelector) { + // Add this keyframe rule to our set. + styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(childItem)); + } + } // for rules + } // if rules + } else if (item->isFontFaceRule() && styleSelector) { + // Add this font face to our set. + const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item); + styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); + } else if (item->isKeyframesRule()) + styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(item)); + } +} + +void CSSRuleSet::addStyleRule(CSSStyleRule* rule) +{ + if (rule->isPageRule()) { + CSSPageRule* pageRule = static_cast<CSSPageRule*>(rule); + addPageRule(pageRule, pageRule->selectorList().first()); + } else { + for (CSSSelector* s = rule->selectorList().first(); s; s = CSSSelectorList::next(s)) + addRule(rule, s); + } +} + +// ------------------------------------------------------------------------------------- +// this is mostly boring stuff on how to apply a certain rule to the renderstyle... + +static Length convertToLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0) +{ + // This function is tolerant of a null style value. The only place style is used is in + // length measurements, like 'ems' and 'px'. And in those cases style is only used + // when the units are EMS or EXS. So we will just fail in those cases. + Length l; + if (!primitiveValue) { + if (ok) + *ok = false; + } else { + int type = primitiveValue->primitiveType(); + + if (!style && (type == CSSPrimitiveValue::CSS_EMS || type == CSSPrimitiveValue::CSS_EXS || type == CSSPrimitiveValue::CSS_REMS)) { + if (ok) + *ok = false; + } else if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style, rootStyle, multiplier), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else if (type == CSSPrimitiveValue::CSS_NUMBER) + l = Length(primitiveValue->getDoubleValue() * 100.0, Percent); + else if (ok) + *ok = false; + } + return l; +} + +template <bool applyFirst> +void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex) +{ + if (startIndex == -1) + return; + + for (int i = startIndex; i <= endIndex; i++) { + CSSMutableStyleDeclaration* decl = m_matchedDecls[i]; + CSSMutableStyleDeclaration::const_iterator end = decl->end(); + for (CSSMutableStyleDeclaration::const_iterator it = decl->begin(); it != end; ++it) { + const CSSProperty& current = *it; + if (isImportant == current.isImportant()) { + int property = current.id(); + + if (applyFirst) { + COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property); + COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 13, CSS_zoom_is_end_of_first_prop_range); + COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom); + + // give special priority to font-xxx, color properties, etc + if (property <= CSSPropertyLineHeight) { + // we apply line-height later + if (property == CSSPropertyLineHeight) + m_lineHeightValue = current.value(); + else + applyProperty(current.id(), current.value()); + } + } else { + if (property > CSSPropertyLineHeight) + applyProperty(current.id(), current.value()); + } + } + } + } +} + +void CSSStyleSelector::matchPageRules(CSSRuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName) +{ + m_matchedRules.clear(); + + if (!rules) + return; + + matchPageRulesForList(rules->getPageRules(), isLeftPage, isFirstPage, pageName); + + // If we didn't match any rules, we're done. + if (m_matchedRules.isEmpty()) + return; + + // Sort the set of matched rules. + sortMatchedRules(0, m_matchedRules.size()); + + // Now transfer the set of matched rules over to our list of decls. + for (unsigned i = 0; i < m_matchedRules.size(); i++) + addMatchedDeclaration(m_matchedRules[i]->rule()->declaration()); +} + +void CSSStyleSelector::matchPageRulesForList(CSSRuleDataList* rules, bool isLeftPage, bool isFirstPage, const String& pageName) +{ + if (!rules) + return; + + for (CSSRuleData* d = rules->first(); d; d = d->next()) { + CSSStyleRule* rule = d->rule(); + const AtomicString& selectorLocalName = d->selector()->m_tag.localName(); + if (selectorLocalName != starAtom && selectorLocalName != pageName) + continue; + CSSSelector::PseudoType pseudoType = d->selector()->pseudoType(); + if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage) + || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage) + || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage)) + continue; + + // If the rule has no properties to apply, then ignore it. + CSSMutableStyleDeclaration* decl = rule->declaration(); + if (!decl || !decl->length()) + continue; + + // Add this rule to our list of matched rules. + addMatchedRule(d); + } +} + +bool CSSStyleSelector::isLeftPage(int pageIndex) const +{ + bool isFirstPageLeft = false; + if (!m_rootElementStyle->isLeftToRightDirection()) + isFirstPageLeft = true; + + return (pageIndex + (isFirstPageLeft ? 1 : 0)) % 2; +} + +bool CSSStyleSelector::isFirstPage(int pageIndex) const +{ + // FIXME: In case of forced left/right page, page at index 1 (not 0) can be the first page. + return (!pageIndex); +} + +String CSSStyleSelector::pageName(int /* pageIndex */) const +{ + // FIXME: Implement page index to page name mapping. + return ""; +} + +static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset) +{ + CounterDirectiveMap& map = style->accessCounterDirectives(); + typedef CounterDirectiveMap::iterator Iterator; + + Iterator end = map.end(); + for (Iterator it = map.begin(); it != end; ++it) + if (isReset) + it->second.m_reset = false; + else + it->second.m_increment = false; + + int length = list ? list->length() : 0; + for (int i = 0; i < length; ++i) { + CSSValue* currValue = list->itemWithoutBoundsCheck(i); + if (!currValue->isPrimitiveValue()) + continue; + + Pair* pair = static_cast<CSSPrimitiveValue*>(currValue)->getPairValue(); + if (!pair || !pair->first() || !pair->second()) + continue; + + AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue(); + // FIXME: What about overflow? + int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue(); + CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second; + if (isReset) { + directives.m_reset = true; + directives.m_resetValue = value; + } else { + if (directives.m_increment) + directives.m_incrementValue += value; + else { + directives.m_increment = true; + directives.m_incrementValue = value; + } + } + } +} + +void CSSStyleSelector::applyPropertyToStyle(int id, CSSValue *value, RenderStyle* style) +{ + initElement(0); + initForStyleResolve(0, style); + m_style = style; + if (value) + applyProperty(id, value); +} + +inline bool isValidVisitedLinkProperty(int id) +{ + switch(static_cast<CSSPropertyID>(id)) { + case CSSPropertyBackgroundColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderTopColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyColor: + case CSSPropertyOutlineColor: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextFillColor: + case CSSPropertyWebkitTextStrokeColor: + // Also allow shorthands so that inherit/initial still work. + case CSSPropertyBackground: + case CSSPropertyBorderLeft: + case CSSPropertyBorderRight: + case CSSPropertyBorderTop: + case CSSPropertyBorderBottom: + case CSSPropertyOutline: + case CSSPropertyWebkitColumnRule: +#if ENABLE(SVG) + case CSSPropertyFill: + case CSSPropertyStroke: +#endif + return true; + default: + break; + } + + return false; +} + +void CSSStyleSelector::applyProperty(int id, CSSValue *value) +{ + CSSPrimitiveValue* primitiveValue = 0; + if (value->isPrimitiveValue()) + primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + float zoomFactor = m_style->effectiveZoom(); + + // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead + // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*() + // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that. + // Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...) + // need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like + // width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale, + // if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific + // properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size). + bool useSVGZoomRules = m_element && m_element->isSVGElement(); + + Length l; + bool apply = false; + + unsigned short valueType = value->cssValueType(); + + bool isInherit = m_parentNode && valueType == CSSValue::CSS_INHERIT; + bool isInitial = valueType == CSSValue::CSS_INITIAL || (!m_parentNode && valueType == CSSValue::CSS_INHERIT); + + id = CSSProperty::resolveDirectionAwareProperty(id, m_style->direction(), m_style->writingMode()); + + if (m_checker.m_matchVisitedPseudoClass && !isValidVisitedLinkProperty(id)) { + // Limit the properties that can be applied to only the ones honored by :visited. + return; + } + + // What follows is a list that maps the CSS properties into their corresponding front-end + // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and + // are only hit when mapping "inherit" or "initial" into front-end values. + CSSPropertyID property = static_cast<CSSPropertyID>(id); + switch (property) { +// ident only properties + case CSSPropertyBackgroundAttachment: + HANDLE_BACKGROUND_VALUE(attachment, Attachment, value) + return; + case CSSPropertyBackgroundClip: + case CSSPropertyWebkitBackgroundClip: + HANDLE_BACKGROUND_VALUE(clip, Clip, value) + return; + case CSSPropertyWebkitBackgroundComposite: + HANDLE_BACKGROUND_VALUE(composite, Composite, value) + return; + case CSSPropertyBackgroundOrigin: + case CSSPropertyWebkitBackgroundOrigin: + HANDLE_BACKGROUND_VALUE(origin, Origin, value) + return; + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + HANDLE_BACKGROUND_VALUE(size, Size, value) + return; + case CSSPropertyWebkitMaskAttachment: + HANDLE_MASK_VALUE(attachment, Attachment, value) + return; + case CSSPropertyWebkitMaskClip: + HANDLE_MASK_VALUE(clip, Clip, value) + return; + case CSSPropertyWebkitMaskComposite: + HANDLE_MASK_VALUE(composite, Composite, value) + return; + case CSSPropertyWebkitMaskOrigin: + HANDLE_MASK_VALUE(origin, Origin, value) + return; + case CSSPropertyWebkitMaskSize: + HANDLE_MASK_VALUE(size, Size, value) + return; + case CSSPropertyBorderCollapse: + HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse) + if (!primitiveValue) + return; + switch (primitiveValue->getIdent()) { + case CSSValueCollapse: + m_style->setBorderCollapse(true); + break; + case CSSValueSeparate: + m_style->setBorderCollapse(false); + break; + default: + return; + } + return; + case CSSPropertyBorderTopStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle) + return; + case CSSPropertyBorderRightStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle) + return; + case CSSPropertyBorderBottomStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle) + return; + case CSSPropertyBorderLeftStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle) + return; + case CSSPropertyOutlineStyle: + HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle) + if (primitiveValue) { + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setOutlineStyle(DOTTED, true); + else + m_style->setOutlineStyle(*primitiveValue); + } + return; + case CSSPropertyCaptionSide: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(captionSide, CaptionSide) + return; + case CSSPropertyClear: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(clear, Clear) + return; + case CSSPropertyDirection: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(direction, Direction) + if (!isInherit && !isInitial && m_element && m_element == m_element->document()->documentElement()) + m_element->document()->setDirectionSetOnDocumentElement(true); + return; + case CSSPropertyDisplay: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(display, Display) +#if ENABLE(WCSS) + if (primitiveValue) { + if (primitiveValue->getIdent() == CSSValueWapMarquee) { + // Initialize WAP Marquee style + m_style->setOverflowX(OMARQUEE); + m_style->setOverflowY(OMARQUEE); + m_style->setWhiteSpace(NOWRAP); + m_style->setMarqueeDirection(MLEFT); + m_style->setMarqueeSpeed(85); // Normal speed + m_style->setMarqueeLoopCount(1); + m_style->setMarqueeBehavior(MSCROLL); + + if (m_parentStyle) + m_style->setDisplay(m_parentStyle->display()); + else + m_style->setDisplay(*primitiveValue); + } else + m_style->setDisplay(*primitiveValue); + } +#endif + return; + case CSSPropertyEmptyCells: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(emptyCells, EmptyCells) + return; + case CSSPropertyFloat: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(floating, Floating) + return; + case CSSPropertyFontStyle: + { + FontDescription fontDescription = m_style->fontDescription(); + if (isInherit) + fontDescription.setItalic(m_parentStyle->fontDescription().italic()); + else if (isInitial) + fontDescription.setItalic(false); + else { + if (!primitiveValue) + return; + switch (primitiveValue->getIdent()) { + case CSSValueOblique: + // FIXME: oblique is the same as italic for the moment... + case CSSValueItalic: + fontDescription.setItalic(true); + break; + case CSSValueNormal: + fontDescription.setItalic(false); + break; + default: + return; + } + } + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyFontVariant: + { + FontDescription fontDescription = m_style->fontDescription(); + if (isInherit) + fontDescription.setSmallCaps(m_parentStyle->fontDescription().smallCaps()); + else if (isInitial) + fontDescription.setSmallCaps(false); + else { + if (!primitiveValue) + return; + int id = primitiveValue->getIdent(); + if (id == CSSValueNormal) + fontDescription.setSmallCaps(false); + else if (id == CSSValueSmallCaps) + fontDescription.setSmallCaps(true); + else + return; + } + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyFontWeight: + { + FontDescription fontDescription = m_style->fontDescription(); + if (isInherit) + fontDescription.setWeight(m_parentStyle->fontDescription().weight()); + else if (isInitial) + fontDescription.setWeight(FontWeightNormal); + else { + if (!primitiveValue) + return; + if (primitiveValue->getIdent()) { + switch (primitiveValue->getIdent()) { + case CSSValueBolder: + fontDescription.setWeight(fontDescription.bolderWeight()); + break; + case CSSValueLighter: + fontDescription.setWeight(fontDescription.lighterWeight()); + break; + case CSSValueBold: + case CSSValue700: + fontDescription.setWeight(FontWeightBold); + break; + case CSSValueNormal: + case CSSValue400: + fontDescription.setWeight(FontWeightNormal); + break; + case CSSValue900: + fontDescription.setWeight(FontWeight900); + break; + case CSSValue800: + fontDescription.setWeight(FontWeight800); + break; + case CSSValue600: + fontDescription.setWeight(FontWeight600); + break; + case CSSValue500: + fontDescription.setWeight(FontWeight500); + break; + case CSSValue300: + fontDescription.setWeight(FontWeight300); + break; + case CSSValue200: + fontDescription.setWeight(FontWeight200); + break; + case CSSValue100: + fontDescription.setWeight(FontWeight100); + break; + default: + return; + } + } else + ASSERT_NOT_REACHED(); + } + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyListStylePosition: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStylePosition, ListStylePosition) + return; + case CSSPropertyListStyleType: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStyleType, ListStyleType) + return; + case CSSPropertyOverflow: + { + if (isInherit) { + m_style->setOverflowX(m_parentStyle->overflowX()); + m_style->setOverflowY(m_parentStyle->overflowY()); + return; + } + + if (isInitial) { + m_style->setOverflowX(RenderStyle::initialOverflowX()); + m_style->setOverflowY(RenderStyle::initialOverflowY()); + return; + } + + EOverflow o = *primitiveValue; + + m_style->setOverflowX(o); + m_style->setOverflowY(o); + return; + } + + case CSSPropertyOverflowX: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(overflowX, OverflowX) + return; + case CSSPropertyOverflowY: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(overflowY, OverflowY) + return; + case CSSPropertyPageBreakBefore: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak) + return; + case CSSPropertyPageBreakAfter: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak) + return; + case CSSPropertyPageBreakInside: { + HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak) + if (!primitiveValue) + return; + EPageBreak pageBreak = *primitiveValue; + if (pageBreak != PBALWAYS) + m_style->setPageBreakInside(pageBreak); + return; + } + + case CSSPropertyPosition: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(position, Position) + return; + case CSSPropertyTableLayout: { + HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout) + + ETableLayout l = *primitiveValue; + if (l == TAUTO) + l = RenderStyle::initialTableLayout(); + + m_style->setTableLayout(l); + return; + } + + case CSSPropertyUnicodeBidi: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(unicodeBidi, UnicodeBidi) + return; + case CSSPropertyTextTransform: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textTransform, TextTransform) + return; + case CSSPropertyVisibility: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(visibility, Visibility) + return; + case CSSPropertyWhiteSpace: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(whiteSpace, WhiteSpace) + return; + + case CSSPropertyBackgroundPosition: + HANDLE_BACKGROUND_INHERIT_AND_INITIAL(xPosition, XPosition); + HANDLE_BACKGROUND_INHERIT_AND_INITIAL(yPosition, YPosition); + return; + case CSSPropertyBackgroundPositionX: { + HANDLE_BACKGROUND_VALUE(xPosition, XPosition, value) + return; + } + case CSSPropertyBackgroundPositionY: { + HANDLE_BACKGROUND_VALUE(yPosition, YPosition, value) + return; + } + case CSSPropertyWebkitMaskPosition: + HANDLE_MASK_INHERIT_AND_INITIAL(xPosition, XPosition); + HANDLE_MASK_INHERIT_AND_INITIAL(yPosition, YPosition); + return; + case CSSPropertyWebkitMaskPositionX: { + HANDLE_MASK_VALUE(xPosition, XPosition, value) + return; + } + case CSSPropertyWebkitMaskPositionY: { + HANDLE_MASK_VALUE(yPosition, YPosition, value) + return; + } + case CSSPropertyBackgroundRepeat: + HANDLE_BACKGROUND_INHERIT_AND_INITIAL(repeatX, RepeatX); + HANDLE_BACKGROUND_INHERIT_AND_INITIAL(repeatY, RepeatY); + return; + case CSSPropertyBackgroundRepeatX: + HANDLE_BACKGROUND_VALUE(repeatX, RepeatX, value) + return; + case CSSPropertyBackgroundRepeatY: + HANDLE_BACKGROUND_VALUE(repeatY, RepeatY, value) + return; + case CSSPropertyWebkitMaskRepeat: + HANDLE_MASK_INHERIT_AND_INITIAL(repeatX, RepeatX); + HANDLE_MASK_INHERIT_AND_INITIAL(repeatY, RepeatY); + return; + case CSSPropertyWebkitMaskRepeatX: + HANDLE_MASK_VALUE(repeatX, RepeatX, value) + return; + case CSSPropertyWebkitMaskRepeatY: + HANDLE_MASK_VALUE(repeatY, RepeatY, value) + return; + case CSSPropertyBorderSpacing: { + if (isInherit) { + m_style->setHorizontalBorderSpacing(m_parentStyle->horizontalBorderSpacing()); + m_style->setVerticalBorderSpacing(m_parentStyle->verticalBorderSpacing()); + } + else if (isInitial) { + m_style->setHorizontalBorderSpacing(0); + m_style->setVerticalBorderSpacing(0); + } + return; + } + case CSSPropertyWebkitBorderHorizontalSpacing: { + HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing) + if (!primitiveValue) + return; + short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor); + m_style->setHorizontalBorderSpacing(spacing); + return; + } + case CSSPropertyWebkitBorderVerticalSpacing: { + HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing) + if (!primitiveValue) + return; + short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor); + m_style->setVerticalBorderSpacing(spacing); + return; + } + case CSSPropertyCursor: + if (isInherit) { + m_style->setCursor(m_parentStyle->cursor()); + m_style->setCursorList(m_parentStyle->cursors()); + return; + } + m_style->clearCursorList(); + if (isInitial) { + m_style->setCursor(RenderStyle::initialCursor()); + return; + } + if (value->isValueList()) { + CSSValueList* list = static_cast<CSSValueList*>(value); + int len = list->length(); + m_style->setCursor(CURSOR_AUTO); + for (int i = 0; i < len; i++) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (!item->isPrimitiveValue()) + continue; + primitiveValue = static_cast<CSSPrimitiveValue*>(item); + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) { + if (primitiveValue->isCursorImageValue()) { + CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue); + if (image->updateIfSVGCursorIsUsed(m_element)) // Elements with SVG cursors are not allowed to share style. + m_style->setUnique(); + m_style->addCursor(cachedOrPendingFromValue(CSSPropertyCursor, image), image->hotSpot()); + } + } else if (type == CSSPrimitiveValue::CSS_IDENT) + m_style->setCursor(*primitiveValue); + } + } else if (primitiveValue) { + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_IDENT && m_style->cursor() != ECursor(*primitiveValue)) + m_style->setCursor(*primitiveValue); + } + return; +// colors || inherit + case CSSPropertyColor: + // If the 'currentColor' keyword is set on the 'color' property itself, + // it is treated as 'color:inherit' at parse time + if (primitiveValue && primitiveValue->getIdent() == CSSValueCurrentcolor) + isInherit = true; + case CSSPropertyBackgroundColor: + case CSSPropertyBorderTopColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyOutlineColor: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitTextStrokeColor: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextFillColor: { + Color col; + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyBackgroundColor, backgroundColor, BackgroundColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderTopColor, borderTopColor, color, BorderTopColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderBottomColor, borderBottomColor, color, BorderBottomColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderRightColor, borderRightColor, color, BorderRightColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderLeftColor, borderLeftColor, color, BorderLeftColor) + HANDLE_INHERIT_COND(CSSPropertyColor, color, Color) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyOutlineColor, outlineColor, color, OutlineColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitColumnRuleColor, columnRuleColor, color, ColumnRuleColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextStrokeColor, textStrokeColor, color, TextStrokeColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextEmphasisColor, textEmphasisColor, color, TextEmphasisColor) + HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextFillColor, textFillColor, color, TextFillColor) + return; + } + if (isInitial) { + // The border/outline colors will just map to the invalid color |col| above. This will have the + // effect of forcing the use of the currentColor when it comes time to draw the borders (and of + // not painting the background since the color won't be valid). + if (id == CSSPropertyColor) + col = RenderStyle::initialColor(); + } else { + if (!primitiveValue) + return; + col = getColorFromPrimitiveValue(primitiveValue); + } + + switch (id) { + case CSSPropertyBackgroundColor: + m_style->setBackgroundColor(col); + break; + case CSSPropertyBorderTopColor: + m_style->setBorderTopColor(col); + break; + case CSSPropertyBorderRightColor: + m_style->setBorderRightColor(col); + break; + case CSSPropertyBorderBottomColor: + m_style->setBorderBottomColor(col); + break; + case CSSPropertyBorderLeftColor: + m_style->setBorderLeftColor(col); + break; + case CSSPropertyColor: + m_style->setColor(col); + break; + case CSSPropertyOutlineColor: + m_style->setOutlineColor(col); + break; + case CSSPropertyWebkitColumnRuleColor: + m_style->setColumnRuleColor(col); + break; + case CSSPropertyWebkitTextStrokeColor: + m_style->setTextStrokeColor(col); + break; + case CSSPropertyWebkitTextEmphasisColor: + m_style->setTextEmphasisColor(col); + break; + case CSSPropertyWebkitTextFillColor: + m_style->setTextFillColor(col); + break; + } + + return; + } + +// uri || inherit + case CSSPropertyBackgroundImage: + HANDLE_BACKGROUND_VALUE(image, Image, value) + return; + case CSSPropertyWebkitMaskImage: + HANDLE_MASK_VALUE(image, Image, value) + return; + case CSSPropertyListStyleImage: + { + HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage) + m_style->setListStyleImage(styleImage(CSSPropertyListStyleImage, value)); + return; + } + +// length + case CSSPropertyBorderTopWidth: + case CSSPropertyBorderRightWidth: + case CSSPropertyBorderBottomWidth: + case CSSPropertyBorderLeftWidth: + case CSSPropertyOutlineWidth: + case CSSPropertyWebkitColumnRuleWidth: + { + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyBorderTopWidth, borderTopWidth, BorderTopWidth) + HANDLE_INHERIT_COND(CSSPropertyBorderRightWidth, borderRightWidth, BorderRightWidth) + HANDLE_INHERIT_COND(CSSPropertyBorderBottomWidth, borderBottomWidth, BorderBottomWidth) + HANDLE_INHERIT_COND(CSSPropertyBorderLeftWidth, borderLeftWidth, BorderLeftWidth) + HANDLE_INHERIT_COND(CSSPropertyOutlineWidth, outlineWidth, OutlineWidth) + HANDLE_INHERIT_COND(CSSPropertyWebkitColumnRuleWidth, columnRuleWidth, ColumnRuleWidth) + return; + } + else if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopWidth, BorderTopWidth, BorderWidth) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderRightWidth, BorderRightWidth, BorderWidth) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomWidth, BorderBottomWidth, BorderWidth) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderLeftWidth, BorderLeftWidth, BorderWidth) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyOutlineWidth, OutlineWidth, BorderWidth) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitColumnRuleWidth, ColumnRuleWidth, BorderWidth) + return; + } + + if (!primitiveValue) + return; + short width = 3; + switch (primitiveValue->getIdent()) { + case CSSValueThin: + width = 1; + break; + case CSSValueMedium: + width = 3; + break; + case CSSValueThick: + width = 5; + break; + case CSSValueInvalid: + width = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor); + break; + default: + return; + } + + if (width < 0) return; + switch (id) { + case CSSPropertyBorderTopWidth: + m_style->setBorderTopWidth(width); + break; + case CSSPropertyBorderRightWidth: + m_style->setBorderRightWidth(width); + break; + case CSSPropertyBorderBottomWidth: + m_style->setBorderBottomWidth(width); + break; + case CSSPropertyBorderLeftWidth: + m_style->setBorderLeftWidth(width); + break; + case CSSPropertyOutlineWidth: + m_style->setOutlineWidth(width); + break; + case CSSPropertyWebkitColumnRuleWidth: + m_style->setColumnRuleWidth(width); + break; + default: + return; + } + return; + } + + case CSSPropertyWebkitFontSmoothing: { + FontDescription fontDescription = m_style->fontDescription(); + if (isInherit) + fontDescription.setFontSmoothing(m_parentStyle->fontDescription().fontSmoothing()); + else if (isInitial) + fontDescription.setFontSmoothing(AutoSmoothing); + else { + if (!primitiveValue) + return; + int id = primitiveValue->getIdent(); + FontSmoothingMode smoothing; + switch (id) { + case CSSValueAuto: + smoothing = AutoSmoothing; + break; + case CSSValueNone: + smoothing = NoSmoothing; + break; + case CSSValueAntialiased: + smoothing = Antialiased; + break; + case CSSValueSubpixelAntialiased: + smoothing = SubpixelAntialiased; + break; + default: + ASSERT_NOT_REACHED(); + smoothing = AutoSmoothing; + } + fontDescription.setFontSmoothing(smoothing); + } + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyLetterSpacing: + case CSSPropertyWordSpacing: + { + + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyLetterSpacing, letterSpacing, LetterSpacing) + HANDLE_INHERIT_COND(CSSPropertyWordSpacing, wordSpacing, WordSpacing) + return; + } + else if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLetterSpacing, LetterSpacing, LetterWordSpacing) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWordSpacing, WordSpacing, LetterWordSpacing) + return; + } + + int width = 0; + if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal) { + width = 0; + } else { + if (!primitiveValue) + return; + width = primitiveValue->computeLengthInt(style(), m_rootElementStyle, useSVGZoomRules ? 1.0f : zoomFactor); + } + switch (id) { + case CSSPropertyLetterSpacing: + m_style->setLetterSpacing(width); + break; + case CSSPropertyWordSpacing: + m_style->setWordSpacing(width); + break; + // ### needs the definitions in renderstyle + default: break; + } + return; + } + + case CSSPropertyWordBreak: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(wordBreak, WordBreak) + return; + case CSSPropertyWordWrap: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(wordWrap, WordWrap) + return; + case CSSPropertyWebkitNbspMode: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(nbspMode, NBSPMode) + return; + case CSSPropertyWebkitLineBreak: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(khtmlLineBreak, KHTMLLineBreak) + return; + case CSSPropertyWebkitMatchNearestMailBlockquoteColor: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor) + return; + + case CSSPropertyResize: + { + HANDLE_INHERIT_AND_INITIAL(resize, Resize) + + if (!primitiveValue->getIdent()) + return; + + EResize r = RESIZE_NONE; + if (primitiveValue->getIdent() == CSSValueAuto) { + if (Settings* settings = m_checker.m_document->settings()) + r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE; + } else + r = *primitiveValue; + + m_style->setResize(r); + return; + } + + // length, percent + case CSSPropertyMaxWidth: + // +none +inherit + if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) + apply = true; + case CSSPropertyTop: + case CSSPropertyLeft: + case CSSPropertyRight: + case CSSPropertyBottom: + case CSSPropertyWidth: + case CSSPropertyMinWidth: + case CSSPropertyMarginTop: + case CSSPropertyMarginRight: + case CSSPropertyMarginBottom: + case CSSPropertyMarginLeft: + // +inherit +auto + if (id == CSSPropertyWidth || id == CSSPropertyMinWidth || id == CSSPropertyMaxWidth) { + if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) { + l = Length(Intrinsic); + apply = true; + } + else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) { + l = Length(MinIntrinsic); + apply = true; + } + } + if (id != CSSPropertyMaxWidth && primitiveValue && primitiveValue->getIdent() == CSSValueAuto) + apply = true; + case CSSPropertyPaddingTop: + case CSSPropertyPaddingRight: + case CSSPropertyPaddingBottom: + case CSSPropertyPaddingLeft: + case CSSPropertyTextIndent: + // +inherit + { + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyMaxWidth, maxWidth, MaxWidth) + HANDLE_INHERIT_COND(CSSPropertyBottom, bottom, Bottom) + HANDLE_INHERIT_COND(CSSPropertyTop, top, Top) + HANDLE_INHERIT_COND(CSSPropertyLeft, left, Left) + HANDLE_INHERIT_COND(CSSPropertyRight, right, Right) + HANDLE_INHERIT_COND(CSSPropertyWidth, width, Width) + HANDLE_INHERIT_COND(CSSPropertyMinWidth, minWidth, MinWidth) + HANDLE_INHERIT_COND(CSSPropertyPaddingTop, paddingTop, PaddingTop) + HANDLE_INHERIT_COND(CSSPropertyPaddingRight, paddingRight, PaddingRight) + HANDLE_INHERIT_COND(CSSPropertyPaddingBottom, paddingBottom, PaddingBottom) + HANDLE_INHERIT_COND(CSSPropertyPaddingLeft, paddingLeft, PaddingLeft) + HANDLE_INHERIT_COND(CSSPropertyMarginTop, marginTop, MarginTop) + HANDLE_INHERIT_COND(CSSPropertyMarginRight, marginRight, MarginRight) + HANDLE_INHERIT_COND(CSSPropertyMarginBottom, marginBottom, MarginBottom) + HANDLE_INHERIT_COND(CSSPropertyMarginLeft, marginLeft, MarginLeft) + HANDLE_INHERIT_COND(CSSPropertyTextIndent, textIndent, TextIndent) + return; + } + else if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxWidth, MaxWidth, MaxSize) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBottom, Bottom, Offset) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyTop, Top, Offset) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLeft, Left, Offset) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyRight, Right, Offset) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWidth, Width, Size) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinWidth, MinWidth, MinSize) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingTop, PaddingTop, Padding) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingRight, PaddingRight, Padding) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingBottom, PaddingBottom, Padding) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingLeft, PaddingLeft, Padding) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginTop, MarginTop, Margin) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginRight, MarginRight, Margin) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginBottom, MarginBottom, Margin) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginLeft, MarginLeft, Margin) + HANDLE_INITIAL_COND(CSSPropertyTextIndent, TextIndent) + return; + } + + if (primitiveValue && !apply) { + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + // Handle our quirky margin units if we have them. + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed, + primitiveValue->isQuirkValue()); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + apply = true; + } + if (!apply) return; + switch (id) { + case CSSPropertyMaxWidth: + m_style->setMaxWidth(l); + break; + case CSSPropertyBottom: + m_style->setBottom(l); + break; + case CSSPropertyTop: + m_style->setTop(l); + break; + case CSSPropertyLeft: + m_style->setLeft(l); + break; + case CSSPropertyRight: + m_style->setRight(l); + break; + case CSSPropertyWidth: + m_style->setWidth(l); + break; + case CSSPropertyMinWidth: + m_style->setMinWidth(l); + break; + case CSSPropertyPaddingTop: + m_style->setPaddingTop(l); + break; + case CSSPropertyPaddingRight: + m_style->setPaddingRight(l); + break; + case CSSPropertyPaddingBottom: + m_style->setPaddingBottom(l); + break; + case CSSPropertyPaddingLeft: + m_style->setPaddingLeft(l); + break; + case CSSPropertyMarginTop: + m_style->setMarginTop(l); + break; + case CSSPropertyMarginRight: + m_style->setMarginRight(l); + break; + case CSSPropertyMarginBottom: + m_style->setMarginBottom(l); + break; + case CSSPropertyMarginLeft: + m_style->setMarginLeft(l); + break; + case CSSPropertyTextIndent: + m_style->setTextIndent(l); + break; + default: + break; + } + return; + } + + case CSSPropertyMaxHeight: + if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { + l = Length(undefinedLength, Fixed); + apply = true; + } + case CSSPropertyHeight: + case CSSPropertyMinHeight: + if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) { + l = Length(Intrinsic); + apply = true; + } else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) { + l = Length(MinIntrinsic); + apply = true; + } else if (id != CSSPropertyMaxHeight && primitiveValue && primitiveValue->getIdent() == CSSValueAuto) + apply = true; + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyMaxHeight, maxHeight, MaxHeight) + HANDLE_INHERIT_COND(CSSPropertyHeight, height, Height) + HANDLE_INHERIT_COND(CSSPropertyMinHeight, minHeight, MinHeight) + return; + } + if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxHeight, MaxHeight, MaxSize) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyHeight, Height, Size) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinHeight, MinHeight, MinSize) + return; + } + + if (primitiveValue && !apply) { + unsigned short type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + apply = true; + } + if (apply) + switch (id) { + case CSSPropertyMaxHeight: + m_style->setMaxHeight(l); + break; + case CSSPropertyHeight: + m_style->setHeight(l); + break; + case CSSPropertyMinHeight: + m_style->setMinHeight(l); + break; + } + return; + + case CSSPropertyVerticalAlign: + HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign) + if (!primitiveValue) + return; + if (primitiveValue->getIdent()) { + EVerticalAlign align; + + switch (primitiveValue->getIdent()) { + case CSSValueTop: + align = TOP; break; + case CSSValueBottom: + align = BOTTOM; break; + case CSSValueMiddle: + align = MIDDLE; break; + case CSSValueBaseline: + align = BASELINE; break; + case CSSValueTextBottom: + align = TEXT_BOTTOM; break; + case CSSValueTextTop: + align = TEXT_TOP; break; + case CSSValueSub: + align = SUB; break; + case CSSValueSuper: + align = SUPER; break; + case CSSValueWebkitBaselineMiddle: + align = BASELINE_MIDDLE; break; + default: + return; + } + m_style->setVerticalAlign(align); + return; + } else { + int type = primitiveValue->primitiveType(); + Length l; + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + + m_style->setVerticalAlign(LENGTH); + m_style->setVerticalAlignLength(l); + } + return; + + case CSSPropertyFontSize: + { + FontDescription fontDescription = m_style->fontDescription(); + fontDescription.setKeywordSize(0); + float oldSize = 0; + float size = 0; + + bool parentIsAbsoluteSize = false; + if (m_parentNode) { + oldSize = m_parentStyle->fontDescription().specifiedSize(); + parentIsAbsoluteSize = m_parentStyle->fontDescription().isAbsoluteSize(); + } + + if (isInherit) { + size = oldSize; + if (m_parentNode) + fontDescription.setKeywordSize(m_parentStyle->fontDescription().keywordSize()); + } else if (isInitial) { + size = fontSizeForKeyword(m_checker.m_document, CSSValueMedium, fontDescription.useFixedDefaultSize()); + fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); + } else if (primitiveValue->getIdent()) { + // Keywords are being used. + switch (primitiveValue->getIdent()) { + case CSSValueXxSmall: + case CSSValueXSmall: + case CSSValueSmall: + case CSSValueMedium: + case CSSValueLarge: + case CSSValueXLarge: + case CSSValueXxLarge: + case CSSValueWebkitXxxLarge: + size = fontSizeForKeyword(m_checker.m_document, primitiveValue->getIdent(), fontDescription.useFixedDefaultSize()); + fontDescription.setKeywordSize(primitiveValue->getIdent() - CSSValueXxSmall + 1); + break; + case CSSValueLarger: + size = largerFontSize(oldSize, m_checker.m_document->inQuirksMode()); + break; + case CSSValueSmaller: + size = smallerFontSize(oldSize, m_checker.m_document->inQuirksMode()); + break; + default: + return; + } + + fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && + (primitiveValue->getIdent() == CSSValueLarger || + primitiveValue->getIdent() == CSSValueSmaller)); + } else { + int type = primitiveValue->primitiveType(); + fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize || + (type != CSSPrimitiveValue::CSS_PERCENTAGE && + type != CSSPrimitiveValue::CSS_EMS && + type != CSSPrimitiveValue::CSS_EXS && + type != CSSPrimitiveValue::CSS_REMS)); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + size = primitiveValue->computeLengthFloat(m_parentStyle, m_rootElementStyle, true); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + size = (primitiveValue->getFloatValue() * oldSize) / 100.0f; + else + return; + } + + if (size < 0) + return; + + setFontSize(fontDescription, size); + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyZIndex: { + if (isInherit) { + if (m_parentStyle->hasAutoZIndex()) + m_style->setHasAutoZIndex(); + else + m_style->setZIndex(m_parentStyle->zIndex()); + return; + } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { + m_style->setHasAutoZIndex(); + return; + } + + // FIXME: Should clamp all sorts of other integer properties too. + const double minIntAsDouble = INT_MIN; + const double maxIntAsDouble = INT_MAX; + m_style->setZIndex(static_cast<int>(max(minIntAsDouble, min(primitiveValue->getDoubleValue(), maxIntAsDouble)))); + return; + } + case CSSPropertyWidows: + { + HANDLE_INHERIT_AND_INITIAL(widows, Widows) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; + m_style->setWidows(primitiveValue->getIntValue()); + return; + } + + case CSSPropertyOrphans: + { + HANDLE_INHERIT_AND_INITIAL(orphans, Orphans) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; + m_style->setOrphans(primitiveValue->getIntValue()); + return; + } + +// length, percent, number + case CSSPropertyLineHeight: + { + HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight) + if (!primitiveValue) + return; + Length lineHeight; + int type = primitiveValue->primitiveType(); + if (primitiveValue->getIdent() == CSSValueNormal) + lineHeight = Length(-100.0, Percent); + else if (CSSPrimitiveValue::isUnitTypeLength(type)) { + double multiplier = zoomFactor; + if (m_style->textSizeAdjust()) { + if (Frame* frame = m_checker.m_document->frame()) + multiplier *= frame->textZoomFactor(); + } + lineHeight = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, multiplier), Fixed); + } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + lineHeight = Length((m_style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed); + else if (type == CSSPrimitiveValue::CSS_NUMBER) + lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent); + else + return; + m_style->setLineHeight(lineHeight); + return; + } + +// string + case CSSPropertyTextAlign: + { + HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign) + if (!primitiveValue) + return; + int id = primitiveValue->getIdent(); + if (id == CSSValueStart) + m_style->setTextAlign(m_style->isLeftToRightDirection() ? LEFT : RIGHT); + else if (id == CSSValueEnd) + m_style->setTextAlign(m_style->isLeftToRightDirection() ? RIGHT : LEFT); + else + m_style->setTextAlign(*primitiveValue); + return; + } + +// rect + case CSSPropertyClip: + { + Length top; + Length right; + Length bottom; + Length left; + bool hasClip = true; + if (isInherit) { + if (m_parentStyle->hasClip()) { + top = m_parentStyle->clipTop(); + right = m_parentStyle->clipRight(); + bottom = m_parentStyle->clipBottom(); + left = m_parentStyle->clipLeft(); + } else { + hasClip = false; + top = right = bottom = left = Length(); + } + } else if (isInitial) { + hasClip = false; + top = right = bottom = left = Length(); + } else if (!primitiveValue) { + return; + } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) { + Rect* rect = primitiveValue->getRectValue(); + if (!rect) + return; + top = convertToLength(rect->top(), style(), m_rootElementStyle, zoomFactor); + right = convertToLength(rect->right(), style(), m_rootElementStyle, zoomFactor); + bottom = convertToLength(rect->bottom(), style(), m_rootElementStyle, zoomFactor); + left = convertToLength(rect->left(), style(), m_rootElementStyle, zoomFactor); + } else if (primitiveValue->getIdent() != CSSValueAuto) { + return; + } + m_style->setClip(top, right, bottom, left); + m_style->setHasClip(hasClip); + + // rect, ident + return; + } + +// lists + case CSSPropertyContent: + // list of string, uri, counter, attr, i + { + // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This + // note is a reminder that eventually "inherit" needs to be supported. + + if (isInitial) { + m_style->clearContent(); + return; + } + + if (!value->isValueList()) + return; + + CSSValueList* list = static_cast<CSSValueList*>(value); + int len = list->length(); + + bool didSet = false; + for (int i = 0; i < len; i++) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (item->isImageGeneratorValue()) { + m_style->setContent(static_cast<CSSImageGeneratorValue*>(item)->generatedImage(), didSet); + didSet = true; + } + + if (!item->isPrimitiveValue()) + continue; + + CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item); + switch (contentValue->primitiveType()) { + case CSSPrimitiveValue::CSS_STRING: + m_style->setContent(contentValue->getStringValue().impl(), didSet); + didSet = true; + break; + case CSSPrimitiveValue::CSS_ATTR: { + // FIXME: Can a namespace be specified for an attr(foo)? + if (m_style->styleType() == NOPSEUDO) + m_style->setUnique(); + else + m_parentStyle->setUnique(); + QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom); + m_style->setContent(m_element->getAttribute(attr).impl(), didSet); + didSet = true; + // register the fact that the attribute value affects the style + m_selectorAttrs.add(attr.localName().impl()); + break; + } + case CSSPrimitiveValue::CSS_URI: { + if (!contentValue->isImageValue()) + break; + m_style->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(contentValue)), didSet); + didSet = true; + break; + } + case CSSPrimitiveValue::CSS_COUNTER: { + Counter* counterValue = contentValue->getCounterValue(); + OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(), + (EListStyleType)counterValue->listStyleNumber(), counterValue->separator())); + m_style->setContent(counter.release(), didSet); + didSet = true; + } + } + } + if (!didSet) + m_style->clearContent(); + return; + } + + case CSSPropertyCounterIncrement: + applyCounterList(style(), value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false); + return; + case CSSPropertyCounterReset: + applyCounterList(style(), value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true); + return; + + case CSSPropertyFontFamily: { + // list of strings and ids + if (isInherit) { + FontDescription parentFontDescription = m_parentStyle->fontDescription(); + FontDescription fontDescription = m_style->fontDescription(); + fontDescription.setGenericFamily(parentFontDescription.genericFamily()); + fontDescription.setFamily(parentFontDescription.firstFamily()); + fontDescription.setIsSpecifiedFont(parentFontDescription.isSpecifiedFont()); + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } else if (isInitial) { + FontDescription initialDesc = FontDescription(); + FontDescription fontDescription = m_style->fontDescription(); + // We need to adjust the size to account for the generic family change from monospace + // to non-monospace. + if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize()) + setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + fontDescription.keywordSize() - 1, false)); + fontDescription.setGenericFamily(initialDesc.genericFamily()); + if (!initialDesc.firstFamily().familyIsEmpty()) + fontDescription.setFamily(initialDesc.firstFamily()); + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + if (!value->isValueList()) + return; + FontDescription fontDescription = m_style->fontDescription(); + CSSValueList* list = static_cast<CSSValueList*>(value); + int len = list->length(); + FontFamily& firstFamily = fontDescription.firstFamily(); + FontFamily* currFamily = 0; + + // Before mapping in a new font-family property, we should reset the generic family. + bool oldFamilyUsedFixedDefaultSize = fontDescription.useFixedDefaultSize(); + fontDescription.setGenericFamily(FontDescription::NoFamily); + + for (int i = 0; i < len; i++) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (!item->isPrimitiveValue()) + continue; + CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item); + AtomicString face; + Settings* settings = m_checker.m_document->settings(); + if (contentValue->primitiveType() == CSSPrimitiveValue::CSS_STRING) { + if (contentValue->isFontFamilyValue()) + face = static_cast<FontFamilyValue*>(contentValue)->familyName(); + } else if (contentValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) { + switch (contentValue->getIdent()) { + case CSSValueWebkitBody: + face = settings->standardFontFamily(); + break; + case CSSValueSerif: + face = "-webkit-serif"; + fontDescription.setGenericFamily(FontDescription::SerifFamily); + break; + case CSSValueSansSerif: + face = "-webkit-sans-serif"; + fontDescription.setGenericFamily(FontDescription::SansSerifFamily); + break; + case CSSValueCursive: + face = "-webkit-cursive"; + fontDescription.setGenericFamily(FontDescription::CursiveFamily); + break; + case CSSValueFantasy: + face = "-webkit-fantasy"; + fontDescription.setGenericFamily(FontDescription::FantasyFamily); + break; + case CSSValueMonospace: + face = "-webkit-monospace"; + fontDescription.setGenericFamily(FontDescription::MonospaceFamily); + break; + } + } + + if (!face.isEmpty()) { + if (!currFamily) { + // Filling in the first family. + firstFamily.setFamily(face); + firstFamily.appendFamily(0); // Remove any inherited family-fallback list. + currFamily = &firstFamily; + fontDescription.setIsSpecifiedFont(fontDescription.genericFamily() == FontDescription::NoFamily); + } else { + RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create(); + newFamily->setFamily(face); + currFamily->appendFamily(newFamily); + currFamily = newFamily.get(); + } + } + } + + // We can't call useFixedDefaultSize() until all new font families have been added + // If currFamily is non-zero then we set at least one family on this description. + if (currFamily) { + if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize) + setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + fontDescription.keywordSize() - 1, !oldFamilyUsedFixedDefaultSize)); + + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + } + return; + } + case CSSPropertyTextDecoration: { + // list of ident + HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration) + int t = RenderStyle::initialTextDecoration(); + if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { + // do nothing + } else { + if (!value->isValueList()) + return; + CSSValueList *list = static_cast<CSSValueList*>(value); + int len = list->length(); + for (int i = 0; i < len; i++) + { + CSSValue *item = list->itemWithoutBoundsCheck(i); + if (!item->isPrimitiveValue()) + continue; + primitiveValue = static_cast<CSSPrimitiveValue*>(item); + switch (primitiveValue->getIdent()) { + case CSSValueNone: + t = TDNONE; break; + case CSSValueUnderline: + t |= UNDERLINE; break; + case CSSValueOverline: + t |= OVERLINE; break; + case CSSValueLineThrough: + t |= LINE_THROUGH; break; + case CSSValueBlink: + t |= BLINK; break; + default: + return; + } + } + } + + m_style->setTextDecoration(t); + return; + } + + case CSSPropertyZoom: + { + // Reset the zoom in effect before we do anything. This allows the setZoom method to accurately compute a new + // zoom in effect. + m_style->setEffectiveZoom(m_parentStyle ? m_parentStyle->effectiveZoom() : RenderStyle::initialZoom()); + + // Now we can handle inherit and initial. + HANDLE_INHERIT_AND_INITIAL(zoom, Zoom) + + // Handle normal/reset, numbers and percentages. + int type = primitiveValue->primitiveType(); + if (primitiveValue->getIdent() == CSSValueNormal) + m_style->setZoom(RenderStyle::initialZoom()); + else if (primitiveValue->getIdent() == CSSValueReset) { + m_style->setEffectiveZoom(RenderStyle::initialZoom()); + m_style->setZoom(RenderStyle::initialZoom()); + } else if (primitiveValue->getIdent() == CSSValueDocument) { + float docZoom = m_checker.m_document->renderer()->style()->zoom(); + m_style->setEffectiveZoom(docZoom); + m_style->setZoom(docZoom); + } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) { + if (primitiveValue->getFloatValue()) + m_style->setZoom(primitiveValue->getFloatValue() / 100.0f); + } else if (type == CSSPrimitiveValue::CSS_NUMBER) { + if (primitiveValue->getFloatValue()) + m_style->setZoom(primitiveValue->getFloatValue()); + } + + m_fontDirty = true; + return; + } +// shorthand properties + case CSSPropertyBackground: + if (isInitial) { + m_style->clearBackgroundLayers(); + m_style->setBackgroundColor(Color()); + } + else if (isInherit) { + m_style->inheritBackgroundLayers(*m_parentStyle->backgroundLayers()); + m_style->setBackgroundColor(m_parentStyle->backgroundColor()); + } + return; + case CSSPropertyWebkitMask: + if (isInitial) + m_style->clearMaskLayers(); + else if (isInherit) + m_style->inheritMaskLayers(*m_parentStyle->maskLayers()); + return; + + case CSSPropertyBorder: + case CSSPropertyBorderStyle: + case CSSPropertyBorderWidth: + case CSSPropertyBorderColor: + if (id == CSSPropertyBorder || id == CSSPropertyBorderColor) + { + if (isInherit) { + m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color()); + m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color()); + m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color()); + m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor(): m_parentStyle->color()); + } + else if (isInitial) { + m_style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead. + m_style->setBorderBottomColor(Color()); + m_style->setBorderLeftColor(Color()); + m_style->setBorderRightColor(Color()); + } + } + if (id == CSSPropertyBorder || id == CSSPropertyBorderStyle) + { + if (isInherit) { + m_style->setBorderTopStyle(m_parentStyle->borderTopStyle()); + m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle()); + m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle()); + m_style->setBorderRightStyle(m_parentStyle->borderRightStyle()); + } + else if (isInitial) { + m_style->setBorderTopStyle(RenderStyle::initialBorderStyle()); + m_style->setBorderBottomStyle(RenderStyle::initialBorderStyle()); + m_style->setBorderLeftStyle(RenderStyle::initialBorderStyle()); + m_style->setBorderRightStyle(RenderStyle::initialBorderStyle()); + } + } + if (id == CSSPropertyBorder || id == CSSPropertyBorderWidth) + { + if (isInherit) { + m_style->setBorderTopWidth(m_parentStyle->borderTopWidth()); + m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth()); + m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth()); + m_style->setBorderRightWidth(m_parentStyle->borderRightWidth()); + } + else if (isInitial) { + m_style->setBorderTopWidth(RenderStyle::initialBorderWidth()); + m_style->setBorderBottomWidth(RenderStyle::initialBorderWidth()); + m_style->setBorderLeftWidth(RenderStyle::initialBorderWidth()); + m_style->setBorderRightWidth(RenderStyle::initialBorderWidth()); + } + } + return; + case CSSPropertyBorderTop: + if (isInherit) { + m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color()); + m_style->setBorderTopStyle(m_parentStyle->borderTopStyle()); + m_style->setBorderTopWidth(m_parentStyle->borderTopWidth()); + } + else if (isInitial) + m_style->resetBorderTop(); + return; + case CSSPropertyBorderRight: + if (isInherit) { + m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor() : m_parentStyle->color()); + m_style->setBorderRightStyle(m_parentStyle->borderRightStyle()); + m_style->setBorderRightWidth(m_parentStyle->borderRightWidth()); + } + else if (isInitial) + m_style->resetBorderRight(); + return; + case CSSPropertyBorderBottom: + if (isInherit) { + m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color()); + m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle()); + m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth()); + } + else if (isInitial) + m_style->resetBorderBottom(); + return; + case CSSPropertyBorderLeft: + if (isInherit) { + m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color()); + m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle()); + m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth()); + } + else if (isInitial) + m_style->resetBorderLeft(); + return; + case CSSPropertyMargin: + if (isInherit) { + m_style->setMarginTop(m_parentStyle->marginTop()); + m_style->setMarginBottom(m_parentStyle->marginBottom()); + m_style->setMarginLeft(m_parentStyle->marginLeft()); + m_style->setMarginRight(m_parentStyle->marginRight()); + } + else if (isInitial) + m_style->resetMargin(); + return; + case CSSPropertyPadding: + if (isInherit) { + m_style->setPaddingTop(m_parentStyle->paddingTop()); + m_style->setPaddingBottom(m_parentStyle->paddingBottom()); + m_style->setPaddingLeft(m_parentStyle->paddingLeft()); + m_style->setPaddingRight(m_parentStyle->paddingRight()); + } + else if (isInitial) + m_style->resetPadding(); + return; + case CSSPropertyFont: + if (isInherit) { + FontDescription fontDescription = m_parentStyle->fontDescription(); + m_style->setLineHeight(m_parentStyle->lineHeight()); + m_lineHeightValue = 0; + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + } else if (isInitial) { + Settings* settings = m_checker.m_document->settings(); + ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings + if (!settings) + return; + FontDescription fontDescription; + fontDescription.setGenericFamily(FontDescription::StandardFamily); + fontDescription.setRenderingMode(settings->fontRenderingMode()); + fontDescription.setUsePrinterFont(m_checker.m_document->printing()); + const AtomicString& standardFontFamily = m_checker.m_document->settings()->standardFontFamily(); + if (!standardFontFamily.isEmpty()) { + fontDescription.firstFamily().setFamily(standardFontFamily); + fontDescription.firstFamily().appendFamily(0); + } + fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); + setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueMedium, false)); + m_style->setLineHeight(RenderStyle::initialLineHeight()); + m_lineHeightValue = 0; + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + } else if (primitiveValue) { + m_style->setLineHeight(RenderStyle::initialLineHeight()); + m_lineHeightValue = 0; + + FontDescription fontDescription; + RenderTheme::defaultTheme()->systemFont(primitiveValue->getIdent(), fontDescription); + + // Double-check and see if the theme did anything. If not, don't bother updating the font. + if (fontDescription.isAbsoluteSize()) { + // Make sure the rendering mode and printer font settings are updated. + Settings* settings = m_checker.m_document->settings(); + ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings + if (!settings) + return; + fontDescription.setRenderingMode(settings->fontRenderingMode()); + fontDescription.setUsePrinterFont(m_checker.m_document->printing()); + + // Handle the zoom factor. + fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.m_document, m_style.get(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules)); + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + } + } else if (value->isFontValue()) { + FontValue *font = static_cast<FontValue*>(value); + if (!font->style || !font->variant || !font->weight || + !font->size || !font->lineHeight || !font->family) + return; + applyProperty(CSSPropertyFontStyle, font->style.get()); + applyProperty(CSSPropertyFontVariant, font->variant.get()); + applyProperty(CSSPropertyFontWeight, font->weight.get()); + applyProperty(CSSPropertyFontSize, font->size.get()); + + m_lineHeightValue = font->lineHeight.get(); + + applyProperty(CSSPropertyFontFamily, font->family.get()); + } + return; + + case CSSPropertyListStyle: + if (isInherit) { + m_style->setListStyleType(m_parentStyle->listStyleType()); + m_style->setListStyleImage(m_parentStyle->listStyleImage()); + m_style->setListStylePosition(m_parentStyle->listStylePosition()); + } + else if (isInitial) { + m_style->setListStyleType(RenderStyle::initialListStyleType()); + m_style->setListStyleImage(RenderStyle::initialListStyleImage()); + m_style->setListStylePosition(RenderStyle::initialListStylePosition()); + } + return; + case CSSPropertyOutline: + if (isInherit) { + m_style->setOutlineWidth(m_parentStyle->outlineWidth()); + m_style->setOutlineColor(m_parentStyle->outlineColor().isValid() ? m_parentStyle->outlineColor() : m_parentStyle->color()); + m_style->setOutlineStyle(m_parentStyle->outlineStyle()); + } + else if (isInitial) + m_style->resetOutline(); + return; + + // CSS3 Properties + case CSSPropertyWebkitAppearance: { + HANDLE_INHERIT_AND_INITIAL(appearance, Appearance) + if (!primitiveValue) + return; + m_style->setAppearance(*primitiveValue); + return; + } + + case CSSPropertyWebkitBorderImage: + case CSSPropertyWebkitMaskBoxImage: { + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyWebkitBorderImage, borderImage, BorderImage) + HANDLE_INHERIT_COND(CSSPropertyWebkitMaskBoxImage, maskBoxImage, MaskBoxImage) + return; + } else if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderImage, BorderImage, NinePieceImage) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitMaskBoxImage, MaskBoxImage, NinePieceImage) + return; + } + + NinePieceImage image; + mapNinePieceImage(property, value, image); + + if (id == CSSPropertyWebkitBorderImage) + m_style->setBorderImage(image); + else + m_style->setMaskBoxImage(image); + return; + } + + case CSSPropertyBorderRadius: + case CSSPropertyWebkitBorderRadius: + if (isInherit) { + m_style->setBorderTopLeftRadius(m_parentStyle->borderTopLeftRadius()); + m_style->setBorderTopRightRadius(m_parentStyle->borderTopRightRadius()); + m_style->setBorderBottomLeftRadius(m_parentStyle->borderBottomLeftRadius()); + m_style->setBorderBottomRightRadius(m_parentStyle->borderBottomRightRadius()); + return; + } + if (isInitial) { + m_style->resetBorderRadius(); + return; + } + // Fall through + case CSSPropertyBorderTopLeftRadius: + case CSSPropertyBorderTopRightRadius: + case CSSPropertyBorderBottomLeftRadius: + case CSSPropertyBorderBottomRightRadius: { + if (isInherit) { + HANDLE_INHERIT_COND(CSSPropertyBorderTopLeftRadius, borderTopLeftRadius, BorderTopLeftRadius) + HANDLE_INHERIT_COND(CSSPropertyBorderTopRightRadius, borderTopRightRadius, BorderTopRightRadius) + HANDLE_INHERIT_COND(CSSPropertyBorderBottomLeftRadius, borderBottomLeftRadius, BorderBottomLeftRadius) + HANDLE_INHERIT_COND(CSSPropertyBorderBottomRightRadius, borderBottomRightRadius, BorderBottomRightRadius) + return; + } + + if (isInitial) { + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopLeftRadius, BorderTopLeftRadius, BorderRadius) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopRightRadius, BorderTopRightRadius, BorderRadius) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomLeftRadius, BorderBottomLeftRadius, BorderRadius) + HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomRightRadius, BorderBottomRightRadius, BorderRadius) + return; + } + + if (!primitiveValue) + return; + + Pair* pair = primitiveValue->getPairValue(); + if (!pair || !pair->first() || !pair->second()) + return; + + Length radiusWidth; + Length radiusHeight; + if (pair->first()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + radiusWidth = Length(pair->first()->getDoubleValue(), Percent); + else + radiusWidth = Length(max(intMinForLength, min(intMaxForLength, pair->first()->computeLengthInt(style(), m_rootElementStyle, zoomFactor))), Fixed); + if (pair->second()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + radiusHeight = Length(pair->second()->getDoubleValue(), Percent); + else + radiusHeight = Length(max(intMinForLength, min(intMaxForLength, pair->second()->computeLengthInt(style(), m_rootElementStyle, zoomFactor))), Fixed); + int width = radiusWidth.rawValue(); + int height = radiusHeight.rawValue(); + if (width < 0 || height < 0) + return; + if (width == 0) + radiusHeight = radiusWidth; // Null out the other value. + else if (height == 0) + radiusWidth = radiusHeight; // Null out the other value. + + LengthSize size(radiusWidth, radiusHeight); + switch (id) { + case CSSPropertyBorderTopLeftRadius: + m_style->setBorderTopLeftRadius(size); + break; + case CSSPropertyBorderTopRightRadius: + m_style->setBorderTopRightRadius(size); + break; + case CSSPropertyBorderBottomLeftRadius: + m_style->setBorderBottomLeftRadius(size); + break; + case CSSPropertyBorderBottomRightRadius: + m_style->setBorderBottomRightRadius(size); + break; + default: + m_style->setBorderRadius(size); + break; + } + return; + } + + case CSSPropertyOutlineOffset: + HANDLE_INHERIT_AND_INITIAL(outlineOffset, OutlineOffset) + m_style->setOutlineOffset(primitiveValue->computeLengthInt(style(), m_rootElementStyle, zoomFactor)); + return; + case CSSPropertyTextRendering: { + FontDescription fontDescription = m_style->fontDescription(); + if (isInherit) + fontDescription.setTextRenderingMode(m_parentStyle->fontDescription().textRenderingMode()); + else if (isInitial) + fontDescription.setTextRenderingMode(AutoTextRendering); + else { + if (!primitiveValue) + return; + fontDescription.setTextRenderingMode(*primitiveValue); + } + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + case CSSPropertyTextShadow: + case CSSPropertyBoxShadow: + case CSSPropertyWebkitBoxShadow: { + if (isInherit) { + if (id == CSSPropertyTextShadow) + return m_style->setTextShadow(m_parentStyle->textShadow() ? new ShadowData(*m_parentStyle->textShadow()) : 0); + return m_style->setBoxShadow(m_parentStyle->boxShadow() ? new ShadowData(*m_parentStyle->boxShadow()) : 0); + } + if (isInitial || primitiveValue) // initial | none + return id == CSSPropertyTextShadow ? m_style->setTextShadow(0) : m_style->setBoxShadow(0); + + if (!value->isValueList()) + return; + + CSSValueList *list = static_cast<CSSValueList*>(value); + int len = list->length(); + for (int i = 0; i < len; i++) { + CSSValue* currValue = list->itemWithoutBoundsCheck(i); + if (!currValue->isShadowValue()) + continue; + ShadowValue* item = static_cast<ShadowValue*>(list->itemWithoutBoundsCheck(i)); + int x = item->x->computeLengthInt(style(), m_rootElementStyle, zoomFactor); + int y = item->y->computeLengthInt(style(), m_rootElementStyle, zoomFactor); + int blur = item->blur ? item->blur->computeLengthInt(style(), m_rootElementStyle, zoomFactor) : 0; + int spread = item->spread ? item->spread->computeLengthInt(style(), m_rootElementStyle, zoomFactor) : 0; + ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal; + Color color; + if (item->color) + color = getColorFromPrimitiveValue(item->color.get()); + ShadowData* shadowData = new ShadowData(x, y, blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent); + if (id == CSSPropertyTextShadow) + m_style->setTextShadow(shadowData, i != 0); + else + m_style->setBoxShadow(shadowData, i != 0); + } + return; + } + case CSSPropertyWebkitBoxReflect: { + HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect) + if (primitiveValue) { + m_style->setBoxReflect(RenderStyle::initialBoxReflect()); + return; + } + + if (!value->isReflectValue()) + return; + + CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value); + RefPtr<StyleReflection> reflection = StyleReflection::create(); + reflection->setDirection(reflectValue->direction()); + if (reflectValue->offset()) { + int type = reflectValue->offset()->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + reflection->setOffset(Length(reflectValue->offset()->getDoubleValue(), Percent)); + else + reflection->setOffset(Length(reflectValue->offset()->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed)); + } + NinePieceImage mask; + mapNinePieceImage(property, reflectValue->mask(), mask); + reflection->setMask(mask); + + m_style->setBoxReflect(reflection.release()); + return; + } + case CSSPropertyOpacity: + HANDLE_INHERIT_AND_INITIAL(opacity, Opacity) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; // Error case. + // Clamp opacity to the range 0-1 + m_style->setOpacity(min(1.0f, max(0.0f, primitiveValue->getFloatValue()))); + return; + case CSSPropertyWebkitBoxAlign: + { + HANDLE_INHERIT_AND_INITIAL(boxAlign, BoxAlign) + if (!primitiveValue) + return; + EBoxAlignment boxAlignment = *primitiveValue; + if (boxAlignment != BJUSTIFY) + m_style->setBoxAlign(boxAlignment); + return; + } + case CSSPropertySrc: // Only used in @font-face rules. + return; + case CSSPropertyUnicodeRange: // Only used in @font-face rules. + return; + case CSSPropertyWebkitBackfaceVisibility: + HANDLE_INHERIT_AND_INITIAL(backfaceVisibility, BackfaceVisibility) + if (primitiveValue) + m_style->setBackfaceVisibility((primitiveValue->getIdent() == CSSValueVisible) ? BackfaceVisibilityVisible : BackfaceVisibilityHidden); + return; + case CSSPropertyWebkitBoxDirection: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxDirection, BoxDirection) + return; + case CSSPropertyWebkitBoxLines: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxLines, BoxLines) + return; + case CSSPropertyWebkitBoxOrient: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxOrient, BoxOrient) + return; + case CSSPropertyWebkitBoxPack: + { + HANDLE_INHERIT_AND_INITIAL(boxPack, BoxPack) + if (!primitiveValue) + return; + EBoxAlignment boxPack = *primitiveValue; + if (boxPack != BSTRETCH && boxPack != BBASELINE) + m_style->setBoxPack(boxPack); + return; + } + case CSSPropertyWebkitBoxFlex: + HANDLE_INHERIT_AND_INITIAL(boxFlex, BoxFlex) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; // Error case. + m_style->setBoxFlex(primitiveValue->getFloatValue()); + return; + case CSSPropertyWebkitBoxFlexGroup: + HANDLE_INHERIT_AND_INITIAL(boxFlexGroup, BoxFlexGroup) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; // Error case. + m_style->setBoxFlexGroup((unsigned int)(primitiveValue->getDoubleValue())); + return; + case CSSPropertyWebkitBoxOrdinalGroup: + HANDLE_INHERIT_AND_INITIAL(boxOrdinalGroup, BoxOrdinalGroup) + if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) + return; // Error case. + m_style->setBoxOrdinalGroup((unsigned int)(primitiveValue->getDoubleValue())); + return; + case CSSPropertyBoxSizing: + HANDLE_INHERIT_AND_INITIAL(boxSizing, BoxSizing) + if (!primitiveValue) + return; + if (primitiveValue->getIdent() == CSSValueContentBox) + m_style->setBoxSizing(CONTENT_BOX); + else + m_style->setBoxSizing(BORDER_BOX); + return; + case CSSPropertyWebkitColumnCount: { + if (isInherit) { + if (m_parentStyle->hasAutoColumnCount()) + m_style->setHasAutoColumnCount(); + else + m_style->setColumnCount(m_parentStyle->columnCount()); + return; + } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { + m_style->setHasAutoColumnCount(); + return; + } + m_style->setColumnCount(static_cast<unsigned short>(primitiveValue->getDoubleValue())); + return; + } + case CSSPropertyWebkitColumnGap: { + if (isInherit) { + if (m_parentStyle->hasNormalColumnGap()) + m_style->setHasNormalColumnGap(); + else + m_style->setColumnGap(m_parentStyle->columnGap()); + return; + } else if (isInitial || primitiveValue->getIdent() == CSSValueNormal) { + m_style->setHasNormalColumnGap(); + return; + } + m_style->setColumnGap(primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor)); + return; + } + case CSSPropertyWebkitColumnSpan: { + HANDLE_INHERIT_AND_INITIAL(columnSpan, ColumnSpan) + m_style->setColumnSpan(primitiveValue->getIdent() == CSSValueAll); + return; + } + case CSSPropertyWebkitColumnWidth: { + if (isInherit) { + if (m_parentStyle->hasAutoColumnWidth()) + m_style->setHasAutoColumnWidth(); + else + m_style->setColumnWidth(m_parentStyle->columnWidth()); + return; + } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { + m_style->setHasAutoColumnWidth(); + return; + } + m_style->setColumnWidth(primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor)); + return; + } + case CSSPropertyWebkitColumnRuleStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnRuleStyle, ColumnRuleStyle, BorderStyle) + return; + case CSSPropertyWebkitColumnBreakBefore: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnBreakBefore, ColumnBreakBefore, PageBreak) + return; + case CSSPropertyWebkitColumnBreakAfter: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnBreakAfter, ColumnBreakAfter, PageBreak) + return; + case CSSPropertyWebkitColumnBreakInside: { + HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnBreakInside, ColumnBreakInside, PageBreak) + EPageBreak pb = *primitiveValue; + if (pb != PBALWAYS) + m_style->setColumnBreakInside(pb); + return; + } + case CSSPropertyWebkitColumnRule: + if (isInherit) { + m_style->setColumnRuleColor(m_parentStyle->columnRuleColor().isValid() ? m_parentStyle->columnRuleColor() : m_parentStyle->color()); + m_style->setColumnRuleStyle(m_parentStyle->columnRuleStyle()); + m_style->setColumnRuleWidth(m_parentStyle->columnRuleWidth()); + } + else if (isInitial) + m_style->resetColumnRule(); + return; + case CSSPropertyWebkitColumns: + if (isInherit) { + if (m_parentStyle->hasAutoColumnWidth()) + m_style->setHasAutoColumnWidth(); + else + m_style->setColumnWidth(m_parentStyle->columnWidth()); + m_style->setColumnCount(m_parentStyle->columnCount()); + } else if (isInitial) { + m_style->setHasAutoColumnWidth(); + m_style->setColumnCount(RenderStyle::initialColumnCount()); + } + return; + case CSSPropertyWebkitMarquee: + if (valueType != CSSValue::CSS_INHERIT || !m_parentNode) return; + m_style->setMarqueeDirection(m_parentStyle->marqueeDirection()); + m_style->setMarqueeIncrement(m_parentStyle->marqueeIncrement()); + m_style->setMarqueeSpeed(m_parentStyle->marqueeSpeed()); + m_style->setMarqueeLoopCount(m_parentStyle->marqueeLoopCount()); + m_style->setMarqueeBehavior(m_parentStyle->marqueeBehavior()); + return; +#if ENABLE(WCSS) + case CSSPropertyWapMarqueeLoop: +#endif + case CSSPropertyWebkitMarqueeRepetition: { + HANDLE_INHERIT_AND_INITIAL(marqueeLoopCount, MarqueeLoopCount) + if (!primitiveValue) + return; + if (primitiveValue->getIdent() == CSSValueInfinite) + m_style->setMarqueeLoopCount(-1); // -1 means repeat forever. + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) + m_style->setMarqueeLoopCount(primitiveValue->getIntValue()); + return; + } +#if ENABLE(WCSS) + case CSSPropertyWapMarqueeSpeed: +#endif + case CSSPropertyWebkitMarqueeSpeed: { + HANDLE_INHERIT_AND_INITIAL(marqueeSpeed, MarqueeSpeed) + if (!primitiveValue) + return; + if (primitiveValue->getIdent()) { + switch (primitiveValue->getIdent()) { + case CSSValueSlow: + m_style->setMarqueeSpeed(500); // 500 msec. + break; + case CSSValueNormal: + m_style->setMarqueeSpeed(85); // 85msec. The WinIE default. + break; + case CSSValueFast: + m_style->setMarqueeSpeed(10); // 10msec. Super fast. + break; + } + } + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) + m_style->setMarqueeSpeed(1000 * primitiveValue->getIntValue()); + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS) + m_style->setMarqueeSpeed(primitiveValue->getIntValue()); + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // For scrollamount support. + m_style->setMarqueeSpeed(primitiveValue->getIntValue()); + return; + } + case CSSPropertyWebkitMarqueeIncrement: { + HANDLE_INHERIT_AND_INITIAL(marqueeIncrement, MarqueeIncrement) + if (!primitiveValue) + return; + if (primitiveValue->getIdent()) { + switch (primitiveValue->getIdent()) { + case CSSValueSmall: + m_style->setMarqueeIncrement(Length(1, Fixed)); // 1px. + break; + case CSSValueNormal: + m_style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default. + break; + case CSSValueLarge: + m_style->setMarqueeIncrement(Length(36, Fixed)); // 36px. + break; + } + } + else { + bool ok = true; + Length l = convertToLength(primitiveValue, style(), m_rootElementStyle, 1, &ok); + if (ok) + m_style->setMarqueeIncrement(l); + } + return; + } +#if ENABLE(WCSS) + case CSSPropertyWapMarqueeStyle: +#endif + case CSSPropertyWebkitMarqueeStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marqueeBehavior, MarqueeBehavior) + return; +#if ENABLE(WCSS) + case CSSPropertyWapMarqueeDir: + HANDLE_INHERIT_AND_INITIAL(marqueeDirection, MarqueeDirection) + if (primitiveValue && primitiveValue->getIdent()) { + switch (primitiveValue->getIdent()) { + case CSSValueLtr: + m_style->setMarqueeDirection(MRIGHT); + break; + case CSSValueRtl: + m_style->setMarqueeDirection(MLEFT); + break; + default: + m_style->setMarqueeDirection(*primitiveValue); + break; + } + } + return; +#endif + case CSSPropertyWebkitMarqueeDirection: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marqueeDirection, MarqueeDirection) + return; + case CSSPropertyWebkitUserDrag: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userDrag, UserDrag) + return; + case CSSPropertyWebkitUserModify: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userModify, UserModify) + return; + case CSSPropertyWebkitUserSelect: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userSelect, UserSelect) + return; + + case CSSPropertyTextOverflow: { + // This property is supported by WinIE, and so we leave off the "-webkit-" in order to + // work with WinIE-specific pages that use the property. + HANDLE_INHERIT_AND_INITIAL(textOverflow, TextOverflow) + if (!primitiveValue || !primitiveValue->getIdent()) + return; + m_style->setTextOverflow(primitiveValue->getIdent() == CSSValueEllipsis); + return; + } + case CSSPropertyWebkitMarginCollapse: { + if (isInherit) { + m_style->setMarginBeforeCollapse(m_parentStyle->marginBeforeCollapse()); + m_style->setMarginAfterCollapse(m_parentStyle->marginAfterCollapse()); + } + else if (isInitial) { + m_style->setMarginBeforeCollapse(MCOLLAPSE); + m_style->setMarginAfterCollapse(MCOLLAPSE); + } + return; + } + + case CSSPropertyWebkitMarginBeforeCollapse: + case CSSPropertyWebkitMarginTopCollapse: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marginBeforeCollapse, MarginBeforeCollapse) + return; + case CSSPropertyWebkitMarginAfterCollapse: + case CSSPropertyWebkitMarginBottomCollapse: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marginAfterCollapse, MarginAfterCollapse) + return; + case CSSPropertyWebkitLineClamp: { + HANDLE_INHERIT_AND_INITIAL(lineClamp, LineClamp) + if (!primitiveValue) + return; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_NUMBER) + m_style->setLineClamp(LineClampValue(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_NUMBER), LineClampLineCount)); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + m_style->setLineClamp(LineClampValue(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_PERCENTAGE), LineClampPercentage)); + return; + } + case CSSPropertyWebkitHighlight: { + HANDLE_INHERIT_AND_INITIAL(highlight, Highlight); + if (primitiveValue->getIdent() == CSSValueNone) + m_style->setHighlight(nullAtom); + else + m_style->setHighlight(primitiveValue->getStringValue()); + return; + } + case CSSPropertyWebkitHyphens: { + HANDLE_INHERIT_AND_INITIAL(hyphens, Hyphens); + m_style->setHyphens(*primitiveValue); + return; + } + case CSSPropertyWebkitHyphenateCharacter: { + HANDLE_INHERIT_AND_INITIAL(hyphenationString, HyphenationString); + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setHyphenationString(nullAtom); + else + m_style->setHyphenationString(primitiveValue->getStringValue()); + return; + } + case CSSPropertyWebkitHyphenateLocale: { + HANDLE_INHERIT_AND_INITIAL(hyphenationLocale, HyphenationLocale); + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setHyphenationLocale(nullAtom); + else + m_style->setHyphenationLocale(primitiveValue->getStringValue()); + return; + } + case CSSPropertyWebkitBorderFit: { + HANDLE_INHERIT_AND_INITIAL(borderFit, BorderFit); + if (primitiveValue->getIdent() == CSSValueBorder) + m_style->setBorderFit(BorderFitBorder); + else + m_style->setBorderFit(BorderFitLines); + return; + } + case CSSPropertyWebkitTextSizeAdjust: { + HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust) + if (!primitiveValue || !primitiveValue->getIdent()) return; + m_style->setTextSizeAdjust(primitiveValue->getIdent() == CSSValueAuto); + m_fontDirty = true; + return; + } + case CSSPropertyWebkitTextSecurity: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textSecurity, TextSecurity) + return; + +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPropertyWebkitDashboardRegion: { + HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions) + if (!primitiveValue) + return; + + if (primitiveValue->getIdent() == CSSValueNone) { + m_style->setDashboardRegions(RenderStyle::noneDashboardRegions()); + return; + } + + DashboardRegion *region = primitiveValue->getDashboardRegionValue(); + if (!region) + return; + + DashboardRegion *first = region; + while (region) { + Length top = convertToLength(region->top(), style(), m_rootElementStyle); + Length right = convertToLength(region->right(), style(), m_rootElementStyle); + Length bottom = convertToLength(region->bottom(), style(), m_rootElementStyle); + Length left = convertToLength(region->left(), style(), m_rootElementStyle); + if (region->m_isCircle) + m_style->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true); + else if (region->m_isRectangle) + m_style->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true); + region = region->m_next.get(); + } + + m_element->document()->setHasDashboardRegions(true); + + return; + } +#endif + case CSSPropertyWebkitRtlOrdering: + HANDLE_INHERIT_AND_INITIAL(visuallyOrdered, VisuallyOrdered) + if (!primitiveValue || !primitiveValue->getIdent()) + return; + m_style->setVisuallyOrdered(primitiveValue->getIdent() == CSSValueVisual); + return; + case CSSPropertyWebkitTextStrokeWidth: { + HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth) + float width = 0; + switch (primitiveValue->getIdent()) { + case CSSValueThin: + case CSSValueMedium: + case CSSValueThick: { + double result = 1.0 / 48; + if (primitiveValue->getIdent() == CSSValueMedium) + result *= 3; + else if (primitiveValue->getIdent() == CSSValueThick) + result *= 5; + width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLengthFloat(style(), m_rootElementStyle, zoomFactor); + break; + } + default: + width = primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor); + break; + } + m_style->setTextStrokeWidth(width); + return; + } + case CSSPropertyWebkitTransform: { + HANDLE_INHERIT_AND_INITIAL(transform, Transform); + TransformOperations operations; + createTransformOperations(value, style(), m_rootElementStyle, operations); + m_style->setTransform(operations); + return; + } + case CSSPropertyWebkitTransformOrigin: + HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX) + HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY) + HANDLE_INHERIT_AND_INITIAL(transformOriginZ, TransformOriginZ) + return; + case CSSPropertyWebkitTransformOriginX: { + HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX) + if (!primitiveValue) + return; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setTransformOriginX(l); + break; + } + case CSSPropertyWebkitTransformOriginY: { + HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY) + if (!primitiveValue) + return; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setTransformOriginY(l); + break; + } + case CSSPropertyWebkitTransformOriginZ: { + HANDLE_INHERIT_AND_INITIAL(transformOriginZ, TransformOriginZ) + if (!primitiveValue) + return; + float f; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + f = static_cast<float>(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle)); + else + return; + m_style->setTransformOriginZ(f); + break; + } + case CSSPropertyWebkitTransformStyle: + HANDLE_INHERIT_AND_INITIAL(transformStyle3D, TransformStyle3D) + if (primitiveValue) + m_style->setTransformStyle3D((primitiveValue->getIdent() == CSSValuePreserve3d) ? TransformStyle3DPreserve3D : TransformStyle3DFlat); + return; + case CSSPropertyWebkitPerspective: { + HANDLE_INHERIT_AND_INITIAL(perspective, Perspective) + if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { + m_style->setPerspective(0); + return; + } + + float perspectiveValue; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + perspectiveValue = static_cast<float>(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor)); + else if (type == CSSPrimitiveValue::CSS_NUMBER) { + // For backward compatibility, treat valueless numbers as px. + perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLengthFloat(style(), m_rootElementStyle, zoomFactor); + } else + return; + + if (perspectiveValue >= 0.0f) + m_style->setPerspective(perspectiveValue); + return; + } + case CSSPropertyWebkitPerspectiveOrigin: + HANDLE_INHERIT_AND_INITIAL(perspectiveOriginX, PerspectiveOriginX) + HANDLE_INHERIT_AND_INITIAL(perspectiveOriginY, PerspectiveOriginY) + return; + case CSSPropertyWebkitPerspectiveOriginX: { + HANDLE_INHERIT_AND_INITIAL(perspectiveOriginX, PerspectiveOriginX) + if (!primitiveValue) + return; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setPerspectiveOriginX(l); + return; + } + case CSSPropertyWebkitPerspectiveOriginY: { + HANDLE_INHERIT_AND_INITIAL(perspectiveOriginY, PerspectiveOriginY) + if (!primitiveValue) + return; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setPerspectiveOriginY(l); + return; + } + case CSSPropertyWebkitAnimation: + if (isInitial) + m_style->clearAnimations(); + else if (isInherit) + m_style->inheritAnimations(m_parentStyle->animations()); + return; + case CSSPropertyWebkitAnimationDelay: + HANDLE_ANIMATION_VALUE(delay, Delay, value) + return; + case CSSPropertyWebkitAnimationDirection: + HANDLE_ANIMATION_VALUE(direction, Direction, value) + return; + case CSSPropertyWebkitAnimationDuration: + HANDLE_ANIMATION_VALUE(duration, Duration, value) + return; + case CSSPropertyWebkitAnimationFillMode: + HANDLE_ANIMATION_VALUE(fillMode, FillMode, value) + return; + case CSSPropertyWebkitAnimationIterationCount: + HANDLE_ANIMATION_VALUE(iterationCount, IterationCount, value) + return; + case CSSPropertyWebkitAnimationName: + HANDLE_ANIMATION_VALUE(name, Name, value) + return; + case CSSPropertyWebkitAnimationPlayState: + HANDLE_ANIMATION_VALUE(playState, PlayState, value) + return; + case CSSPropertyWebkitAnimationTimingFunction: + HANDLE_ANIMATION_VALUE(timingFunction, TimingFunction, value) + return; + case CSSPropertyWebkitTransition: + if (isInitial) + m_style->clearTransitions(); + else if (isInherit) + m_style->inheritTransitions(m_parentStyle->transitions()); + return; + case CSSPropertyWebkitTransitionDelay: + HANDLE_TRANSITION_VALUE(delay, Delay, value) + return; + case CSSPropertyWebkitTransitionDuration: + HANDLE_TRANSITION_VALUE(duration, Duration, value) + return; + case CSSPropertyWebkitTransitionProperty: + HANDLE_TRANSITION_VALUE(property, Property, value) + return; + case CSSPropertyWebkitTransitionTimingFunction: + HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value) + return; + case CSSPropertyPointerEvents: + { +#if ENABLE(DASHBOARD_SUPPORT) + // <rdar://problem/6561077> Work around the Stocks widget's misuse of the + // pointer-events property by not applying it in Dashboard. + Settings* settings = m_checker.m_document->settings(); + if (settings && settings->usesDashboardBackwardCompatibilityMode()) + return; +#endif + HANDLE_INHERIT_AND_INITIAL(pointerEvents, PointerEvents) + if (!primitiveValue) + return; + m_style->setPointerEvents(*primitiveValue); + return; + } + case CSSPropertyWebkitColorCorrection: + if (isInherit) + m_style->setColorSpace(m_parentStyle->colorSpace()); + else if (isInitial) + m_style->setColorSpace(ColorSpaceDeviceRGB); + else { + if (!primitiveValue) + return; + m_style->setColorSpace(*primitiveValue); + } + return; + case CSSPropertySize: + applyPageSizeProperty(value); + return; + + case CSSPropertySpeak: + HANDLE_INHERIT_AND_INITIAL(speak, Speak); + if (!primitiveValue) + return; + m_style->setSpeak(*primitiveValue); + return; + + case CSSPropertyInvalid: + return; + + // Directional properties are resolved by resolveDirectionAwareProperty() before the switch. + case CSSPropertyWebkitBorderEnd: + case CSSPropertyWebkitBorderEndColor: + case CSSPropertyWebkitBorderEndStyle: + case CSSPropertyWebkitBorderEndWidth: + case CSSPropertyWebkitBorderStart: + case CSSPropertyWebkitBorderStartColor: + case CSSPropertyWebkitBorderStartStyle: + case CSSPropertyWebkitBorderStartWidth: + case CSSPropertyWebkitBorderBefore: + case CSSPropertyWebkitBorderBeforeColor: + case CSSPropertyWebkitBorderBeforeStyle: + case CSSPropertyWebkitBorderBeforeWidth: + case CSSPropertyWebkitBorderAfter: + case CSSPropertyWebkitBorderAfterColor: + case CSSPropertyWebkitBorderAfterStyle: + case CSSPropertyWebkitBorderAfterWidth: + case CSSPropertyWebkitMarginEnd: + case CSSPropertyWebkitMarginStart: + case CSSPropertyWebkitMarginBefore: + case CSSPropertyWebkitMarginAfter: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitPaddingAfter: + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + case CSSPropertyWebkitMaxLogicalWidth: + case CSSPropertyWebkitMaxLogicalHeight: + ASSERT_NOT_REACHED(); + break; + + case CSSPropertyFontStretch: + case CSSPropertyPage: + case CSSPropertyQuotes: + case CSSPropertyTextLineThrough: + case CSSPropertyTextLineThroughColor: + case CSSPropertyTextLineThroughMode: + case CSSPropertyTextLineThroughStyle: + case CSSPropertyTextLineThroughWidth: + case CSSPropertyTextOverline: + case CSSPropertyTextOverlineColor: + case CSSPropertyTextOverlineMode: + case CSSPropertyTextOverlineStyle: + case CSSPropertyTextOverlineWidth: + case CSSPropertyTextUnderline: + case CSSPropertyTextUnderlineColor: + case CSSPropertyTextUnderlineMode: + case CSSPropertyTextUnderlineStyle: + case CSSPropertyTextUnderlineWidth: + case CSSPropertyWebkitFontSizeDelta: + case CSSPropertyWebkitTextDecorationsInEffect: + case CSSPropertyWebkitTextStroke: + case CSSPropertyWebkitTextEmphasis: + return; +#if ENABLE(WCSS) + case CSSPropertyWapInputFormat: + if (primitiveValue && m_element->hasTagName(WebCore::inputTag)) { + String mask = primitiveValue->getStringValue(); + static_cast<HTMLInputElement*>(m_element)->setWapInputFormat(mask); + } + return; + + case CSSPropertyWapInputRequired: + if (primitiveValue && m_element->isFormControlElement()) { + HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(m_element); + bool required = primitiveValue->getStringValue() == "true"; + element->setRequired(required); + } + return; +#endif + + // CSS Text Layout Module Level 3: Vertical writing support + case CSSPropertyWebkitWritingMode: { + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(writingMode, WritingMode) + if (!isInherit && !isInitial && m_element && m_element == m_element->document()->documentElement()) + m_element->document()->setWritingModeSetOnDocumentElement(true); + FontDescription fontDescription = m_style->fontDescription(); + fontDescription.setOrientation(m_style->isHorizontalWritingMode() ? Horizontal : Vertical); + if (m_style->setFontDescription(fontDescription)) + m_fontDirty = true; + return; + } + + case CSSPropertyWebkitTextCombine: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textCombine, TextCombine) + return; + + case CSSPropertyWebkitTextEmphasisPosition: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textEmphasisPosition, TextEmphasisPosition) + return; + + case CSSPropertyWebkitTextEmphasisStyle: + HANDLE_INHERIT_AND_INITIAL(textEmphasisFill, TextEmphasisFill) + HANDLE_INHERIT_AND_INITIAL(textEmphasisMark, TextEmphasisMark) + HANDLE_INHERIT_AND_INITIAL(textEmphasisCustomMark, TextEmphasisCustomMark) + if (isInherit || isInitial) + return; + + if (value->isValueList()) { + CSSValueList* list = static_cast<CSSValueList*>(value); + ASSERT(list->length() == 2); + if (list->length() != 2) + return; + for (unsigned i = 0; i < 2; ++i) { + ASSERT(list->itemWithoutBoundsCheck(i)->isPrimitiveValue()); + CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(list->itemWithoutBoundsCheck(i)); + if (value->getIdent() == CSSValueFilled || value->getIdent() == CSSValueOpen) + m_style->setTextEmphasisFill(*value); + else + m_style->setTextEmphasisMark(*value); + } + m_style->setTextEmphasisCustomMark(nullAtom); + return; + } + + if (!primitiveValue) + return; + + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING) { + m_style->setTextEmphasisFill(TextEmphasisFillFilled); + m_style->setTextEmphasisMark(TextEmphasisMarkCustom); + m_style->setTextEmphasisCustomMark(primitiveValue->getStringValue()); + return; + } + + m_style->setTextEmphasisCustomMark(nullAtom); + + if (primitiveValue->getIdent() == CSSValueFilled || primitiveValue->getIdent() == CSSValueOpen) { + m_style->setTextEmphasisFill(*primitiveValue); + m_style->setTextEmphasisMark(TextEmphasisMarkAuto); + } else { + m_style->setTextEmphasisFill(TextEmphasisFillFilled); + m_style->setTextEmphasisMark(*primitiveValue); + } + + return; + +#ifdef ANDROID_CSS_RING + case CSSPropertyWebkitRing: + if (valueType != CSSValue::CSS_INHERIT || !m_parentNode) return; + m_style->setRingFillColor(m_parentStyle->ringFillColor()); + m_style->setRingInnerWidth(m_parentStyle->ringInnerWidth()); + m_style->setRingOuterWidth(m_parentStyle->ringOuterWidth()); + m_style->setRingOutset(m_parentStyle->ringOutset()); + m_style->setRingPressedInnerColor(m_parentStyle->ringPressedInnerColor()); + m_style->setRingPressedOuterColor(m_parentStyle->ringPressedOuterColor()); + m_style->setRingRadius(m_parentStyle->ringRadius()); + m_style->setRingSelectedInnerColor(m_parentStyle->ringSelectedInnerColor()); + m_style->setRingSelectedOuterColor(m_parentStyle->ringSelectedOuterColor()); + return; + case CSSPropertyWebkitRingFillColor: { + HANDLE_INHERIT_AND_INITIAL(ringFillColor, RingFillColor); + if (!primitiveValue) + break; + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setRingFillColor(col); + return; + } + case CSSPropertyWebkitRingInnerWidth: { + HANDLE_INHERIT_AND_INITIAL(ringInnerWidth, RingInnerWidth) + if (!primitiveValue) + break; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) { + // width can be specified with fractional px + // scale by 16 here (and unscale in android_graphics) to keep + // 4 bits of fraction + RefPtr<CSSPrimitiveValue> scaledValue = CSSPrimitiveValue::create( + primitiveValue->getFloatValue() * 16, + (CSSPrimitiveValue::UnitTypes) type); + l = Length(scaledValue->computeLengthIntForLength(style(), + m_rootElementStyle, zoomFactor), Fixed); + scaledValue.release(); + } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setRingInnerWidth(l); + return; + } + case CSSPropertyWebkitRingOuterWidth: { + HANDLE_INHERIT_AND_INITIAL(ringOuterWidth, RingOuterWidth) + if (!primitiveValue) + break; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) { + // width can be specified with fractional px + // scale by 16 here (and unscale in android_graphics) to keep + // 4 bits of fraction + RefPtr<CSSPrimitiveValue> scaledValue = CSSPrimitiveValue::create( + primitiveValue->getFloatValue() * 16, + (CSSPrimitiveValue::UnitTypes) type); + l = Length(scaledValue->computeLengthIntForLength(style(), + m_rootElementStyle, zoomFactor), Fixed); + scaledValue.release(); + } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setRingOuterWidth(l); + return; + } + case CSSPropertyWebkitRingOutset: { + HANDLE_INHERIT_AND_INITIAL(ringOutset, RingOutset) + if (!primitiveValue) + break; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), + m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setRingOutset(l); + return; + } + case CSSPropertyWebkitRingPressedInnerColor: { + HANDLE_INHERIT_AND_INITIAL(ringPressedInnerColor, RingPressedInnerColor); + if (!primitiveValue) + break; + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setRingPressedInnerColor(col); + return; + } + case CSSPropertyWebkitRingPressedOuterColor: { + HANDLE_INHERIT_AND_INITIAL(ringPressedOuterColor, RingPressedOuterColor); + if (!primitiveValue) + break; + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setRingPressedOuterColor(col); + return; + } + case CSSPropertyWebkitRingRadius: { + HANDLE_INHERIT_AND_INITIAL(ringRadius, RingRadius) + if (!primitiveValue) + break; + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), + m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + m_style->setRingRadius(l); + return; + } + case CSSPropertyWebkitRingSelectedInnerColor: { + HANDLE_INHERIT_AND_INITIAL(ringSelectedInnerColor, RingSelectedInnerColor); + if (!primitiveValue) + break; + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setRingSelectedInnerColor(col); + return; + } + case CSSPropertyWebkitRingSelectedOuterColor: { + HANDLE_INHERIT_AND_INITIAL(ringSelectedOuterColor, RingSelectedOuterColor); + if (!primitiveValue) + break; + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setRingSelectedOuterColor(col); + return; + } +#endif +#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR + case CSSPropertyWebkitTapHighlightColor: { + HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor); + if (!primitiveValue) + break; + + Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); + m_style->setTapHighlightColor(col); + return; + } +#endif + +#if ENABLE(SVG) + default: + // Try the SVG properties + applySVGProperty(id, value); +#endif + } +} + +void CSSStyleSelector::applyPageSizeProperty(CSSValue* value) +{ + m_style->resetPageSizeType(); + if (!value->isValueList()) + return; + CSSValueList* valueList = static_cast<CSSValueList*>(value); + Length width; + Length height; + PageSizeType pageSizeType = PAGE_SIZE_AUTO; + switch (valueList->length()) { + case 2: { + // <length>{2} | <page-size> <orientation> + pageSizeType = PAGE_SIZE_RESOLVED; + if (!valueList->item(0)->isPrimitiveValue() || !valueList->item(1)->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue0 = static_cast<CSSPrimitiveValue*>(valueList->item(0)); + CSSPrimitiveValue* primitiveValue1 = static_cast<CSSPrimitiveValue*>(valueList->item(1)); + int type0 = primitiveValue0->primitiveType(); + int type1 = primitiveValue1->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type0)) { + // <length>{2} + if (!CSSPrimitiveValue::isUnitTypeLength(type1)) + return; + width = Length(primitiveValue0->computeLengthIntForLength(style(), m_rootElementStyle), Fixed); + height = Length(primitiveValue1->computeLengthIntForLength(style(), m_rootElementStyle), Fixed); + } else { + // <page-size> <orientation> + // The value order is guaranteed. See CSSParser::parseSizeParameter. + if (!pageSizeFromName(primitiveValue0, primitiveValue1, width, height)) + return; + } + break; + } + case 1: { + // <length> | auto | <page-size> | [ portrait | landscape] + if (!valueList->item(0)->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(valueList->item(0)); + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) { + // <length> + pageSizeType = PAGE_SIZE_RESOLVED; + width = height = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle), Fixed); + } else { + if (type != CSSPrimitiveValue::CSS_IDENT) + return; + switch (primitiveValue->getIdent()) { + case CSSValueAuto: + pageSizeType = PAGE_SIZE_AUTO; + break; + case CSSValuePortrait: + pageSizeType = PAGE_SIZE_AUTO_PORTRAIT; + break; + case CSSValueLandscape: + pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE; + break; + default: + // <page-size> + pageSizeType = PAGE_SIZE_RESOLVED; + if (!pageSizeFromName(primitiveValue, 0, width, height)) + return; + } + } + break; + } + default: + return; + } + m_style->setPageSizeType(pageSizeType); + m_style->setPageSize(LengthSize(width, height)); + return; +} + +bool CSSStyleSelector::pageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height) +{ + static const Length a5Width = mmLength(148), a5Height = mmLength(210); + static const Length a4Width = mmLength(210), a4Height = mmLength(297); + static const Length a3Width = mmLength(297), a3Height = mmLength(420); + static const Length b5Width = mmLength(176), b5Height = mmLength(250); + static const Length b4Width = mmLength(250), b4Height = mmLength(353); + static const Length letterWidth = inchLength(8.5), letterHeight = inchLength(11); + static const Length legalWidth = inchLength(8.5), legalHeight = inchLength(14); + static const Length ledgerWidth = inchLength(11), ledgerHeight = inchLength(17); + + if (!pageSizeName || pageSizeName->primitiveType() != CSSPrimitiveValue::CSS_IDENT) + return false; + + switch (pageSizeName->getIdent()) { + case CSSValueA5: + width = a5Width; + height = a5Height; + break; + case CSSValueA4: + width = a4Width; + height = a4Height; + break; + case CSSValueA3: + width = a3Width; + height = a3Height; + break; + case CSSValueB5: + width = b5Width; + height = b5Height; + break; + case CSSValueB4: + width = b4Width; + height = b4Height; + break; + case CSSValueLetter: + width = letterWidth; + height = letterHeight; + break; + case CSSValueLegal: + width = legalWidth; + height = legalHeight; + break; + case CSSValueLedger: + width = ledgerWidth; + height = ledgerHeight; + break; + default: + return false; + } + + if (pageOrientation) { + if (pageOrientation->primitiveType() != CSSPrimitiveValue::CSS_IDENT) + return false; + switch (pageOrientation->getIdent()) { + case CSSValueLandscape: + std::swap(width, height); + break; + case CSSValuePortrait: + // Nothing to do. + break; + default: + return false; + } + } + return true; +} + +Length CSSStyleSelector::mmLength(double mm) const +{ + return Length(CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM)->computeLengthIntForLength(style(), m_rootElementStyle), Fixed); +} + +Length CSSStyleSelector::inchLength(double inch) const +{ + return Length(CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN)->computeLengthIntForLength(style(), m_rootElementStyle), Fixed); +} + +void CSSStyleSelector::mapFillAttachment(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setAttachment(FillLayer::initialFillAttachment(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + switch (primitiveValue->getIdent()) { + case CSSValueFixed: + layer->setAttachment(FixedBackgroundAttachment); + break; + case CSSValueScroll: + layer->setAttachment(ScrollBackgroundAttachment); + break; + case CSSValueLocal: + layer->setAttachment(LocalBackgroundAttachment); + break; + default: + return; + } +} + +void CSSStyleSelector::mapFillClip(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setClip(FillLayer::initialFillClip(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setClip(*primitiveValue); +} + +void CSSStyleSelector::mapFillComposite(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setComposite(FillLayer::initialFillComposite(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setComposite(*primitiveValue); +} + +void CSSStyleSelector::mapFillOrigin(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setOrigin(FillLayer::initialFillOrigin(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setOrigin(*primitiveValue); +} + +StyleImage* CSSStyleSelector::styleImage(CSSPropertyID property, CSSValue* value) +{ + if (value->isImageValue()) + return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value)); + + if (value->isImageGeneratorValue()) + return static_cast<CSSImageGeneratorValue*>(value)->generatedImage(); + + return 0; +} + +StyleImage* CSSStyleSelector::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value) +{ + StyleImage* image = value->cachedOrPendingImage(); + if (image && image->isPendingImage()) + m_pendingImageProperties.add(property); + return image; +} + +void CSSStyleSelector::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setImage(FillLayer::initialFillImage(layer->type())); + return; + } + + layer->setImage(styleImage(property, value)); +} + +void CSSStyleSelector::mapFillRepeatX(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setRepeatX(*primitiveValue); +} + +void CSSStyleSelector::mapFillRepeatY(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setRepeatY(*primitiveValue); +} + +void CSSStyleSelector::mapFillSize(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (!value->isPrimitiveValue()) { + layer->setSizeType(SizeNone); + return; + } + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == CSSValueContain) + layer->setSizeType(Contain); + else if (primitiveValue->getIdent() == CSSValueCover) + layer->setSizeType(Cover); + else + layer->setSizeType(SizeLength); + + LengthSize b = FillLayer::initialFillSizeLength(layer->type()); + + if (value->cssValueType() == CSSValue::CSS_INITIAL || primitiveValue->getIdent() == CSSValueContain + || primitiveValue->getIdent() == CSSValueCover) { + layer->setSizeLength(b); + return; + } + + Pair* pair = primitiveValue->getPairValue(); + if (!pair || !pair->first() || !pair->second()) + return; + + CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(pair->first()); + CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(pair->second()); + + Length firstLength, secondLength; + int firstType = first->primitiveType(); + int secondType = second->primitiveType(); + + float zoomFactor = m_style->effectiveZoom(); + + if (firstType == CSSPrimitiveValue::CSS_UNKNOWN) + firstLength = Length(Auto); + else if (CSSPrimitiveValue::isUnitTypeLength(firstType)) + firstLength = Length(first->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (firstType == CSSPrimitiveValue::CSS_PERCENTAGE) + firstLength = Length(first->getDoubleValue(), Percent); + else + return; + + if (secondType == CSSPrimitiveValue::CSS_UNKNOWN) + secondLength = Length(Auto); + else if (CSSPrimitiveValue::isUnitTypeLength(secondType)) + secondLength = Length(second->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (secondType == CSSPrimitiveValue::CSS_PERCENTAGE) + secondLength = Length(second->getDoubleValue(), Percent); + else + return; + + b.setWidth(firstLength); + b.setHeight(secondLength); + layer->setSizeLength(b); +} + +void CSSStyleSelector::mapFillXPosition(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setXPosition(FillLayer::initialFillXPosition(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + float zoomFactor = m_style->effectiveZoom(); + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + layer->setXPosition(l); +} + +void CSSStyleSelector::mapFillYPosition(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setYPosition(FillLayer::initialFillYPosition(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + float zoomFactor = m_style->effectiveZoom(); + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + Length l; + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) + l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed); + else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + l = Length(primitiveValue->getDoubleValue(), Percent); + else + return; + layer->setYPosition(l); +} + +void CSSStyleSelector::mapAnimationDelay(Animation* animation, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + animation->setDelay(Animation::initialAnimationDelay()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) + animation->setDelay(primitiveValue->getFloatValue()); + else + animation->setDelay(primitiveValue->getFloatValue()/1000.0f); +} + +void CSSStyleSelector::mapAnimationDirection(Animation* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setDirection(Animation::initialAnimationDirection()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setDirection(primitiveValue->getIdent() == CSSValueAlternate ? Animation::AnimationDirectionAlternate : Animation::AnimationDirectionNormal); +} + +void CSSStyleSelector::mapAnimationDuration(Animation* animation, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + animation->setDuration(Animation::initialAnimationDuration()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) + animation->setDuration(primitiveValue->getFloatValue()); + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS) + animation->setDuration(primitiveValue->getFloatValue()/1000.0f); +} + +void CSSStyleSelector::mapAnimationFillMode(Animation* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setFillMode(Animation::initialAnimationFillMode()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + switch (primitiveValue->getIdent()) { + case CSSValueNone: + layer->setFillMode(AnimationFillModeNone); + break; + case CSSValueForwards: + layer->setFillMode(AnimationFillModeForwards); + break; + case CSSValueBackwards: + layer->setFillMode(AnimationFillModeBackwards); + break; + case CSSValueBoth: + layer->setFillMode(AnimationFillModeBoth); + break; + } +} + +void CSSStyleSelector::mapAnimationIterationCount(Animation* animation, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + animation->setIterationCount(Animation::initialAnimationIterationCount()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == CSSValueInfinite) + animation->setIterationCount(-1); + else + animation->setIterationCount(int(primitiveValue->getFloatValue())); +} + +void CSSStyleSelector::mapAnimationName(Animation* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setName(Animation::initialAnimationName()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == CSSValueNone) + layer->setIsNoneAnimation(true); + else + layer->setName(primitiveValue->getStringValue()); +} + +void CSSStyleSelector::mapAnimationPlayState(Animation* layer, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + layer->setPlayState(Animation::initialAnimationPlayState()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + EAnimPlayState playState = (primitiveValue->getIdent() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying; + layer->setPlayState(playState); +} + +void CSSStyleSelector::mapAnimationProperty(Animation* animation, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + animation->setProperty(Animation::initialAnimationProperty()); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == CSSValueAll) + animation->setProperty(cAnimateAll); + else if (primitiveValue->getIdent() == CSSValueNone) + animation->setProperty(cAnimateNone); + else + animation->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent())); +} + +void CSSStyleSelector::mapAnimationTimingFunction(Animation* animation, CSSValue* value) +{ + if (value->cssValueType() == CSSValue::CSS_INITIAL) { + animation->setTimingFunction(Animation::initialAnimationTimingFunction()); + return; + } + + if (value->isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + switch (primitiveValue->getIdent()) { + case CSSValueLinear: + animation->setTimingFunction(LinearTimingFunction::create()); + break; + case CSSValueEase: + animation->setTimingFunction(CubicBezierTimingFunction::create()); + break; + case CSSValueEaseIn: + animation->setTimingFunction(CubicBezierTimingFunction::create(0.42, 0.0, 1.0, 1.0)); + break; + case CSSValueEaseOut: + animation->setTimingFunction(CubicBezierTimingFunction::create(0.0, 0.0, 0.58, 1.0)); + break; + case CSSValueEaseInOut: + animation->setTimingFunction(CubicBezierTimingFunction::create(0.42, 0.0, 0.58, 1.0)); + break; + case CSSValueStepStart: + animation->setTimingFunction(StepsTimingFunction::create(1, true)); + break; + case CSSValueStepEnd: + animation->setTimingFunction(StepsTimingFunction::create(1, false)); + break; + } + return; + } + + if (value->isTimingFunctionValue()) { + CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value); + if (timingFunction->isCubicBezierTimingFunctionValue()) { + CSSCubicBezierTimingFunctionValue* cubicTimingFunction = static_cast<CSSCubicBezierTimingFunctionValue*>(value); + animation->setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2())); + } else if (timingFunction->isStepsTimingFunctionValue()) { + CSSStepsTimingFunctionValue* stepsTimingFunction = static_cast<CSSStepsTimingFunctionValue*>(value); + animation->setTimingFunction(StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart())); + } else + animation->setTimingFunction(LinearTimingFunction::create()); + } +} + +void CSSStyleSelector::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image) +{ + // If we're a primitive value, then we are "none" and don't need to alter the empty image at all. + if (!value || value->isPrimitiveValue() || !value->isBorderImageValue()) + return; + + // Retrieve the border image value. + CSSBorderImageValue* borderImage = static_cast<CSSBorderImageValue*>(value); + + // Set the image (this kicks off the load). + image.setImage(styleImage(property, borderImage->imageValue())); + + // Set up a length box to represent our image slices. + LengthBox l; + Rect* r = borderImage->m_imageSliceRect.get(); + if (r->top()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + l.m_top = Length(r->top()->getDoubleValue(), Percent); + else + l.m_top = Length(r->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (r->bottom()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + l.m_bottom = Length(r->bottom()->getDoubleValue(), Percent); + else + l.m_bottom = Length((int)r->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (r->left()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + l.m_left = Length(r->left()->getDoubleValue(), Percent); + else + l.m_left = Length(r->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (r->right()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + l.m_right = Length(r->right()->getDoubleValue(), Percent); + else + l.m_right = Length(r->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + image.setSlices(l); + + // Set the appropriate rules for stretch/round/repeat of the slices + ENinePieceImageRule horizontalRule; + switch (borderImage->m_horizontalSizeRule) { + case CSSValueStretch: + horizontalRule = StretchImageRule; + break; + case CSSValueRound: + horizontalRule = RoundImageRule; + break; + default: // CSSValueRepeat + horizontalRule = RepeatImageRule; + break; + } + image.setHorizontalRule(horizontalRule); + + ENinePieceImageRule verticalRule; + switch (borderImage->m_verticalSizeRule) { + case CSSValueStretch: + verticalRule = StretchImageRule; + break; + case CSSValueRound: + verticalRule = RoundImageRule; + break; + default: // CSSValueRepeat + verticalRule = RepeatImageRule; + break; + } + image.setVerticalRule(verticalRule); +} + +void CSSStyleSelector::checkForTextSizeAdjust() +{ + if (m_style->textSizeAdjust()) + return; + + FontDescription newFontDescription(m_style->fontDescription()); + newFontDescription.setComputedSize(newFontDescription.specifiedSize()); + m_style->setFontDescription(newFontDescription); +} + +void CSSStyleSelector::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle) +{ + if (style->effectiveZoom() == parentStyle->effectiveZoom()) + return; + + const FontDescription& childFont = style->fontDescription(); + FontDescription newFontDescription(childFont); + setFontSize(newFontDescription, childFont.specifiedSize()); + style->setFontDescription(newFontDescription); +} + +void CSSStyleSelector::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle) +{ + const FontDescription& childFont = style->fontDescription(); + + if (childFont.isAbsoluteSize() || !parentStyle) + return; + + const FontDescription& parentFont = parentStyle->fontDescription(); + if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize()) + return; + + // For now, lump all families but monospace together. + if (childFont.genericFamily() != FontDescription::MonospaceFamily && + parentFont.genericFamily() != FontDescription::MonospaceFamily) + return; + + // We know the parent is monospace or the child is monospace, and that font + // size was unspecified. We want to scale our font size as appropriate. + // If the font uses a keyword size, then we refetch from the table rather than + // multiplying by our scale factor. + float size; + if (childFont.keywordSize()) + size = fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize()); + else { + Settings* settings = m_checker.m_document->settings(); + float fixedScaleFactor = settings + ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize() + : 1; + size = parentFont.useFixedDefaultSize() ? + childFont.specifiedSize() / fixedScaleFactor : + childFont.specifiedSize() * fixedScaleFactor; + } + + FontDescription newFontDescription(childFont); + setFontSize(newFontDescription, size); + style->setFontDescription(newFontDescription); +} + +void CSSStyleSelector::setFontSize(FontDescription& fontDescription, float size) +{ + fontDescription.setSpecifiedSize(size); + + bool useSVGZoomRules = m_element && m_element->isSVGElement(); + fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.m_document, m_style.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules)); +} + +float CSSStyleSelector::getComputedSizeFromSpecifiedSize(Document* document, RenderStyle* style, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules) +{ + float zoomFactor = 1.0f; + if (!useSVGZoomRules) { + zoomFactor = style->effectiveZoom(); + if (Frame* frame = document->frame()) + zoomFactor *= frame->textZoomFactor(); + } + + // We support two types of minimum font size. The first is a hard override that applies to + // all fonts. This is "minSize." The second type of minimum font size is a "smart minimum" + // that is applied only when the Web page can't know what size it really asked for, e.g., + // when it uses logical sizes like "small" or expresses the font-size as a percentage of + // the user's default font setting. + + // With the smart minimum, we never want to get smaller than the minimum font size to keep fonts readable. + // However we always allow the page to set an explicit pixel size that is smaller, + // since sites will mis-render otherwise (e.g., http://www.gamespot.com with a 9px minimum). + + Settings* settings = document->settings(); + if (!settings) + return 1.0f; + + int minSize = settings->minimumFontSize(); + int minLogicalSize = settings->minimumLogicalFontSize(); + float zoomedSize = specifiedSize * zoomFactor; + + // Apply the hard minimum first. We only apply the hard minimum if after zooming we're still too small. + if (zoomedSize < minSize) + zoomedSize = minSize; + + // Now apply the "smart minimum." This minimum is also only applied if we're still too small + // after zooming. The font size must either be relative to the user default or the original size + // must have been acceptable. In other words, we only apply the smart minimum whenever we're positive + // doing so won't disrupt the layout. + if (zoomedSize < minLogicalSize && (specifiedSize >= minLogicalSize || !isAbsoluteSize)) + zoomedSize = minLogicalSize; + + // Also clamp to a reasonable maximum to prevent insane font sizes from causing crashes on various + // platforms (I'm looking at you, Windows.) + return min(1000000.0f, zoomedSize); +} + +const int fontSizeTableMax = 16; +const int fontSizeTableMin = 9; +const int totalKeywords = 8; + +// WinIE/Nav4 table for font sizes. Designed to match the legacy font mapping system of HTML. +static const int quirksFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = +{ + { 9, 9, 9, 9, 11, 14, 18, 28 }, + { 9, 9, 9, 10, 12, 15, 20, 31 }, + { 9, 9, 9, 11, 13, 17, 22, 34 }, + { 9, 9, 10, 12, 14, 18, 24, 37 }, + { 9, 9, 10, 13, 16, 20, 26, 40 }, // fixed font default (13) + { 9, 9, 11, 14, 17, 21, 28, 42 }, + { 9, 10, 12, 15, 17, 23, 30, 45 }, + { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) +}; +// HTML 1 2 3 4 5 6 7 +// CSS xxs xs s m l xl xxl +// | +// user pref + +// Strict mode table matches MacIE and Mozilla's settings exactly. +static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = +{ + { 9, 9, 9, 9, 11, 14, 18, 27 }, + { 9, 9, 9, 10, 12, 15, 20, 30 }, + { 9, 9, 10, 11, 13, 17, 22, 33 }, + { 9, 9, 10, 12, 14, 18, 24, 36 }, + { 9, 10, 12, 13, 16, 20, 26, 39 }, // fixed font default (13) + { 9, 10, 12, 14, 17, 21, 28, 42 }, + { 9, 10, 13, 15, 18, 23, 30, 45 }, + { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) +}; +// HTML 1 2 3 4 5 6 7 +// CSS xxs xs s m l xl xxl +// | +// user pref + +// For values outside the range of the table, we use Todd Fahrner's suggested scale +// factors for each keyword value. +static const float fontSizeFactors[totalKeywords] = { 0.60f, 0.75f, 0.89f, 1.0f, 1.2f, 1.5f, 2.0f, 3.0f }; + +float CSSStyleSelector::fontSizeForKeyword(Document* document, int keyword, bool shouldUseFixedDefaultSize) +{ + Settings* settings = document->settings(); + if (!settings) + return 1.0f; + + bool quirksMode = document->inQuirksMode(); + int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize(); + if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) { + // Look up the entry in the table. + int row = mediumSize - fontSizeTableMin; + int col = (keyword - CSSValueXxSmall); + return quirksMode ? quirksFontSizeTable[row][col] : strictFontSizeTable[row][col]; + } + + // Value is outside the range of the table. Apply the scale factor instead. + float minLogicalSize = max(settings->minimumLogicalFontSize(), 1); + return max(fontSizeFactors[keyword - CSSValueXxSmall]*mediumSize, minLogicalSize); +} + +template<typename T> +static int findNearestLegacyFontSize(int pixelFontSize, const T* table, int multiplier) +{ + // Ignore table[0] because xx-small does not correspond to any legacy font size. + for (int i = 1; i < totalKeywords - 1; i++) { + if (pixelFontSize * 2 < (table[i] + table[i + 1]) * multiplier) + return i; + } + return totalKeywords - 1; +} + +int CSSStyleSelector::legacyFontSize(Document* document, int pixelFontSize, bool shouldUseFixedDefaultSize) +{ + Settings* settings = document->settings(); + if (!settings) + return 1; + + bool quirksMode = document->inQuirksMode(); + int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize(); + if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) { + int row = mediumSize - fontSizeTableMin; + return findNearestLegacyFontSize<int>(pixelFontSize, quirksMode ? quirksFontSizeTable[row] : strictFontSizeTable[row], 1); + } + + return findNearestLegacyFontSize<float>(pixelFontSize, fontSizeFactors, mediumSize); +} + +float CSSStyleSelector::largerFontSize(float size, bool) const +{ + // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale up to + // the next size level. + return size * 1.2f; +} + +float CSSStyleSelector::smallerFontSize(float size, bool) const +{ + // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale down to + // the next size level. + return size / 1.2f; +} + +static Color colorForCSSValue(int cssValueId) +{ + struct ColorValue { + int cssValueId; + RGBA32 color; + }; + + static const ColorValue colorValues[] = { + { CSSValueAqua, 0xFF00FFFF }, + { CSSValueBlack, 0xFF000000 }, + { CSSValueBlue, 0xFF0000FF }, + { CSSValueFuchsia, 0xFFFF00FF }, + { CSSValueGray, 0xFF808080 }, + { CSSValueGreen, 0xFF008000 }, + { CSSValueGrey, 0xFF808080 }, + { CSSValueLime, 0xFF00FF00 }, + { CSSValueMaroon, 0xFF800000 }, + { CSSValueNavy, 0xFF000080 }, + { CSSValueOlive, 0xFF808000 }, + { CSSValueOrange, 0xFFFFA500 }, + { CSSValuePurple, 0xFF800080 }, + { CSSValueRed, 0xFFFF0000 }, + { CSSValueSilver, 0xFFC0C0C0 }, + { CSSValueTeal, 0xFF008080 }, + { CSSValueTransparent, 0x00000000 }, + { CSSValueWhite, 0xFFFFFFFF }, + { CSSValueYellow, 0xFFFFFF00 }, + { 0, 0 } + }; + + for (const ColorValue* col = colorValues; col->cssValueId; ++col) { + if (col->cssValueId == cssValueId) + return col->color; + } + return RenderTheme::defaultTheme()->systemColor(cssValueId); +} + +Color CSSStyleSelector::getColorFromPrimitiveValue(CSSPrimitiveValue* primitiveValue) const +{ + Color col; + int ident = primitiveValue->getIdent(); + if (ident) { + if (ident == CSSValueWebkitText) + col = m_element->document()->textColor(); + else if (ident == CSSValueWebkitLink) + col = m_element->isLink() && m_checker.m_matchVisitedPseudoClass ? m_element->document()->visitedLinkColor() : m_element->document()->linkColor(); + else if (ident == CSSValueWebkitActivelink) + col = m_element->document()->activeLinkColor(); + else if (ident == CSSValueWebkitFocusRingColor) + col = RenderTheme::focusRingColor(); + else if (ident == CSSValueCurrentcolor) + col = m_style->color(); + else + col = colorForCSSValue(ident); + } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) + col.setRGB(primitiveValue->getRGBA32Value()); + return col; +} + +bool CSSStyleSelector::hasSelectorForAttribute(const AtomicString &attrname) const +{ + return m_selectorAttrs.contains(attrname.impl()); +} + +void CSSStyleSelector::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result) +{ + m_viewportDependentMediaQueryResults.append(new MediaQueryResult(*expr, result)); +} + +bool CSSStyleSelector::affectedByViewportChange() const +{ + unsigned s = m_viewportDependentMediaQueryResults.size(); + for (unsigned i = 0; i < s; i++) { + if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result) + return true; + } + return false; +} + +void CSSStyleSelector::SelectorChecker::allVisitedStateChanged() +{ + if (m_linksCheckedForVisitedState.isEmpty()) + return; + for (Node* node = m_document; node; node = node->traverseNextNode()) { + if (node->isLink()) + node->setNeedsStyleRecalc(); + } +} + +void CSSStyleSelector::SelectorChecker::visitedStateChanged(LinkHash visitedHash) +{ + if (!m_linksCheckedForVisitedState.contains(visitedHash)) + return; + for (Node* node = m_document; node; node = node->traverseNextNode()) { + const AtomicString* attr = linkAttribute(node); + if (attr && visitedLinkHash(m_document->baseURL(), *attr) == visitedHash) + node->setNeedsStyleRecalc(); + } +} + +static TransformOperation::OperationType getTransformOperationType(WebKitCSSTransformValue::TransformOperationType type) +{ + switch (type) { + case WebKitCSSTransformValue::ScaleTransformOperation: return TransformOperation::SCALE; + case WebKitCSSTransformValue::ScaleXTransformOperation: return TransformOperation::SCALE_X; + case WebKitCSSTransformValue::ScaleYTransformOperation: return TransformOperation::SCALE_Y; + case WebKitCSSTransformValue::ScaleZTransformOperation: return TransformOperation::SCALE_Z; + case WebKitCSSTransformValue::Scale3DTransformOperation: return TransformOperation::SCALE_3D; + case WebKitCSSTransformValue::TranslateTransformOperation: return TransformOperation::TRANSLATE; + case WebKitCSSTransformValue::TranslateXTransformOperation: return TransformOperation::TRANSLATE_X; + case WebKitCSSTransformValue::TranslateYTransformOperation: return TransformOperation::TRANSLATE_Y; + case WebKitCSSTransformValue::TranslateZTransformOperation: return TransformOperation::TRANSLATE_Z; + case WebKitCSSTransformValue::Translate3DTransformOperation: return TransformOperation::TRANSLATE_3D; + case WebKitCSSTransformValue::RotateTransformOperation: return TransformOperation::ROTATE; + case WebKitCSSTransformValue::RotateXTransformOperation: return TransformOperation::ROTATE_X; + case WebKitCSSTransformValue::RotateYTransformOperation: return TransformOperation::ROTATE_Y; + case WebKitCSSTransformValue::RotateZTransformOperation: return TransformOperation::ROTATE_Z; + case WebKitCSSTransformValue::Rotate3DTransformOperation: return TransformOperation::ROTATE_3D; + case WebKitCSSTransformValue::SkewTransformOperation: return TransformOperation::SKEW; + case WebKitCSSTransformValue::SkewXTransformOperation: return TransformOperation::SKEW_X; + case WebKitCSSTransformValue::SkewYTransformOperation: return TransformOperation::SKEW_Y; + case WebKitCSSTransformValue::MatrixTransformOperation: return TransformOperation::MATRIX; + case WebKitCSSTransformValue::Matrix3DTransformOperation: return TransformOperation::MATRIX_3D; + case WebKitCSSTransformValue::PerspectiveTransformOperation: return TransformOperation::PERSPECTIVE; + case WebKitCSSTransformValue::UnknownTransformOperation: return TransformOperation::NONE; + } + return TransformOperation::NONE; +} + +bool CSSStyleSelector::createTransformOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, TransformOperations& outOperations) +{ + if (!inValue || !inValue->isValueList()) { + outOperations.clear(); + return false; + } + + float zoomFactor = style ? style->effectiveZoom() : 1; + TransformOperations operations; + CSSValueList* list = static_cast<CSSValueList*>(inValue); + unsigned size = list->length(); + for (unsigned i = 0; i < size; i++) { + CSSValue* currValue = list->itemWithoutBoundsCheck(i); + if (!currValue->isWebKitCSSTransformValue()) + continue; + + WebKitCSSTransformValue* transformValue = static_cast<WebKitCSSTransformValue*>(list->itemWithoutBoundsCheck(i)); + if (!transformValue->length()) + continue; + + bool haveNonPrimitiveValue = false; + for (unsigned j = 0; j < transformValue->length(); ++j) { + if (!transformValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { + haveNonPrimitiveValue = true; + break; + } + } + if (haveNonPrimitiveValue) + continue; + + CSSPrimitiveValue* firstValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0)); + + switch (transformValue->operationType()) { + case WebKitCSSTransformValue::ScaleTransformOperation: + case WebKitCSSTransformValue::ScaleXTransformOperation: + case WebKitCSSTransformValue::ScaleYTransformOperation: { + double sx = 1.0; + double sy = 1.0; + if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation) + sy = firstValue->getDoubleValue(); + else { + sx = firstValue->getDoubleValue(); + if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) { + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + sy = secondValue->getDoubleValue(); + } else + sy = sx; + } + } + operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::ScaleZTransformOperation: + case WebKitCSSTransformValue::Scale3DTransformOperation: { + double sx = 1.0; + double sy = 1.0; + double sz = 1.0; + if (transformValue->operationType() == WebKitCSSTransformValue::ScaleZTransformOperation) + sz = firstValue->getDoubleValue(); + else if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation) + sy = firstValue->getDoubleValue(); + else { + sx = firstValue->getDoubleValue(); + if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) { + if (transformValue->length() > 2) { + CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2)); + sz = thirdValue->getDoubleValue(); + } + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + sy = secondValue->getDoubleValue(); + } else + sy = sx; + } + } + operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::TranslateTransformOperation: + case WebKitCSSTransformValue::TranslateXTransformOperation: + case WebKitCSSTransformValue::TranslateYTransformOperation: { + bool ok = true; + Length tx = Length(0, Fixed); + Length ty = Length(0, Fixed); + if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation) + ty = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok); + else { + tx = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok); + if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) { + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + ty = convertToLength(secondValue, style, rootStyle, zoomFactor, &ok); + } + } + } + + if (!ok) + return false; + + operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::TranslateZTransformOperation: + case WebKitCSSTransformValue::Translate3DTransformOperation: { + bool ok = true; + Length tx = Length(0, Fixed); + Length ty = Length(0, Fixed); + Length tz = Length(0, Fixed); + if (transformValue->operationType() == WebKitCSSTransformValue::TranslateZTransformOperation) + tz = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok); + else if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation) + ty = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok); + else { + tx = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok); + if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) { + if (transformValue->length() > 2) { + CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2)); + tz = convertToLength(thirdValue, style, rootStyle, zoomFactor, &ok); + } + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + ty = convertToLength(secondValue, style, rootStyle, zoomFactor, &ok); + } + } + } + + if (!ok) + return false; + + operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::RotateTransformOperation: { + double angle = firstValue->getDoubleValue(); + if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) + angle = rad2deg(angle); + else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) + angle = grad2deg(angle); + else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_TURN) + angle = turn2deg(angle); + + operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::RotateXTransformOperation: + case WebKitCSSTransformValue::RotateYTransformOperation: + case WebKitCSSTransformValue::RotateZTransformOperation: { + double x = 0; + double y = 0; + double z = 0; + double angle = firstValue->getDoubleValue(); + if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) + angle = rad2deg(angle); + else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) + angle = grad2deg(angle); + + if (transformValue->operationType() == WebKitCSSTransformValue::RotateXTransformOperation) + x = 1; + else if (transformValue->operationType() == WebKitCSSTransformValue::RotateYTransformOperation) + y = 1; + else + z = 1; + operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::Rotate3DTransformOperation: { + if (transformValue->length() < 4) + break; + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2)); + CSSPrimitiveValue* fourthValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3)); + double x = firstValue->getDoubleValue(); + double y = secondValue->getDoubleValue(); + double z = thirdValue->getDoubleValue(); + double angle = fourthValue->getDoubleValue(); + if (fourthValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) + angle = rad2deg(angle); + else if (fourthValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) + angle = grad2deg(angle); + operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::SkewTransformOperation: + case WebKitCSSTransformValue::SkewXTransformOperation: + case WebKitCSSTransformValue::SkewYTransformOperation: { + double angleX = 0; + double angleY = 0; + double angle = firstValue->getDoubleValue(); + if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) + angle = rad2deg(angle); + else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) + angle = grad2deg(angle); + else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_TURN) + angle = turn2deg(angle); + if (transformValue->operationType() == WebKitCSSTransformValue::SkewYTransformOperation) + angleY = angle; + else { + angleX = angle; + if (transformValue->operationType() == WebKitCSSTransformValue::SkewTransformOperation) { + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + angleY = secondValue->getDoubleValue(); + if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) + angleY = rad2deg(angleY); + else if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) + angleY = grad2deg(angleY); + else if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_TURN) + angleY = turn2deg(angleY); + } + } + } + operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType()))); + break; + } + case WebKitCSSTransformValue::MatrixTransformOperation: { + if (transformValue->length() < 6) + break; + double a = firstValue->getDoubleValue(); + double b = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(); + double c = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(); + double d = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(); + double e = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(); + double f = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(); + operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f)); + break; + } + case WebKitCSSTransformValue::Matrix3DTransformOperation: { + if (transformValue->length() < 16) + break; + TransformationMatrix matrix(static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(6))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(7))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(8))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(9))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(10))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(11))->getDoubleValue(), + zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(12))->getDoubleValue(), + zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(13))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(14))->getDoubleValue(), + static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(15))->getDoubleValue()); + operations.operations().append(Matrix3DTransformOperation::create(matrix)); + break; + } + case WebKitCSSTransformValue::PerspectiveTransformOperation: { + double p = firstValue->getDoubleValue(); + if (p < 0.0) + return false; + operations.operations().append(PerspectiveTransformOperation::create(p)); + break; + } + case WebKitCSSTransformValue::UnknownTransformOperation: + ASSERT_NOT_REACHED(); + break; + } + } + + outOperations = operations; + return true; +} + +void CSSStyleSelector::loadPendingImages() +{ + if (m_pendingImageProperties.isEmpty()) + return; + + HashSet<int>::const_iterator end = m_pendingImageProperties.end(); + for (HashSet<int>::const_iterator it = m_pendingImageProperties.begin(); it != end; ++it) { + CSSPropertyID currentProperty = static_cast<CSSPropertyID>(*it); + + CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader(); + + switch (currentProperty) { + case CSSPropertyBackgroundImage: { + for (FillLayer* backgroundLayer = m_style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { + if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(backgroundLayer->image())->cssImageValue(); + backgroundLayer->setImage(imageValue->cachedImage(cachedResourceLoader)); + } + } + break; + } + + case CSSPropertyContent: { + for (ContentData* contentData = const_cast<ContentData*>(m_style->contentData()); contentData; contentData = contentData->next()) { + if (contentData->isImage() && contentData->image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(contentData->image())->cssImageValue(); + if (StyleCachedImage* cachedImage = imageValue->cachedImage(cachedResourceLoader)) + contentData->setImage(cachedImage); + } + } + break; + } + + case CSSPropertyCursor: { + if (CursorList* cursorList = m_style->cursors()) { + for (size_t i = 0; i < cursorList->size(); ++i) { + CursorData& currentCursor = cursorList->at(i); + if (StyleImage* image = currentCursor.image()) { + if (image->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(image)->cssImageValue(); + currentCursor.setImage(imageValue->cachedImage(cachedResourceLoader)); + } + } + } + } + break; + } + + case CSSPropertyListStyleImage: { + if (m_style->listStyleImage() && m_style->listStyleImage()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(m_style->listStyleImage())->cssImageValue(); + m_style->setListStyleImage(imageValue->cachedImage(cachedResourceLoader)); + } + break; + } + + case CSSPropertyWebkitBorderImage: { + const NinePieceImage& borderImage = m_style->borderImage(); + if (borderImage.image() && borderImage.image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(borderImage.image())->cssImageValue(); + m_style->setBorderImage(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), borderImage.slices(), borderImage.horizontalRule(), borderImage.verticalRule())); + } + break; + } + + case CSSPropertyWebkitBoxReflect: { + if (StyleReflection* reflection = m_style->boxReflect()) { + const NinePieceImage& maskImage = reflection->mask(); + if (maskImage.image() && maskImage.image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskImage.image())->cssImageValue(); + reflection->setMask(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), maskImage.slices(), maskImage.horizontalRule(), maskImage.verticalRule())); + } + } + break; + } + + case CSSPropertyWebkitMaskBoxImage: { + const NinePieceImage& maskBoxImage = m_style->maskBoxImage(); + if (maskBoxImage.image() && maskBoxImage.image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskBoxImage.image())->cssImageValue(); + m_style->setMaskBoxImage(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), maskBoxImage.slices(), maskBoxImage.horizontalRule(), maskBoxImage.verticalRule())); + } + break; + } + + case CSSPropertyWebkitMaskImage: { + for (FillLayer* maskLayer = m_style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { + if (maskLayer->image() && maskLayer->image()->isPendingImage()) { + CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskLayer->image())->cssImageValue(); + maskLayer->setImage(imageValue->cachedImage(cachedResourceLoader)); + } + } + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + m_pendingImageProperties.clear(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSStyleSelector.h b/Source/WebCore/css/CSSStyleSelector.h new file mode 100644 index 0000000..b57ba13 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSelector.h @@ -0,0 +1,320 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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. + * + */ + +#ifndef CSSStyleSelector_h +#define CSSStyleSelector_h + +#include "CSSFontSelector.h" +#include "CSSRule.h" +#include "LinkHash.h" +#include "MediaQueryExp.h" +#include "RenderStyle.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; +class CSSPageRule; +class CSSPrimitiveValue; +class CSSProperty; +class CSSFontFace; +class CSSFontFaceRule; +class CSSImageValue; +class CSSRuleData; +class CSSRuleDataList; +class CSSRuleList; +class CSSRuleSet; +class CSSSelector; +class CSSStyleRule; +class CSSStyleSheet; +class CSSValue; +class ContainerNode; +class DataGridColumn; +class Document; +class Element; +class Frame; +class FrameView; +class KURL; +class KeyframeList; +class KeyframeValue; +class MediaQueryEvaluator; +class Node; +class Settings; +class StyleImage; +class StyleSheet; +class StyleSheetList; +class StyledElement; +class WebKitCSSKeyframeRule; +class WebKitCSSKeyframesRule; + +class MediaQueryResult : public Noncopyable { +public: + MediaQueryResult(const MediaQueryExp& expr, bool result) + : m_expression(expr) + , m_result(result) + { + } + + MediaQueryExp m_expression; + bool m_result; +}; + + // This class selects a RenderStyle for a given element based on a collection of stylesheets. + class CSSStyleSelector : public Noncopyable { + public: + CSSStyleSelector(Document*, StyleSheetList* authorSheets, CSSStyleSheet* mappedElementSheet, + CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets, + bool strictParsing, bool matchAuthorAndUserStyles); + ~CSSStyleSelector(); + + PassRefPtr<RenderStyle> styleForElement(Element* e, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false, bool matchVisitedPseudoClass = false); + + void keyframeStylesForAnimation(Element*, const RenderStyle*, KeyframeList& list); + + PassRefPtr<RenderStyle> pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle = 0, bool matchVisitedPseudoClass = false); + + PassRefPtr<RenderStyle> styleForPage(int pageIndex); + + static PassRefPtr<RenderStyle> styleForDocument(Document*); + +#if ENABLE(DATAGRID) + // Datagrid style computation (uses unique pseudo elements and structures) + PassRefPtr<RenderStyle> pseudoStyleForDataGridColumn(DataGridColumn*, RenderStyle* parentStyle); + PassRefPtr<RenderStyle> pseudoStyleForDataGridColumnHeader(DataGridColumn*, RenderStyle* parentStyle); +#endif + + private: + void initForStyleResolve(Element*, RenderStyle* parentStyle = 0, PseudoId = NOPSEUDO); + void initElement(Element*); + ALWAYS_INLINE RenderStyle* locateSharedStyle() const; + Node* locateCousinList(Element* parent, unsigned depth = 1) const; + bool canShareStyleWithElement(Node*) const; + + RenderStyle* style() const { return m_style.get(); } + + PassRefPtr<RenderStyle> styleForKeyframe(const RenderStyle*, const WebKitCSSKeyframeRule*, KeyframeValue&); + + public: + // These methods will give back the set of rules that matched for a given element (or a pseudo-element). + PassRefPtr<CSSRuleList> styleRulesForElement(Element*, bool authorOnly, bool includeEmptyRules = false, CSSRuleFilter filter = AllCSSRules); + PassRefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, PseudoId, bool authorOnly, bool includeEmptyRules = false, CSSRuleFilter filter = AllCSSRules); + + // Given a CSS keyword in the range (xx-small to -webkit-xxx-large), this function will return + // the correct font size scaled relative to the user's default (medium). + static float fontSizeForKeyword(Document*, int keyword, bool shouldUseFixedDefaultSize); + + // Given a font size in pixel, this function will return legacy font size between 1 and 7. + static int legacyFontSize(Document*, int pixelFontSize, bool shouldUseFixedDefaultSize); + + private: + + // When the CSS keyword "larger" is used, this function will attempt to match within the keyword + // table, and failing that, will simply multiply by 1.2. + float largerFontSize(float size, bool quirksMode) const; + + // Like the previous function, but for the keyword "smaller". + float smallerFontSize(float size, bool quirksMode) const; + + public: + void setStyle(PassRefPtr<RenderStyle> s) { m_style = s; } // Used by the document when setting up its root style. + + void applyPropertyToStyle(int id, CSSValue*, RenderStyle*); + + private: + void setFontSize(FontDescription&, float size); + static float getComputedSizeFromSpecifiedSize(Document*, RenderStyle*, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules); + + public: + Color getColorFromPrimitiveValue(CSSPrimitiveValue*) const; + + bool hasSelectorForAttribute(const AtomicString&) const; + + CSSFontSelector* fontSelector() const { return m_fontSelector.get(); } + + // Checks if a compound selector (which can consist of multiple simple selectors) matches the current element. + bool checkSelector(CSSSelector*); + + void addViewportDependentMediaQueryResult(const MediaQueryExp*, bool result); + + bool affectedByViewportChange() const; + + void allVisitedStateChanged() { m_checker.allVisitedStateChanged(); } + void visitedStateChanged(LinkHash visitedHash) { m_checker.visitedStateChanged(visitedHash); } + + void addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule); + void addPageStyle(PassRefPtr<CSSPageRule>); + + static bool createTransformOperations(CSSValue* inValue, RenderStyle* inStyle, RenderStyle* rootStyle, TransformOperations& outOperations); + + private: + enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsCompletely }; + + // This function fixes up the default font size if it detects that the current generic font family has changed. -dwh + void checkForGenericFamilyChange(RenderStyle*, RenderStyle* parentStyle); + void checkForZoomChange(RenderStyle*, RenderStyle* parentStyle); + void checkForTextSizeAdjust(); + + void adjustRenderStyle(RenderStyle* styleToAdjust, RenderStyle* parentStyle, Element*); + + void addMatchedRule(CSSRuleData* rule) { m_matchedRules.append(rule); } + void addMatchedDeclaration(CSSMutableStyleDeclaration* decl); + + void matchRules(CSSRuleSet*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules); + void matchRulesForList(CSSRuleDataList*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules); + void sortMatchedRules(unsigned start, unsigned end); + + template <bool firstPass> + void applyDeclarations(bool important, int startIndex, int endIndex); + + void matchPageRules(CSSRuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName); + void matchPageRulesForList(CSSRuleDataList*, bool isLeftPage, bool isFirstPage, const String& pageName); + bool isLeftPage(int pageIndex) const; + bool isRightPage(int pageIndex) const { return !isLeftPage(pageIndex); } + bool isFirstPage(int pageIndex) const; + String pageName(int pageIndex) const; + + OwnPtr<CSSRuleSet> m_authorStyle; + OwnPtr<CSSRuleSet> m_userStyle; + + bool m_hasUAAppearance; + BorderData m_borderData; + FillLayer m_backgroundData; + Color m_backgroundColor; + + typedef HashMap<AtomicStringImpl*, RefPtr<WebKitCSSKeyframesRule> > KeyframesRuleMap; + KeyframesRuleMap m_keyframesRuleMap; + + public: + static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; } + + class SelectorChecker : public Noncopyable { + public: + SelectorChecker(Document*, bool strictParsing); + + bool checkSelector(CSSSelector*, Element*) const; + SelectorMatch checkSelector(CSSSelector*, Element*, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* = 0, RenderStyle* elementParentStyle = 0) const; + bool checkOneSelector(CSSSelector*, Element*, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, RenderStyle*, RenderStyle* elementParentStyle) const; + bool checkScrollbarPseudoClass(CSSSelector*, PseudoId& dynamicPseudo) const; + + EInsideLink determineLinkState(Element* element) const; + EInsideLink determineLinkStateSlowCase(Element* element) const; + void allVisitedStateChanged(); + void visitedStateChanged(LinkHash visitedHash); + + Document* m_document; + bool m_strictParsing; + bool m_collectRulesOnly; + bool m_sameOriginOnly; + PseudoId m_pseudoStyle; + bool m_documentIsHTML; + mutable bool m_matchVisitedPseudoClass; + mutable HashSet<LinkHash, LinkHashHash> m_linksCheckedForVisitedState; + }; + + private: + static RenderStyle* s_styleNotYetAvailable; + + void matchUARules(int& firstUARule, int& lastUARule); + void updateFont(); + void cacheBorderAndBackground(); + + void mapFillAttachment(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillClip(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillComposite(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillOrigin(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillImage(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillRepeatX(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillRepeatY(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillSize(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillXPosition(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillYPosition(CSSPropertyID, FillLayer*, CSSValue*); + + void mapAnimationDelay(Animation*, CSSValue*); + void mapAnimationDirection(Animation*, CSSValue*); + void mapAnimationDuration(Animation*, CSSValue*); + void mapAnimationFillMode(Animation*, CSSValue*); + void mapAnimationIterationCount(Animation*, CSSValue*); + void mapAnimationName(Animation*, CSSValue*); + void mapAnimationPlayState(Animation*, CSSValue*); + void mapAnimationProperty(Animation*, CSSValue*); + void mapAnimationTimingFunction(Animation*, CSSValue*); + + void mapNinePieceImage(CSSPropertyID, CSSValue*, NinePieceImage&); + + void applyProperty(int id, CSSValue*); + void applyPageSizeProperty(CSSValue*); + bool pageSizeFromName(CSSPrimitiveValue*, CSSPrimitiveValue*, Length& width, Length& height); + Length mmLength(double mm) const; + Length inchLength(double inch) const; +#if ENABLE(SVG) + void applySVGProperty(int id, CSSValue*); +#endif + + void loadPendingImages(); + + StyleImage* styleImage(CSSPropertyID, CSSValue* value); + StyleImage* cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value); + + // We collect the set of decls that match in |m_matchedDecls|. We then walk the + // set of matched decls four times, once for those properties that others depend on (like font-size), + // and then a second time for all the remaining properties. We then do the same two passes + // for any !important rules. + Vector<CSSMutableStyleDeclaration*, 64> m_matchedDecls; + + // A buffer used to hold the set of matched rules for an element, and a temporary buffer used for + // merge sorting. + Vector<CSSRuleData*, 32> m_matchedRules; + + RefPtr<CSSRuleList> m_ruleList; + + HashSet<int> m_pendingImageProperties; // Hash of CSSPropertyIDs + + OwnPtr<MediaQueryEvaluator> m_medium; + RefPtr<RenderStyle> m_rootDefaultStyle; + + PseudoId m_dynamicPseudo; + + SelectorChecker m_checker; + + RefPtr<RenderStyle> m_style; + RenderStyle* m_parentStyle; + RenderStyle* m_rootElementStyle; + Element* m_element; + StyledElement* m_styledElement; + EInsideLink m_elementLinkState; + ContainerNode* m_parentNode; + CSSValue* m_lineHeightValue; + bool m_fontDirty; + bool m_matchAuthorAndUserStyles; + + RefPtr<CSSFontSelector> m_fontSelector; + HashSet<AtomicStringImpl*> m_selectorAttrs; + Vector<CSSMutableStyleDeclaration*> m_additionalAttributeStyleDecls; + Vector<MediaQueryResult*> m_viewportDependentMediaQueryResults; + }; + +} // namespace WebCore + +#endif // CSSStyleSelector_h diff --git a/Source/WebCore/css/CSSStyleSheet.cpp b/Source/WebCore/css/CSSStyleSheet.cpp new file mode 100644 index 0000000..d5487a1 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSheet.cpp @@ -0,0 +1,285 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2007 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 "CSSStyleSheet.h" + +#include "CSSImportRule.h" +#include "CSSNamespace.h" +#include "CSSParser.h" +#include "CSSRuleList.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "HTMLNames.h" +#include "Node.h" +#include "SVGNames.h" +#include "SecurityOrigin.h" +#include "TextEncoding.h" +#include <wtf/Deque.h> + +namespace WebCore { + +#if !ASSERT_DISABLED +static bool isAcceptableCSSStyleSheetParent(Node* parentNode) +{ + // Only these nodes can be parents of StyleSheets, and they need to call clearOwnerNode() when moved out of document. + return !parentNode + || parentNode->isDocumentNode() + || parentNode->hasTagName(HTMLNames::linkTag) + || parentNode->hasTagName(HTMLNames::styleTag) +#if ENABLE(SVG) + || parentNode->hasTagName(SVGNames::styleTag) +#endif + || parentNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE; +} +#endif + +CSSStyleSheet::CSSStyleSheet(CSSStyleSheet* parentSheet, const String& href, const KURL& baseURL, const String& charset) + : StyleSheet(parentSheet, href, baseURL) + , m_document(parentSheet ? parentSheet->document() : 0) + , m_charset(charset) + , m_loadCompleted(false) + , m_strictParsing(!parentSheet || parentSheet->useStrictParsing()) + , m_isUserStyleSheet(parentSheet ? parentSheet->isUserStyleSheet() : false) + , m_hasSyntacticallyValidCSSHeader(true) +{ +} + +CSSStyleSheet::CSSStyleSheet(Node* parentNode, const String& href, const KURL& baseURL, const String& charset) + : StyleSheet(parentNode, href, baseURL) + , m_document(parentNode->document()) + , m_charset(charset) + , m_loadCompleted(false) + , m_strictParsing(false) + , m_isUserStyleSheet(false) + , m_hasSyntacticallyValidCSSHeader(true) +{ + ASSERT(isAcceptableCSSStyleSheetParent(parentNode)); +} + +CSSStyleSheet::CSSStyleSheet(CSSRule* ownerRule, const String& href, const KURL& baseURL, const String& charset) + : StyleSheet(ownerRule, href, baseURL) + , m_charset(charset) + , m_loadCompleted(false) + , m_strictParsing(!ownerRule || ownerRule->useStrictParsing()) + , m_hasSyntacticallyValidCSSHeader(true) +{ + CSSStyleSheet* parentSheet = ownerRule ? ownerRule->parentStyleSheet() : 0; + m_document = parentSheet ? parentSheet->document() : 0; + m_isUserStyleSheet = parentSheet ? parentSheet->isUserStyleSheet() : false; +} + +CSSStyleSheet::~CSSStyleSheet() +{ +} + +CSSRule *CSSStyleSheet::ownerRule() const +{ + return (parent() && parent()->isRule()) ? static_cast<CSSRule*>(parent()) : 0; +} + +unsigned CSSStyleSheet::insertRule(const String& rule, unsigned index, ExceptionCode& ec) +{ + ec = 0; + if (index > length()) { + ec = INDEX_SIZE_ERR; + return 0; + } + CSSParser p(useStrictParsing()); + RefPtr<CSSRule> r = p.parseRule(this, rule); + + if (!r) { + ec = SYNTAX_ERR; + return 0; + } + + // Throw a HIERARCHY_REQUEST_ERR exception if the rule cannot be inserted at the specified index. The best + // example of this is an @import rule inserted after regular rules. + if (index > 0) { + if (r->isImportRule()) { + // Check all the rules that come before this one to make sure they are only @charset and @import rules. + for (unsigned i = 0; i < index; ++i) { + if (!item(i)->isCharsetRule() && !item(i)->isImportRule()) { + ec = HIERARCHY_REQUEST_ERR; + return 0; + } + } + } else if (r->isCharsetRule()) { + // The @charset rule has to come first and there can be only one. + ec = HIERARCHY_REQUEST_ERR; + return 0; + } + } + + insert(index, r.release()); + + styleSheetChanged(); + + return index; +} + +int CSSStyleSheet::addRule(const String& selector, const String& style, int index, ExceptionCode& ec) +{ + insertRule(selector + " { " + style + " }", index, ec); + + // As per Microsoft documentation, always return -1. + return -1; +} + +int CSSStyleSheet::addRule(const String& selector, const String& style, ExceptionCode& ec) +{ + return addRule(selector, style, length(), ec); +} + +PassRefPtr<CSSRuleList> CSSStyleSheet::cssRules(bool omitCharsetRules) +{ + KURL url = finalURL(); + if (!url.isEmpty() && document() && !document()->securityOrigin()->canRequest(url)) + return 0; + return CSSRuleList::create(this, omitCharsetRules); +} + +void CSSStyleSheet::deleteRule(unsigned index, ExceptionCode& ec) +{ + if (index >= length()) { + ec = INDEX_SIZE_ERR; + return; + } + + ec = 0; + item(index)->setParent(0); + remove(index); + styleSheetChanged(); +} + +void CSSStyleSheet::addNamespace(CSSParser* p, const AtomicString& prefix, const AtomicString& uri) +{ + if (uri.isNull()) + return; + + m_namespaces = adoptPtr(new CSSNamespace(prefix, uri, m_namespaces.release())); + + if (prefix.isEmpty()) + // Set the default namespace on the parser so that selectors that omit namespace info will + // be able to pick it up easily. + p->m_defaultNamespace = uri; +} + +const AtomicString& CSSStyleSheet::determineNamespace(const AtomicString& prefix) +{ + if (prefix.isNull()) + return nullAtom; // No namespace. If an element/attribute has a namespace, we won't match it. + if (prefix == starAtom) + return starAtom; // We'll match any namespace. + if (m_namespaces) { + if (CSSNamespace* namespaceForPrefix = m_namespaces->namespaceForPrefix(prefix)) + return namespaceForPrefix->uri; + } + return nullAtom; // Assume we won't match any namespaces. +} + +bool CSSStyleSheet::parseString(const String &string, bool strict) +{ + return parseStringAtLine(string, strict, 0); +} + +bool CSSStyleSheet::parseStringAtLine(const String& string, bool strict, int startLineNumber) +{ + setStrictParsing(strict); + CSSParser p(strict); + p.parseSheet(this, string, startLineNumber); + return true; +} + +bool CSSStyleSheet::isLoading() +{ + unsigned len = length(); + for (unsigned i = 0; i < len; ++i) { + StyleBase* rule = item(i); + if (rule->isImportRule() && static_cast<CSSImportRule*>(rule)->isLoading()) + return true; + } + return false; +} + +void CSSStyleSheet::checkLoaded() +{ + if (isLoading()) + return; + if (parent()) + parent()->checkLoaded(); + + // Avoid |this| being deleted by scripts that run via + // ScriptableDocumentParser::executeScriptsWaitingForStylesheets(). + // See <rdar://problem/6622300>. + RefPtr<CSSStyleSheet> protector(this); + m_loadCompleted = ownerNode() ? ownerNode()->sheetLoaded() : true; +} + +void CSSStyleSheet::styleSheetChanged() +{ + StyleBase* root = this; + while (StyleBase* parent = root->parent()) + root = parent; + Document* documentToUpdate = root->isCSSStyleSheet() ? static_cast<CSSStyleSheet*>(root)->document() : 0; + + /* FIXME: We don't need to do everything updateStyleSelector does, + * basically we just need to recreate the document's selector with the + * already existing style sheets. + */ + if (documentToUpdate) + documentToUpdate->styleSelectorChanged(DeferRecalcStyle); +} + +KURL CSSStyleSheet::completeURL(const String& url) const +{ + // Always return a null URL when passed a null string. + // FIXME: Should we change the KURL constructor to have this behavior? + // See also Document::completeURL(const String&) + if (url.isNull() || m_charset.isEmpty()) + return StyleSheet::completeURL(url); + const TextEncoding encoding = TextEncoding(m_charset); + return KURL(baseURL(), url, encoding); +} + +void CSSStyleSheet::addSubresourceStyleURLs(ListHashSet<KURL>& urls) +{ + Deque<CSSStyleSheet*> styleSheetQueue; + styleSheetQueue.append(this); + + while (!styleSheetQueue.isEmpty()) { + CSSStyleSheet* styleSheet = styleSheetQueue.takeFirst(); + + for (unsigned i = 0; i < styleSheet->length(); ++i) { + StyleBase* styleBase = styleSheet->item(i); + if (!styleBase->isRule()) + continue; + + CSSRule* rule = static_cast<CSSRule*>(styleBase); + if (rule->isImportRule()) { + if (CSSStyleSheet* ruleStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet()) + styleSheetQueue.append(ruleStyleSheet); + } + rule->addSubresourceStyleURLs(urls); + } + } +} + +} diff --git a/Source/WebCore/css/CSSStyleSheet.h b/Source/WebCore/css/CSSStyleSheet.h new file mode 100644 index 0000000..725518f --- /dev/null +++ b/Source/WebCore/css/CSSStyleSheet.h @@ -0,0 +1,126 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 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. + */ + +#ifndef CSSStyleSheet_h +#define CSSStyleSheet_h + +#include "CSSRuleList.h" +#include "StyleSheet.h" + +namespace WebCore { + +struct CSSNamespace; +class CSSParser; +class CSSRule; +class CachedResourceLoader; +class Document; + +typedef int ExceptionCode; + +class CSSStyleSheet : public StyleSheet { +public: + static PassRefPtr<CSSStyleSheet> create() + { + return adoptRef(new CSSStyleSheet(static_cast<CSSStyleSheet*>(0), String(), KURL(), String())); + } + static PassRefPtr<CSSStyleSheet> create(Node* ownerNode) + { + return adoptRef(new CSSStyleSheet(ownerNode, String(), KURL(), String())); + } + static PassRefPtr<CSSStyleSheet> create(Node* ownerNode, const String& originalURL, const KURL& finalURL) + { + return adoptRef(new CSSStyleSheet(ownerNode, originalURL, finalURL, String())); + } + static PassRefPtr<CSSStyleSheet> create(Node* ownerNode, const String& originalURL, const KURL& finalURL, const String& charset) + { + return adoptRef(new CSSStyleSheet(ownerNode, originalURL, finalURL, charset)); + } + static PassRefPtr<CSSStyleSheet> create(CSSRule* ownerRule, const String& originalURL, const KURL& finalURL, const String& charset) + { + return adoptRef(new CSSStyleSheet(ownerRule, originalURL, finalURL, charset)); + } + static PassRefPtr<CSSStyleSheet> createInline(Node* ownerNode, const KURL& finalURL) + { + return adoptRef(new CSSStyleSheet(ownerNode, finalURL.string(), finalURL, String())); + } + + virtual ~CSSStyleSheet(); + + CSSRule* ownerRule() const; + PassRefPtr<CSSRuleList> cssRules(bool omitCharsetRules = false); + unsigned insertRule(const String& rule, unsigned index, ExceptionCode&); + void deleteRule(unsigned index, ExceptionCode&); + + // IE Extensions + PassRefPtr<CSSRuleList> rules() { return cssRules(true); } + int addRule(const String& selector, const String& style, int index, ExceptionCode&); + int addRule(const String& selector, const String& style, ExceptionCode&); + void removeRule(unsigned index, ExceptionCode& ec) { deleteRule(index, ec); } + + void addNamespace(CSSParser*, const AtomicString& prefix, const AtomicString& uri); + const AtomicString& determineNamespace(const AtomicString& prefix); + + virtual void styleSheetChanged(); + + virtual bool parseString(const String&, bool strict = true); + + bool parseStringAtLine(const String&, bool strict, int startLineNumber); + + virtual bool isLoading(); + + virtual void checkLoaded(); + + Document* document() { return m_document; } + + const String& charset() const { return m_charset; } + + bool loadCompleted() const { return m_loadCompleted; } + + virtual KURL completeURL(const String& url) const; + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&); + + void setStrictParsing(bool b) { m_strictParsing = b; } + bool useStrictParsing() const { return m_strictParsing; } + + void setIsUserStyleSheet(bool b) { m_isUserStyleSheet = b; } + bool isUserStyleSheet() const { return m_isUserStyleSheet; } + void setHasSyntacticallyValidCSSHeader(bool b) { m_hasSyntacticallyValidCSSHeader = b; } + bool hasSyntacticallyValidCSSHeader() const { return m_hasSyntacticallyValidCSSHeader; } + +private: + CSSStyleSheet(Node* ownerNode, const String& originalURL, const KURL& finalURL, const String& charset); + CSSStyleSheet(CSSStyleSheet* parentSheet, const String& originalURL, const KURL& finalURL, const String& charset); + CSSStyleSheet(CSSRule* ownerRule, const String& originalURL, const KURL& finalURL, const String& charset); + + virtual bool isCSSStyleSheet() const { return true; } + virtual String type() const { return "text/css"; } + + Document* m_document; + OwnPtr<CSSNamespace> m_namespaces; + String m_charset; + bool m_loadCompleted : 1; + bool m_strictParsing : 1; + bool m_isUserStyleSheet : 1; + bool m_hasSyntacticallyValidCSSHeader : 1; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/CSSStyleSheet.idl b/Source/WebCore/css/CSSStyleSheet.idl new file mode 100644 index 0000000..e488657 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSheet.idl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface CSSStyleSheet : StyleSheet { + readonly attribute CSSRule ownerRule; + readonly attribute CSSRuleList cssRules; + + [OldStyleObjC] unsigned long insertRule(in DOMString rule, + in unsigned long index) + raises(DOMException); + void deleteRule(in unsigned long index) + raises(DOMException); + + // IE Extensions + readonly attribute CSSRuleList rules; + + long addRule(in DOMString selector, + in DOMString style, + in [Optional] unsigned long index) + raises(DOMException); + void removeRule(in unsigned long index) + raises(DOMException); + }; + +} diff --git a/Source/WebCore/css/CSSTimingFunctionValue.cpp b/Source/WebCore/css/CSSTimingFunctionValue.cpp new file mode 100644 index 0000000..9eecb2c --- /dev/null +++ b/Source/WebCore/css/CSSTimingFunctionValue.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSTimingFunctionValue.h" + +#include "PlatformString.h" + +namespace WebCore { + +String CSSLinearTimingFunctionValue::cssText() const +{ + return "linear"; +} + +String CSSCubicBezierTimingFunctionValue::cssText() const +{ + String text("cubic-bezier("); + text += String::number(m_x1); + text += ", "; + text += String::number(m_y1); + text += ", "; + text += String::number(m_x2); + text += ", "; + text += String::number(m_y2); + text += ")"; + return text; +} + +String CSSStepsTimingFunctionValue::cssText() const +{ + String text("steps("); + text += String::number(m_steps); + text += ", "; + text += m_stepAtStart ? "start" : "end"; + text += ")"; + return text; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSTimingFunctionValue.h b/Source/WebCore/css/CSSTimingFunctionValue.h new file mode 100644 index 0000000..27e899b --- /dev/null +++ b/Source/WebCore/css/CSSTimingFunctionValue.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSTimingFunctionValue_h +#define CSSTimingFunctionValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class CSSTimingFunctionValue : public CSSValue { +public: + virtual String cssText() const = 0; + + virtual bool isLinearTimingFunctionValue() const { return false; } + virtual bool isCubicBezierTimingFunctionValue() const { return false; } + virtual bool isStepsTimingFunctionValue() const { return false; } + +protected: + CSSTimingFunctionValue() + { + } + + virtual bool isTimingFunctionValue() const { return true; } +}; + +class CSSLinearTimingFunctionValue : public CSSTimingFunctionValue { +public: + static PassRefPtr<CSSLinearTimingFunctionValue> create() + { + return adoptRef(new CSSLinearTimingFunctionValue); + } + +private: + CSSLinearTimingFunctionValue() + { + } + + virtual String cssText() const; + + virtual bool isLinearTimingFunctionValue() const { return true; } +}; + +class CSSCubicBezierTimingFunctionValue : public CSSTimingFunctionValue { +public: + static PassRefPtr<CSSCubicBezierTimingFunctionValue> create(double x1, double y1, double x2, double y2) + { + return adoptRef(new CSSCubicBezierTimingFunctionValue(x1, y1, x2, y2)); + } + + double x1() const { return m_x1; } + double y1() const { return m_y1; } + double x2() const { return m_x2; } + double y2() const { return m_y2; } + +private: + CSSCubicBezierTimingFunctionValue(double x1, double y1, double x2, double y2) + : m_x1(x1) + , m_y1(y1) + , m_x2(x2) + , m_y2(y2) + { + } + + virtual String cssText() const; + + virtual bool isCubicBezierTimingFunctionValue() const { return true; } + + double m_x1; + double m_y1; + double m_x2; + double m_y2; +}; + +class CSSStepsTimingFunctionValue : public CSSTimingFunctionValue { +public: + static PassRefPtr<CSSStepsTimingFunctionValue> create(int steps, bool stepAtStart) + { + return adoptRef(new CSSStepsTimingFunctionValue(steps, stepAtStart)); + } + + int numberOfSteps() const { return m_steps; } + bool stepAtStart() const { return m_stepAtStart; } + +private: + CSSStepsTimingFunctionValue(int steps, bool stepAtStart) + : m_steps(steps) + , m_stepAtStart(stepAtStart) + { + } + + virtual String cssText() const; + + virtual bool isStepsTimingFunctionValue() const { return true; } + + int m_steps; + bool m_stepAtStart; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/CSSUnicodeRangeValue.cpp b/Source/WebCore/css/CSSUnicodeRangeValue.cpp new file mode 100644 index 0000000..599c078 --- /dev/null +++ b/Source/WebCore/css/CSSUnicodeRangeValue.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSUnicodeRangeValue.h" + +#include "PlatformString.h" + +namespace WebCore { + +CSSUnicodeRangeValue::~CSSUnicodeRangeValue() +{ +} + +String CSSUnicodeRangeValue::cssText() const +{ + String result; + // FIXME: Implement. + return result; +} + +} diff --git a/Source/WebCore/css/CSSUnicodeRangeValue.h b/Source/WebCore/css/CSSUnicodeRangeValue.h new file mode 100644 index 0000000..0ba1980 --- /dev/null +++ b/Source/WebCore/css/CSSUnicodeRangeValue.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CSSUnicodeRangeValue_h +#define CSSUnicodeRangeValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class CSSUnicodeRangeValue : public CSSValue { +public: + static PassRefPtr<CSSUnicodeRangeValue> create(UChar32 from, UChar32 to) + { + return adoptRef(new CSSUnicodeRangeValue(from, to)); + } + + virtual ~CSSUnicodeRangeValue(); + + UChar32 from() const { return m_from; } + UChar32 to() const { return m_to; } + + virtual String cssText() const; + +private: + CSSUnicodeRangeValue(UChar32 from, UChar32 to) + : m_from(from) + , m_to(to) + { + } + + UChar32 m_from; + UChar32 m_to; +}; + +} // namespace WebCore + +#endif // CSSUnicodeRangeValue_h diff --git a/Source/WebCore/css/CSSUnknownRule.h b/Source/WebCore/css/CSSUnknownRule.h new file mode 100644 index 0000000..b2448dd --- /dev/null +++ b/Source/WebCore/css/CSSUnknownRule.h @@ -0,0 +1,36 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * (C) 2002-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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. + */ + +#ifndef CSSUnknownRule_h +#define CSSUnknownRule_h + +#include "CSSRule.h" + +namespace WebCore { + +class CSSUnknownRule : public CSSRule { +private: + virtual unsigned short type() const { return UNKNOWN_RULE; } +}; + +} // namespace WebCore + +#endif // CSSUnknownRule_h diff --git a/Source/WebCore/css/CSSUnknownRule.idl b/Source/WebCore/css/CSSUnknownRule.idl new file mode 100644 index 0000000..b62ceb8 --- /dev/null +++ b/Source/WebCore/css/CSSUnknownRule.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface [ + OmitConstructor + ] CSSUnknownRule : CSSRule { + }; + +} diff --git a/Source/WebCore/css/CSSValue.h b/Source/WebCore/css/CSSValue.h new file mode 100644 index 0000000..ec1b15e --- /dev/null +++ b/Source/WebCore/css/CSSValue.h @@ -0,0 +1,82 @@ +/* + * (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. + */ + +#ifndef CSSValue_h +#define CSSValue_h + +#include "StyleBase.h" + +#include "CSSParserValues.h" +#include "KURLHash.h" +#include <wtf/ListHashSet.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSStyleSheet; + +typedef int ExceptionCode; + +class CSSValue : public RefCounted<CSSValue> { +public: + // FIXME: Change name to Type. + enum UnitTypes { + CSS_INHERIT = 0, + CSS_PRIMITIVE_VALUE = 1, + CSS_VALUE_LIST = 2, + CSS_CUSTOM = 3, + CSS_INITIAL = 4 + }; + + virtual ~CSSValue() { } + + // FIXME: Change this to return UnitTypes. + virtual unsigned short cssValueType() const { return CSS_CUSTOM; } + + virtual String cssText() const = 0; + void setCssText(const String&, ExceptionCode&) { } // FIXME: Not implemented. + + virtual bool isBorderImageValue() const { return false; } + virtual bool isCursorImageValue() const { return false; } + virtual bool isFontFamilyValue() const { return false; } + virtual bool isFontValue() const { return false; } + virtual bool isImageGeneratorValue() const { return false; } + virtual bool isImageValue() const { return false; } + virtual bool isImplicitInitialValue() const { return false; } + virtual bool isPrimitiveValue() const { return false; } + virtual bool isReflectValue() const { return false; } + virtual bool isShadowValue() const { return false; } + virtual bool isTimingFunctionValue() const { return false; } + virtual bool isValueList() const { return false; } + virtual bool isWebKitCSSTransformValue() const { return false; } + +#if ENABLE(SVG) + virtual bool isSVGColor() const { return false; } + virtual bool isSVGPaint() const { return false; } +#endif + + virtual CSSParserValue parserValue() const { ASSERT_NOT_REACHED(); return CSSParserValue(); } + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*) { } +}; + +} // namespace WebCore + +#endif // CSSValue_h diff --git a/Source/WebCore/css/CSSValue.idl b/Source/WebCore/css/CSSValue.idl new file mode 100644 index 0000000..fe6b8f2 --- /dev/null +++ b/Source/WebCore/css/CSSValue.idl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + interface [ + CustomToJS, + Polymorphic + ] CSSValue { + + // UnitTypes + const unsigned short CSS_INHERIT = 0; + const unsigned short CSS_PRIMITIVE_VALUE = 1; + const unsigned short CSS_VALUE_LIST = 2; + const unsigned short CSS_CUSTOM = 3; + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString cssText + setter raises(DOMException); + + readonly attribute unsigned short cssValueType; + + }; + +} diff --git a/Source/WebCore/css/CSSValueKeywords.in b/Source/WebCore/css/CSSValueKeywords.in new file mode 100644 index 0000000..4fce4f3 --- /dev/null +++ b/Source/WebCore/css/CSSValueKeywords.in @@ -0,0 +1,792 @@ +# These are all values accepted for CSS2. +# +# WARNING: +# -------- +# +# The Values are sorted according to the properties they belong to, +# and have to be in the same order as the enums in RenderStyle.h. +# +# If not, the optimizations in the cssparser and style selector will fail, +# and produce incorrect results. +# +inherit +initial +# +# CSS_PROP_OUTLINE_STYLE +# CSS_PROP_BORDER_TOP_STYLE +# CSS_PROP_BORDER_BOTTOM_STYLE +# CSS_PROP_BORDER_LEFT_STYLE +none +hidden +inset +groove +ridge +outset +dotted +dashed +solid +double +# +# CSS_PROP_FONT: +# +caption +icon +menu +message-box +small-caption +-webkit-mini-control +-webkit-small-control +-webkit-control +status-bar + +# +# CSS_PROP_FONT_STYLE: +# +#normal +italic +oblique +# The following is only allowed in @font-face: +all +# +# CSS_PROP_FONT_VARIANT: +# +#normal +small-caps +# +# CSS_PROP_FONT_WEIGHT: +# +normal +bold +bolder +lighter +100 +200 +300 +400 +500 +600 +700 +800 +900 +# +# CSS_PROP_FONT_SIZE: +# +xx-small +x-small +small +medium +large +x-large +xx-large +-webkit-xxx-large +smaller +larger +# +# CSS_PROP_FONT_STRETCH: +# +#normal +wider +narrower +ultra-condensed +extra-condensed +condensed +semi-condensed +semi-expanded +expanded +extra-expanded +ultra-expanded +# +# CSS_PROP_GENERIC_FONT_FAMILY: +# +serif +sans-serif +cursive +fantasy +monospace +-webkit-body +# +# +# CSS_PROP_*_COLOR +# +aqua +black +blue +fuchsia +gray +green +lime +maroon +navy +olive +orange +purple +red +silver +teal +white +yellow +transparent +-webkit-link +-webkit-activelink +activeborder +activecaption +appworkspace +background +buttonface +buttonhighlight +buttonshadow +buttontext +captiontext +graytext +highlight +highlighttext +inactiveborder +inactivecaption +inactivecaptiontext +infobackground +infotext +match +menutext +scrollbar +threeddarkshadow +threedface +threedhighlight +threedlightshadow +threedshadow +window +windowframe +windowtext +-webkit-focus-ring-color +currentcolor +# +# colors in non strict mode +grey +-webkit-text +# +# CSS_PROP_BACKGROUND_REPEAT: +# +repeat +repeat-x +repeat-y +no-repeat +# round +# space +# +# CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE: +# +clear +copy +source-over +source-in +source-out +source-atop +destination-over +destination-in +destination-out +destination-atop +xor +plus-darker +# highlight +plus-lighter +# +# CSS_PROP_VERTICAL_ALIGN: +# +baseline +middle +sub +super +text-top +text-bottom +top +bottom +# HTML alignment MIDDLE has no corresponding CSS alignment +-webkit-baseline-middle +# +# CSS_PROP_TEXT_ALIGN: +# +-webkit-auto +left +right +center +justify +-webkit-left +-webkit-right +-webkit-center +# +# CSS_PROP_LIST_STYLE_POSITION: +# +outside +inside +# +# CSS_PROP_LIST_STYLE_TYPE: +# +disc +circle +square +decimal +decimal-leading-zero +arabic-indic +binary +bengali +cambodian +khmer +devanagari +gujarati +gurmukhi +kannada +lower-hexadecimal +lao +malayalam +mongolian +myanmar +octal +oriya +persian +urdu +telugu +tibetan +thai +upper-hexadecimal +lower-roman +upper-roman +lower-greek +lower-alpha +lower-latin +upper-alpha +upper-latin +afar +ethiopic-halehame-aa-et +ethiopic-halehame-aa-er +amharic +ethiopic-halehame-am-et +amharic-abegede +ethiopic-abegede-am-et +cjk-earthly-branch +cjk-heavenly-stem +ethiopic +ethiopic-halehame-gez +ethiopic-abegede +ethiopic-abegede-gez +hangul-consonant +hangul +lower-norwegian +oromo +ethiopic-halehame-om-et +sidama +ethiopic-halehame-sid-et +somali +ethiopic-halehame-so-et +tigre +ethiopic-halehame-tig +tigrinya-er +ethiopic-halehame-ti-er +tigrinya-er-abegede +ethiopic-abegede-ti-er +tigrinya-et +ethiopic-halehame-ti-et +tigrinya-et-abegede +ethiopic-abegede-ti-et +upper-greek +upper-norwegian +asterisks +footnotes +hebrew +armenian +lower-armenian +upper-armenian +georgian +cjk-ideographic +hiragana +katakana +hiragana-iroha +katakana-iroha +#none +# +# CSS_PROP_DISPLAY: +# +inline +block +list-item +run-in +compact +inline-block +table +inline-table +table-row-group +table-header-group +table-footer-group +table-row +table-column-group +table-column +table-cell +table-caption +-webkit-box +-webkit-inline-box +-wap-marquee +#none +# +# CSS_PROP_CURSOR: +# +auto +crosshair +default +pointer +move +vertical-text +cell +context-menu +alias +# copy +progress +no-drop +not-allowed +-webkit-zoom-in +-webkit-zoom-out +e-resize +ne-resize +nw-resize +n-resize +se-resize +sw-resize +s-resize +w-resize +ew-resize +ns-resize +nesw-resize +nwse-resize +col-resize +row-resize +text +wait +help +all-scroll +-webkit-grab +-webkit-grabbing +# none +# +# CSS_PROP_DIRECTION: +# +ltr +rtl +# +# CSS_PROP_TEXT_TRANSFORM: +# +capitalize +uppercase +lowercase +#none +# +# CSS_PROP_VISIBILITY: +# +visible +#hidden +collapse +# +# Unordered rest +# +a3 +a4 +a5 +above +absolute +always +avoid +b4 +b5 +below +bidi-override +blink +both +close-quote +crop +cross +embed +fixed +hand +hide +higher +invert +landscape +ledger +legal +letter +level +line-through +local +loud +lower +-webkit-marquee +mix +no-close-quote +no-open-quote +nowrap +open-quote +overlay +overline +portrait +pre +pre-line +pre-wrap +relative +scroll +separate +show +static +thick +thin +underline +-webkit-nowrap + +# CSS3 Values +# CSS_PROP_BOX_ALIGN +stretch +start +end +#center +#baseline + +# CSS_PROP_BOX_DIRECTION +# normal +reverse + +# CSS_PROP_BOX_ORIENT +horizontal +vertical +inline-axis +block-axis + +# CSS_PROP_BOX_PACK +# start +# end +# center +# justify + +# CSS_PROP_BOX_LINES +single +multiple + +# CSS_PROP_MARQUEE_DIRECTION +forwards +backwards +ahead +# reverse +# left +# right +up +down +# auto + +# CSS_PROP_MARQUEE_SPEED +slow +# normal +fast + +# CSS_PROP_MARQUEE_REPETITION +infinite + +# CSS_PROP_MARQUEE_STYLE +# none +slide +# scroll +alternate + +# +# CSS_PROP__KHTML_USER_MODIFY +# +read-only +read-write +read-write-plaintext-only + +# +# CSS_PROP__KHTML_USER_DRAG +# +element + +# +# CSS_PROP__KHTML_USER_SELECT +# +ignore + +# +# CSS_PROP_WIDTH/MIN_WIDTH/MAX_WIDTH +# +intrinsic +min-intrinsic + +# +# CSS_PROP_TEXT_OVERFLOW +# +clip +ellipsis + +# +# CSS_PROP__KHTML_MARGIN_COLLAPSE +# +# collapse +# separate +discard + +# +# CSS_PROP_TEXT_*_COLOR +# +dot-dash +dot-dot-dash +wave + +# +# CSS_PROP_TEXT_*_MODE +# +continuous +skip-white-space + +# +# CSS_PROP_WORD_BREAK +# +break-all + +# +# CSS_PROP_WORD_WRAP +# +break-word + +# +# CSS_PROP__KHTML_NBSP_MODE +# +space + +# +# CSS_PROP__KHTML_LINE_BREAK +# +after-white-space + +# -webkit-appearance +# The order here should match the order in the ControlPart enum in ThemeTypes.h. +# All appearance values that should be accepted by the parser should be listed between 'checkbox' and 'textarea': +checkbox +radio +push-button +square-button +button +button-bevel +default-button +inner-spin-button +-webkit-input-speech-button +list-button +listbox +listitem +media-fullscreen-button +media-mute-button +media-play-button +media-seek-back-button +media-seek-forward-button +media-rewind-button +media-return-to-realtime-button +media-toggle-closed-captions-button +media-slider +media-sliderthumb +media-volume-slider-container +media-volume-slider +media-volume-sliderthumb +media-volume-slider-mute-button +media-controls-background +media-controls-fullscreen-background +media-current-time-display +media-time-remaining-display +menulist +menulist-button +menulist-text +menulist-textfield +meter +outer-spin-button +progress-bar +progress-bar-value +slider-horizontal +slider-vertical +sliderthumb-horizontal +sliderthumb-vertical +caret +searchfield +searchfield-decoration +searchfield-results-decoration +searchfield-results-button +searchfield-cancel-button +textfield +relevancy-level-indicator +continuous-capacity-level-indicator +discrete-capacity-level-indicator +rating-level-indicator +textarea +# An appearance value that should not be accepted by the parser: +caps-lock-indicator + +# +# CSS_PROP_BORDER_IMAGE +# +# stretch +# repeat +round + +# +# CSS_PROP_BACKGROUND_CLIP/ORIGIN +# +# border/content/padding are deprecated and ultimately will only apply to the -webkit- form of these properties. +# border-box/content-box/padding-box should be used instead. +# +border +border-box +content +content-box +padding +padding-box + +# +# background-size +# +contain +cover + +# +# CSS_PROP__KHTML_RTL_ORDERING +# +logical +visual + +# +# CSS_PROP__WEBKIT_BORDER_FIT +# +lines + +# +# CSS_PROP__WEBKIT_ANIMATION_DIRECTION +# +# alternate + +# +# CSS_PROP__WEBKIT_ANIMATION_FILL_MODE +# +# forwards +# backwards +# both + +# +# CSS_PROP__WEBKIT_ANIMATION_ITERATION_COUNT +# +# infinite + +# +# CSS_PROP__WEBKIT_ANIMATION_PLAY_STATE +# +running +paused + +# +# CSS_PROP__WEBKIT_TRANSFORM_STYLE +# +flat +preserve-3d + +# +# CSS_PROP__WEBKIT_TRANSITION_TIMING_FUNCTION +# CSS_PROP__WEBKIT_ANIMATION_TIMING_FUNCTION +# +ease +linear +ease-in +ease-out +ease-in-out +step-start +step-end + +# +# CSS_PROP_ZOOM +# +document +reset + +# +# CSS_PROP_POINTER_EVENTS +# +visiblePainted +visibleFill +visibleStroke +#visible +painted +fill +stroke +#all +#none + +# +# CSS_PROP_SPEECH +# +spell-out +digits +literal-punctuation +no-punctuation + +# +# -webkit-font-smoothing +# +# auto +# none +antialiased +subpixel-antialiased + +# text-rendering +#auto +optimizeSpeed +optimizeLegibility +geometricPrecision + +# -webkit-color-correction +#default +sRGB + +# (-webkit-view-mode:) media feature: +floating +fullscreen +maximized +minimized +windowed + +# -webkit-hyphens +# none +manual +# auto + +# -webkit-writing-mode +# SVG compatibility +lr +rl +tb +lr-tb +rl-tb +tb-rl +# Standard values from CSS3 +horizontal-tb +vertical-rl +vertical-lr +horizontal-bt + +# -webkit-text-emphasis-position +over +under + +# -webkit-text-emphasis-style +filled +open +dot +# circle +double-circle +triangle +sesame + +# -webkit-radial-gradient +# circle +ellipse +closest-side +closest-corner +farthest-side +farthest-corner +# contain +# cover diff --git a/Source/WebCore/css/CSSValueList.cpp b/Source/WebCore/css/CSSValueList.cpp new file mode 100644 index 0000000..f8d8457 --- /dev/null +++ b/Source/WebCore/css/CSSValueList.cpp @@ -0,0 +1,141 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2010 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 "CSSValueList.h" + +#include "CSSParserValues.h" +#include "PlatformString.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +CSSValueList::CSSValueList(bool isSpaceSeparated) + : m_isSpaceSeparated(isSpaceSeparated) +{ +} + +CSSValueList::CSSValueList(CSSParserValueList* list) + : m_isSpaceSeparated(true) +{ + if (list) { + size_t size = list->size(); + for (unsigned i = 0; i < size; ++i) + append(list->valueAt(i)->createCSSValue()); + } +} + +CSSValueList::~CSSValueList() +{ +} + +CSSValue* CSSValueList::item(unsigned index) +{ + if (index >= m_values.size()) + return 0; + return m_values[index].get(); +} + +unsigned short CSSValueList::cssValueType() const +{ + return CSS_VALUE_LIST; +} + +void CSSValueList::append(PassRefPtr<CSSValue> val) +{ + m_values.append(val); +} + +void CSSValueList::prepend(PassRefPtr<CSSValue> val) +{ + m_values.prepend(val); +} + +bool CSSValueList::removeAll(CSSValue* val) +{ + bool found = false; + // FIXME: we should be implementing operator== to CSSValue and its derived classes + // to make comparison more flexible and fast. + for (size_t index = 0; index < m_values.size(); index++) { + if (m_values.at(index)->cssText() == val->cssText()) { + m_values.remove(index); + found = true; + } + } + + return found; +} + +bool CSSValueList::hasValue(CSSValue* val) +{ + // FIXME: we should be implementing operator== to CSSValue and its derived classes + // to make comparison more flexible and fast. + for (size_t index = 0; index < m_values.size(); index++) { + if (m_values.at(index)->cssText() == val->cssText()) + return true; + } + return false; +} + +PassRefPtr<CSSValueList> CSSValueList::copy() +{ + PassRefPtr<CSSValueList> newList = m_isSpaceSeparated ? createSpaceSeparated() : createCommaSeparated(); + for (size_t index = 0; index < m_values.size(); index++) + newList->append(item(index)); + return newList; +} + +String CSSValueList::cssText() const +{ + String result = ""; + + unsigned size = m_values.size(); + for (unsigned i = 0; i < size; i++) { + if (!result.isEmpty()) { + if (m_isSpaceSeparated) + result += " "; + else + result += ", "; + } + result += m_values[i]->cssText(); + } + + return result; +} + +PassOwnPtr<CSSParserValueList> CSSValueList::createParserValueList() const +{ + size_t size = m_values.size(); + if (!size) + return 0; + OwnPtr<CSSParserValueList> result = adoptPtr(new CSSParserValueList); + for (size_t i = 0; i < size; ++i) + result->addValue(m_values[i]->parserValue()); + return result.release(); +} + +void CSSValueList::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + size_t size = m_values.size(); + for (size_t i = 0; i < size; ++i) + m_values[i]->addSubresourceStyleURLs(urls, styleSheet); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSValueList.h b/Source/WebCore/css/CSSValueList.h new file mode 100644 index 0000000..0d5c882 --- /dev/null +++ b/Source/WebCore/css/CSSValueList.h @@ -0,0 +1,80 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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. + */ + +#ifndef CSSValueList_h +#define CSSValueList_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSParserValueList; + +class CSSValueList : public CSSValue { +public: + static PassRefPtr<CSSValueList> createCommaSeparated() + { + return adoptRef(new CSSValueList(false)); + } + static PassRefPtr<CSSValueList> createSpaceSeparated() + { + return adoptRef(new CSSValueList(true)); + } + static PassRefPtr<CSSValueList> createFromParserValueList(CSSParserValueList* list) + { + return adoptRef(new CSSValueList(list)); + } + + virtual ~CSSValueList(); + + size_t length() const { return m_values.size(); } + CSSValue* item(unsigned); + CSSValue* itemWithoutBoundsCheck(unsigned index) { return m_values[index].get(); } + + void append(PassRefPtr<CSSValue>); + void prepend(PassRefPtr<CSSValue>); + bool removeAll(CSSValue*); + bool hasValue(CSSValue*); + PassRefPtr<CSSValueList> copy(); + + virtual String cssText() const; + + PassOwnPtr<CSSParserValueList> createParserValueList() const; + + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +protected: + CSSValueList(bool isSpaceSeparated); + CSSValueList(CSSParserValueList*); + +private: + virtual bool isValueList() const { return true; } + + virtual unsigned short cssValueType() const; + + Vector<RefPtr<CSSValue> > m_values; + bool m_isSpaceSeparated; +}; + +} // namespace WebCore + +#endif // CSSValueList_h diff --git a/Source/WebCore/css/CSSValueList.idl b/Source/WebCore/css/CSSValueList.idl new file mode 100644 index 0000000..06df5d7 --- /dev/null +++ b/Source/WebCore/css/CSSValueList.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + // Introduced in DOM Level 2: + interface [ + HasIndexGetter + ] CSSValueList : CSSValue { + readonly attribute unsigned long length; + CSSValue item(in unsigned long index); + }; + +} diff --git a/Source/WebCore/css/Counter.h b/Source/WebCore/css/Counter.h new file mode 100644 index 0000000..0a45009 --- /dev/null +++ b/Source/WebCore/css/Counter.h @@ -0,0 +1,61 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef Counter_h +#define Counter_h + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +namespace WebCore { + +class Counter : public RefCounted<Counter> { +public: + static PassRefPtr<Counter> create(PassRefPtr<CSSPrimitiveValue> identifier, PassRefPtr<CSSPrimitiveValue> listStyle, PassRefPtr<CSSPrimitiveValue> separator) + { + return adoptRef(new Counter(identifier, listStyle, separator)); + } + + String identifier() const { return m_identifier ? m_identifier->getStringValue() : String(); } + String listStyle() const { return m_listStyle ? m_listStyle->getStringValue() : String(); } + String separator() const { return m_separator ? m_separator->getStringValue() : String(); } + + int listStyleNumber() const { return m_listStyle ? m_listStyle->getIntValue() : 0; } + + void setIdentifier(PassRefPtr<CSSPrimitiveValue> identifier) { m_identifier = identifier; } + void setListStyle(PassRefPtr<CSSPrimitiveValue> listStyle) { m_listStyle = listStyle; } + void setSeparator(PassRefPtr<CSSPrimitiveValue> separator) { m_separator = separator; } + +private: + Counter(PassRefPtr<CSSPrimitiveValue> identifier, PassRefPtr<CSSPrimitiveValue> listStyle, PassRefPtr<CSSPrimitiveValue> separator) + : m_identifier(identifier) + , m_listStyle(listStyle) + , m_separator(separator) + { + } + + RefPtr<CSSPrimitiveValue> m_identifier; // string + RefPtr<CSSPrimitiveValue> m_listStyle; // int + RefPtr<CSSPrimitiveValue> m_separator; // string +}; + +} // namespace WebCore + +#endif // Counter_h diff --git a/Source/WebCore/css/Counter.idl b/Source/WebCore/css/Counter.idl new file mode 100644 index 0000000..6236c45 --- /dev/null +++ b/Source/WebCore/css/Counter.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006, 2007 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface Counter { + readonly attribute DOMString identifier; + readonly attribute DOMString listStyle; + readonly attribute DOMString separator; + }; + +} diff --git a/Source/WebCore/css/DashboardRegion.h b/Source/WebCore/css/DashboardRegion.h new file mode 100644 index 0000000..91e5d7a --- /dev/null +++ b/Source/WebCore/css/DashboardRegion.h @@ -0,0 +1,48 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef DashboardRegion_h +#define DashboardRegion_h + +#include "Rect.h" + +#if ENABLE(DASHBOARD_SUPPORT) + +namespace WebCore { + +class DashboardRegion : public RectBase, public RefCounted<DashboardRegion> { +public: + static PassRefPtr<DashboardRegion> create() { return adoptRef(new DashboardRegion); } + + RefPtr<DashboardRegion> m_next; + String m_label; + String m_geometryType; + bool m_isCircle : 1; + bool m_isRectangle : 1; + +private: + DashboardRegion() : m_isCircle(false), m_isRectangle(false) { } +}; + +} // namespace + +#endif + +#endif diff --git a/Source/WebCore/css/DashboardSupportCSSPropertyNames.in b/Source/WebCore/css/DashboardSupportCSSPropertyNames.in new file mode 100644 index 0000000..615bd6c --- /dev/null +++ b/Source/WebCore/css/DashboardSupportCSSPropertyNames.in @@ -0,0 +1 @@ +-webkit-dashboard-region diff --git a/Source/WebCore/css/FontFamilyValue.cpp b/Source/WebCore/css/FontFamilyValue.cpp new file mode 100644 index 0000000..ebe9645 --- /dev/null +++ b/Source/WebCore/css/FontFamilyValue.cpp @@ -0,0 +1,72 @@ +/* + * (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 "FontFamilyValue.h" + +#include "CSSParser.h" + +namespace WebCore { + +FontFamilyValue::FontFamilyValue(const String& familyName) + : CSSPrimitiveValue(String(), CSS_STRING) + , m_familyName(familyName) +{ + // If there is anything in parentheses or square brackets at the end, delete it. + // FIXME: Do we really need this? The original code mentioned "a language tag in + // braces at the end" and "[Xft] qualifiers", but it's not clear either of those + // is in active use on the web. + unsigned length = m_familyName.length(); + while (length >= 3) { + UChar startCharacter = 0; + switch (m_familyName[length - 1]) { + case ']': + startCharacter = '['; + break; + case ')': + startCharacter = '('; + break; + } + if (!startCharacter) + break; + unsigned first = 0; + for (unsigned i = length - 2; i > 0; --i) { + if (m_familyName[i - 1] == ' ' && m_familyName[i] == startCharacter) + first = i - 1; + } + if (!first) + break; + length = first; + } + m_familyName.truncate(length); +} + +void FontFamilyValue::appendSpaceSeparated(const UChar* characters, unsigned length) +{ + m_familyName.append(' '); + m_familyName.append(characters, length); +} + +String FontFamilyValue::cssText() const +{ + return quoteCSSStringIfNeeded(m_familyName); +} + +} diff --git a/Source/WebCore/css/FontFamilyValue.h b/Source/WebCore/css/FontFamilyValue.h new file mode 100644 index 0000000..3f7d3a3 --- /dev/null +++ b/Source/WebCore/css/FontFamilyValue.h @@ -0,0 +1,51 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef FontFamilyValue_h +#define FontFamilyValue_h + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +namespace WebCore { + +class FontFamilyValue : public CSSPrimitiveValue { +public: + static PassRefPtr<FontFamilyValue> create(const String& familyName) + { + return adoptRef(new FontFamilyValue(familyName)); + } + + void appendSpaceSeparated(const UChar* characters, unsigned length); + + const String& familyName() const { return m_familyName; } + + virtual String cssText() const; + +private: + FontFamilyValue(const String& familyName); + virtual bool isFontFamilyValue() const { return true; } + + String m_familyName; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/FontValue.cpp b/Source/WebCore/css/FontValue.cpp new file mode 100644 index 0000000..991fc6e --- /dev/null +++ b/Source/WebCore/css/FontValue.cpp @@ -0,0 +1,67 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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 "FontValue.h" + +#include "CSSValueList.h" +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +namespace WebCore { + +String FontValue::cssText() const +{ + // font variant weight size / line-height family + + String result(""); + + if (style) + result += style->cssText(); + if (variant) { + if (!result.isEmpty()) + result += " "; + result += variant->cssText(); + } + if (weight) { + if (!result.isEmpty()) + result += " "; + result += weight->cssText(); + } + if (size) { + if (!result.isEmpty()) + result += " "; + result += size->cssText(); + } + if (lineHeight) { + if (!size) + result += " "; + result += "/"; + result += lineHeight->cssText(); + } + if (family) { + if (!result.isEmpty()) + result += " "; + result += family->cssText(); + } + + return result; +} + +} diff --git a/Source/WebCore/css/FontValue.h b/Source/WebCore/css/FontValue.h new file mode 100644 index 0000000..5c7406c --- /dev/null +++ b/Source/WebCore/css/FontValue.h @@ -0,0 +1,57 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 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. + */ + +#ifndef FontValue_h +#define FontValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSPrimitiveValue; +class CSSValueList; + +class FontValue : public CSSValue { +public: + static PassRefPtr<FontValue> create() + { + return adoptRef(new FontValue); + } + + virtual String cssText() const; + + RefPtr<CSSPrimitiveValue> style; + RefPtr<CSSPrimitiveValue> variant; + RefPtr<CSSPrimitiveValue> weight; + RefPtr<CSSPrimitiveValue> size; + RefPtr<CSSPrimitiveValue> lineHeight; + RefPtr<CSSValueList> family; + +private: + FontValue() { } + + virtual bool isFontValue() const { return true; } +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaFeatureNames.cpp b/Source/WebCore/css/MediaFeatureNames.cpp new file mode 100644 index 0000000..85b8cbc --- /dev/null +++ b/Source/WebCore/css/MediaFeatureNames.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. + * + * 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" + +#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC +#define CSS_MEDIAQUERY_NAMES_HIDE_GLOBALS 1 +#endif + +#include "MediaFeatureNames.h" +#include <wtf/StaticConstructors.h> + +namespace WebCore { +namespace MediaFeatureNames { + +#define DEFINE_MEDIAFEATURE_GLOBAL(name, str) \ + DEFINE_GLOBAL(AtomicString, name##MediaFeature, str) +CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(DEFINE_MEDIAFEATURE_GLOBAL) +#undef DEFINE_MEDIAFEATURE_GLOBAL + +void init() +{ + static bool initialized; + if (!initialized) { + // Use placement new to initialize the globals. + + AtomicString::init(); + #define INITIALIZE_GLOBAL(name, str) new ((void*)&name##MediaFeature) AtomicString(str); + CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(INITIALIZE_GLOBAL) + #undef INITIALIZE_GLOBAL + initialized = true; + } +} + +} // namespace MediaFeatureNames +} // namespace WebCore diff --git a/Source/WebCore/css/MediaFeatureNames.h b/Source/WebCore/css/MediaFeatureNames.h new file mode 100644 index 0000000..1daa4e9 --- /dev/null +++ b/Source/WebCore/css/MediaFeatureNames.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. + * + * 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. + * + */ +#ifndef MediaFeatureNames_h +#define MediaFeatureNames_h + +#include <wtf/text/AtomicString.h> + +namespace WebCore { + namespace MediaFeatureNames { + +#define CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(macro) \ + macro(color, "color") \ + macro(grid, "grid") \ + macro(monochrome, "monochrome") \ + macro(height, "height") \ + macro(width, "width") \ + macro(orientation, "orientation") \ + macro(aspect_ratio, "aspect-ratio") \ + macro(device_aspect_ratio, "device-aspect-ratio") \ + macro(device_pixel_ratio, "-webkit-device-pixel-ratio") \ + macro(device_height, "device-height") \ + macro(device_width, "device-width") \ + macro(max_color, "max-color") \ + macro(max_aspect_ratio, "max-aspect-ratio") \ + macro(max_device_aspect_ratio, "max-device-aspect-ratio") \ + macro(max_device_pixel_ratio, "-webkit-max-device-pixel-ratio") \ + macro(max_device_height, "max-device-height") \ + macro(max_device_width, "max-device-width") \ + macro(max_height, "max-height") \ + macro(max_monochrome, "max-monochrome") \ + macro(max_width, "max-width") \ + macro(min_color, "min-color") \ + macro(min_aspect_ratio, "min-aspect-ratio") \ + macro(min_device_aspect_ratio, "min-device-aspect-ratio") \ + macro(min_device_pixel_ratio, "-webkit-min-device-pixel-ratio") \ + macro(min_device_height, "min-device-height") \ + macro(min_device_width, "min-device-width") \ + macro(min_height, "min-height") \ + macro(min_monochrome, "min-monochrome") \ + macro(min_width, "min-width") \ + macro(transform_2d, "-webkit-transform-2d") \ + macro(transform_3d, "-webkit-transform-3d") \ + macro(transition, "-webkit-transition") \ + macro(animation, "-webkit-animation") \ + macro(view_mode, "-webkit-view-mode") + +// end of macro + +#ifndef CSS_MEDIAQUERY_NAMES_HIDE_GLOBALS + #define CSS_MEDIAQUERY_NAMES_DECLARE(name, str) extern const AtomicString name##MediaFeature; + CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(CSS_MEDIAQUERY_NAMES_DECLARE) + #undef CSS_MEDIAQUERY_NAMES_DECLARE +#endif + + void init(); + + } // namespace MediaFeatureNames +} // namespace WebCore + +#endif // MediaFeatureNames_h diff --git a/Source/WebCore/css/MediaList.cpp b/Source/WebCore/css/MediaList.cpp new file mode 100644 index 0000000..81f8712 --- /dev/null +++ b/Source/WebCore/css/MediaList.cpp @@ -0,0 +1,257 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2010 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 "MediaList.h" + +#include "CSSImportRule.h" +#include "CSSParser.h" +#include "CSSStyleSheet.h" +#include "ExceptionCode.h" +#include "MediaQuery.h" +#include "MediaQueryExp.h" + +namespace WebCore { + +/* MediaList is used to store 3 types of media related entities which mean the same: + * Media Queries, Media Types and Media Descriptors. + * Currently MediaList always tries to parse media queries and if parsing fails, + * tries to fallback to Media Descriptors if m_fallback flag is set. + * Slight problem with syntax error handling: + * CSS 2.1 Spec (http://www.w3.org/TR/CSS21/media.html) + * specifies that failing media type parsing is a syntax error + * CSS 3 Media Queries Spec (http://www.w3.org/TR/css3-mediaqueries/) + * specifies that failing media query is a syntax error + * HTML 4.01 spec (http://www.w3.org/TR/REC-html40/present/styles.html#adef-media) + * specifies that Media Descriptors should be parsed with forward-compatible syntax + * DOM Level 2 Style Sheet spec (http://www.w3.org/TR/DOM-Level-2-Style/) + * talks about MediaList.mediaText and refers + * - to Media Descriptors of HTML 4.0 in context of StyleSheet + * - to Media Types of CSS 2.0 in context of CSSMediaRule and CSSImportRule + * + * These facts create situation where same (illegal) media specification may result in + * different parses depending on whether it is media attr of style element or part of + * css @media rule. + * <style media="screen and resolution > 40dpi"> ..</style> will be enabled on screen devices where as + * @media screen and resolution > 40dpi {..} will not. + * This gets more counter-intuitive in JavaScript: + * document.styleSheets[0].media.mediaText = "screen and resolution > 40dpi" will be ok and + * enabled, while + * document.styleSheets[0].cssRules[0].media.mediaText = "screen and resolution > 40dpi" will + * throw SYNTAX_ERR exception. + */ + +MediaList::MediaList(CSSStyleSheet* parentSheet, bool fallbackToDescriptor) + : StyleBase(parentSheet) + , m_fallback(fallbackToDescriptor) +{ +} + +MediaList::MediaList(CSSStyleSheet* parentSheet, const String& media, bool fallbackToDescriptor) + : StyleBase(parentSheet) + , m_fallback(fallbackToDescriptor) +{ + ExceptionCode ec = 0; + setMediaText(media, ec); + // FIXME: parsing can fail. The problem with failing constructor is that + // we would need additional flag saying MediaList is not valid + // Parse can fail only when fallbackToDescriptor == false, i.e when HTML4 media descriptor + // forward-compatible syntax is not in use. + // DOMImplementationCSS seems to mandate that media descriptors are used + // for both html and svg, even though svg:style doesn't use media descriptors + // Currently the only places where parsing can fail are + // creating <svg:style>, creating css media / import rules from js + if (ec) + setMediaText("invalid", ec); +} + +MediaList::MediaList(CSSImportRule* parentRule, const String& media) + : StyleBase(parentRule) + , m_fallback(false) +{ + ExceptionCode ec = 0; + setMediaText(media, ec); + if (ec) + setMediaText("invalid", ec); +} + +MediaList::~MediaList() +{ + deleteAllValues(m_queries); +} + +static String parseMediaDescriptor(const String& s) +{ + int len = s.length(); + + // http://www.w3.org/TR/REC-html40/types.html#type-media-descriptors + // "Each entry is truncated just before the first character that isn't a + // US ASCII letter [a-zA-Z] (ISO 10646 hex 41-5a, 61-7a), digit [0-9] (hex 30-39), + // or hyphen (hex 2d)." + int i; + unsigned short c; + for (i = 0; i < len; ++i) { + c = s[i]; + if (! ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '1' && c <= '9') + || (c == '-'))) + break; + } + return s.left(i); +} + +void MediaList::deleteMedium(const String& oldMedium, ExceptionCode& ec) +{ + RefPtr<MediaList> tempMediaList = MediaList::create(); + CSSParser p(true); + + MediaQuery* oldQuery = 0; + OwnPtr<MediaQuery> createdQuery; + + if (p.parseMediaQuery(tempMediaList.get(), oldMedium)) { + if (tempMediaList->m_queries.size() > 0) + oldQuery = tempMediaList->m_queries[0]; + } else if (m_fallback) { + String medium = parseMediaDescriptor(oldMedium); + if (!medium.isNull()) { + createdQuery = adoptPtr(new MediaQuery(MediaQuery::None, medium, 0)); + oldQuery = createdQuery.get(); + } + } + + // DOM Style Sheets spec doesn't allow SYNTAX_ERR to be thrown in deleteMedium + ec = NOT_FOUND_ERR; + + if (oldQuery) { + for (size_t i = 0; i < m_queries.size(); ++i) { + MediaQuery* a = m_queries[i]; + if (*a == *oldQuery) { + m_queries.remove(i); + delete a; + ec = 0; + break; + } + } + } + + if (!ec) + notifyChanged(); +} + +String MediaList::mediaText() const +{ + String text(""); + + bool first = true; + for (size_t i = 0; i < m_queries.size(); ++i) { + if (!first) + text += ", "; + else + first = false; + text += m_queries[i]->cssText(); + } + + return text; +} + +void MediaList::setMediaText(const String& value, ExceptionCode& ec) +{ + RefPtr<MediaList> tempMediaList = MediaList::create(); + CSSParser p(true); + + Vector<String> list; + value.split(',', list); + Vector<String>::const_iterator end = list.end(); + for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) { + String medium = (*it).stripWhiteSpace(); + if (!medium.isEmpty()) { + if (!p.parseMediaQuery(tempMediaList.get(), medium)) { + if (m_fallback) { + String mediaDescriptor = parseMediaDescriptor(medium); + if (!mediaDescriptor.isNull()) + tempMediaList->m_queries.append(new MediaQuery(MediaQuery::None, mediaDescriptor, 0)); + } else { + ec = SYNTAX_ERR; + return; + } + } + } else if (!m_fallback) { + ec = SYNTAX_ERR; + return; + } + } + // ",,,," falls straight through, but is not valid unless fallback + if (!m_fallback && list.begin() == list.end()) { + String s = value.stripWhiteSpace(); + if (!s.isEmpty()) { + ec = SYNTAX_ERR; + return; + } + } + + ec = 0; + deleteAllValues(m_queries); + m_queries = tempMediaList->m_queries; + tempMediaList->m_queries.clear(); + notifyChanged(); +} + +String MediaList::item(unsigned index) const +{ + if (index < m_queries.size()) { + MediaQuery* query = m_queries[index]; + return query->cssText(); + } + + return String(); +} + +void MediaList::appendMedium(const String& newMedium, ExceptionCode& ec) +{ + ec = INVALID_CHARACTER_ERR; + CSSParser p(true); + if (p.parseMediaQuery(this, newMedium)) { + ec = 0; + } else if (m_fallback) { + String medium = parseMediaDescriptor(newMedium); + if (!medium.isNull()) { + m_queries.append(new MediaQuery(MediaQuery::None, medium, 0)); + ec = 0; + } + } + + if (!ec) + notifyChanged(); +} + +void MediaList::appendMediaQuery(PassOwnPtr<MediaQuery> mediaQuery) +{ + m_queries.append(mediaQuery.leakPtr()); +} + +void MediaList::notifyChanged() +{ + for (StyleBase* p = parent(); p; p = p->parent()) { + if (p->isCSSStyleSheet()) + return static_cast<CSSStyleSheet*>(p)->styleSheetChanged(); + } +} + +} diff --git a/Source/WebCore/css/MediaList.h b/Source/WebCore/css/MediaList.h new file mode 100644 index 0000000..f4b1fa7 --- /dev/null +++ b/Source/WebCore/css/MediaList.h @@ -0,0 +1,92 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2008, 2009, 2010 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. + */ + +#ifndef MediaList_h +#define MediaList_h + +#include "StyleBase.h" +#include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSImportRule; +class CSSStyleSheet; +class MediaQuery; + +typedef int ExceptionCode; + +class MediaList : public StyleBase { +public: + static PassRefPtr<MediaList> create() + { + return adoptRef(new MediaList(0, false)); + } + static PassRefPtr<MediaList> create(CSSImportRule* parentRule, const String& media) + { + return adoptRef(new MediaList(parentRule, media)); + } + static PassRefPtr<MediaList> create(CSSStyleSheet* parentSheet, const String& media) + { + return adoptRef(new MediaList(parentSheet, media, false)); + } + + static PassRefPtr<MediaList> createAllowingDescriptionSyntax(const String& mediaQueryOrDescription) + { + return adoptRef(new MediaList(0, mediaQueryOrDescription, true)); + } + static PassRefPtr<MediaList> createAllowingDescriptionSyntax(CSSStyleSheet* parentSheet, const String& mediaQueryOrDescription) + { + return adoptRef(new MediaList(parentSheet, mediaQueryOrDescription, true)); + } + + static PassRefPtr<MediaList> create(const String& media, bool allowDescriptionSyntax) + { + return adoptRef(new MediaList(0, media, allowDescriptionSyntax)); + } + + virtual ~MediaList(); + + unsigned length() const { return m_queries.size(); } + String item(unsigned index) const; + void deleteMedium(const String& oldMedium, ExceptionCode&); + void appendMedium(const String& newMedium, ExceptionCode&); + + String mediaText() const; + void setMediaText(const String&, ExceptionCode&xo); + + void appendMediaQuery(PassOwnPtr<MediaQuery>); + const Vector<MediaQuery*>& mediaQueries() const { return m_queries; } + +private: + MediaList(CSSStyleSheet* parentSheet, bool fallbackToDescription); + MediaList(CSSStyleSheet* parentSheet, const String& media, bool fallbackToDescription); + MediaList(CSSImportRule* parentRule, const String& media); + + void notifyChanged(); + + Vector<MediaQuery*> m_queries; + bool m_fallback; // true if failed media query parsing should fallback to media description parsing +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaList.idl b/Source/WebCore/css/MediaList.idl new file mode 100644 index 0000000..54ad4f8 --- /dev/null +++ b/Source/WebCore/css/MediaList.idl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module stylesheets { + + // Introduced in DOM Level 2: + interface [ + HasIndexGetter + ] MediaList { + + attribute [ConvertNullToNullString, ConvertNullStringTo=Null] DOMString mediaText + setter raises(DOMException); + readonly attribute unsigned long length; + + [ConvertNullStringTo=Null] DOMString item(in unsigned long index); + void deleteMedium(in DOMString oldMedium) + raises(DOMException); + void appendMedium(in DOMString newMedium) + raises(DOMException); + + }; + +} diff --git a/Source/WebCore/css/MediaQuery.cpp b/Source/WebCore/css/MediaQuery.cpp new file mode 100644 index 0000000..c476a21 --- /dev/null +++ b/Source/WebCore/css/MediaQuery.cpp @@ -0,0 +1,125 @@ +/* + * CSS Media Query + * + * Copyright (C) 2005, 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MediaQuery.h" + +#include "MediaQueryExp.h" +#include <wtf/NonCopyingSort.h> +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +// http://dev.w3.org/csswg/cssom/#serialize-a-media-query +String MediaQuery::serialize() const +{ + StringBuilder result; + + switch (m_restrictor) { + case MediaQuery::Only: + result.append("only "); + break; + case MediaQuery::Not: + result.append("not "); + break; + case MediaQuery::None: + break; + } + + if (m_expressions->isEmpty()) { + result.append(m_mediaType); + return result.toString(); + } + + if (m_mediaType != "all" || m_restrictor != None) { + result.append(m_mediaType); + result.append(" and "); + } + + result.append(m_expressions->at(0)->serialize()); + for (size_t i = 1; i < m_expressions->size(); ++i) { + result.append(" and "); + result.append(m_expressions->at(i)->serialize()); + } + return result.toString(); +} + +static bool expressionCompare(const OwnPtr<MediaQueryExp>& a, const OwnPtr<MediaQueryExp>& b) +{ + return codePointCompare(a->serialize(), b->serialize()) < 0; +} + + +MediaQuery::MediaQuery(Restrictor r, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > exprs) + : m_restrictor(r) + , m_mediaType(mediaType.lower()) + , m_expressions(exprs) + , m_ignored(false) +{ + if (!m_expressions) { + m_expressions = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >); + return; + } + + nonCopyingSort(m_expressions->begin(), m_expressions->end(), expressionCompare); + + // remove all duplicated expressions + String key; + for (int i = m_expressions->size() - 1; i >= 0; --i) { + + // if not all of the expressions is valid the media query must be ignored. + if (!m_ignored) + m_ignored = !m_expressions->at(i)->isValid(); + + if (m_expressions->at(i)->serialize() == key) + m_expressions->remove(i); + else + key = m_expressions->at(i)->serialize(); + } +} + +MediaQuery::~MediaQuery() +{ +} + +// http://dev.w3.org/csswg/cssom/#compare-media-queries +bool MediaQuery::operator==(const MediaQuery& other) const +{ + return cssText() == other.cssText(); +} + +// http://dev.w3.org/csswg/cssom/#serialize-a-list-of-media-queries +String MediaQuery::cssText() const +{ + if (m_serializationCache.isNull()) + const_cast<MediaQuery*>(this)->m_serializationCache = serialize(); + + return m_serializationCache; +} + +} //namespace diff --git a/Source/WebCore/css/MediaQuery.h b/Source/WebCore/css/MediaQuery.h new file mode 100644 index 0000000..281009b --- /dev/null +++ b/Source/WebCore/css/MediaQuery.h @@ -0,0 +1,68 @@ +/* + * CSS Media Query + * + * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaQuery_h +#define MediaQuery_h + +#include "PlatformString.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { +class MediaQueryExp; + +class MediaQuery : public Noncopyable { +public: + enum Restrictor { + Only, Not, None + }; + + MediaQuery(Restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > exprs); + ~MediaQuery(); + + Restrictor restrictor() const { return m_restrictor; } + const Vector<OwnPtr<MediaQueryExp> >* expressions() const { return m_expressions.get(); } + String mediaType() const { return m_mediaType; } + bool operator==(const MediaQuery& other) const; + String cssText() const; + bool ignored() const { return m_ignored; } + + private: + Restrictor m_restrictor; + String m_mediaType; + OwnPtr<Vector<OwnPtr<MediaQueryExp> > > m_expressions; + bool m_ignored; + String m_serializationCache; + + String serialize() const; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp new file mode 100644 index 0000000..fa2e099 --- /dev/null +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -0,0 +1,540 @@ +/* + * CSS Media Query Evaluator + * + * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MediaQueryEvaluator.h" + +#include "Chrome.h" +#include "ChromeClient.h" +#include "CSSPrimitiveValue.h" +#include "CSSStyleSelector.h" +#include "CSSValueList.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameView.h" +#include "IntRect.h" +#include "MediaFeatureNames.h" +#include "MediaList.h" +#include "MediaQuery.h" +#include "MediaQueryExp.h" +#include "NodeRenderStyle.h" +#include "Page.h" +#include "RenderView.h" +#include "RenderStyle.h" +#include "PlatformScreen.h" +#include <wtf/HashMap.h> + +#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif + +namespace WebCore { + +using namespace MediaFeatureNames; + +enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; + +typedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix); +typedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap; +static FunctionMap* gFunctionMap; + +/* + * FIXME: following media features are not implemented: color_index, scan, resolution + * + * color_index, min-color-index, max_color_index: It's unknown how to retrieve + * the information if the display mode is indexed + * scan: The "scan" media feature describes the scanning process of + * tv output devices. It's unknown how to retrieve this information from + * the platform + * resolution, min-resolution, max-resolution: css parser doesn't seem to + * support CSS_DIMENSION + */ + +MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) + : m_frame(0) + , m_style(0) + , m_expResult(mediaFeatureResult) +{ +} + +MediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult) + : m_mediaType(acceptedMediaType) + , m_frame(0) + , m_style(0) + , m_expResult(mediaFeatureResult) +{ +} + +MediaQueryEvaluator:: MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult) + : m_mediaType(acceptedMediaType) + , m_frame(0) + , m_style(0) + , m_expResult(mediaFeatureResult) +{ +} + +MediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style) + : m_mediaType(acceptedMediaType) + , m_frame(frame) + , m_style(style) + , m_expResult(false) // doesn't matter when we have m_frame and m_style +{ +} + +MediaQueryEvaluator::~MediaQueryEvaluator() +{ +} + +bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const +{ + return mediaTypeToMatch.isEmpty() + || equalIgnoringCase(mediaTypeToMatch, "all") + || equalIgnoringCase(mediaTypeToMatch, m_mediaType); +} + +bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const +{ + // Like mediaTypeMatch, but without the special cases for "" and "all". + ASSERT(mediaTypeToMatch); + ASSERT(mediaTypeToMatch[0] != '\0'); + ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all"))); + return equalIgnoringCase(mediaTypeToMatch, m_mediaType); +} + +static bool applyRestrictor(MediaQuery::Restrictor r, bool value) +{ + return r == MediaQuery::Not ? !value : value; +} + +bool MediaQueryEvaluator::eval(const MediaList* mediaList, CSSStyleSelector* styleSelector) const +{ + if (!mediaList) + return true; + + const Vector<MediaQuery*>& queries = mediaList->mediaQueries(); + if (!queries.size()) + return true; // empty query list evaluates to true + + // iterate over queries, stop if any of them eval to true (OR semantics) + bool result = false; + for (size_t i = 0; i < queries.size() && !result; ++i) { + MediaQuery* query = queries.at(i); + + if (query->ignored()) + continue; + + if (mediaTypeMatch(query->mediaType())) { + const Vector<OwnPtr<MediaQueryExp> >* exps = query->expressions(); + // iterate through expressions, stop if any of them eval to false + // (AND semantics) + size_t j = 0; + for (; j < exps->size(); ++j) { + bool exprResult = eval(exps->at(j).get()); + if (styleSelector && exps->at(j)->isViewportDependent()) + styleSelector->addViewportDependentMediaQueryResult(exps->at(j).get(), exprResult); + if (!exprResult) + break; + } + + // assume true if we are at the end of the list, + // otherwise assume false + result = applyRestrictor(query->restrictor(), exps->size() == j); + } else + result = applyRestrictor(query->restrictor(), false); + } + + return result; +} + +static bool parseAspectRatio(CSSValue* value, int& h, int& v) +{ + if (value->isValueList()) { + CSSValueList* valueList = static_cast<CSSValueList*>(value); + if (valueList->length() == 3) { + CSSValue* i0 = valueList->itemWithoutBoundsCheck(0); + CSSValue* i1 = valueList->itemWithoutBoundsCheck(1); + CSSValue* i2 = valueList->itemWithoutBoundsCheck(2); + if (i0->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i0)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER + && i1->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i1)->primitiveType() == CSSPrimitiveValue::CSS_STRING + && i2->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i2)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + String str = static_cast<CSSPrimitiveValue*>(i1)->getStringValue(); + if (!str.isNull() && str.length() == 1 && str[0] == '/') { + h = static_cast<CSSPrimitiveValue*>(i0)->getIntValue(CSSPrimitiveValue::CSS_NUMBER); + v = static_cast<CSSPrimitiveValue*>(i2)->getIntValue(CSSPrimitiveValue::CSS_NUMBER); + return true; + } + } + } + } + return false; +} + +template<typename T> +bool compareValue(T a, T b, MediaFeaturePrefix op) +{ + switch (op) { + case MinPrefix: + return a >= b; + case MaxPrefix: + return a <= b; + case NoPrefix: + return a == b; + } + return false; +} + +static bool numberValue(CSSValue* value, float& result) +{ + if (value->isPrimitiveValue() + && static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); + return true; + } + return false; +} + +static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame()->view()); + float number; + if (value) + return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); + + return bitsPerComponent != 0; +} + +static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + if (!screenIsMonochrome(frame->page()->mainFrame()->view())) { + if (value) { + float number; + return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); + } + return false; + } + + return colorMediaFeatureEval(value, style, frame, op); +} + +static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +{ + // A missing parameter should fail + if (!value) + return false; + + FrameView* view = frame->view(); + int width = view->layoutWidth(); + int height = view->layoutHeight(); + if (width > height) // Square viewport is portrait + return "landscape" == static_cast<CSSPrimitiveValue*>(value)->getStringValue(); + return "portrait" == static_cast<CSSPrimitiveValue*>(value)->getStringValue(); +} + +static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + if (value) { + FrameView* view = frame->view(); + int width = view->layoutWidth(); + int height = view->layoutHeight(); + int h = 0; + int v = 0; + if (parseAspectRatio(value, h, v)) + return v != 0 && compareValue(width * v, height * h, op); + return false; + } + + // ({,min-,max-}aspect-ratio) + // assume if we have a device, its aspect ratio is non-zero + return true; +} + +static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + if (value) { + FloatRect sg = screenRect(frame->page()->mainFrame()->view()); + int h = 0; + int v = 0; + if (parseAspectRatio(value, h, v)) + return v != 0 && compareValue(static_cast<int>(sg.width()) * v, static_cast<int>(sg.height()) * h, op); + return false; + } + + // ({,min-,max-}device-aspect-ratio) + // assume if we have a device, its aspect ratio is non-zero + return true; +} + +static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + if (value) + return value->isPrimitiveValue() && compareValue(frame->page()->chrome()->scaleFactor(), static_cast<CSSPrimitiveValue*>(value)->getFloatValue(), op); + + return frame->page()->chrome()->scaleFactor() != 0; +} + +static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +{ + // if output device is bitmap, grid: 0 == true + // assume we have bitmap device + float number; + if (value && numberValue(value, number)) + return compareValue(static_cast<int>(number), 0, op); + return false; +} + +static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + if (value) { + FloatRect sg = screenRect(frame->page()->mainFrame()->view()); + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.height()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); + } + // ({,min-,max-}device-height) + // assume if we have a device, assume non-zero + return true; +} + +static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + if (value) { + FloatRect sg = screenRect(frame->page()->mainFrame()->view()); + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.width()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); + } + // ({,min-,max-}device-width) + // assume if we have a device, assume non-zero + return true; +} + +static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + FrameView* view = frame->view(); + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + + if (value) + return value->isPrimitiveValue() && compareValue(view->layoutHeight(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); + + return view->layoutHeight() != 0; +} + +static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + FrameView* view = frame->view(); + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + + if (value) + return value->isPrimitiveValue() && compareValue(view->layoutWidth(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); + + return view->layoutWidth() != 0; +} + +// rest of the functions are trampolines which set the prefix according to the media feature expression used + +static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return colorMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return colorMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return monochromeMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return monochromeMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return heightMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return heightMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return widthMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return widthMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_heightMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_heightMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_widthMediaFeatureEval(value, style, frame, MinPrefix); +} + +static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +{ + return device_widthMediaFeatureEval(value, style, frame, MaxPrefix); +} + +static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +{ + if (value) { + float number; + return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); + } + return true; +} + +static bool transitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +{ + if (value) { + float number; + return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); + } + return true; +} + +static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +{ + if (value) { + float number; + return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); + } + return true; +} + +static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + bool returnValueIfNoParameter; + int have3dRendering; + +#if ENABLE(3D_RENDERING) + bool threeDEnabled = false; +#if USE(ACCELERATED_COMPOSITING) + if (RenderView* view = frame->contentRenderer()) + threeDEnabled = view->compositor()->canRender3DTransforms(); +#endif + + returnValueIfNoParameter = threeDEnabled; + have3dRendering = threeDEnabled ? 1 : 0; +#else + UNUSED_PARAM(frame); + returnValueIfNoParameter = false; + have3dRendering = 0; +#endif + + if (value) { + float number; + return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op); + } + return returnValueIfNoParameter; +} + +static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +{ + UNUSED_PARAM(op); + if (!value) + return true; + return Page::stringToViewMode(static_cast<CSSPrimitiveValue*>(value)->getStringValue()) == frame->page()->viewMode(); +} + +static void createFunctionMap() +{ + // Create the table. + gFunctionMap = new FunctionMap; +#define ADD_TO_FUNCTIONMAP(name, str) \ + gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval); + CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); +#undef ADD_TO_FUNCTIONMAP +} + +bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const +{ + if (!m_frame || !m_style) + return m_expResult; + + if (!expr->isValid()) + return false; + + if (!gFunctionMap) + createFunctionMap(); + + // call the media feature evaluation function. Assume no prefix + // and let trampoline functions override the prefix if prefix is + // used + EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); + if (func) + return func(expr->value(), m_style, m_frame, NoPrefix); + + return false; +} + +} // namespace diff --git a/Source/WebCore/css/MediaQueryEvaluator.h b/Source/WebCore/css/MediaQueryEvaluator.h new file mode 100644 index 0000000..00ac394 --- /dev/null +++ b/Source/WebCore/css/MediaQueryEvaluator.h @@ -0,0 +1,90 @@ +/* + * CSS Media Query Evaluator + * + * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaQueryEvaluator_h +#define MediaQueryEvaluator_h + +#include "PlatformString.h" + +namespace WebCore { +class CSSStyleSelector; +class Frame; +class RenderStyle; +class MediaList; +class MediaQueryExp; + +/** + * Class that evaluates css media queries as defined in + * CSS3 Module "Media Queries" (http://www.w3.org/TR/css3-mediaqueries/) + * Special constructors are needed, if simple media queries are to be + * evaluated without knowledge of the medium features. This can happen + * for example when parsing UA stylesheets, if evaluation is done + * right after parsing. + * + * the boolean parameter is used to approximate results of evaluation, if + * the device characteristics are not known. This can be used to prune the loading + * of stylesheets to only those which are probable to match. + */ +class MediaQueryEvaluator : public Noncopyable { +public: + /** Creates evaluator which evaluates only simple media queries + * Evaluator returns true for "all", and returns value of \mediaFeatureResult + * for any media features + */ + MediaQueryEvaluator(bool mediaFeatureResult = false); + + /** Creates evaluator which evaluates only simple media queries + * Evaluator returns true for acceptedMediaType and returns value of \mediafeatureResult + * for any media features + */ + MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult = false); + MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult = false); + + /** Creates evaluator which evaluates full media queries + */ + MediaQueryEvaluator(const String& acceptedMediaType, Frame*, RenderStyle*); + + ~MediaQueryEvaluator(); + + bool mediaTypeMatch(const String& mediaTypeToMatch) const; + bool mediaTypeMatchSpecific(const char* mediaTypeToMatch) const; + + /** Evaluates a list of media queries */ + bool eval(const MediaList*, CSSStyleSelector* = 0) const; + + /** Evaluates media query subexpression, ie "and (media-feature: value)" part */ + bool eval(const MediaQueryExp*) const; + +private: + String m_mediaType; + Frame* m_frame; // not owned + RenderStyle* m_style; // not owned + bool m_expResult; +}; + +} // namespace +#endif diff --git a/Source/WebCore/css/MediaQueryExp.cpp b/Source/WebCore/css/MediaQueryExp.cpp new file mode 100644 index 0000000..e970400 --- /dev/null +++ b/Source/WebCore/css/MediaQueryExp.cpp @@ -0,0 +1,111 @@ +/* + * CSS Media Query + * + * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MediaQueryExp.h" + +#include "CSSParser.h" +#include "CSSPrimitiveValue.h" +#include "CSSValueList.h" +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +inline MediaQueryExp::MediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* valueList) + : m_mediaFeature(mediaFeature) + , m_value(0) + , m_isValid(true) +{ + if (valueList) { + if (valueList->size() == 1) { + CSSParserValue* value = valueList->current(); + + if (value->id != 0) + m_value = CSSPrimitiveValue::createIdentifier(value->id); + else if (value->unit == CSSPrimitiveValue::CSS_STRING) + m_value = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && + value->unit <= CSSPrimitiveValue::CSS_KHZ) + m_value = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + + valueList->next(); + } else if (valueList->size() > 1) { + // create list of values + // currently accepts only <integer>/<integer> + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + CSSParserValue* value = 0; + bool isValid = true; + + while ((value = valueList->current()) && isValid) { + if (value->unit == CSSParserValue::Operator && value->iValue == '/') + list->append(CSSPrimitiveValue::create("/", CSSPrimitiveValue::CSS_STRING)); + else if (value->unit == CSSPrimitiveValue::CSS_NUMBER) + list->append(CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER)); + else + isValid = false; + + value = valueList->next(); + } + + if (isValid) + m_value = list.release(); + } + m_isValid = m_value; + } +} + + +PassOwnPtr<MediaQueryExp> MediaQueryExp::create(const AtomicString& mediaFeature, CSSParserValueList* values) +{ + return adoptPtr(new MediaQueryExp(mediaFeature, values)); +} + +MediaQueryExp::~MediaQueryExp() +{ +} + +String MediaQueryExp::serialize() const +{ + if (!m_serializationCache.isNull()) + return m_serializationCache; + + StringBuilder result; + result.append("("); + result.append(m_mediaFeature.lower()); + if (m_value) { + result.append(": "); + result.append(m_value->cssText()); + } + result.append(")"); + + const_cast<MediaQueryExp*>(this)->m_serializationCache = result.toString(); + return m_serializationCache; +} + +} // namespace diff --git a/Source/WebCore/css/MediaQueryExp.h b/Source/WebCore/css/MediaQueryExp.h new file mode 100644 index 0000000..72d3fff --- /dev/null +++ b/Source/WebCore/css/MediaQueryExp.h @@ -0,0 +1,83 @@ +/* + * CSS Media Query + * + * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaQueryExp_h +#define MediaQueryExp_h + +#include "CSSValue.h" +#include "MediaFeatureNames.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { +class CSSParserValueList; + +class MediaQueryExp : public FastAllocBase { +public: + static PassOwnPtr<MediaQueryExp> create(const AtomicString& mediaFeature, CSSParserValueList* values); + ~MediaQueryExp(); + + AtomicString mediaFeature() const { return m_mediaFeature; } + + CSSValue* value() const { return m_value.get(); } + + bool operator==(const MediaQueryExp& other) const + { + return (other.m_mediaFeature == m_mediaFeature) + && ((!other.m_value && !m_value) + || (other.m_value && m_value && other.m_value->cssText() == m_value->cssText())); + } + + bool isValid() const { return m_isValid; } + + bool isViewportDependent() const { return m_mediaFeature == MediaFeatureNames::widthMediaFeature || + m_mediaFeature == MediaFeatureNames::heightMediaFeature || + m_mediaFeature == MediaFeatureNames::min_widthMediaFeature || + m_mediaFeature == MediaFeatureNames::min_heightMediaFeature || + m_mediaFeature == MediaFeatureNames::max_widthMediaFeature || + m_mediaFeature == MediaFeatureNames::max_heightMediaFeature || + m_mediaFeature == MediaFeatureNames::orientationMediaFeature || + m_mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature || + m_mediaFeature == MediaFeatureNames::min_aspect_ratioMediaFeature || + m_mediaFeature == MediaFeatureNames::max_aspect_ratioMediaFeature; } + + String serialize() const; + +private: + MediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values); + + AtomicString m_mediaFeature; + RefPtr<CSSValue> m_value; + bool m_isValid; + String m_serializationCache; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaQueryList.cpp b/Source/WebCore/css/MediaQueryList.cpp new file mode 100644 index 0000000..aa3ef60 --- /dev/null +++ b/Source/WebCore/css/MediaQueryList.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "MediaQueryList.h" + +#include "MediaList.h" +#include "MediaQueryEvaluator.h" +#include "MediaQueryListListener.h" +#include "MediaQueryMatcher.h" + +namespace WebCore { + +PassRefPtr<MediaQueryList> MediaQueryList::create(PassRefPtr<MediaQueryMatcher> vector, PassRefPtr<MediaList> media, bool matches) +{ + return adoptRef(new MediaQueryList(vector, media, matches)); +} + +MediaQueryList::MediaQueryList(PassRefPtr<MediaQueryMatcher> vector, PassRefPtr<MediaList> media, bool matches) + : m_matcher(vector) + , m_media(media) + , m_evaluationRound(m_matcher->evaluationRound()) + , m_changeRound(m_evaluationRound - 1) // m_evaluationRound and m_changeRound initial values must be different. + , m_matches(matches) +{ +} + +MediaQueryList::~MediaQueryList() +{ +} + +String MediaQueryList::media() const +{ + return m_media->mediaText(); +} + +void MediaQueryList::addListener(PassRefPtr<MediaQueryListListener> listener) +{ + if (!listener) + return; + + m_matcher->addListener(listener, this); +} + +void MediaQueryList::removeListener(PassRefPtr<MediaQueryListListener> listener) +{ + if (!listener) + return; + + m_matcher->removeListener(listener.get(), this); +} + +void MediaQueryList::evaluate(MediaQueryEvaluator* evaluator, bool& notificationNeeded) +{ + if (m_evaluationRound != m_matcher->evaluationRound() && evaluator) + setMatches(evaluator->eval(m_media.get())); + notificationNeeded = m_changeRound == m_matcher->evaluationRound(); +} + +void MediaQueryList::setMatches(bool newValue) +{ + m_evaluationRound = m_matcher->evaluationRound(); + + if (newValue == m_matches) + return; + + m_matches = newValue; + m_changeRound = m_evaluationRound; +} + +bool MediaQueryList::matches() +{ + if (m_evaluationRound != m_matcher->evaluationRound()) + setMatches(m_matcher->evaluate(m_media.get())); + return m_matches; +} + +} diff --git a/Source/WebCore/css/MediaQueryList.h b/Source/WebCore/css/MediaQueryList.h new file mode 100644 index 0000000..8ff4988 --- /dev/null +++ b/Source/WebCore/css/MediaQueryList.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + */ + +#ifndef MediaQueryList_h +#define MediaQueryList_h + +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class MediaList; +class MediaQueryListListener; +class MediaQueryEvaluator; +class MediaQueryMatcher; + +// MediaQueryList interface is specified at http://dev.w3.org/csswg/cssom-view/#the-mediaquerylist-interface +// The objects of this class are returned by window.matchMedia. They may be used to +// retrieve the current value of the given media query and to add/remove listeners that +// will be called whenever the value of the query changes. + +class MediaQueryList : public RefCounted<MediaQueryList> { +public: + static PassRefPtr<MediaQueryList> create(PassRefPtr<MediaQueryMatcher>, PassRefPtr<MediaList>, bool); + ~MediaQueryList(); + + String media() const; + bool matches(); + + void addListener(PassRefPtr<MediaQueryListListener>); + void removeListener(PassRefPtr<MediaQueryListListener>); + + void evaluate(MediaQueryEvaluator*, bool& notificationNeeded); + +private: + MediaQueryList(PassRefPtr<MediaQueryMatcher>, PassRefPtr<MediaList>, bool matches); + void setMatches(bool); + + RefPtr<MediaQueryMatcher> m_matcher; + RefPtr<MediaList> m_media; + unsigned m_evaluationRound; // Indicates if the query has been evaluated after the last style selector change. + unsigned m_changeRound; // Used to know if the query has changed in the last style selector change. + bool m_matches; +}; + +} + +#endif // MediaQueryList_h diff --git a/Source/WebCore/css/MediaQueryList.idl b/Source/WebCore/css/MediaQueryList.idl new file mode 100644 index 0000000..e775db8 --- /dev/null +++ b/Source/WebCore/css/MediaQueryList.idl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + */ + +module view { + interface MediaQueryList { + readonly attribute DOMString media; + readonly attribute boolean matches; + void addListener(in MediaQueryListListener listener); + void removeListener(in MediaQueryListListener listener); + }; +} diff --git a/Source/WebCore/css/MediaQueryListListener.cpp b/Source/WebCore/css/MediaQueryListListener.cpp new file mode 100644 index 0000000..ab73b1d --- /dev/null +++ b/Source/WebCore/css/MediaQueryListListener.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "MediaQueryListListener.h" + +#include "MediaQueryList.h" +#include "ScriptFunctionCall.h" + +#if USE(JSC) +#include "JSMediaQueryList.h" +#else +#include "V8MediaQueryList.h" +#endif + +namespace WebCore { + +void MediaQueryListListener::queryChanged(ScriptState* state, MediaQueryList* query) +{ + ScriptCallback callback(state, m_value); +#if USE(JSC) + callback.appendArgument(toJS(state, query)); +#else + callback.appendArgument(toV8(query)); +#endif + callback.call(); +} + +} diff --git a/Source/WebCore/css/MediaQueryListListener.h b/Source/WebCore/css/MediaQueryListListener.h new file mode 100644 index 0000000..de62683 --- /dev/null +++ b/Source/WebCore/css/MediaQueryListListener.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + */ + +#ifndef MediaQueryListListener_h +#define MediaQueryListListener_h + +#include "PlatformString.h" +#include "ScriptState.h" +#include "ScriptValue.h" + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class MediaQueryList; + +// See http://dev.w3.org/csswg/cssom-view/#the-mediaquerylist-interface + +class MediaQueryListListener : public RefCounted<MediaQueryListListener> { +public: + static PassRefPtr<MediaQueryListListener> create(ScriptValue value) + { + if (!value.isFunction()) + return 0; + return adoptRef(new MediaQueryListListener(value)); + } + void queryChanged(ScriptState*, MediaQueryList*); + + bool operator==(const MediaQueryListListener& other) const { return m_value == other.m_value; } + +private: + MediaQueryListListener(ScriptValue value) : m_value(value) { } + + ScriptValue m_value; +}; + +} + +#endif // MediaQueryListListener_h diff --git a/Source/WebCore/css/MediaQueryListListener.idl b/Source/WebCore/css/MediaQueryListListener.idl new file mode 100644 index 0000000..7031557 --- /dev/null +++ b/Source/WebCore/css/MediaQueryListListener.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + */ + +module view { + interface [ + NoStaticTables, + ObjCProtocol, + PureInterface, + OmitConstructor + ] MediaQueryListListener { + void queryChanged(in MediaQueryList list); + }; +} diff --git a/Source/WebCore/css/MediaQueryMatcher.cpp b/Source/WebCore/css/MediaQueryMatcher.cpp new file mode 100644 index 0000000..e076837 --- /dev/null +++ b/Source/WebCore/css/MediaQueryMatcher.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "MediaQueryMatcher.h" + +#include "CSSStyleSelector.h" +#include "Document.h" +#include "Element.h" +#include "FrameView.h" +#include "MediaList.h" +#include "MediaQueryEvaluator.h" +#include "MediaQueryList.h" +#include "MediaQueryListListener.h" + +namespace WebCore { + +MediaQueryMatcher::Listener::Listener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query) + : m_listener(listener) + , m_query(query) +{ +} + +MediaQueryMatcher::Listener::~Listener() +{ +} + +void MediaQueryMatcher::Listener::evaluate(ScriptState* state, MediaQueryEvaluator* evaluator) +{ + bool notify; + m_query->evaluate(evaluator, notify); + if (notify) + m_listener->queryChanged(state, m_query.get()); +} + +MediaQueryMatcher::MediaQueryMatcher(Document* document) + : m_document(document) + , m_evaluationRound(1) +{ + ASSERT(m_document); +} + +MediaQueryMatcher::~MediaQueryMatcher() +{ +} + +void MediaQueryMatcher::documentDestroyed() +{ + m_listeners.clear(); + m_document = 0; +} + +String MediaQueryMatcher::mediaType() const +{ + if (!m_document || !m_document->frame() || !m_document->frame()->view()) + return String(); + + return m_document->frame()->view()->mediaType(); +} + +PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::prepareEvaluator() const +{ + if (!m_document || !m_document->frame()) + return 0; + + Element* documentElement = m_document->documentElement(); + if (!documentElement) + return 0; + + CSSStyleSelector* styleSelector = m_document->styleSelector(); + if (!styleSelector) + return 0; + + RefPtr<RenderStyle> rootStyle = styleSelector->styleForElement(documentElement, 0 /*defaultParent*/, false /*allowSharing*/, true /*resolveForRootDefault*/); + + return adoptPtr(new MediaQueryEvaluator(mediaType(), m_document->frame(), rootStyle.get())); +} + +bool MediaQueryMatcher::evaluate(MediaList* media) +{ + if (!media) + return false; + + OwnPtr<MediaQueryEvaluator> evaluator(prepareEvaluator()); + return evaluator && evaluator->eval(media); +} + +PassRefPtr<MediaQueryList> MediaQueryMatcher::matchMedia(const String& query) +{ + if (!m_document) + return 0; + + RefPtr<MediaList> media = MediaList::create(query, false); + return MediaQueryList::create(this, media, evaluate(media.get())); +} + +void MediaQueryMatcher::addListener(PassRefPtr<MediaQueryListListener> listener, PassRefPtr<MediaQueryList> query) +{ + if (!m_document) + return; + + for (size_t i = 0; i < m_listeners.size(); ++i) { + if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) + return; + } + + m_listeners.append(new Listener(listener, query)); +} + +void MediaQueryMatcher::removeListener(MediaQueryListListener* listener, MediaQueryList* query) +{ + if (!m_document) + return; + + for (size_t i = 0; i < m_listeners.size(); ++i) { + if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) { + m_listeners.remove(i); + return; + } + } +} + +void MediaQueryMatcher::styleSelectorChanged() +{ + ASSERT(m_document); + + ScriptState* scriptState = mainWorldScriptState(m_document->frame()); + if (!scriptState) + return; + + ++m_evaluationRound; + OwnPtr<MediaQueryEvaluator> evaluator = prepareEvaluator(); + if (!evaluator) + return; + + for (size_t i = 0; i < m_listeners.size(); ++i) + m_listeners[i]->evaluate(scriptState, evaluator.get()); +} + +} diff --git a/Source/WebCore/css/MediaQueryMatcher.h b/Source/WebCore/css/MediaQueryMatcher.h new file mode 100644 index 0000000..96bbf83 --- /dev/null +++ b/Source/WebCore/css/MediaQueryMatcher.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + */ + +#ifndef MediaQueryMatcher_h +#define MediaQueryMatcher_h + +#include "ScriptState.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class Document; +class MediaList; +class MediaQueryList; +class MediaQueryListListener; +class MediaQueryEvaluator; + +// MediaQueryMatcher class is responsible for keeping a vector of pairs +// MediaQueryList x MediaQueryListListener. It is responsible for evaluating the queries +// whenever it is needed and to call the listeners if the corresponding query has changed. +// The listeners must be called in the very same order in which they have been added. + +class MediaQueryMatcher : public RefCounted<MediaQueryMatcher> { +public: + static PassRefPtr<MediaQueryMatcher> create(Document* document) { return adoptRef(new MediaQueryMatcher(document)); } + ~MediaQueryMatcher(); + void documentDestroyed(); + + void addListener(PassRefPtr<MediaQueryListListener>, PassRefPtr<MediaQueryList>); + void removeListener(MediaQueryListListener*, MediaQueryList*); + + PassRefPtr<MediaQueryList> matchMedia(const String&); + + unsigned evaluationRound() const { return m_evaluationRound; } + void styleSelectorChanged(); + bool evaluate(MediaList*); + +private: + class Listener { + public: + Listener(PassRefPtr<MediaQueryListListener>, PassRefPtr<MediaQueryList>); + ~Listener(); + + void evaluate(ScriptState*, MediaQueryEvaluator*); + + MediaQueryListListener* listener() { return m_listener.get(); } + MediaQueryList* query() { return m_query.get(); } + + private: + RefPtr<MediaQueryListListener> m_listener; + RefPtr<MediaQueryList> m_query; + }; + + MediaQueryMatcher(Document*); + PassOwnPtr<MediaQueryEvaluator> prepareEvaluator() const; + String mediaType() const; + + Document* m_document; + Vector<OwnPtr<Listener> > m_listeners; + + // This value is incremented at style selector changes. + // It is used to avoid evaluating queries more then once and to make sure + // that a media query result change is notified exactly once. + unsigned m_evaluationRound; +}; + +} + +#endif // MediaQueryMatcher_h diff --git a/Source/WebCore/css/Pair.h b/Source/WebCore/css/Pair.h new file mode 100644 index 0000000..c76bd82 --- /dev/null +++ b/Source/WebCore/css/Pair.h @@ -0,0 +1,63 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * 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. + */ + +#ifndef Pair_h +#define Pair_h + +#include <wtf/RefCounted.h> +#include "CSSPrimitiveValue.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +// A primitive value representing a pair. This is useful for properties like border-radius, background-size/position, +// and border-spacing (all of which are space-separated sets of two values). At the moment we are only using it for +// border-radius and background-size, but (FIXME) border-spacing and background-position could be converted over to use +// it (eliminating some extra -webkit- internal properties). +class Pair : public RefCounted<Pair> { +public: + static PassRefPtr<Pair> create() + { + return adoptRef(new Pair); + } + static PassRefPtr<Pair> create(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second) + { + return adoptRef(new Pair(first, second)); + } + virtual ~Pair() { } + + CSSPrimitiveValue* first() const { return m_first.get(); } + CSSPrimitiveValue* second() const { return m_second.get(); } + + void setFirst(PassRefPtr<CSSPrimitiveValue> first) { m_first = first; } + void setSecond(PassRefPtr<CSSPrimitiveValue> second) { m_second = second; } + +private: + Pair() : m_first(0), m_second(0) { } + Pair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second) + : m_first(first), m_second(second) { } + + RefPtr<CSSPrimitiveValue> m_first; + RefPtr<CSSPrimitiveValue> m_second; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/RGBColor.cpp b/Source/WebCore/css/RGBColor.cpp new file mode 100644 index 0000000..5c8c104 --- /dev/null +++ b/Source/WebCore/css/RGBColor.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008, 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RGBColor.h" + +namespace WebCore { + +PassRefPtr<RGBColor> RGBColor::create(unsigned rgbColor) +{ + return adoptRef(new RGBColor(rgbColor)); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::red() +{ + unsigned value = (m_rgbColor >> 16) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::green() +{ + unsigned value = (m_rgbColor >> 8) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::blue() +{ + unsigned value = m_rgbColor & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::alpha() +{ + float value = static_cast<float>((m_rgbColor >> 24) & 0xFF) / 0xFF; + return WebCore::CSSPrimitiveValue::create(value, WebCore::CSSPrimitiveValue::CSS_NUMBER); +} + +} // namespace WebCore + diff --git a/Source/WebCore/css/RGBColor.h b/Source/WebCore/css/RGBColor.h new file mode 100644 index 0000000..7937a08 --- /dev/null +++ b/Source/WebCore/css/RGBColor.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RGBColor_h +#define RGBColor_h + +#include "CSSPrimitiveValue.h" +#include "Color.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + + class RGBColor : public RefCounted<RGBColor> { + public: + static PassRefPtr<RGBColor> create(unsigned rgbColor); + + PassRefPtr<CSSPrimitiveValue> red(); + PassRefPtr<CSSPrimitiveValue> green(); + PassRefPtr<CSSPrimitiveValue> blue(); + PassRefPtr<CSSPrimitiveValue> alpha(); + + Color color() const { return Color(m_rgbColor); } + + private: + RGBColor(unsigned rgbColor) + : m_rgbColor(rgbColor) + { + } + + RGBA32 m_rgbColor; + }; + +} // namespace WebCore + +#endif // RGBColor_h diff --git a/Source/WebCore/css/RGBColor.idl b/Source/WebCore/css/RGBColor.idl new file mode 100644 index 0000000..1dc87bc --- /dev/null +++ b/Source/WebCore/css/RGBColor.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module css { + + // Introduced in DOM Level 2: + interface RGBColor { + readonly attribute CSSPrimitiveValue red; + readonly attribute CSSPrimitiveValue green; + readonly attribute CSSPrimitiveValue blue; + + // WebKit extensions +#if !defined(LANGUAGE_JAVASCRIPT) || !LANGUAGE_JAVASCRIPT + readonly attribute CSSPrimitiveValue alpha; +#endif +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C + readonly attribute Color color; +#endif + }; + +} diff --git a/Source/WebCore/css/Rect.h b/Source/WebCore/css/Rect.h new file mode 100644 index 0000000..ca6dd25 --- /dev/null +++ b/Source/WebCore/css/Rect.h @@ -0,0 +1,62 @@ +/* + * Copyright (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. + */ + +#ifndef Rect_h +#define Rect_h + +#include "CSSPrimitiveValue.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + + class RectBase { + public: + CSSPrimitiveValue* top() const { return m_top.get(); } + CSSPrimitiveValue* right() const { return m_right.get(); } + CSSPrimitiveValue* bottom() const { return m_bottom.get(); } + CSSPrimitiveValue* left() const { return m_left.get(); } + + void setTop(PassRefPtr<CSSPrimitiveValue> top) { m_top = top; } + void setRight(PassRefPtr<CSSPrimitiveValue> right) { m_right = right; } + void setBottom(PassRefPtr<CSSPrimitiveValue> bottom) { m_bottom = bottom; } + void setLeft(PassRefPtr<CSSPrimitiveValue> left) { m_left = left; } + + protected: + RectBase() { } + ~RectBase() { } + + private: + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_right; + RefPtr<CSSPrimitiveValue> m_bottom; + RefPtr<CSSPrimitiveValue> m_left; + }; + + class Rect : public RectBase, public RefCounted<Rect> { + public: + static PassRefPtr<Rect> create() { return adoptRef(new Rect); } + + private: + Rect() { } + }; + +} // namespace WebCore + +#endif // Rect_h diff --git a/Source/WebCore/css/Rect.idl b/Source/WebCore/css/Rect.idl new file mode 100644 index 0000000..60eb70e --- /dev/null +++ b/Source/WebCore/css/Rect.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006, 2007 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. + */ + +module css { + + interface Rect { + readonly attribute CSSPrimitiveValue top; + readonly attribute CSSPrimitiveValue right; + readonly attribute CSSPrimitiveValue bottom; + readonly attribute CSSPrimitiveValue left; + }; + +} diff --git a/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp b/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp new file mode 100644 index 0000000..0cf6181 --- /dev/null +++ b/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp @@ -0,0 +1,204 @@ +/* + Copyright (C) 2007 Eric Seidel <eric@webkit.org> + Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + + 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" + +#if ENABLE(SVG) +#include "CSSComputedStyleDeclaration.h" + +#include "CSSPrimitiveValueMappings.h" +#include "CSSPropertyNames.h" +#include "Document.h" +#include "RenderStyle.h" + +namespace WebCore { + +static PassRefPtr<CSSPrimitiveValue> glyphOrientationToCSSPrimitiveValue(EGlyphOrientation orientation) +{ + switch (orientation) { + case GO_0DEG: + return CSSPrimitiveValue::create(0.0f, CSSPrimitiveValue::CSS_DEG); + case GO_90DEG: + return CSSPrimitiveValue::create(90.0f, CSSPrimitiveValue::CSS_DEG); + case GO_180DEG: + return CSSPrimitiveValue::create(180.0f, CSSPrimitiveValue::CSS_DEG); + case GO_270DEG: + return CSSPrimitiveValue::create(270.0f, CSSPrimitiveValue::CSS_DEG); + default: + return 0; + } +} + +static PassRefPtr<CSSValue> strokeDashArrayToCSSValueList(const Vector<SVGLength>& dashes) +{ + if (dashes.isEmpty()) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + const Vector<SVGLength>::const_iterator end = dashes.end(); + for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) + list->append(SVGLength::toCSSPrimitiveValue(*it)); + + return list.release(); +} + +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getSVGPropertyCSSValue(int propertyID, EUpdateLayout updateLayout) const +{ + Node* node = m_node.get(); + if (!node) + return 0; + + // Make sure our layout is up to date before we allow a query on these attributes. + if (updateLayout) + node->document()->updateLayout(); + + RenderStyle* style = node->computedStyle(); + if (!style) + return 0; + + const SVGRenderStyle* svgStyle = style->svgStyle(); + if (!svgStyle) + return 0; + + switch (static_cast<CSSPropertyID>(propertyID)) { + case CSSPropertyClipRule: + return CSSPrimitiveValue::create(svgStyle->clipRule()); + case CSSPropertyFloodOpacity: + return CSSPrimitiveValue::create(svgStyle->floodOpacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyStopOpacity: + return CSSPrimitiveValue::create(svgStyle->stopOpacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyColorInterpolation: + return CSSPrimitiveValue::create(svgStyle->colorInterpolation()); + case CSSPropertyColorInterpolationFilters: + return CSSPrimitiveValue::create(svgStyle->colorInterpolationFilters()); + case CSSPropertyFillOpacity: + return CSSPrimitiveValue::create(svgStyle->fillOpacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyFillRule: + return CSSPrimitiveValue::create(svgStyle->fillRule()); + case CSSPropertyColorRendering: + return CSSPrimitiveValue::create(svgStyle->colorRendering()); + case CSSPropertyImageRendering: + return CSSPrimitiveValue::create(svgStyle->imageRendering()); + case CSSPropertyShapeRendering: + return CSSPrimitiveValue::create(svgStyle->shapeRendering()); + case CSSPropertyStrokeLinecap: + return CSSPrimitiveValue::create(svgStyle->capStyle()); + case CSSPropertyStrokeLinejoin: + return CSSPrimitiveValue::create(svgStyle->joinStyle()); + case CSSPropertyStrokeMiterlimit: + return CSSPrimitiveValue::create(svgStyle->strokeMiterLimit(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyStrokeOpacity: + return CSSPrimitiveValue::create(svgStyle->strokeOpacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyAlignmentBaseline: + return CSSPrimitiveValue::create(svgStyle->alignmentBaseline()); + case CSSPropertyDominantBaseline: + return CSSPrimitiveValue::create(svgStyle->dominantBaseline()); + case CSSPropertyTextAnchor: + return CSSPrimitiveValue::create(svgStyle->textAnchor()); + case CSSPropertyWritingMode: + return CSSPrimitiveValue::create(svgStyle->writingMode()); + case CSSPropertyClipPath: + if (!svgStyle->clipperResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->clipperResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyMask: + if (!svgStyle->maskerResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->maskerResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyFilter: + if (!svgStyle->filterResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->filterResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyFloodColor: + return CSSPrimitiveValue::createColor(svgStyle->floodColor().rgb()); + case CSSPropertyLightingColor: + return CSSPrimitiveValue::createColor(svgStyle->lightingColor().rgb()); + case CSSPropertyStopColor: + return CSSPrimitiveValue::createColor(svgStyle->stopColor().rgb()); + case CSSPropertyFill: + return svgStyle->fillPaint(); + case CSSPropertyKerning: + return SVGLength::toCSSPrimitiveValue(svgStyle->kerning()); + case CSSPropertyMarkerEnd: + if (!svgStyle->markerEndResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->markerEndResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyMarkerMid: + if (!svgStyle->markerMidResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->markerMidResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyMarkerStart: + if (!svgStyle->markerStartResource().isEmpty()) + return CSSPrimitiveValue::create(svgStyle->markerStartResource(), CSSPrimitiveValue::CSS_URI); + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + case CSSPropertyStroke: + return svgStyle->strokePaint(); + case CSSPropertyStrokeDasharray: + return strokeDashArrayToCSSValueList(svgStyle->strokeDashArray()); + case CSSPropertyStrokeDashoffset: + return SVGLength::toCSSPrimitiveValue(svgStyle->strokeDashOffset()); + case CSSPropertyStrokeWidth: + return SVGLength::toCSSPrimitiveValue(svgStyle->strokeWidth()); + case CSSPropertyBaselineShift: { + switch (svgStyle->baselineShift()) { + case BS_BASELINE: + return CSSPrimitiveValue::createIdentifier(CSSValueBaseline); + case BS_SUPER: + return CSSPrimitiveValue::createIdentifier(CSSValueSuper); + case BS_SUB: + return CSSPrimitiveValue::createIdentifier(CSSValueSub); + case BS_LENGTH: + return SVGLength::toCSSPrimitiveValue(svgStyle->baselineShiftValue()); + } + } + case CSSPropertyGlyphOrientationHorizontal: + return glyphOrientationToCSSPrimitiveValue(svgStyle->glyphOrientationHorizontal()); + case CSSPropertyGlyphOrientationVertical: { + if (RefPtr<CSSPrimitiveValue> value = glyphOrientationToCSSPrimitiveValue(svgStyle->glyphOrientationVertical())) + return value.release(); + + if (svgStyle->glyphOrientationVertical() == GO_AUTO) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + + return 0; + } + case CSSPropertyWebkitSvgShadow: + return valueForShadow(svgStyle->shadow(), propertyID, style); + case CSSPropertyVectorEffect: + return CSSPrimitiveValue::create(svgStyle->vectorEffect()); + case CSSPropertyMarker: + case CSSPropertyEnableBackground: + case CSSPropertyColorProfile: + // the above properties are not yet implemented in the engine + break; + default: + // If you crash here, it's because you added a css property and are not handling it + // in either this switch statement or the one in CSSComputedStyleDelcaration::getPropertyCSSValue + ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propertyID); + } + LOG_ERROR("unimplemented propertyID: %d", propertyID); + return 0; +} + +} + +#endif // ENABLE(SVG) + +// vim:ts=4:noet diff --git a/Source/WebCore/css/SVGCSSParser.cpp b/Source/WebCore/css/SVGCSSParser.cpp new file mode 100644 index 0000000..3c42d40 --- /dev/null +++ b/Source/WebCore/css/SVGCSSParser.cpp @@ -0,0 +1,358 @@ +/* + Copyright (C) 2008 Eric Seidel <eric@webkit.org> + Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005, 2007, 2010 Rob Buis <buis@kde.org> + Copyright (C) 2005, 2006 Apple Computer, Inc. + + 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" + +#if ENABLE(SVG) +#include "CSSInheritedValue.h" +#include "CSSInitialValue.h" +#include "CSSParser.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSQuirkPrimitiveValue.h" +#include "CSSValueKeywords.h" +#include "CSSValueList.h" +#include "RenderTheme.h" +#include "SVGPaint.h" + +using namespace std; + +namespace WebCore { + +bool CSSParser::parseSVGValue(int propId, bool important) +{ + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + int id = value->id; + + bool valid_primitive = false; + RefPtr<CSSValue> parsedValue; + + switch (propId) { + /* The comment to the right defines all valid value of these + * properties as defined in SVG 1.1, Appendix N. Property index */ + case CSSPropertyAlignmentBaseline: + // auto | baseline | before-edge | text-before-edge | middle | + // central | after-edge | text-after-edge | ideographic | alphabetic | + // hanging | mathematical | inherit + if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle || + (id >= CSSValueBeforeEdge && id <= CSSValueMathematical)) + valid_primitive = true; + break; + + case CSSPropertyBaselineShift: + // baseline | super | sub | <percentage> | <length> | inherit + if (id == CSSValueBaseline || id == CSSValueSub || + id >= CSSValueSuper) + valid_primitive = true; + else + valid_primitive = validUnit(value, FLength|FPercent, false); + break; + + case CSSPropertyDominantBaseline: + // auto | use-script | no-change | reset-size | ideographic | + // alphabetic | hanging | mathematical | central | middle | + // text-after-edge | text-before-edge | inherit + if (id == CSSValueAuto || id == CSSValueMiddle || + (id >= CSSValueUseScript && id <= CSSValueResetSize) || + (id >= CSSValueCentral && id <= CSSValueMathematical)) + valid_primitive = true; + break; + + case CSSPropertyEnableBackground: + // accumulate | new [x] [y] [width] [height] | inherit + if (id == CSSValueAccumulate) // TODO : new + valid_primitive = true; + break; + + case CSSPropertyMarkerStart: + case CSSPropertyMarkerMid: + case CSSPropertyMarkerEnd: + case CSSPropertyMask: + if (id == CSSValueNone) + valid_primitive = true; + else if (value->unit == CSSPrimitiveValue::CSS_URI) { + parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI); + if (parsedValue) + m_valueList->next(); + } + break; + + case CSSPropertyClipRule: // nonzero | evenodd | inherit + case CSSPropertyFillRule: + if (id == CSSValueNonzero || id == CSSValueEvenodd) + valid_primitive = true; + break; + + case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit + valid_primitive = validUnit(value, FNumber|FNonNeg, false); + break; + + case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit + if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel) + valid_primitive = true; + break; + + case CSSPropertyStrokeLinecap: // butt | round | square | inherit + if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare) + valid_primitive = true; + break; + + case CSSPropertyStrokeOpacity: // <opacity-value> | inherit + case CSSPropertyFillOpacity: + case CSSPropertyStopOpacity: + case CSSPropertyFloodOpacity: + valid_primitive = (!id && validUnit(value, FNumber|FPercent, false)); + break; + + case CSSPropertyShapeRendering: + // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit + if (id == CSSValueAuto || id == CSSValueOptimizespeed || + id == CSSValueCrispedges || id == CSSValueGeometricprecision) + valid_primitive = true; + break; + + case CSSPropertyImageRendering: // auto | optimizeSpeed | + case CSSPropertyColorRendering: // optimizeQuality | inherit + if (id == CSSValueAuto || id == CSSValueOptimizespeed || + id == CSSValueOptimizequality) + valid_primitive = true; + break; + + case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit + if (id == CSSValueAuto || id == CSSValueSrgb) + valid_primitive = true; + break; + + case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit + case CSSPropertyColorInterpolationFilters: + if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb) + valid_primitive = true; + break; + + /* Start of supported CSS properties with validation. This is needed for parseShortHand to work + * correctly and allows optimization in applyRule(..) + */ + + case CSSPropertyTextAnchor: // start | middle | end | inherit + if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd) + valid_primitive = true; + break; + + case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit + if (id == CSSValueAuto) { + valid_primitive = true; + break; + } + /* fallthrough intentional */ + case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit + if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) { + parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG); + + if (parsedValue) + m_valueList->next(); + } + break; + + case CSSPropertyFill: // <paint> | inherit + case CSSPropertyStroke: // <paint> | inherit + { + if (id == CSSValueNone) + parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_NONE); + else if (id == CSSValueCurrentcolor) + parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR); + else if ((id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu) + parsedValue = SVGPaint::create(RenderTheme::defaultTheme()->systemColor(id)); + else if (value->unit == CSSPrimitiveValue::CSS_URI) { + RGBA32 c = Color::transparent; + if (m_valueList->next() && parseColorFromValue(m_valueList->current(), c)) { + parsedValue = SVGPaint::create(value->string, c); + } else + parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_URI, value->string); + } else + parsedValue = parseSVGPaint(); + + if (parsedValue) + m_valueList->next(); + } + break; + + case CSSPropertyColor: // <color> | inherit + if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || + (id >= CSSValueAliceblue && id <= CSSValueYellowgreen)) + parsedValue = SVGColor::create(value->string); + else + parsedValue = parseSVGColor(); + + if (parsedValue) + m_valueList->next(); + break; + + case CSSPropertyStopColor: // TODO : icccolor + case CSSPropertyFloodColor: + case CSSPropertyLightingColor: + if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || + (id >= CSSValueAliceblue && id <= CSSValueYellowgreen)) + parsedValue = SVGColor::create(value->string); + else if (id == CSSValueCurrentcolor) + parsedValue = SVGColor::createCurrentColor(); + else // TODO : svgcolor (iccColor) + parsedValue = parseSVGColor(); + + if (parsedValue) + m_valueList->next(); + + break; + + case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit + if (id == CSSValueNone || id == CSSValueNonScalingStroke) + valid_primitive = true; + break; + + case CSSPropertyWritingMode: + // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit + if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb) + valid_primitive = true; + break; + + case CSSPropertyStrokeWidth: // <length> | inherit + case CSSPropertyStrokeDashoffset: + valid_primitive = validUnit(value, FLength | FPercent, false); + break; + case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit + if (id == CSSValueNone) + valid_primitive = true; + else + parsedValue = parseSVGStrokeDasharray(); + + break; + + case CSSPropertyKerning: // auto | normal | <length> | inherit + if (id == CSSValueAuto || id == CSSValueNormal) + valid_primitive = true; + else + valid_primitive = validUnit(value, FLength, false); + break; + + case CSSPropertyClipPath: // <uri> | none | inherit + case CSSPropertyFilter: + if (id == CSSValueNone) + valid_primitive = true; + else if (value->unit == CSSPrimitiveValue::CSS_URI) { + parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); + if (parsedValue) + m_valueList->next(); + } + break; + case CSSPropertyWebkitSvgShadow: + if (id == CSSValueNone) + valid_primitive = true; + else + return parseShadow(propId, important); + + /* shorthand properties */ + case CSSPropertyMarker: + { + ShorthandScope scope(this, propId); + m_implicitShorthand = true; + if (!parseValue(CSSPropertyMarkerStart, important)) + return false; + if (m_valueList->current()) { + rollbackLastProperties(1); + return false; + } + CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value(); + addProperty(CSSPropertyMarkerMid, value, important); + addProperty(CSSPropertyMarkerEnd, value, important); + m_implicitShorthand = false; + return true; + } + default: + // If you crash here, it's because you added a css property and are not handling it + // in either this switch statement or the one in CSSParser::parseValue + ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); + return false; + } + + if (valid_primitive) { + if (id != 0) + parsedValue = CSSPrimitiveValue::createIdentifier(id); + else if (value->unit == CSSPrimitiveValue::CSS_STRING) + parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) + parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); + else if (value->unit >= CSSParserValue::Q_EMS) + parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS); + m_valueList->next(); + } + if (!parsedValue || (m_valueList->current() && !inShorthand())) + return false; + + addProperty(propId, parsedValue.release(), important); + return true; +} + +PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray() +{ + RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated(); + CSSParserValue* value = m_valueList->current(); + bool valid_primitive = true; + while (value) { + valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false); + if (!valid_primitive) + break; + if (value->id != 0) + ret->append(CSSPrimitiveValue::createIdentifier(value->id)); + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) + ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit)); + value = m_valueList->next(); + if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') + value = m_valueList->next(); + } + if (!valid_primitive) + return 0; + return ret.release(); +} + +PassRefPtr<CSSValue> CSSParser::parseSVGPaint() +{ + RGBA32 c = Color::transparent; + if (!parseColorFromValue(m_valueList->current(), c)) + return SVGPaint::create(); + return SVGPaint::create(Color(c)); +} + +PassRefPtr<CSSValue> CSSParser::parseSVGColor() +{ + RGBA32 c = Color::transparent; + if (!parseColorFromValue(m_valueList->current(), c)) + return 0; + return SVGColor::create(Color(c)); +} + +} + +#endif // ENABLE(SVG) + +// vim:ts=4:noet diff --git a/Source/WebCore/css/SVGCSSPropertyNames.in b/Source/WebCore/css/SVGCSSPropertyNames.in new file mode 100644 index 0000000..7c157a8 --- /dev/null +++ b/Source/WebCore/css/SVGCSSPropertyNames.in @@ -0,0 +1,51 @@ +# +# all valid SVG CSS2 properties. +# + +# SVG style props +clip-path +clip-rule +mask +# opacity +enable-background +filter +flood-color +flood-opacity +lighting-color +stop-color +stop-opacity +# pointer-events +color-interpolation +color-interpolation-filters +color-profile +color-rendering +fill +fill-opacity +fill-rule +#font-size-adjust +image-rendering +marker +marker-end +marker-mid +marker-start +shape-rendering +stroke +stroke-dasharray +stroke-dashoffset +stroke-linecap +stroke-linejoin +stroke-miterlimit +stroke-opacity +stroke-width +# text-rendering +alignment-baseline +baseline-shift +dominant-baseline +glyph-orientation-horizontal +glyph-orientation-vertical +kerning +text-anchor +vector-effect +writing-mode + +-webkit-svg-shadow diff --git a/Source/WebCore/css/SVGCSSStyleSelector.cpp b/Source/WebCore/css/SVGCSSStyleSelector.cpp new file mode 100644 index 0000000..64665d4 --- /dev/null +++ b/Source/WebCore/css/SVGCSSStyleSelector.cpp @@ -0,0 +1,594 @@ +/* + Copyright (C) 2005 Apple Computer, Inc. + Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005, 2008 Rob Buis <buis@kde.org> + Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + + Based on khtml css code by: + Copyright(C) 1999-2003 Lars Knoll(knoll@kde.org) + (C) 2003 Apple Computer, Inc. + (C) 2004 Allan Sandfeld Jensen(kde@carewolf.com) + (C) 2004 Germain Garand(germain@ebooksfrance.org) + + 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" + +#if ENABLE(SVG) +#include "CSSStyleSelector.h" + +#include "CSSPrimitiveValueMappings.h" +#include "CSSPropertyNames.h" +#include "CSSValueList.h" +#include "Document.h" +#include "ShadowValue.h" +#include "SVGColor.h" +#include "SVGNames.h" +#include "SVGPaint.h" +#include "SVGRenderStyle.h" +#include "SVGRenderStyleDefs.h" +#include "SVGStyledElement.h" +#include "SVGURIReference.h" +#include <stdlib.h> +#include <wtf/MathExtras.h> + +#define HANDLE_INHERIT(prop, Prop) \ +if (isInherit) \ +{ \ + svgstyle->set##Prop(m_parentStyle->svgStyle()->prop()); \ + return; \ +} + +#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ +HANDLE_INHERIT(prop, Prop) \ +if (isInitial) { \ + svgstyle->set##Prop(SVGRenderStyle::initial##Prop()); \ + return; \ +} + +namespace WebCore { + +static float roundToNearestGlyphOrientationAngle(float angle) +{ + angle = fabsf(fmodf(angle, 360.0f)); + + if (angle <= 45.0f || angle > 315.0f) + return 0.0f; + else if (angle > 45.0f && angle <= 135.0f) + return 90.0f; + else if (angle > 135.0f && angle <= 225.0f) + return 180.0f; + + return 270.0f; +} + +static int angleToGlyphOrientation(float angle) +{ + angle = roundToNearestGlyphOrientationAngle(angle); + + if (angle == 0.0f) + return GO_0DEG; + else if (angle == 90.0f) + return GO_90DEG; + else if (angle == 180.0f) + return GO_180DEG; + else if (angle == 270.0f) + return GO_270DEG; + + return -1; +} + +static Color colorFromSVGColorCSSValue(SVGColor* svgColor, const Color& fgColor) +{ + Color color; + if (svgColor->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR) + color = fgColor; + else + color = svgColor->color(); + return color; +} + +void CSSStyleSelector::applySVGProperty(int id, CSSValue* value) +{ + ASSERT(value); + CSSPrimitiveValue* primitiveValue = 0; + if (value->isPrimitiveValue()) + primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + SVGRenderStyle* svgstyle = m_style->accessSVGStyle(); + unsigned short valueType = value->cssValueType(); + + bool isInherit = m_parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT; + bool isInitial = valueType == CSSPrimitiveValue::CSS_INITIAL || (!m_parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT); + + // What follows is a list that maps the CSS properties into their + // corresponding front-end RenderStyle values. Shorthands(e.g. border, + // background) occur in this list as well and are only hit when mapping + // "inherit" or "initial" into front-end values. + switch (id) + { + // ident only properties + case CSSPropertyAlignmentBaseline: + { + HANDLE_INHERIT_AND_INITIAL(alignmentBaseline, AlignmentBaseline) + if (!primitiveValue) + break; + + svgstyle->setAlignmentBaseline(*primitiveValue); + break; + } + case CSSPropertyBaselineShift: + { + HANDLE_INHERIT_AND_INITIAL(baselineShift, BaselineShift); + if (!primitiveValue) + break; + + if (primitiveValue->getIdent()) { + switch (primitiveValue->getIdent()) { + case CSSValueBaseline: + svgstyle->setBaselineShift(BS_BASELINE); + break; + case CSSValueSub: + svgstyle->setBaselineShift(BS_SUB); + break; + case CSSValueSuper: + svgstyle->setBaselineShift(BS_SUPER); + break; + default: + break; + } + } else { + svgstyle->setBaselineShift(BS_LENGTH); + svgstyle->setBaselineShiftValue(SVGLength::fromCSSPrimitiveValue(primitiveValue)); + } + + break; + } + case CSSPropertyKerning: + { + HANDLE_INHERIT_AND_INITIAL(kerning, Kerning); + if (primitiveValue) + svgstyle->setKerning(SVGLength::fromCSSPrimitiveValue(primitiveValue)); + break; + } + case CSSPropertyDominantBaseline: + { + HANDLE_INHERIT_AND_INITIAL(dominantBaseline, DominantBaseline) + if (primitiveValue) + svgstyle->setDominantBaseline(*primitiveValue); + break; + } + case CSSPropertyColorInterpolation: + { + HANDLE_INHERIT_AND_INITIAL(colorInterpolation, ColorInterpolation) + if (primitiveValue) + svgstyle->setColorInterpolation(*primitiveValue); + break; + } + case CSSPropertyColorInterpolationFilters: + { + HANDLE_INHERIT_AND_INITIAL(colorInterpolationFilters, ColorInterpolationFilters) + if (primitiveValue) + svgstyle->setColorInterpolationFilters(*primitiveValue); + break; + } + case CSSPropertyColorRendering: + { + HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering) + if (primitiveValue) + svgstyle->setColorRendering(*primitiveValue); + break; + } + case CSSPropertyClipRule: + { + HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule) + if (primitiveValue) + svgstyle->setClipRule(*primitiveValue); + break; + } + case CSSPropertyFillRule: + { + HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule) + if (primitiveValue) + svgstyle->setFillRule(*primitiveValue); + break; + } + case CSSPropertyStrokeLinejoin: + { + HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle) + if (primitiveValue) + svgstyle->setJoinStyle(*primitiveValue); + break; + } + case CSSPropertyImageRendering: + { + HANDLE_INHERIT_AND_INITIAL(imageRendering, ImageRendering) + if (primitiveValue) + svgstyle->setImageRendering(*primitiveValue); + break; + } + case CSSPropertyShapeRendering: + { + HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) + if (primitiveValue) + svgstyle->setShapeRendering(*primitiveValue); + break; + } + // end of ident only properties + case CSSPropertyFill: + { + HANDLE_INHERIT_AND_INITIAL(fillPaint, FillPaint) + if (value->isSVGPaint()) + svgstyle->setFillPaint(static_cast<SVGPaint*>(value)); + break; + } + case CSSPropertyStroke: + { + HANDLE_INHERIT_AND_INITIAL(strokePaint, StrokePaint) + if (value->isSVGPaint()) + svgstyle->setStrokePaint(static_cast<SVGPaint*>(value)); + + break; + } + case CSSPropertyStrokeWidth: + { + HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth) + if (primitiveValue) + svgstyle->setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue)); + break; + } + case CSSPropertyStrokeDasharray: + { + HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray) + if (!value->isValueList()) + break; + + CSSValueList* dashes = static_cast<CSSValueList*>(value); + + Vector<SVGLength> array; + size_t length = dashes->length(); + for (size_t i = 0; i < length; ++i) { + CSSValue* currValue = dashes->itemWithoutBoundsCheck(i); + if (!currValue->isPrimitiveValue()) + continue; + + CSSPrimitiveValue* dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i)); + array.append(SVGLength::fromCSSPrimitiveValue(dash)); + } + + svgstyle->setStrokeDashArray(array); + break; + } + case CSSPropertyStrokeDashoffset: + { + HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset) + if (primitiveValue) + svgstyle->setStrokeDashOffset(SVGLength::fromCSSPrimitiveValue(primitiveValue)); + break; + } + case CSSPropertyFillOpacity: + { + HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity) + if (!primitiveValue) + return; + + float f = 0.0f; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + f = primitiveValue->getFloatValue() / 100.0f; + else if (type == CSSPrimitiveValue::CSS_NUMBER) + f = primitiveValue->getFloatValue(); + else + return; + + svgstyle->setFillOpacity(f); + break; + } + case CSSPropertyStrokeOpacity: + { + HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity) + if (!primitiveValue) + return; + + float f = 0.0f; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + f = primitiveValue->getFloatValue() / 100.0f; + else if (type == CSSPrimitiveValue::CSS_NUMBER) + f = primitiveValue->getFloatValue(); + else + return; + + svgstyle->setStrokeOpacity(f); + break; + } + case CSSPropertyStopOpacity: + { + HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity) + if (!primitiveValue) + return; + + float f = 0.0f; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + f = primitiveValue->getFloatValue() / 100.0f; + else if (type == CSSPrimitiveValue::CSS_NUMBER) + f = primitiveValue->getFloatValue(); + else + return; + + svgstyle->setStopOpacity(f); + break; + } + case CSSPropertyMarkerStart: + { + HANDLE_INHERIT_AND_INITIAL(markerStartResource, MarkerStartResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setMarkerStartResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyMarkerMid: + { + HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setMarkerMidResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyMarkerEnd: + { + HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setMarkerEndResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyStrokeLinecap: + { + HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle) + if (primitiveValue) + svgstyle->setCapStyle(*primitiveValue); + break; + } + case CSSPropertyStrokeMiterlimit: + { + HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit) + if (!primitiveValue) + return; + + float f = 0.0f; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_NUMBER) + f = primitiveValue->getFloatValue(); + else + return; + + svgstyle->setStrokeMiterLimit(f); + break; + } + case CSSPropertyFilter: + { + HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setFilterResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyMask: + { + HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setMaskerResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyClipPath: + { + HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource) + if (!primitiveValue) + return; + + String s; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_URI) + s = primitiveValue->getStringValue(); + else + return; + + svgstyle->setClipperResource(SVGURIReference::getTarget(s)); + break; + } + case CSSPropertyTextAnchor: + { + HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor) + if (primitiveValue) + svgstyle->setTextAnchor(*primitiveValue); + break; + } + case CSSPropertyWritingMode: + { + HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode) + if (primitiveValue) + svgstyle->setWritingMode(*primitiveValue); + break; + } + case CSSPropertyStopColor: + { + HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor); + if (value->isSVGColor()) + svgstyle->setStopColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); + break; + } + case CSSPropertyLightingColor: + { + HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor); + if (value->isSVGColor()) + svgstyle->setLightingColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); + break; + } + case CSSPropertyFloodOpacity: + { + HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity) + if (!primitiveValue) + return; + + float f = 0.0f; + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + f = primitiveValue->getFloatValue() / 100.0f; + else if (type == CSSPrimitiveValue::CSS_NUMBER) + f = primitiveValue->getFloatValue(); + else + return; + + svgstyle->setFloodOpacity(f); + break; + } + case CSSPropertyFloodColor: + { + HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor); + if (value->isSVGColor()) + svgstyle->setFloodColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); + break; + } + case CSSPropertyGlyphOrientationHorizontal: + { + HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal) + if (!primitiveValue) + return; + + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { + int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); + ASSERT(orientation != -1); + + svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation); + } + + break; + } + case CSSPropertyGlyphOrientationVertical: + { + HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical) + if (!primitiveValue) + return; + + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { + int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); + ASSERT(orientation != -1); + + svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation); + } else if (primitiveValue->getIdent() == CSSValueAuto) + svgstyle->setGlyphOrientationVertical(GO_AUTO); + + break; + } + case CSSPropertyEnableBackground: + // Silently ignoring this property for now + // http://bugs.webkit.org/show_bug.cgi?id=6022 + break; + case CSSPropertyWebkitSvgShadow: { + if (isInherit) + return svgstyle->setShadow(m_parentStyle->svgStyle()->shadow() ? new ShadowData(*m_parentStyle->svgStyle()->shadow()) : 0); + if (isInitial || primitiveValue) // initial | none + return svgstyle->setShadow(0); + + if (!value->isValueList()) + return; + + CSSValueList *list = static_cast<CSSValueList*>(value); + if (!list->length()) + return; + + CSSValue* firstValue = list->itemWithoutBoundsCheck(0); + if (!firstValue->isShadowValue()) + return; + ShadowValue* item = static_cast<ShadowValue*>(firstValue); + int x = item->x->computeLengthInt(style(), m_rootElementStyle); + int y = item->y->computeLengthInt(style(), m_rootElementStyle); + int blur = item->blur ? item->blur->computeLengthInt(style(), m_rootElementStyle) : 0; + Color color; + if (item->color) + color = getColorFromPrimitiveValue(item->color.get()); + + // -webkit-svg-shadow does should not have a spread or style + ASSERT(!item->spread); + ASSERT(!item->style); + + ShadowData* shadowData = new ShadowData(x, y, blur, 0, Normal, false, color.isValid() ? color : Color::transparent); + svgstyle->setShadow(shadowData); + return; + } + case CSSPropertyVectorEffect: { + HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect) + if (!primitiveValue) + break; + + svgstyle->setVectorEffect(*primitiveValue); + break; + } + default: + // If you crash here, it's because you added a css property and are not handling it + // in either this switch statement or the one in CSSStyleSelector::applyProperty + ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id); + return; + } +} + +} + +#endif diff --git a/Source/WebCore/css/SVGCSSValueKeywords.in b/Source/WebCore/css/SVGCSSValueKeywords.in new file mode 100644 index 0000000..a2c9f83 --- /dev/null +++ b/Source/WebCore/css/SVGCSSValueKeywords.in @@ -0,0 +1,278 @@ +# These are all values accepted for CSS2. +# +# WARNING: +# -------- +# +# The Values are sorted according to the properties they belong to, +# and have to be in the same order as the enums in RenderStyle.h. +# +# If not, the optimizations in the cssparser and style selector will fail, +# and produce incorrect results. +# +# +# CSS_PROP_*_COLOR +# +aliceblue +antiquewhite +# aqua +aquamarine +azure +beige +bisque +# black +blanchedalmond +# blue +blueviolet +brown +burlywood +cadetblue +chartreuse +chocolate +coral +cornflowerblue +cornsilk +crimson +cyan +darkblue +darkcyan +darkgoldenrod +darkgray +darkgreen +darkgrey +darkkhaki +darkmagenta +darkolivegreen +darkorange +darkorchid +darkred +darksalmon +darkseagreen +darkslateblue +darkslategray +darkslategrey +darkturquoise +darkviolet +deeppink +deepskyblue +dimgray +dimgrey +dodgerblue +firebrick +floralwhite +forestgreen +# fuchsia +gainsboro +ghostwhite +gold +goldenrod +# gray +# grey +# green +greenyellow +honeydew +hotpink +indianred +indigo +ivory +khaki +lavender +lavenderblush +lawngreen +lemonchiffon +lightblue +lightcoral +lightcyan +lightgoldenrodyellow +lightgray +lightgreen +lightgrey +lightpink +lightsalmon +lightseagreen +lightskyblue +lightslategray +lightslategrey +lightsteelblue +lightyellow +# lime +limegreen +linen +magenta +# maroon +mediumaquamarine +mediumblue +mediumorchid +mediumpurple +mediumseagreen +mediumslateblue +mediumspringgreen +mediumturquoise +mediumvioletred +midnightblue +mintcream +mistyrose +moccasin +navajowhite +# navy +oldlace +# olive +olivedrab +# orange +orangered +orchid +palegoldenrod +palegreen +paleturquoise +palevioletred +papayawhip +peachpuff +peru +pink +plum +powderblue +# purple +# red +rosybrown +royalblue +saddlebrown +salmon +sandybrown +seagreen +seashell +sienna +# silver +skyblue +slateblue +slategray +slategrey +snow +springgreen +steelblue +tan +# teal +thistle +tomato +turquoise +violet +wheat +# white +whitesmoke +# yellow +yellowgreen + +# CSS_PROP_CLIP_PATH +# CSS_PROP_CLIP_RULE +nonzero +evenodd + +# CSS_PROP_MASK +# CSS_PROP_OPACITY +# CSS_PROP_ENABLE_BACKGROUND +accumulate +new + +# CSS_PROP_FILTER +# CSS_PROP_FLOOD_COLOR +#currentColor + +# CSS_PROP_FLOOD_OPACITY +# CSS_PROP_LIGHTING_COLOR +#currentColor + +# CSS_PROP_STOP_COLOR +# CSS_PROP_STOP_OPACITY +# CSS_PROP_COLOR_INTERPOLATION +#auto +#sRGB +linearRGB + +# CSS_PROP_COLOR_INTERPOLATION_FILTERS +#auto +#sRGB +#linearRGB + +# CSS_PROP_COLOR_PROFILE +#sRGB + +# CSS_PROP_COLOR_RENDERING +#auto +#optimizeSpeed +optimizeQuality + +## CSS_PROP_FILL +#currentColor + +# CSS_PROP_FILL_OPACITY +# CSS_PROP_FILL_RULE +#nonzero +#evenodd + +# CSS_PROP_IMAGE_RENDERING +#auto +#optimizeSpeed +#optimizeQuality + +# CSS_PROP_MARKER +# CSS_PROP_MARKER_END +# CSS_PROP_MARKER_MID +# CSS_PROP_MARKER_START +# CSS_PROP_SHAPE_RENDERING +#auto +#optimizeSpeed +crispEdges +#geometricPrecision + +# CSS_PROP_STROKE +# CSS_PROP_STROKE_DASHARRAY +# CSS_PROP_STROKE_DASHOFFSET +# CSS_PROP_STROKE_LINECAP +butt +# round +# square + +# CSS_PROP_STROKE_LINEJOIN +miter +# round +bevel + +# CSS_PROP_STROKE_MITERLIMIT +# CSS_PROP_STROKE_OPACITY +# CSS_PROP_STROKE_WIDTH + +# CSS_PROP_ALIGNMENT_BASELINE +#auto +# baseline +before-edge +after-edge +#middle +central +text-before-edge +text-after-edge +ideographic +alphabetic +hanging +mathematical + +# CSS_PROP_BASELINE_SHIFT +#baseline +# sub +# super + +# CSS_PROP_DOMINANT_BASELINE +#auto +use-script +no-change +reset-size + +# CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL + +# CSS_PROP_GLYPH_ORIENTATION_VERTICAL +# CSS_PROP_KERNING +# CSS_PROP_TEXT_ANCHOR +# start +# middle +# end + +# CSS_PROP_VECTOR_EFFECT +# none +non-scaling-stroke diff --git a/Source/WebCore/css/ShadowValue.cpp b/Source/WebCore/css/ShadowValue.cpp new file mode 100644 index 0000000..060a322 --- /dev/null +++ b/Source/WebCore/css/ShadowValue.cpp @@ -0,0 +1,79 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2009 Apple Computer, Inc. + * + * 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 "ShadowValue.h" + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +namespace WebCore { + +// Used for text-shadow and box-shadow +ShadowValue::ShadowValue(PassRefPtr<CSSPrimitiveValue> _x, + PassRefPtr<CSSPrimitiveValue> _y, + PassRefPtr<CSSPrimitiveValue> _blur, + PassRefPtr<CSSPrimitiveValue> _spread, + PassRefPtr<CSSPrimitiveValue> _style, + PassRefPtr<CSSPrimitiveValue> _color) + : x(_x) + , y(_y) + , blur(_blur) + , spread(_spread) + , style(_style) + , color(_color) +{ +} + +String ShadowValue::cssText() const +{ + String text(""); + + if (color) + text += color->cssText(); + if (x) { + if (!text.isEmpty()) + text += " "; + text += x->cssText(); + } + if (y) { + if (!text.isEmpty()) + text += " "; + text += y->cssText(); + } + if (blur) { + if (!text.isEmpty()) + text += " "; + text += blur->cssText(); + } + if (spread) { + if (!text.isEmpty()) + text += " "; + text += spread->cssText(); + } + if (style) { + if (!text.isEmpty()) + text += " "; + text += style->cssText(); + } + + return text; +} + +} diff --git a/Source/WebCore/css/ShadowValue.h b/Source/WebCore/css/ShadowValue.h new file mode 100644 index 0000000..fab1071 --- /dev/null +++ b/Source/WebCore/css/ShadowValue.h @@ -0,0 +1,67 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2008, 2009 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. + */ + +#ifndef ShadowValue_h +#define ShadowValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSPrimitiveValue; + +// Used for text-shadow and box-shadow +class ShadowValue : public CSSValue { +public: + static PassRefPtr<ShadowValue> create(PassRefPtr<CSSPrimitiveValue> x, + PassRefPtr<CSSPrimitiveValue> y, + PassRefPtr<CSSPrimitiveValue> blur, + PassRefPtr<CSSPrimitiveValue> spread, + PassRefPtr<CSSPrimitiveValue> style, + PassRefPtr<CSSPrimitiveValue> color) + { + return adoptRef(new ShadowValue(x, y, blur, spread, style, color)); + } + + virtual String cssText() const; + + RefPtr<CSSPrimitiveValue> x; + RefPtr<CSSPrimitiveValue> y; + RefPtr<CSSPrimitiveValue> blur; + RefPtr<CSSPrimitiveValue> spread; + RefPtr<CSSPrimitiveValue> style; + RefPtr<CSSPrimitiveValue> color; + +private: + ShadowValue(PassRefPtr<CSSPrimitiveValue> x, + PassRefPtr<CSSPrimitiveValue> y, + PassRefPtr<CSSPrimitiveValue> blur, + PassRefPtr<CSSPrimitiveValue> spread, + PassRefPtr<CSSPrimitiveValue> style, + PassRefPtr<CSSPrimitiveValue> color); + + virtual bool isShadowValue() const { return true; } +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/StyleBase.cpp b/Source/WebCore/css/StyleBase.cpp new file mode 100644 index 0000000..5d9d79d --- /dev/null +++ b/Source/WebCore/css/StyleBase.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) + * 2001-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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 "StyleBase.h" + +#include "Document.h" +#include "Node.h" +#include "StyleSheet.h" + +namespace WebCore { + +String StyleBase::cssText() const +{ + return ""; +} + +void StyleBase::checkLoaded() +{ + if (parent()) + parent()->checkLoaded(); +} + +StyleSheet* StyleBase::stylesheet() +{ + StyleBase *b = this; + while (b && !b->isStyleSheet()) + b = b->parent(); + return static_cast<StyleSheet*>(b); +} + +KURL StyleBase::baseURL() const +{ + // Try to find the style sheet. If found look for its URL. + // If it has none, get the URL from the parent sheet or the parent node. + + StyleSheet* sheet = const_cast<StyleBase*>(this)->stylesheet(); + if (!sheet) + return KURL(); + if (!sheet->finalURL().isNull()) + return sheet->finalURL(); + if (sheet->parent()) + return sheet->parent()->baseURL(); + if (!sheet->ownerNode()) + return KURL(); + return sheet->ownerNode()->document()->baseURL(); +} + +#ifdef ANDROID_INSTRUMENT +static size_t styleSize = 0; + +void* StyleBase::operator new(size_t size) +{ + styleSize += size; + return ::operator new(size); +} + +void* StyleBase::operator new[](size_t size) +{ + styleSize += size; + return ::operator new[](size); +} + +void StyleBase::operator delete(void* p, size_t size) +{ + styleSize -= size; + ::operator delete(p); +} + +void StyleBase::operator delete[](void* p, size_t size) +{ + styleSize -= size; + ::operator delete[](p); +} + +size_t StyleBase::reportStyleSize() +{ + return styleSize; +} +#endif + +} diff --git a/Source/WebCore/css/StyleBase.h b/Source/WebCore/css/StyleBase.h new file mode 100644 index 0000000..94efa01 --- /dev/null +++ b/Source/WebCore/css/StyleBase.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 1999 Waldo Bastian (bastian@kde.org) + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmial.com) + * Copyright (C) 2004, 2006, 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. + */ + +#ifndef StyleBase_h +#define StyleBase_h + +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class StyleSheet; + class KURL; + + // Base class for most CSS DOM objects. + + // FIXME: We don't need these to all share one base class. + // Refactor so they don't any more. + + class StyleBase : public RefCounted<StyleBase> { + public: + virtual ~StyleBase() { } + + StyleBase* parent() const { return m_parent; } + void setParent(StyleBase* parent) { m_parent = parent; } + + // returns the url of the style sheet this object belongs to + KURL baseURL() const; + + virtual bool isCSSStyleSheet() const { return false; } + virtual bool isCharsetRule() { return false; } + virtual bool isFontFaceRule() { return false; } + virtual bool isImportRule() { return false; } + virtual bool isKeyframeRule() { return false; } + virtual bool isKeyframesRule() { return false; } + virtual bool isMediaRule() { return false; } + virtual bool isPageRule() { return false; } + + virtual bool isRule() { return false; } + virtual bool isStyleRule() { return false; } + virtual bool isStyleSheet() const { return false; } + virtual bool isXSLStyleSheet() const { return false; } + + virtual bool isMutableStyleDeclaration() const { return false; } + + virtual String cssText() const; + + virtual void checkLoaded(); + + bool useStrictParsing() const { return !m_parent || m_parent->useStrictParsing(); } + + virtual void insertedIntoParent() { } + + StyleSheet* stylesheet(); + +#ifdef ANDROID_INSTRUMENT + // Overridden to prevent the normal new from being called. + void* operator new(size_t size); + void* operator new[](size_t size); + + // Overridden to prevent the normal delete from being called. + void operator delete(void* p, size_t size); + void operator delete[](void* p, size_t size); + + static size_t reportStyleSize(); +#endif + + protected: + StyleBase(StyleBase* parent) + : m_parent(parent) + { + } + + private: + StyleBase* m_parent; + }; +} + +#endif diff --git a/Source/WebCore/css/StyleList.cpp b/Source/WebCore/css/StyleList.cpp new file mode 100644 index 0000000..2510470 --- /dev/null +++ b/Source/WebCore/css/StyleList.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) + * 2001-2003 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2002, 2006, 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 "StyleList.h" + +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +void StyleList::append(PassRefPtr<StyleBase> child) +{ + StyleBase* c = child.get(); + m_children.append(child); + c->insertedIntoParent(); +} + +void StyleList::insert(unsigned position, PassRefPtr<StyleBase> child) +{ + StyleBase* c = child.get(); + if (position >= length()) + m_children.append(child); + else + m_children.insert(position, child); + c->insertedIntoParent(); +} + +void StyleList::remove(unsigned position) +{ + if (position >= length()) + return; + m_children.remove(position); +} + +} diff --git a/Source/WebCore/css/StyleList.h b/Source/WebCore/css/StyleList.h new file mode 100644 index 0000000..ceca28a --- /dev/null +++ b/Source/WebCore/css/StyleList.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * 1999 Waldo Bastian (bastian@kde.org) + * Copyright (C) 2004, 2006, 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. + */ + +#ifndef StyleList_h +#define StyleList_h + +#include "StyleBase.h" +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + + // a style class which has a list of children (StyleSheets for example) + class StyleList : public StyleBase { + public: + unsigned length() { return m_children.size(); } + StyleBase* item(unsigned num) { return num < length() ? m_children[num].get() : 0; } + + void append(PassRefPtr<StyleBase>); + void insert(unsigned position, PassRefPtr<StyleBase>); + void remove(unsigned position); + + protected: + StyleList(StyleBase* parent) : StyleBase(parent) { } + + Vector<RefPtr<StyleBase> > m_children; + }; +} + +#endif diff --git a/Source/WebCore/css/StyleMedia.cpp b/Source/WebCore/css/StyleMedia.cpp new file mode 100644 index 0000000..8971d35 --- /dev/null +++ b/Source/WebCore/css/StyleMedia.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "StyleMedia.h" + +#include "CSSStyleSelector.h" +#include "Frame.h" +#include "FrameView.h" +#include "MediaList.h" +#include "MediaQueryEvaluator.h" + +namespace WebCore { + +StyleMedia::StyleMedia(Frame* frame) + : m_frame(frame) +{ +} + +String StyleMedia::type() const +{ + FrameView* view = m_frame ? m_frame->view() : 0; + if (view) + return view->mediaType(); + + return String(); +} + +bool StyleMedia::matchMedium(const String& query) const +{ + if (!m_frame) + return false; + + Document* document = m_frame->document(); + ASSERT(document); + Element* documentElement = document->documentElement(); + if (!documentElement) + return false; + + CSSStyleSelector* styleSelector = document->styleSelector(); + if (!styleSelector) + return false; + + RefPtr<RenderStyle> rootStyle = styleSelector->styleForElement(documentElement, 0 /*defaultParent*/, false /*allowSharing*/, true /*resolveForRootDefault*/); + RefPtr<MediaList> media = MediaList::create(); + + ExceptionCode ec = 0; + media->setMediaText(query, ec); + if (ec) + return false; + + MediaQueryEvaluator screenEval(type(), m_frame, rootStyle.get()); + return screenEval.eval(media.get()); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/StyleMedia.h b/Source/WebCore/css/StyleMedia.h new file mode 100644 index 0000000..82c9eba --- /dev/null +++ b/Source/WebCore/css/StyleMedia.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StyleMedia_h +#define StyleMedia_h + +#include "PlatformString.h" + +namespace WebCore { + +class Frame; + +class StyleMedia : public RefCounted<StyleMedia> { +public: + static PassRefPtr<StyleMedia> create(Frame* frame) + { + return adoptRef(new StyleMedia(frame)); + } + + void disconnectFrame() { m_frame = 0; } + + String type() const; + + bool matchMedium(const String&) const; + +private: + StyleMedia(Frame*); + + Frame* m_frame; +}; + +} // namespace + +#endif // StyleMedia_h diff --git a/Source/WebCore/css/StyleMedia.idl b/Source/WebCore/css/StyleMedia.idl new file mode 100644 index 0000000..7be35cc --- /dev/null +++ b/Source/WebCore/css/StyleMedia.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module view { + interface StyleMedia { + readonly attribute DOMString type; + boolean matchMedium(in DOMString mediaquery); + }; +} diff --git a/Source/WebCore/css/StyleSheet.cpp b/Source/WebCore/css/StyleSheet.cpp new file mode 100644 index 0000000..68a0772 --- /dev/null +++ b/Source/WebCore/css/StyleSheet.cpp @@ -0,0 +1,93 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006 Apple Computer, Inc. + * + * 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 "StyleSheet.h" + +#include "MediaList.h" +#include "Node.h" + +namespace WebCore { + +StyleSheet::StyleSheet(StyleSheet* parentSheet, const String& originalURL, const KURL& finalURL) + : StyleList(parentSheet) + , m_parentNode(0) + , m_originalURL(originalURL) + , m_finalURL(finalURL) + , m_disabled(false) +{ +} + +StyleSheet::StyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL) + : StyleList(0) + , m_parentNode(parentNode) + , m_originalURL(originalURL) + , m_finalURL(finalURL) + , m_disabled(false) +{ +} + +StyleSheet::StyleSheet(StyleBase* owner, const String& originalURL, const KURL& finalURL) + : StyleList(owner) + , m_parentNode(0) + , m_originalURL(originalURL) + , m_finalURL(finalURL) + , m_disabled(false) +{ +} + +StyleSheet::~StyleSheet() +{ + if (m_media) + m_media->setParent(0); + + // For style rules outside the document, .parentStyleSheet can become null even if the style rule + // is still observable from JavaScript. This matches the behavior of .parentNode for nodes, but + // it's not ideal because it makes the CSSOM's behavior depend on the timing of garbage collection. + for (unsigned i = 0; i < length(); ++i) { + ASSERT(item(i)->parent() == this); + item(i)->setParent(0); + } +} + +StyleSheet* StyleSheet::parentStyleSheet() const +{ + return (parent() && parent()->isStyleSheet()) ? static_cast<StyleSheet*>(parent()) : 0; +} + +void StyleSheet::setMedia(PassRefPtr<MediaList> media) +{ + if (m_media) + m_media->setParent(0); + + m_media = media; + m_media->setParent(this); +} + +KURL StyleSheet::completeURL(const String& url) const +{ + // Always return a null URL when passed a null string. + // FIXME: Should we change the KURL constructor to have this behavior? + // See also Document::completeURL(const String&) + if (url.isNull()) + return KURL(); + return KURL(baseURL(), url); +} + +} diff --git a/Source/WebCore/css/StyleSheet.h b/Source/WebCore/css/StyleSheet.h new file mode 100644 index 0000000..2ff9a01 --- /dev/null +++ b/Source/WebCore/css/StyleSheet.h @@ -0,0 +1,86 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 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. + */ + +#ifndef StyleSheet_h +#define StyleSheet_h + +#include "KURLHash.h" +#include "PlatformString.h" +#include "StyleList.h" +#include <wtf/ListHashSet.h> + +namespace WebCore { + +class CachedCSSStyleSheet; +class MediaList; +class Node; + +class StyleSheet : public StyleList { +public: + virtual ~StyleSheet(); + + bool disabled() const { return m_disabled; } + void setDisabled(bool disabled) { m_disabled = disabled; styleSheetChanged(); } + + Node* ownerNode() const { return m_parentNode; } + void clearOwnerNode() { m_parentNode = 0; } + StyleSheet *parentStyleSheet() const; + + // Note that href is the URL that started the redirect chain that led to + // this style sheet. This property probably isn't useful for much except + // the JavaScript binding (which needs to use this value for security). + const String& href() const { return m_originalURL; } + + void setFinalURL(const KURL& finalURL) { m_finalURL = finalURL; } + const KURL& finalURL() const { return m_finalURL; } + + const String& title() const { return m_strTitle; } + void setTitle(const String& s) { m_strTitle = s; } + MediaList* media() const { return m_media.get(); } + void setMedia(PassRefPtr<MediaList>); + + virtual String type() const = 0; + virtual bool isLoading() = 0; + virtual void styleSheetChanged() { } + + virtual KURL completeURL(const String& url) const; + virtual void addSubresourceStyleURLs(ListHashSet<KURL>&) { } + + virtual bool parseString(const String&, bool strict = true) = 0; + +protected: + StyleSheet(Node* ownerNode, const String& href, const KURL& finalURL); + StyleSheet(StyleSheet* parentSheet, const String& href, const KURL& finalURL); + StyleSheet(StyleBase* owner, const String& href, const KURL& finalURL); + +private: + virtual bool isStyleSheet() const { return true; } + + Node* m_parentNode; + String m_originalURL; + KURL m_finalURL; + String m_strTitle; + RefPtr<MediaList> m_media; + bool m_disabled; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/StyleSheet.idl b/Source/WebCore/css/StyleSheet.idl new file mode 100644 index 0000000..5b52a33 --- /dev/null +++ b/Source/WebCore/css/StyleSheet.idl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module stylesheets { + + // Introduced in DOM Level 2: + interface [ + CustomMarkFunction, + CustomToJS, + Polymorphic + ] StyleSheet { + readonly attribute [ConvertNullStringTo=Null] DOMString type; + attribute boolean disabled; + readonly attribute Node ownerNode; + readonly attribute StyleSheet parentStyleSheet; + readonly attribute [ConvertNullStringTo=Null] DOMString href; + readonly attribute [ConvertNullStringTo=Null] DOMString title; + readonly attribute MediaList media; + +#if defined(LANGUAGE_CPP) && LANGUAGE_CPP + // Extra WebCore methods exposed to allowe compile-time casting in C++ + boolean isCSSStyleSheet(); +#endif + + }; + +} diff --git a/Source/WebCore/css/StyleSheetList.cpp b/Source/WebCore/css/StyleSheetList.cpp new file mode 100644 index 0000000..2c90258 --- /dev/null +++ b/Source/WebCore/css/StyleSheetList.cpp @@ -0,0 +1,75 @@ +/** + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2007 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 "StyleSheetList.h" + +#include "CSSStyleSheet.h" +#include "Document.h" +#include "HTMLNames.h" +#include "HTMLStyleElement.h" +#include "PlatformString.h" + +namespace WebCore { + +using namespace HTMLNames; + +StyleSheetList::StyleSheetList(Document* doc) + : m_doc(doc) +{ +} + +StyleSheetList::~StyleSheetList() +{ +} + +void StyleSheetList::documentDestroyed() +{ + m_doc = 0; +} + +unsigned StyleSheetList::length() const +{ + return m_sheets.size(); +} + +StyleSheet* StyleSheetList::item(unsigned index) +{ + return index < length() ? m_sheets[index].get() : 0; +} + +HTMLStyleElement* StyleSheetList::getNamedItem(const String& name) const +{ + if (!m_doc) + return 0; + + // IE also supports retrieving a stylesheet by name, using the name/id of the <style> tag + // (this is consistent with all the other collections) + // ### Bad implementation because returns a single element (are IDs always unique?) + // and doesn't look for name attribute. + // But unicity of stylesheet ids is good practice anyway ;) + + Element* element = m_doc->getElementById(name); + if (element && element->hasTagName(styleTag)) + return static_cast<HTMLStyleElement*>(element); + return 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/StyleSheetList.h b/Source/WebCore/css/StyleSheetList.h new file mode 100644 index 0000000..a486511 --- /dev/null +++ b/Source/WebCore/css/StyleSheetList.h @@ -0,0 +1,63 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2007 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. + */ + +#ifndef StyleSheetList_h +#define StyleSheetList_h + +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class Document; +class HTMLStyleElement; +class StyleSheet; + +typedef Vector<RefPtr<StyleSheet> > StyleSheetVector; + +class StyleSheetList : public RefCounted<StyleSheetList> { +public: + static PassRefPtr<StyleSheetList> create(Document* doc) { return adoptRef(new StyleSheetList(doc)); } + ~StyleSheetList(); + + void documentDestroyed(); + + unsigned length() const; + StyleSheet* item(unsigned index); + + HTMLStyleElement* getNamedItem(const String&) const; + + void swap(StyleSheetVector& sheets) + { + m_sheets.swap(sheets); + } + +private: + StyleSheetList(Document*); + + Document* m_doc; + StyleSheetVector m_sheets; +}; + +} // namespace WebCore + +#endif // StyleSheetList_h diff --git a/Source/WebCore/css/StyleSheetList.idl b/Source/WebCore/css/StyleSheetList.idl new file mode 100644 index 0000000..6cef99d --- /dev/null +++ b/Source/WebCore/css/StyleSheetList.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * + * 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. + */ + +module stylesheets { + + // Introduced in DOM Level 2: + interface [ + CustomMarkFunction, + HasIndexGetter, + HasNameGetter + ] StyleSheetList { + readonly attribute unsigned long length; + StyleSheet item(in unsigned long index); + }; + +} diff --git a/Source/WebCore/css/WCSSPropertyNames.in b/Source/WebCore/css/WCSSPropertyNames.in new file mode 100644 index 0000000..66be83b --- /dev/null +++ b/Source/WebCore/css/WCSSPropertyNames.in @@ -0,0 +1,6 @@ +-wap-input-format +-wap-input-required +-wap-marquee-dir +-wap-marquee-loop +-wap-marquee-speed +-wap-marquee-style diff --git a/Source/WebCore/css/WCSSValueKeywords.in b/Source/WebCore/css/WCSSValueKeywords.in new file mode 100644 index 0000000..00657ba --- /dev/null +++ b/Source/WebCore/css/WCSSValueKeywords.in @@ -0,0 +1 @@ +# place holder for all WCSS specific CSS value keywords diff --git a/Source/WebCore/css/WebKitCSSKeyframeRule.cpp b/Source/WebCore/css/WebKitCSSKeyframeRule.cpp new file mode 100644 index 0000000..8f3d676 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframeRule.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitCSSKeyframeRule.h" + +#include "CSSMutableStyleDeclaration.h" + +namespace WebCore { + +WebKitCSSKeyframeRule::WebKitCSSKeyframeRule(CSSStyleSheet* parent) + : CSSRule(parent) +{ +} + +WebKitCSSKeyframeRule::~WebKitCSSKeyframeRule() +{ + if (m_style) + m_style->setParent(0); +} + +String WebKitCSSKeyframeRule::cssText() const +{ + String result = m_key; + + result += " { "; + result += m_style->cssText(); + result += "}"; + + return result; +} + +bool WebKitCSSKeyframeRule::parseString(const String& /*string*/, bool /*strict*/) +{ + // FIXME + return false; +} + +void WebKitCSSKeyframeRule::setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) +{ + m_style = style; + m_style->setParent(parent()); +} + +/* static */ +void WebKitCSSKeyframeRule::parseKeyString(const String& s, Vector<float>& keys) +{ + keys.clear(); + Vector<String> strings; + s.split(',', strings); + + for (size_t i = 0; i < strings.size(); ++i) { + float key = -1; + String cur = strings[i].stripWhiteSpace(); + + // For now the syntax MUST be 'xxx%' or 'from' or 'to', where xxx is a legal floating point number + if (cur == "from") + key = 0; + else if (cur == "to") + key = 1; + else if (cur.endsWith("%")) { + float k = cur.substring(0, cur.length() - 1).toFloat(); + if (k >= 0 && k <= 100) + key = k/100; + } + + if (key < 0) { + keys.clear(); + return; + } + else + keys.append(key); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/WebKitCSSKeyframeRule.h b/Source/WebCore/css/WebKitCSSKeyframeRule.h new file mode 100644 index 0000000..e41510a --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframeRule.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebKitCSSKeyframeRule_h +#define WebKitCSSKeyframeRule_h + +#include "CSSRule.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; + +typedef int ExceptionCode; + +class WebKitCSSKeyframeRule : public CSSRule { +public: + static PassRefPtr<WebKitCSSKeyframeRule> create() + { + return adoptRef(new WebKitCSSKeyframeRule(0)); + } + static PassRefPtr<WebKitCSSKeyframeRule> create(CSSStyleSheet* parent) + { + return adoptRef(new WebKitCSSKeyframeRule(parent)); + } + + virtual ~WebKitCSSKeyframeRule(); + + virtual bool isKeyframeRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return WEBKIT_KEYFRAME_RULE; } + + String keyText() const { return m_key; } + void setKeyText(const String& s) { m_key = s; } + + void getKeys(Vector<float>& keys) const { parseKeyString(m_key, keys); } + + CSSMutableStyleDeclaration* style() const { return m_style.get(); } + + virtual String cssText() const; + + // Not part of the CSSOM + virtual bool parseString(const String&, bool = false); + + void setDeclaration(PassRefPtr<CSSMutableStyleDeclaration>); + + CSSMutableStyleDeclaration* declaration() { return m_style.get(); } + const CSSMutableStyleDeclaration* declaration() const { return m_style.get(); } + +private: + static void parseKeyString(const String& s, Vector<float>& keys); + + WebKitCSSKeyframeRule(CSSStyleSheet* parent); + + RefPtr<CSSMutableStyleDeclaration> m_style; + String m_key; // comma separated list of keys +}; + +} // namespace WebCore + +#endif // WebKitCSSKeyframeRule_h diff --git a/Source/WebCore/css/WebKitCSSKeyframeRule.idl b/Source/WebCore/css/WebKitCSSKeyframeRule.idl new file mode 100644 index 0000000..901b72a --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframeRule.idl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + // Introduced in DOM Level ?: + interface [CustomMarkFunction] WebKitCSSKeyframeRule : CSSRule { + + attribute DOMString keyText; + readonly attribute CSSStyleDeclaration style; + + }; + +} diff --git a/Source/WebCore/css/WebKitCSSKeyframesRule.cpp b/Source/WebCore/css/WebKitCSSKeyframesRule.cpp new file mode 100644 index 0000000..23f9f34 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "CSSParser.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSKeyframeRule.h" +#include "CSSRuleList.h" +#include "StyleSheet.h" + +namespace WebCore { + +WebKitCSSKeyframesRule::WebKitCSSKeyframesRule(CSSStyleSheet* parent) + : CSSRule(parent) + , m_lstCSSRules(CSSRuleList::create()) +{ +} + +WebKitCSSKeyframesRule::~WebKitCSSKeyframesRule() +{ + int length = m_lstCSSRules->length(); + if (length == 0) + return; + + for (int i = 0; i < length; i++) + m_lstCSSRules->item(i)->setParent(0); +} + +String WebKitCSSKeyframesRule::name() const +{ + return m_name; +} + +void WebKitCSSKeyframesRule::setName(const String& name) +{ + m_name = name; + + // Since the name is used in the keyframe map list in CSSStyleSelector, we need + // to recompute the style sheet to get the updated name. + stylesheet()->styleSheetChanged(); +} + +unsigned WebKitCSSKeyframesRule::length() const +{ + return m_lstCSSRules.get()->length(); +} + +WebKitCSSKeyframeRule* WebKitCSSKeyframesRule::item(unsigned index) +{ + CSSRule* rule = m_lstCSSRules.get()->item(index); + return (rule && rule->isKeyframeRule()) ? static_cast<WebKitCSSKeyframeRule*>(rule) : 0; +} + +const WebKitCSSKeyframeRule* WebKitCSSKeyframesRule::item(unsigned index) const +{ + CSSRule* rule = m_lstCSSRules.get()->item(index); + return (rule && rule->isKeyframeRule()) ? static_cast<const WebKitCSSKeyframeRule*>(rule) : 0; +} + +void WebKitCSSKeyframesRule::append(WebKitCSSKeyframeRule* rule) +{ + m_lstCSSRules.get()->append(rule); +} + +void WebKitCSSKeyframesRule::insertRule(const String& rule) +{ + CSSParser p(useStrictParsing()); + RefPtr<CSSRule> newRule = p.parseKeyframeRule(parentStyleSheet(), rule); + if (newRule.get() && newRule.get()->isKeyframeRule()) + append(static_cast<WebKitCSSKeyframeRule*>(newRule.get())); +} + +void WebKitCSSKeyframesRule::deleteRule(const String& s) +{ + int i = findRuleIndex(s); + if (i >= 0) + m_lstCSSRules.get()->deleteRule(i); +} + +WebKitCSSKeyframeRule* WebKitCSSKeyframesRule::findRule(const String& s) +{ + int i = findRuleIndex(s); + return (i >= 0) ? item(i) : 0; +} + +int WebKitCSSKeyframesRule::findRuleIndex(const String& key) const +{ + String percentageString; + if (equalIgnoringCase(key, "from")) + percentageString = "0%"; + else if (equalIgnoringCase(key, "to")) + percentageString = "100%"; + else + percentageString = key; + + for (unsigned i = 0; i < length(); ++i) { + if (item(i)->keyText() == percentageString) + return i; + } + + return -1; +} + +String WebKitCSSKeyframesRule::cssText() const +{ + String result = "@-webkit-keyframes "; + result += m_name; + result += " { \n"; + + if (m_lstCSSRules) { + unsigned len = m_lstCSSRules->length(); + for (unsigned i = 0; i < len; i++) { + result += " "; + result += m_lstCSSRules->item(i)->cssText(); + result += "\n"; + } + } + + result += "}"; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/WebKitCSSKeyframesRule.h b/Source/WebCore/css/WebKitCSSKeyframesRule.h new file mode 100644 index 0000000..6ac0243 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebKitCSSKeyframesRule_h +#define WebKitCSSKeyframesRule_h + +#include "CSSRule.h" +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class CSSRuleList; +class WebKitCSSKeyframeRule; + +typedef int ExceptionCode; + +class WebKitCSSKeyframesRule : public CSSRule { +public: + static PassRefPtr<WebKitCSSKeyframesRule> create() + { + return adoptRef(new WebKitCSSKeyframesRule(0)); + } + static PassRefPtr<WebKitCSSKeyframesRule> create(CSSStyleSheet* parent) + { + return adoptRef(new WebKitCSSKeyframesRule(parent)); + } + + ~WebKitCSSKeyframesRule(); + + virtual bool isKeyframesRule() { return true; } + + // Inherited from CSSRule + virtual unsigned short type() const { return WEBKIT_KEYFRAMES_RULE; } + + String name() const; + void setName(const String&); + + // This version of setName does not call styleSheetChanged to avoid + // unnecessary work. It assumes callers will either make that call + // themselves, or know that it will get called later. + void setNameInternal(const String& name) + { + m_name = AtomicString(name); + } + + CSSRuleList* cssRules() { return m_lstCSSRules.get(); } + + void insertRule(const String& rule); + void deleteRule(const String& key); + WebKitCSSKeyframeRule* findRule(const String& key); + + virtual String cssText() const; + + /* not part of the DOM */ + unsigned length() const; + WebKitCSSKeyframeRule* item(unsigned index); + const WebKitCSSKeyframeRule* item(unsigned index) const; + void append(WebKitCSSKeyframeRule* rule); + +private: + WebKitCSSKeyframesRule(CSSStyleSheet* parent); + + int findRuleIndex(const String& key) const; + + RefPtr<CSSRuleList> m_lstCSSRules; + AtomicString m_name; +}; + +} // namespace WebCore + +#endif // WebKitCSSKeyframesRule_h diff --git a/Source/WebCore/css/WebKitCSSKeyframesRule.idl b/Source/WebCore/css/WebKitCSSKeyframesRule.idl new file mode 100644 index 0000000..f97a2fe --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.idl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + // Introduced in DOM Level ?: + interface [ + CustomMarkFunction, + HasIndexGetter + ] WebKitCSSKeyframesRule : CSSRule { + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString name; + readonly attribute CSSRuleList cssRules; + + void insertRule(in DOMString rule); + void deleteRule(in DOMString key); + WebKitCSSKeyframeRule findRule(in DOMString key); + }; + +} diff --git a/Source/WebCore/css/WebKitCSSMatrix.cpp b/Source/WebCore/css/WebKitCSSMatrix.cpp new file mode 100644 index 0000000..a4af7f8 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitCSSMatrix.h" + +#include "CSSParser.h" +#include "CSSStyleSelector.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPropertyNames.h" +#include "ExceptionCode.h" +#include "RenderStyle.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +WebKitCSSMatrix::WebKitCSSMatrix(const TransformationMatrix& m) + : m_matrix(m) +{ +} + +WebKitCSSMatrix::WebKitCSSMatrix(const String& s, ExceptionCode& ec) +{ + setMatrixValue(s, ec); +} + +WebKitCSSMatrix::~WebKitCSSMatrix() +{ +} + +void WebKitCSSMatrix::setMatrixValue(const String& string, ExceptionCode& ec) +{ + CSSParser p(true); + RefPtr<CSSMutableStyleDeclaration> styleDeclaration = CSSMutableStyleDeclaration::create(); + if (p.parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true)) { + // Convert to TransformOperations. This can fail if a property + // requires style (i.e., param uses 'ems' or 'exs') + PassRefPtr<CSSValue> val = styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform); + TransformOperations operations; + if (!CSSStyleSelector::createTransformOperations(val.get(), 0, 0, operations)) { + ec = SYNTAX_ERR; + return; + } + + // Convert transform operations to a TransformationMatrix. This can fail + // if a param has a percentage ('%') + TransformationMatrix t; + for (unsigned i = 0; i < operations.operations().size(); ++i) { + if (operations.operations()[i].get()->apply(t, IntSize(0, 0))) { + ec = SYNTAX_ERR; + return; + } + } + + // set the matrix + m_matrix = t; + } else if (!string.isEmpty()) // There is something there but parsing failed + ec = SYNTAX_ERR; +} + +// Perform a concatenation of the matrices (this * secondMatrix) +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::multiply(WebKitCSSMatrix* secondMatrix) const +{ + if (!secondMatrix) + return 0; + + TransformationMatrix tmp(secondMatrix->m_matrix); + tmp.multiply(m_matrix); + return WebKitCSSMatrix::create(tmp); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::inverse(ExceptionCode& ec) const +{ + if (!m_matrix.isInvertible()) { + ec = NOT_SUPPORTED_ERR; + return 0; + } + + return WebKitCSSMatrix::create(m_matrix.inverse()); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::translate(double x, double y, double z) const +{ + if (isnan(x)) + x = 0; + if (isnan(y)) + y = 0; + if (isnan(z)) + z = 0; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).translate3d(x, y, z)); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::scale(double scaleX, double scaleY, double scaleZ) const +{ + if (isnan(scaleX)) + scaleX = 1; + if (isnan(scaleY)) + scaleY = scaleX; + if (isnan(scaleZ)) + scaleZ = 1; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).scale3d(scaleX, scaleY, scaleZ)); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::rotate(double rotX, double rotY, double rotZ) const +{ + if (isnan(rotX)) + rotX = 0; + + if (isnan(rotY) && isnan(rotZ)) { + rotZ = rotX; + rotX = 0; + rotY = 0; + } + + if (isnan(rotY)) + rotY = 0; + if (isnan(rotZ)) + rotZ = 0; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).rotate3d(rotX, rotY, rotZ)); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::rotateAxisAngle(double x, double y, double z, double angle) const +{ + if (isnan(x)) + x = 0; + if (isnan(y)) + y = 0; + if (isnan(z)) + z = 0; + if (isnan(angle)) + angle = 0; + if (x == 0 && y == 0 && z == 0) + z = 1; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).rotate3d(x, y, z, angle)); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::skewX(double angle) const +{ + if (isnan(angle)) + angle = 0; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).skewX(angle)); +} + +PassRefPtr<WebKitCSSMatrix> WebKitCSSMatrix::skewY(double angle) const +{ + if (isnan(angle)) + angle = 0; + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).skewY(angle)); +} + +String WebKitCSSMatrix::toString() const +{ + // FIXME - Need to ensure valid CSS floating point values (https://bugs.webkit.org/show_bug.cgi?id=20674) + if (m_matrix.isAffine()) + return String::format("matrix(%f, %f, %f, %f, %f, %f)", + m_matrix.a(), m_matrix.b(), m_matrix.c(), m_matrix.d(), m_matrix.e(), m_matrix.f()); + return String::format("matrix3d(%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f)", + m_matrix.m11(), m_matrix.m12(), m_matrix.m13(), m_matrix.m14(), + m_matrix.m21(), m_matrix.m22(), m_matrix.m23(), m_matrix.m24(), + m_matrix.m31(), m_matrix.m32(), m_matrix.m33(), m_matrix.m34(), + m_matrix.m41(), m_matrix.m42(), m_matrix.m43(), m_matrix.m44()); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/WebKitCSSMatrix.h b/Source/WebCore/css/WebKitCSSMatrix.h new file mode 100644 index 0000000..107bf8b --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebKitCSSMatrix_h +#define WebKitCSSMatrix_h + +#include "ExceptionCode.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class WebKitCSSMatrix : public RefCounted<WebKitCSSMatrix> { +public: + static PassRefPtr<WebKitCSSMatrix> create(const TransformationMatrix& m) + { + return adoptRef(new WebKitCSSMatrix(m)); + } + static PassRefPtr<WebKitCSSMatrix> create(const String& s, ExceptionCode& ec) + { + return adoptRef(new WebKitCSSMatrix(s, ec)); + } + + virtual ~WebKitCSSMatrix(); + + double a() const { return m_matrix.a(); } + double b() const { return m_matrix.b(); } + double c() const { return m_matrix.c(); } + double d() const { return m_matrix.d(); } + double e() const { return m_matrix.e(); } + double f() const { return m_matrix.f(); } + + void setA(double f) { m_matrix.setA(f); } + void setB(double f) { m_matrix.setB(f); } + void setC(double f) { m_matrix.setC(f); } + void setD(double f) { m_matrix.setD(f); } + void setE(double f) { m_matrix.setE(f); } + void setF(double f) { m_matrix.setF(f); } + + double m11() const { return m_matrix.m11(); } + double m12() const { return m_matrix.m12(); } + double m13() const { return m_matrix.m13(); } + double m14() const { return m_matrix.m14(); } + double m21() const { return m_matrix.m21(); } + double m22() const { return m_matrix.m22(); } + double m23() const { return m_matrix.m23(); } + double m24() const { return m_matrix.m24(); } + double m31() const { return m_matrix.m31(); } + double m32() const { return m_matrix.m32(); } + double m33() const { return m_matrix.m33(); } + double m34() const { return m_matrix.m34(); } + double m41() const { return m_matrix.m41(); } + double m42() const { return m_matrix.m42(); } + double m43() const { return m_matrix.m43(); } + double m44() const { return m_matrix.m44(); } + + void setM11(double f) { m_matrix.setM11(f); } + void setM12(double f) { m_matrix.setM12(f); } + void setM13(double f) { m_matrix.setM13(f); } + void setM14(double f) { m_matrix.setM14(f); } + void setM21(double f) { m_matrix.setM21(f); } + void setM22(double f) { m_matrix.setM22(f); } + void setM23(double f) { m_matrix.setM23(f); } + void setM24(double f) { m_matrix.setM24(f); } + void setM31(double f) { m_matrix.setM31(f); } + void setM32(double f) { m_matrix.setM32(f); } + void setM33(double f) { m_matrix.setM33(f); } + void setM34(double f) { m_matrix.setM34(f); } + void setM41(double f) { m_matrix.setM41(f); } + void setM42(double f) { m_matrix.setM42(f); } + void setM43(double f) { m_matrix.setM43(f); } + void setM44(double f) { m_matrix.setM44(f); } + + void setMatrixValue(const String&, ExceptionCode&); + + // The following math function return a new matrix with the + // specified operation applied. The this value is not modified. + + // Multiply this matrix by secondMatrix, on the right (result = this * secondMatrix) + PassRefPtr<WebKitCSSMatrix> multiply(WebKitCSSMatrix* secondMatrix) const; + + // Return the inverse of this matrix. Throw an exception if the matrix is not invertible + PassRefPtr<WebKitCSSMatrix> inverse(ExceptionCode&) const; + + // Return this matrix translated by the passed values. + // Passing a NaN will use a value of 0. This allows the 3D form to used for 2D operations + // Operation is performed as though the this matrix is multiplied by a matrix with + // the translation values on the left (result = translation(x,y,z) * this) + PassRefPtr<WebKitCSSMatrix> translate(double x, double y, double z) const; + + // Returns this matrix scaled by the passed values. + // Passing scaleX or scaleZ as NaN uses a value of 1, but passing scaleY of NaN + // makes it the same as scaleX. This allows the 3D form to used for 2D operations + // Operation is performed as though the this matrix is multiplied by a matrix with + // the scale values on the left (result = scale(x,y,z) * this) + PassRefPtr<WebKitCSSMatrix> scale(double scaleX, double scaleY, double scaleZ) const; + + // Returns this matrix rotated by the passed values. + // If rotY and rotZ are NaN, rotate about Z (rotX=0, rotateY=0, rotateZ=rotX). + // Otherwise use a rotation value of 0 for any passed NaN. + // Operation is performed as though the this matrix is multiplied by a matrix with + // the rotation values on the left (result = rotation(x,y,z) * this) + PassRefPtr<WebKitCSSMatrix> rotate(double rotX, double rotY, double rotZ) const; + + // Returns this matrix rotated about the passed axis by the passed angle. + // Passing a NaN will use a value of 0. If the axis is (0,0,0) use a value + // Operation is performed as though the this matrix is multiplied by a matrix with + // the rotation values on the left (result = rotation(x,y,z,angle) * this) + PassRefPtr<WebKitCSSMatrix> rotateAxisAngle(double x, double y, double z, double angle) const; + + // Return this matrix skewed along the X axis by the passed values. + // Passing a NaN will use a value of 0. + // Operation is performed as though the this matrix is multiplied by a matrix with + // the skew values on the left (result = skewX(angle) * this) + PassRefPtr<WebKitCSSMatrix> skewX(double angle) const; + + // Return this matrix skewed along the Y axis by the passed values. + // Passing a NaN will use a value of 0. + // Operation is performed as though the this matrix is multiplied by a matrix with + // the skew values on the left (result = skewY(angle) * this) + PassRefPtr<WebKitCSSMatrix> skewY(double angle) const; + + const TransformationMatrix& transform() const { return m_matrix; } + + String toString() const; + +protected: + WebKitCSSMatrix(const TransformationMatrix&); + WebKitCSSMatrix(const String&, ExceptionCode&); + + TransformationMatrix m_matrix; +}; + +} // namespace WebCore + +#endif // WebKitCSSMatrix_h diff --git a/Source/WebCore/css/WebKitCSSMatrix.idl b/Source/WebCore/css/WebKitCSSMatrix.idl new file mode 100644 index 0000000..d32cd97 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.idl @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + // Introduced in DOM Level ?: + interface [ + CanBeConstructed, + CustomConstructFunction, + ConstructorParameters=1, + V8CustomConstructor + ] WebKitCSSMatrix { + + // These attributes are simple aliases for certain elements of the 4x4 matrix + attribute double a; // alias for m11 + attribute double b; // alias for m12 + attribute double c; // alias for m21 + attribute double d; // alias for m22 + attribute double e; // alias for m41 + attribute double f; // alias for m42 + + attribute double m11; + attribute double m12; + attribute double m13; + attribute double m14; + attribute double m21; + attribute double m22; + attribute double m23; + attribute double m24; + attribute double m31; + attribute double m32; + attribute double m33; + attribute double m34; + attribute double m41; + attribute double m42; + attribute double m43; + attribute double m44; + + void setMatrixValue(in DOMString string) raises (DOMException); + + // Multiply this matrix by secondMatrix, on the right (result = this * secondMatrix) + [Immutable] WebKitCSSMatrix multiply(in WebKitCSSMatrix secondMatrix); + + // Return the inverse of this matrix. Throw an exception if the matrix is not invertible + [Immutable] WebKitCSSMatrix inverse() raises (DOMException); + + // Return this matrix translated by the passed values. + // Passing a NaN will use a value of 0. This allows the 3D form to used for 2D operations + [Immutable] WebKitCSSMatrix translate(in double x, in double y, in double z); + + // Returns this matrix scaled by the passed values. + // Passing scaleX or scaleZ as NaN uses a value of 1, but passing scaleY of NaN + // makes it the same as scaleX. This allows the 3D form to used for 2D operations + [Immutable] WebKitCSSMatrix scale(in double scaleX, in double scaleY, in double scaleZ); + + // Returns this matrix rotated by the passed values. + // If rotY and rotZ are NaN, rotate about Z (rotX=0, rotateY=0, rotateZ=rotX). + // Otherwise use a rotation value of 0 for any passed NaN. + [Immutable] WebKitCSSMatrix rotate(in double rotX, in double rotY, in double rotZ); + + // Returns this matrix rotated about the passed axis by the passed angle. + // Passing a NaN will use a value of 0. If the axis is (0,0,0) use a value + // of (0,0,1). + [Immutable] WebKitCSSMatrix rotateAxisAngle(in double x, in double y, in double z, in double angle); + + // Returns this matrix skewed along the X axis by the passed values. + // Passing a NaN will use a value of 0. + [Immutable] WebKitCSSMatrix skewX(in double angle); + + // Returns this matrix skewed along the Y axis by the passed values. + // Passing a NaN will use a value of 0. + [Immutable] WebKitCSSMatrix skewY(in double angle); + + [DontEnum] DOMString toString(); + }; + +} diff --git a/Source/WebCore/css/WebKitCSSTransformValue.cpp b/Source/WebCore/css/WebKitCSSTransformValue.cpp new file mode 100644 index 0000000..3b4286e --- /dev/null +++ b/Source/WebCore/css/WebKitCSSTransformValue.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitCSSTransformValue.h" + +#include "CSSValueList.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +WebKitCSSTransformValue::WebKitCSSTransformValue(TransformOperationType op) + : CSSValueList(false) + , m_type(op) +{ +} + +WebKitCSSTransformValue::~WebKitCSSTransformValue() +{ +} + +String WebKitCSSTransformValue::cssText() const +{ + String result; + switch (m_type) { + case TranslateTransformOperation: + result += "translate("; + break; + case TranslateXTransformOperation: + result += "translateX("; + break; + case TranslateYTransformOperation: + result += "translateY("; + break; + case RotateTransformOperation: + result += "rotate("; + break; + case ScaleTransformOperation: + result += "scale("; + break; + case ScaleXTransformOperation: + result += "scaleX("; + break; + case ScaleYTransformOperation: + result += "scaleY("; + break; + case SkewTransformOperation: + result += "skew("; + break; + case SkewXTransformOperation: + result += "skewX("; + break; + case SkewYTransformOperation: + result += "skewY("; + break; + case MatrixTransformOperation: + result += "matrix("; + break; + case TranslateZTransformOperation: + result += "translateZ("; + break; + case Translate3DTransformOperation: + result += "translate3d("; + break; + case RotateXTransformOperation: + result += "rotateX("; + break; + case RotateYTransformOperation: + result += "rotateY("; + break; + case RotateZTransformOperation: + result += "rotateZ("; + break; + case Rotate3DTransformOperation: + result += "rotate3d("; + break; + case ScaleZTransformOperation: + result += "scaleZ("; + break; + case Scale3DTransformOperation: + result += "scale3d("; + break; + case PerspectiveTransformOperation: + result += "perspective("; + break; + case Matrix3DTransformOperation: + result += "matrix3d("; + break; + default: + break; + } + + result += CSSValueList::cssText(); + + result += ")"; + return result; +} + +} diff --git a/Source/WebCore/css/WebKitCSSTransformValue.h b/Source/WebCore/css/WebKitCSSTransformValue.h new file mode 100644 index 0000000..0c3c038 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSTransformValue.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebKitCSSTransformValue_h +#define WebKitCSSTransformValue_h + +#include "CSSValueList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class WebKitCSSTransformValue : public CSSValueList { +public: + // NOTE: these have to match the values in the IDL + enum TransformOperationType { + UnknownTransformOperation, + TranslateTransformOperation, + TranslateXTransformOperation, + TranslateYTransformOperation, + RotateTransformOperation, + ScaleTransformOperation, + ScaleXTransformOperation, + ScaleYTransformOperation, + SkewTransformOperation, + SkewXTransformOperation, + SkewYTransformOperation, + MatrixTransformOperation, + TranslateZTransformOperation, + Translate3DTransformOperation, + RotateXTransformOperation, + RotateYTransformOperation, + RotateZTransformOperation, + Rotate3DTransformOperation, + ScaleZTransformOperation, + Scale3DTransformOperation, + PerspectiveTransformOperation, + Matrix3DTransformOperation + }; + + static PassRefPtr<WebKitCSSTransformValue> create(TransformOperationType type) + { + return adoptRef(new WebKitCSSTransformValue(type)); + } + + virtual ~WebKitCSSTransformValue(); + + virtual String cssText() const; + + TransformOperationType operationType() const { return m_type; } + +private: + WebKitCSSTransformValue(TransformOperationType); + + virtual bool isWebKitCSSTransformValue() const { return true; } + + TransformOperationType m_type; +}; + +} + +#endif diff --git a/Source/WebCore/css/WebKitCSSTransformValue.idl b/Source/WebCore/css/WebKitCSSTransformValue.idl new file mode 100644 index 0000000..007097e --- /dev/null +++ b/Source/WebCore/css/WebKitCSSTransformValue.idl @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module css { + + interface [ + HasIndexGetter, + DontCheckEnums + ] WebKitCSSTransformValue : CSSValueList { + + // OperationTypes + + const unsigned short CSS_TRANSLATE = 1; + const unsigned short CSS_TRANSLATEX = 2; + const unsigned short CSS_TRANSLATEY = 3; + const unsigned short CSS_ROTATE = 4; + const unsigned short CSS_SCALE = 5; + const unsigned short CSS_SCALEX = 6; + const unsigned short CSS_SCALEY = 7; + const unsigned short CSS_SKEW = 8; + const unsigned short CSS_SKEWX = 9; + const unsigned short CSS_SKEWY = 10; + const unsigned short CSS_MATRIX = 11; + const unsigned short CSS_TRANSLATEZ = 12; + const unsigned short CSS_TRANSLATE3D = 13; + const unsigned short CSS_ROTATEX = 14; + const unsigned short CSS_ROTATEY = 15; + const unsigned short CSS_ROTATEZ = 16; + const unsigned short CSS_ROTATE3D = 17; + const unsigned short CSS_SCALEZ = 18; + const unsigned short CSS_SCALE3D = 19; + const unsigned short CSS_PERSPECTIVE = 20; + const unsigned short CSS_MATRIX3D = 21; + + readonly attribute unsigned short operationType; + }; + +} diff --git a/Source/WebCore/css/fullscreen.css b/Source/WebCore/css/fullscreen.css new file mode 100644 index 0000000..2e38c95 --- /dev/null +++ b/Source/WebCore/css/fullscreen.css @@ -0,0 +1,24 @@ +:-webkit-full-screen { + background-color: white; +} + +:root:full-screen-document:not(:full-screen) { + overflow:hidden; +} + +video:-webkit-full-screen { + background-color: black; + width: auto; + height: 100%; + max-width: 100%; +} + +img:-webkit-full-screen { + width: auto; + height: 100%; + max-width: 100%; +} + +video:-webkit-full-page-media:-webkit-full-screen::-webkit-media-controls-panel { + bottom: 0px; +} diff --git a/Source/WebCore/css/html.css b/Source/WebCore/css/html.css new file mode 100644 index 0000000..823f5f3 --- /dev/null +++ b/Source/WebCore/css/html.css @@ -0,0 +1,789 @@ +/* + * The default style sheet used to render HTML. + * + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 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. + * + */ + +@namespace "http://www.w3.org/1999/xhtml"; + +html { + display: block +} + +/* children of the <head> element all have display:none */ +head { + display: none +} + +meta { + display: none +} + +title { + display: none +} + +link { + display: none +} + +style { + display: none +} + +script { + display: none +} + +/* generic block-level elements */ + +body { + display: block; + margin: 8px +} + +p { + display: block; + margin: 1.0__qem 0px +} + +div { + display: block +} + +layer { + display: block +} + +article, aside, footer, header, hgroup, nav, section { + display: block +} + +marquee { + display: inline-block; + overflow: -webkit-marquee +} + +address { + display: block +} + +blockquote { + display: block; + margin: 1__qem 40px 1em 40px +} + +figcaption { + display: block +} + +figure { + display: block; + margin: 1em 40px 1em 40px +} + +q { + display: inline +} + +q:before { + content: '"' + /* FIXME: content: open-quote; */ +} + +q:after { + content: '"' + /* FIXME: content: close-quote; */ +} + +center { + display: block; + /* special centering to be able to emulate the html4/netscape behaviour */ + text-align: -webkit-center +} + +hr { + display: block; + margin: 0.5em auto; + border-style: inset; + border-width: 1px +} + +map { + display: inline +} + +/* heading elements */ + +h1 { + display: block; + font-size: 2em; + margin: .67__qem 0 .67em 0; + font-weight: bold +} + +h2 { + display: block; + font-size: 1.5em; + margin: .83__qem 0 .83em 0; + font-weight: bold +} + +h3 { + display: block; + font-size: 1.17em; + margin: 1__qem 0 1em 0; + font-weight: bold +} + +h4 { + display: block; + margin: 1.33__qem 0 1.33em 0; + font-weight: bold +} + +h5 { + display: block; + font-size: .83em; + margin: 1.67__qem 0 1.67em 0; + font-weight: bold +} + +h6 { + display: block; + font-size: .67em; + margin: 2.33__qem 0 2.33em 0; + font-weight: bold +} + +/* tables */ + +table { + display: table; + border-collapse: separate; + border-spacing: 2px; + border-color: gray +} + +thead { + display: table-header-group; + vertical-align: middle; + border-color: inherit +} + +tbody { + display: table-row-group; + vertical-align: middle; + border-color: inherit +} + +tfoot { + display: table-footer-group; + vertical-align: middle; + border-color: inherit +} + +/* for tables without table section elements (can happen with XHTML or dynamically created tables) */ +table > tr { + vertical-align: middle; +} + +col { + display: table-column +} + +colgroup { + display: table-column-group +} + +tr { + display: table-row; + vertical-align: inherit; + border-color: inherit +} + +td, th { + display: table-cell; + vertical-align: inherit +} + +th { + font-weight: bold +} + +caption { + display: table-caption; + text-align: -webkit-center +} + +/* lists */ + +ul, menu, dir { + display: block; + list-style-type: disc; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + -webkit-padding-start: 40px +} + +ol { + display: block; + list-style-type: decimal; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + -webkit-padding-start: 40px +} + +li { + display: list-item +} + +ul ul, ol ul { + list-style-type: circle +} + +ol ol ul, ol ul ul, ul ol ul, ul ul ul { + list-style-type: square +} + +dd { + display: block; + -webkit-margin-start: 40px +} + +dl { + display: block; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; +} + +dt { + display: block +} + +ol ul, ul ol, ul ul, ol ol { + -webkit-margin-before: 0; + -webkit-margin-after: 0 +} + +/* form elements */ + +form { + display: block; + margin-top: 0__qem +} + +label { + cursor: default; +} + +legend { + display: block; + -webkit-padding-start: 2px; + -webkit-padding-end: 2px; + border: none +} + +fieldset { + display: block; + -webkit-margin-start: 2px; + -webkit-margin-end: 2px; + -webkit-padding-before: 0.35em; + -webkit-padding-start: 0.75em; + -webkit-padding-end: 0.75em; + -webkit-padding-after: 0.625em; + border: 2px groove ThreeDFace +} + +button { + -webkit-appearance: button; +} + +/* Form controls don't go vertical. */ +input, textarea, keygen, select, button, isindex, meter, progress { + -webkit-block-flow: tb !important; +} + +input, textarea, keygen, select, button, isindex, datagrid { + margin: 0__qem; + font: -webkit-small-control; + color: initial; + letter-spacing: normal; + word-spacing: normal; + line-height: normal; + text-transform: none; + text-indent: 0; + text-shadow: none; + display: inline-block; + text-align: -webkit-auto; +} + +input[type="hidden"] { + display: none +} + +input, input[type="password"], input[type="search"], isindex { + -webkit-appearance: textfield; + padding: 1px; + background-color: white; + border: 2px inset; + -webkit-rtl-ordering: logical; + -webkit-user-select: text; + cursor: auto; +} + +input[type="search"] { + -webkit-appearance: searchfield; + -webkit-box-sizing: border-box; +} + +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: searchfield-cancel-button; + display: inline-block; +} + +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: searchfield-decoration; + display: inline-block; +} + +input[type="search"]::-webkit-search-results-decoration { + -webkit-appearance: searchfield-results-decoration; + display: inline-block; +} + +input[type="search"]::-webkit-search-results-button { + -webkit-appearance: searchfield-results-button; + display: inline-block; +} + +input::-webkit-input-list-button { + -webkit-appearance: list-button; + display: inline-block; +} + +input::-webkit-inner-spin-button { + -webkit-appearance: inner-spin-button; + display: inline-block; + -webkit-user-select: none; +} + +input::-webkit-outer-spin-button { + -webkit-appearance: outer-spin-button; + display: inline-block; + margin-left: 2px; + -webkit-user-select: none; +} + +input::-webkit-input-speech-button { + -webkit-appearance: -webkit-input-speech-button; + display: inline-block; +} + +textarea { + -webkit-appearance: textarea; + background-color: white; + border: 1px solid; + -webkit-rtl-ordering: logical; + -webkit-user-select: text; + -webkit-box-orient: vertical; + resize: auto; + cursor: auto; + padding: 2px; + white-space: pre-wrap; + word-wrap: break-word; +} + +input::-webkit-input-placeholder, isindex::-webkit-input-placeholder, textarea::-webkit-input-placeholder { + color: darkGray; +} + +input[type="password"] { + -webkit-text-security: disc !important; +} + +input[type="hidden"], input[type="image"], input[type="file"] { + -webkit-appearance: initial; + padding: initial; + background-color: initial; + border: initial; +} + +input[type="file"] { + -webkit-box-align: baseline; + text-align: start !important; +} + +input:-webkit-autofill { + background-color: #FAFFBD !important; + background-image:none !important; +} + +input[type="radio"], input[type="checkbox"] { + margin: 3px 0.5ex; + padding: initial; + background-color: initial; + border: initial; +} + +input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button { + -webkit-appearance: push-button; + white-space: pre +} + +input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button, button { + -webkit-box-align: center; + text-align: center; + cursor: default; + color: ButtonText; + padding: 2px 6px 3px 6px; + border: 2px outset ButtonFace; + background-color: ButtonFace; + -webkit-box-sizing: border-box +} + +input[type="range"] { + -webkit-appearance: slider-horizontal; + padding: initial; + border: initial; + margin: 2px; +} + +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: sliderthumb-horizontal; +} + +input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled, +input[type="file"]:disabled::-webkit-file-upload-button, button:disabled, +select:disabled, keygen:disabled, optgroup:disabled, option:disabled, datagrid:disabled { + color: GrayText +} + +input[type="button"]:active, input[type="submit"]:active, input[type="reset"]:active, input[type="file"]:active::-webkit-file-upload-button, button:active { + border-style: inset +} + +input[type="button"]:active:disabled, input[type="submit"]:active:disabled, input[type="reset"]:active:disabled, input[type="file"]:active:disabled::-webkit-file-upload-button, button:active:disabled { + border-style: outset +} + +area, param { + display: none +} + +input[type="checkbox"] { + -webkit-appearance: checkbox; + -webkit-box-sizing: border-box; +} + +input[type="radio"] { + -webkit-appearance: radio; + -webkit-box-sizing: border-box; +} + +keygen, select { + -webkit-appearance: menulist; + -webkit-box-sizing: border-box; + -webkit-box-align: center; + border: 1px solid; + -webkit-border-radius: 5px; + white-space: pre; + -webkit-rtl-ordering: logical; + color: black; + background-color: white; + cursor: default; +} + +select[size], +select[multiple], +select[size][multiple] { + -webkit-appearance: listbox; + -webkit-box-align: start; + border: 1px inset gray; + -webkit-border-radius: initial; + white-space: initial; +} + +select[size="0"], +select[size="1"] { + -webkit-appearance: menulist; + -webkit-box-align: center; + border: 1px solid; + -webkit-border-radius: 5px; + white-space: pre; +} + +datalist { + display: none; +} + +optgroup { + font-weight: bolder; +} + +option { + font-weight: normal; +} + +output { + display: inline; +} + +/* meter */ + +meter { + -webkit-appearance: meter; + display: inline-block; + height: 1em; + width: 5em; + vertical-align: -0.2em; +} + +meter::-webkit-meter { + -webkit-appearance: meter; +} + +meter::-webkit-meter-horizontal-bar { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#ddd), color-stop(0.20, #eee), color-stop(0.45, #ccc), color-stop(0.55, #ccc)); +} + +meter::-webkit-meter-vertical-bar { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, right top, from(#ddd), to(#ddd), color-stop(0.20, #eee), color-stop(0.45, #ccc), color-stop(0.55, #ccc)); +} + +meter::-webkit-meter-horizontal-optimum-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, left bottom, from(#ad7), to(#ad7), color-stop(0.20, #cea), color-stop(0.45, #7a3), color-stop(0.55, #7a3)); +} + +meter::-webkit-meter-horizontal-suboptimal-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, left bottom, from(#fe7), to(#fe7), color-stop(0.20, #ffc), color-stop(0.45, #db3), color-stop(0.55, #db3)); +} + +meter::-webkit-meter-horizontal-even-less-good-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, left bottom, from(#f77), to(#f77), color-stop(0.20, #fcc), color-stop(0.45, #d44), color-stop(0.55, #d44)); +} + +meter::-webkit-meter-vertical-optimum-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, right top, from(#ad7), to(#ad7), color-stop(0.20, #cea), color-stop(0.45, #7a3), color-stop(0.55, #7a3)); +} + +meter::-webkit-meter-vertical-suboptimal-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, right top, from(#fe7), to(#fe7), color-stop(0.20, #ffc), color-stop(0.45, #db3), color-stop(0.55, #db3)); +} + +meter::-webkit-meter-vertical-even-less-good-value { + -webkit-appearance: meter; + background: -webkit-gradient(linear, left top, right top, from(#f77), to(#f77), color-stop(0.20, #fcc), color-stop(0.45, #d44), color-stop(0.55, #d44)); +} + +/* progress */ + +progress { + -webkit-appearance: progress-bar; + display: inline-block; + height: 1em; + width: 10em; + vertical-align: -0.2em; + background-color: gray; +} + +progress::-webkit-progress-bar-value { + -webkit-appearance: progress-bar; + background-color: green; +} + +/* datagrid */ + +datagrid { + height: 150px; /* We don't use width:300px in CSS, since we want width:intrinsic and width:min-intrinsic to reset to 300 properly. */ + -webkit-appearance: datagrid; + -webkit-box-sizing: border-box; + -webkit-rtl-ordering: logical; + color: black; + background-color: white; + cursor: default; + border: 1px inset gray; + white-space: initial; +} + +/* inline elements */ + +u, ins { + text-decoration: underline +} + +strong, b { + font-weight: bolder +} + +i, cite, em, var, address { + font-style: italic +} + +tt, code, kbd, samp { + font-family: monospace +} + +pre, xmp, plaintext, listing { + display: block; + font-family: monospace; + white-space: pre; + margin: 1__qem 0 +} + +mark { + background-color: yellow; + color: black +} + +big { + font-size: larger +} + +small { + font-size: smaller +} + +s, strike, del { + text-decoration: line-through +} + +sub { + vertical-align: sub; + font-size: smaller +} + +sup { + vertical-align: super; + font-size: smaller +} + +nobr { + white-space: nowrap +} + +/* states */ + +:focus { + outline: auto 5px -webkit-focus-ring-color +} + +/* Read-only text fields do not show a focus ring but do still receive focus */ +html:focus, body:focus, input[readonly]:focus { + outline: none +} + +input:focus, textarea:focus, isindex:focus, keygen:focus, select:focus { + outline-offset: -2px +} + +input[type="button"]:focus, +input[type="checkbox"]:focus, +input[type="file"]:focus, +input[type="hidden"]:focus, +input[type="image"]:focus, +input[type="radio"]:focus, +input[type="reset"]:focus, +input[type="search"]:focus, +input[type="submit"]:focus, +input[type="file"]:focus::-webkit-file-upload-button { + outline-offset: 0 +} + +a:-webkit-any-link { + color: -webkit-link; + text-decoration: underline; + cursor: auto; +} + +a:-webkit-any-link:active { + color: -webkit-activelink +} + +/* HTML5 ruby elements */ + +ruby, rt { + text-indent: 0; /* blocks used for ruby rendering should not trigger this */ +} + +rt { + line-height: normal; +} + +ruby > rt { + display: block; + font-size: 60%; /* make slightly larger than 50% for better readability */ + text-align: center; +} + +ruby > rp { + display: none; +} + +/* other elements */ + +noframes { + display: none +} + +frameset, frame { + display: block +} + +frameset { + border-color: inherit +} + +iframe { + border: 2px inset +} + +details { + display: block +} + +summary { + display: block +} + +/* page */ + +@page { + /* FIXME: Define the right default values for page properties. */ + size: auto; + margin: auto; + padding: 0px; + border-width: 0px; +} + +/* noscript is handled internally, as it depends on settings */ diff --git a/Source/WebCore/css/make-css-file-arrays.pl b/Source/WebCore/css/make-css-file-arrays.pl new file mode 100755 index 0000000..dad530c --- /dev/null +++ b/Source/WebCore/css/make-css-file-arrays.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2006 Apple Computer, Inc. +# +# 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. +# + +# Usage: make-css-file-arrays.pl <header> <output> <input> ... + +use strict; +use Getopt::Long; + +my $header = $ARGV[0]; +shift; + +my $out = $ARGV[0]; +shift; + +open HEADER, ">", $header or die; +open OUT, ">", $out or die; + +print HEADER "namespace WebCore {\n"; +print OUT "namespace WebCore {\n"; + +for my $in (@ARGV) { + $in =~ /(\w+)\.css$/ or die; + my $name = $1; + + # Slurp in the CSS file. + open IN, "<", $in or die; + my $text; { local $/; $text = <IN>; } + close IN; + + # Remove comments in a simple-minded way that will work fine for our files. + # Could do this a fancier way if we were worried about arbitrary CSS source. + $text =~ s|/\*.*?\*/||gs; + + # Crunch whitespace just to make it a little smaller. + # Could do work to avoid doing this inside quote marks but our files don't have runs of spaces in quotes. + # Could crunch further based on places where whitespace is optional. + $text =~ s|\s+| |gs; + $text =~ s|^ ||; + $text =~ s| $||; + + # Write out a C array of the characters. + my $length = length $text; + print HEADER "extern const char ${name}UserAgentStyleSheet[${length}];\n"; + print OUT "extern const char ${name}UserAgentStyleSheet[${length}] = {\n"; + my $i = 0; + while ($i < $length) { + print OUT " "; + my $j = 0; + while ($j < 16 && $i < $length) { + print OUT ", " unless $j == 0; + print OUT ord substr $text, $i, 1; + ++$i; + ++$j; + } + print OUT "," unless $i == $length; + print OUT "\n"; + } + print OUT "};\n"; + +} + +print HEADER "}\n"; +print OUT "}\n"; diff --git a/Source/WebCore/css/makegrammar.pl b/Source/WebCore/css/makegrammar.pl new file mode 100644 index 0000000..06faaa9 --- /dev/null +++ b/Source/WebCore/css/makegrammar.pl @@ -0,0 +1,55 @@ +#! /usr/bin/perl +# +# This file is part of the WebKit project +# +# Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) +# +# 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. +use strict; +use warnings; + +my $grammar = $ARGV[0]; +my $fileBase = $ARGV[1]; + +system("bison -d -p cssyy " . $grammar . " -o " . $fileBase . ".tab.c"); + +open HEADER, ">" . $fileBase . ".h" or die; +print HEADER << "EOF"; +#ifndef CSSGRAMMAR_H +#define CSSGRAMMAR_H +EOF + +open HPP, "<" . $fileBase . ".tab.h" or die; +while (<HPP>) { + print HEADER; +} +close HPP; + +print HEADER "#endif\n"; + +close HEADER; + +unlink($fileBase . ".tab.h"); + +open CPP, ">" . $fileBase . ".cpp" or die; +open GENSRC, "<" . $fileBase . ".tab.c" or die; +while (<GENSRC>) { + print CPP; +} +close GENSRC; +close CPP; + +unlink($fileBase . ".tab.c"); diff --git a/Source/WebCore/css/makeprop.pl b/Source/WebCore/css/makeprop.pl new file mode 100644 index 0000000..d394739 --- /dev/null +++ b/Source/WebCore/css/makeprop.pl @@ -0,0 +1,140 @@ +#! /usr/bin/perl +# +# This file is part of the WebKit project +# +# Copyright (C) 1999 Waldo Bastian (bastian@kde.org) +# Copyright (C) 2007, 2008 Apple Inc. All rights reserved. +# Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) +# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged +# +# 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. +use strict; +use warnings; + +open NAMES, "<CSSPropertyNames.in" || die "Could not find CSSPropertyNames.in"; +my @names = (); +while (<NAMES>) { + next if (m/(^#)|(^\s*$)/); + # Input may use a different EOL sequence than $/, so avoid chomp. + $_ =~ s/[\r\n]+$//g; + push @names, $_; +} +close(NAMES); + +open GPERF, ">CSSPropertyNames.gperf" || die "Could not open CSSPropertyNames.gperf for writing"; +print GPERF << "EOF"; +%{ +/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */ +#include \"CSSPropertyNames.h\" +#include \"HashTools.h\" +#include <string.h> + +namespace WebCore { +%} +%struct-type +struct Property; +%omit-struct-type +%language=C++ +%readonly-tables +%global-table +%compare-strncmp +%define class-name CSSPropertyNamesHash +%define lookup-function-name findPropertyImpl +%define hash-function-name propery_hash_function +%define word-array-name property_wordlist +%enum +%% +EOF + +foreach my $name (@names) { + my $id = $name; + $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge; + print GPERF $name . ", CSSProperty" . $id . "\n"; +} + +print GPERF<< "EOF"; +%% +const Property* findProperty(register const char* str, register unsigned int len) +{ + return CSSPropertyNamesHash::findPropertyImpl(str, len); +} + +const char* getPropertyName(CSSPropertyID id) +{ + if (id < firstCSSProperty) + return 0; + int index = id - firstCSSProperty; + if (index >= numCSSProperties) + return 0; + return propertyNameStrings[index]; +} + +} // namespace WebCore +EOF + +open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing"; +print HEADER << "EOF"; +/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */ + +#ifndef CSSPropertyNames_h +#define CSSPropertyNames_h + +#include <string.h> + +namespace WebCore { + +enum CSSPropertyID { + CSSPropertyInvalid = 0, +EOF + +my $first = 1001; +my $i = 1001; +my $maxLen = 0; +foreach my $name (@names) { + my $id = $name; + $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge; + print HEADER " CSSProperty" . $id . " = " . $i . ",\n"; + $i = $i + 1; + if (length($name) > $maxLen) { + $maxLen = length($name); + } +} +my $num = $i - $first; + +print HEADER "};\n\n"; +print HEADER "const int firstCSSProperty = $first;\n"; +print HEADER "const int numCSSProperties = $num;\n"; +print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n"; + +print HEADER "const char* const propertyNameStrings[$num] = {\n"; +foreach my $name (@names) { + print HEADER "\"$name\",\n"; +} +print HEADER "};\n"; + +print HEADER << "EOF"; + +const char* getPropertyName(CSSPropertyID); + +} // namespace WebCore + +#endif // CSSPropertyNames_h + +EOF + +close HEADER; + +system("gperf --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf > CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?"; diff --git a/Source/WebCore/css/maketokenizer b/Source/WebCore/css/maketokenizer new file mode 100644 index 0000000..90d5fcb --- /dev/null +++ b/Source/WebCore/css/maketokenizer @@ -0,0 +1,150 @@ +print <<END; +/* + * Copyright (C) 2003 Lars Knoll (knoll\@kde.org) + * + * + * 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. + */ + +/* This file is mostly data generated by flex. Unfortunately flex + can't handle 16bit strings directly, so we just copy the part of + the code we need and modify it to our needs. + + Most of the defines below are to make sure we can easily use the + flex generated code, using as little editing as possible. + + The flex syntax to generate the lexer are more or less directly + copied from the CSS2.1 specs, with some fixes for comments and + the important symbol. + + To regenerate, run flex on tokenizer.flex. After this, copy the + data tables and the YY_DECL method over to this file. Remove the + init code from YY_DECL and change the YY_END_OF_BUFFER to only call + yyterminate(). + +*/ + +// --------- begin generated code ------------------- + +END + +{ +print<<END + +#include "CSSGrammar.h" + +#define INITIAL 0 +#define mediaquery 1 +#define forkeyword 2 + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ +END +} + +# Skip over the flex output prologue: the above typedefs, forward declarations, etc. +# Stop when we get to the declarations of tables. +while (<>) { + last if /YY_NUM_RULES/; +} + +# Dump the generated tables. /yy_last_accepting/ matches the first declaration after the tables. +print; +while (<>) { + last if /yy_last_accepting/; + print; +} + +# Skip down the the declaration of yytext; the body of the flex output begins after it. +while (<>) { + last if /yytext/; +} +# Dump the definitions of states (INITIAL, media query, tokenizer state support). +while (<>) { + last if not (/define/ || /line/) ; + print; +} + +# Skip to main scanner function. +while (<>) { + last if /^YY_DECL/; +} + +# Dump main scanner declarations, substituting in our 16-bit character type. +# Declarations end with the declaration matching /yy_act/. +print; +while (<>) { + s/char/UChar/; + print; + last if /yy_act/; +} + +# Skip past initialization code, down to main loop. +while (<>) { + last if /while \( 1 \)/; +} + +# Dump the main loop, skipping over labels we don't use. +# Stop before dumping the end-of-buffer handling, because we output our own custom end-of-buffer handling. +print; +while (<>) { + next if /^yy_match:/; + next if /^do_action:/; + last if /YY_END_OF_BUFFER/; + if (/^case YY_STATE_EOF\(INITIAL\):/) { + print "case YY_END_OF_BUFFER:\n"; + # flex outputs a ton of logic related to end-of-buffer handling; we just want to fall through to + # the yyterminate() found in other EOF states. But we need to be careful to back up to behind + # the terminating double-NUL so that subsequent calls to flex will have the pointers in order, + # so this logic is a reduction of the normal flex-generated YY_END_OF_BUFFER code. + print "\tyy_c_buf_p = yy_cp - 1;\n"; + print "\tyy_cp = yy_c_buf_p;\n"; + } + print; +} + +# Skip over the end-of-buffer handling; dump the rest of the function. +while (<>) { + last if /default:/; +} +print; +while (<>) { + print; + last if /end of yylex/; +} + +# We don't want the remainder of flex's output. +# However, flex may choke with "flex: error writing output file <stdout>" +# if its stdout is unexpectedly closed on it. +# Consume the remaining output. +while (<>) { +} diff --git a/Source/WebCore/css/makevalues.pl b/Source/WebCore/css/makevalues.pl new file mode 100644 index 0000000..183cd35 --- /dev/null +++ b/Source/WebCore/css/makevalues.pl @@ -0,0 +1,137 @@ +#! /usr/bin/perl +# +# This file is part of the WebKit project +# +# Copyright (C) 1999 Waldo Bastian (bastian@kde.org) +# Copyright (C) 2007 Apple Inc. All rights reserved. +# Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) +# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged +# +# 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. +use strict; +use warnings; + +open NAMES, "<CSSValueKeywords.in" || die "Could not open CSSValueKeywords.in"; +my @names = (); +while (<NAMES>) { + next if (m/(^#)|(^\s*$)/); + # Input may use a different EOL sequence than $/, so avoid chomp. + $_ =~ s/[\r\n]+$//g; + push @names, $_; +} +close(NAMES); + +open GPERF, ">CSSValueKeywords.gperf" || die "Could not open CSSValueKeywords.gperf for writing"; +print GPERF << "EOF"; +%{ +/* This file is automatically generated from CSSValueKeywords.in by makevalues, do not edit */ + +#include \"CSSValueKeywords.h\" +#include \"HashTools.h\" +#include <string.h> + +namespace WebCore { +%} +%struct-type +struct Value; +%omit-struct-type +%language=C++ +%readonly-tables +%compare-strncmp +%define class-name CSSValueKeywordsHash +%define lookup-function-name findValueImpl +%define hash-function-name value_hash_function +%define word-array-name value_word_list +%enum +%% +EOF + +foreach my $name (@names) { + my $id = $name; + $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge; + print GPERF $name . ", CSSValue" . $id . "\n"; +} + +print GPERF << "EOF"; +%% +static const char* const valueList[] = { + "", +EOF + +foreach my $name (@names) { + print GPERF " \"" . $name . "\",\n"; +} + +print GPERF << "EOF"; + 0 +}; + +const Value* findValue(register const char* str, register unsigned int len) +{ + return CSSValueKeywordsHash::findValueImpl(str, len); +} + +const char* getValueName(unsigned short id) +{ + if (id >= numCSSValueKeywords || id <= 0) + return 0; + return valueList[id]; +} + +} // namespace WebCore +EOF +close GPERF; + + +open HEADER, ">CSSValueKeywords.h" || die "Could not open CSSValueKeywords.h for writing"; +print HEADER << "EOF"; +/* This file is automatically generated from CSSValueKeywords.in by makevalues, do not edit */ + +#ifndef CSSValueKeywords_h +#define CSSValueKeywords_h + +#include <string.h> + +namespace WebCore { + +const int CSSValueInvalid = 0; +EOF + +my $i = 1; +my $maxLen = 0; +foreach my $name (@names) { + my $id = $name; + $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge; + print HEADER "const int CSSValue" . $id . " = " . $i . ";\n"; + $i = $i + 1; + if (length($name) > $maxLen) { + $maxLen = length($name); + } +} +print HEADER "const int numCSSValueKeywords = " . $i . ";\n"; +print HEADER "const size_t maxCSSValueKeywordLength = " . $maxLen . ";\n"; +print HEADER << "EOF"; + +const char* getValueName(unsigned short id); + +} // namespace WebCore + +#endif // CSSValueKeywords_h + +EOF +close HEADER; + +system("gperf --key-positions=\"*\" -D -n -s 2 CSSValueKeywords.gperf > CSSValueKeywords.cpp") == 0 || die "calling gperf failed: $?"; diff --git a/Source/WebCore/css/mathml.css b/Source/WebCore/css/mathml.css new file mode 100644 index 0000000..b797b21 --- /dev/null +++ b/Source/WebCore/css/mathml.css @@ -0,0 +1,238 @@ +@namespace "http://www.w3.org/1998/Math/MathML"; + +math { + font-family: STIXGeneral, Symbol, "Times New Roman", sans-serif; + display: inline-block; + padding: 0px; + margin: 0px; + text-align: left; + vertical-align: baseline; + line-height: 1.0; + padding-left: 1px; + padding-right: 1px; +} + +math[display="block"] { + display: block; + page-break-inside: avoid; + margin-bottom: 1em; + text-align: center; + margin-left: auto; + margin-right: auto; +} + +mrow, mfenced { + display: inline-block; + white-space: nowrap; + vertical-align: baseline; +} + +mfenced { + padding-left: 1px; + padding-right: 1px; +} + +mi { + font-style: italic; + padding-right: 0.1em; +} + +mi + mrow { + margin-left: 0.1em; +} + +mfrac { + display: inline-block; +} + +msub, msup { + display: inline-block; + vertical-align: baseline; +} + +msub > * + * { + vertical-align: sub; + font-size: 0.75em; +} + +msup > * + * { + vertical-align: super; + font-size: 0.75em; +} + +msubsup { + display: inline-block; + vertical-align: baseline; +} + +msubsup > * { + margin: 0px; + padding: 0px; +} + +msubsup > * + * { + font-size: 0.75em; +} + +munder, mover, munderover { + display: inline-block; + vertical-align: baseline; +} + +munderover > * + *, mover > * + *, munder > * + * { + font-size: 0.75em; +} + +mo, mn, mi, mtext { + padding: 0px; + margin: 0px; +} + +mo { + display: inline-block; +} + +math > mo, mrow > mo, mfenced > mo { + padding-right: 0.1em; +} + +math[mathvariant="normal"], mstyle[mathvariant="normal"], mo[mathvariant="normal"], mn[mathvariant="normal"], mi[mathvariant="normal"], mtext[mathvariant="normal"], mspace[mathvariant="normal"], ms[mathvariant="normal"] { + font-style: normal; + font-weight: normal; +} + +math[mathvariant="bold"], mstyle[mathvariant="bold"], mo[mathvariant="bold"], mn[mathvariant="bold"], mi[mathvariant="bold"], mtext[mathvariant="bold"], mspace[mathvariant="bold"], ms[mathvariant="bold"] { + font-style: normal; + font-weight: bold; +} + +math[mathvariant="italic"], mstyle[mathvariant="italic"], mo[mathvariant="italic"], mn[mathvariant="italic"], mi[mathvariant="italic"], mtext[mathvariant="italic"], mspace[mathvariant="italic"], ms[mathvariant="italic"] { + font-style: italic; + font-weight: normal; +} + +math[mathvariant="bold-italic"], mstyle[mathvariant="bold-italic"], mo[mathvariant="bold-italic"], mn[mathvariant="bold-italic"], mi[mathvariant="bold-italic"], mtext[mathvariant="bold-italic"], mspace[mathvariant="bold-italic"], ms[mathvariant="bold-italic"] { + font-weight: bold; + font-style: italic; +} + +math[mathsize="small"], mstyle[mathsize="small"], mo[mathsize="small"], mn[mathsize="small"], mi[mathsize="small"], mtext[mathsize="small"], mspace[mathsize="small"], ms[mathsize="small"] { + font-size: 0.75em; +} + +math[mathsize="normal"], mstyle[mathsize="normal"], mo[mathsize="normal"], mn[mathsize="normal"], mi[mathsize="normal"], mtext[mathsize="normal"], mspace[mathsize="normal"], ms[mathsize="normal"] { + font-size: 1em; +} + +math[mathsize="big"], mstyle[mathsize="big"], mo[mathsize="big"], mn[mathsize="big"], mi[mathsize="big"], mtext[mathsize="big"], mspace[mathsize="big"], ms[mathsize="big"] { + font-size: 1.5em; +} + +annotation, annotation-xml { + display:none; +} + +mphantom { + visibility: hidden; +} + +merror { + outline: solid thin red; + font-weight: bold; + font-family: sans-serif; + background-color: lightYellow; +} + +msqrt { + display: inline-block; + padding-top: 0.2em; + padding-left: 0.75em; +} + +mroot { + display: inline-block; + position: relative; + padding-top: 0.2em; + padding-left: 0.2em; +} + +mroot > * + * { + font-size: 0.75em; + vertical-align: bottom; + position: absolute; + left: 0px; + padding-right: 0.4em; + padding-left: 0.2em; + padding-bottom: 0.2em; +} + +mroot > * + mrow, mroot > * + mfenced { + padding-bottom: 0.4em; +} + +mtable { + display: inline-table; + text-align: center; + vertical-align: -40%; +} + +mtr { + display: table-row; +} + +mtd { + display: table-cell; + padding: 0 0.5ex; +} + +mtable[columnalign="left"], mtr[columnalign="left"], mtd[columnalign="left"] { + text-align: left; +} + +mtable[columnalign="right"], mtr[columnalign="right"], mtd[columnalign="right"] { + text-align: right; +} + +mtable[rowalign="top"] mtd, mtable mtr[rowalign="top"] mtd, mtable mtr mtd[rowalign="top"] { + vertical-align: top; +} + +mtable[rowalign="bottom"] mtd, mtable mtr[rowalign="bottom"] mtd, mtable mtr mtd[rowalign="bottom"] { + vertical-align: bottom; +} + +mtable[rowalign="center"] mtd, mtable mtr[rowalign="center"] mtd, mtable mtr mtd[rowalign="center"] { + vertical-align: middle; +} + +mtable[frame="solid"] { + border: solid thin; +} + +mtable[frame="dashed"] { + border: dashed thin; +} + +mtable[rowlines="solid"], mtable[rowlines="dashed"], mtable[columnlines="solid"], mtable[columnlines="dashed"] { + border-collapse: collapse; +} + +mtable[rowlines="solid"] > mtr + mtr { + border-top: solid thin; +} + +mtable[rowlines="dashed"] > mtr + mtr { + border-top: dashed thin; +} + +mtable[columnlines="solid"] > mtr > mtd + mtd { + border-left: solid thin; +} + +mtable[columnlines="dashed"] > mtr > mtd + mtd { + border-left: dashed thin; +} + +mspace[linebreak="newline"] { + display: block; +} diff --git a/Source/WebCore/css/mediaControls.css b/Source/WebCore/css/mediaControls.css new file mode 100644 index 0000000..6a0f14b --- /dev/null +++ b/Source/WebCore/css/mediaControls.css @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* media controls */ + +audio { + width: 200px; + height: 16px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-user-select: none; + position: absolute; + bottom: 0; + width: 100%; + z-index: 0; + overflow: hidden; + height: 16px; + text-align: right; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: -16px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + -webkit-appearance: media-mute-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + -webkit-appearance: media-play-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + -webkit-appearance: media-controls-background; + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-box-pack: end; + -webkit-box-flex: 1; + -webkit-user-select: none; + height: 16px; +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + display: none; +} + +audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-controls-time-remaining-display { + display: none; +} + +audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { + -webkit-appearance: media-slider; + display: -webkit-box; + -webkit-box-flex: 1; + height: 16px; + padding: 0px 2px; +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + display: none; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + display: none; +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + -webkit-appearance: media-seek-back-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + -webkit-appearance: media-seek-forward-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + -webkit-appearance: media-fullscreen-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: none; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button { + -webkit-appearance: media-toggle-closed-captions-button; + display: -webkit-box; + width: 16px; + height: 16px; +} + +audio::-webkit-media-controls-volume-slider-mute-button, video::-webkit-media-controls-volume-slider-mute-button { + -webkit-appearance: media-volume-slider-mute-button; + display: none; +} diff --git a/Source/WebCore/css/mediaControlsChromium.css b/Source/WebCore/css/mediaControlsChromium.css new file mode 100644 index 0000000..61cbb0d --- /dev/null +++ b/Source/WebCore/css/mediaControlsChromium.css @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Chromium default media controls */ + +audio { + width: 300px; + height: 32px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + -webkit-user-select: none; + position: absolute; + overflow: visible; + bottom: 0; + width: 100%; + height: 32px; + z-index: 0; + background-color: rgba(0, 0, 0, 0.6); +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: -32px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + -webkit-appearance: media-mute-button; + position: absolute; + top: auto; + bottom: 0; + right: 0; + left: auto; + + width: 34px; + height: 32px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + -webkit-appearance: media-play-button; + + position: absolute; + top: auto; + bottom: 7px; + left: 7px; + right: 6px; + + width: 18px; + height: 19px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + -webkit-appearance: media-timeline-container; + -webkit-user-select: none; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-box-pack: center; + -webkit-box-direction: reverse; + -webkit-box-flex: 1; + + position: absolute; + top: auto; + bottom: 0; + left: 30px; + right: 34px; + + width: auto; + height: 32px; + + border-left: 1px solid rgba(255, 255, 255, 0.2); + border-right: 1px solid rgba(255, 255, 255, 0.2); +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + -webkit-appearance: media-current-time-display; + -webkit-user-select: none; + display: -webkit-box; + -webkit-box-flex: 0; + -webkit-box-pack: center; + -webkit-box-align: center; + + overflow: hidden; + cursor: default; + + line-height: 21px; + height: 20px; + width: 58px; + + text-align: center; + font-family: Arial; + font-size: 16px; + font-weight: bold; + color: white; + + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0; + text-shadow: none; + text-decoration: none; +} + +audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-controls-time-remaining-display { + -webkit-appearance: media-time-remaining-display; + -webkit-user-select: none; + display: none; + -webkit-box-flex: 0; + -webkit-box-pack: center; + -webkit-box-align: center; + + overflow: hidden; + cursor: default; + + line-height: 21px; + height: 20px; + width: 58px; + + text-align: center; + font-family: Arial; + font-size: 16px; + font-weight: bold; + color: white; + + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0; + text-shadow: none; + text-decoration: none; +} + +audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { + -webkit-appearance: media-slider; + display: -webkit-box; + -webkit-box-flex: 1; + + padding: 0px; + margin: 0px 6px; + height: 16px; + + border-color: rgba(255, 255, 255, 0.2); + border-style: solid; + border-width: 1px; + border-radius: 2px; + background-color: rgba(255, 255, 255, 0.08); + color: rgb(50, 140, 223); +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + -webkit-appearance: media-seek-back-button; + display: none; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + -webkit-appearance: media-seek-forward-button; + display: none; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + -webkit-appearance: media-fullscreen-button; + display: none; +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + position: absolute; + + width: 34px; + height: 100px; + + background-color: rgba(0, 0, 0, 0.6); +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + + top: 10px; + left: 12px; + + width: 10px; + height: 80px; +} diff --git a/Source/WebCore/css/mediaControlsGtk.css b/Source/WebCore/css/mediaControlsGtk.css new file mode 100644 index 0000000..18b7dcc --- /dev/null +++ b/Source/WebCore/css/mediaControlsGtk.css @@ -0,0 +1,77 @@ +/* + * WebKitGTK+ specific overrides for HTML5 media elements. + * + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * + * 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. + * + */ + +audio { + height: 20px; + width: 300px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + height: 20px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + width: 20px; + height: 20px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + width: 20px; + height: 20px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + height: 20px; + border-left: 1px solid rgba(255, 255, 255, 0.2); + border-right: 1px solid rgba(255, 255, 255, 0.2); +} + +audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { + height: 20px; +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + -webkit-appearance: media-current-time-display; + -webkit-user-select: none; + display: inline-block; + height: 20px; + + padding: 5px; + + text-align: center; + font-size: 10px; +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + width: 20px; + height: 20px; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + width: 20px; + height: 20px; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + width: 20px; + height: 20px; +} diff --git a/Source/WebCore/css/mediaControlsQt.css b/Source/WebCore/css/mediaControlsQt.css new file mode 100644 index 0000000..4ea444c --- /dev/null +++ b/Source/WebCore/css/mediaControlsQt.css @@ -0,0 +1,140 @@ +/* + * QtWebKit specific overrides for HTML5 media elements. + * + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /* QtWebKit media controls. Extends mediaControls.css */ + +audio { + height: 34px; + width: 400px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + display: -webkit-box; + -webkit-box-orient: horizontal; + -webkit-box-align: end; + -webkit-user-select: none; + position: absolute; + bottom: 0; + width: 100%; + z-index: 0; + overflow: hidden; + height: 100%; + text-align: right; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: 0px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + width: 12px; + height: 12px; + padding: 6px; + margin: 5px 5px 5px 3px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + width: 9px; + height: 12px; + padding: 6px 12px 6px 11px; + margin: 5px 3px 5px 5px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + height: 34px; +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + -webkit-appearance: media-current-time-display; + -webkit-user-select: none; + display: inline-block; + height: 12px; + padding: 6px; + margin: 5px 3px; + + overflow: hidden; + cursor: default; + + text-align: center; + font-size: 10px; + font-family: Verdana; + font-weight: bold; + color: white; +} + +audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-controls-time-remaining-display { + display: none; +} + +audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { + height: 12px; + padding: 6px 8px; + margin: 5px 3px; +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + position: absolute; + height: 103px; + width: 24px; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + + width: 12px; + padding: 6px; + height: 88px; + margin: 0 0 3px 0; +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + display: none; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + display: none; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + display: none; +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: none; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button { + display: none; +} + diff --git a/Source/WebCore/css/mediaControlsQuickTime.css b/Source/WebCore/css/mediaControlsQuickTime.css new file mode 100644 index 0000000..06f31ae --- /dev/null +++ b/Source/WebCore/css/mediaControlsQuickTime.css @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* alternate media controls - Extend mediaControls.css */ + +audio { + width: 200px; + height: 25px; +} + +audio::-webkit-media-controls-panel, video::-webkit-media-controls-panel { + /* In mediaControls.css */ + -webkit-appearance: media-controls-background; + overflow: visible; + height: 25px; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: -25px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + -webkit-box-ordinal-group: 2; /* Before the fullscreen button */ + + width: 14px; + height: 12px; + margin-left: 2px; + margin-right: 9px; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + width: 16px; + height: 16px; + margin-left: 6px; + margin-right: 1px; +} + +audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container { + -webkit-appearance: none; + -webkit-box-orient: horizontal; + -webkit-box-align: center; + -webkit-box-pack: center; + -webkit-box-flex: 1; + text-align: right; + height: auto; +} + +audio::-webkit-media-controls-current-time-display, video::-webkit-media-controls-current-time-display { + -webkit-user-select: none; + display: -webkit-box; + -webkit-box-flex: 0; + -webkit-box-pack: center; + -webkit-box-align: center; + cursor: default; + font: -webkit-small-control; + font-size: 9px; + overflow: hidden; + width: 45px; + color: white; + text-shadow: black 0px 1px 1px; + + letter-spacing: normal; + word-spacing: normal; + line-height: normal; + text-transform: none; + text-indent: 0; + text-decoration: none; +} + +audio::-webkit-media-controls-time-remaining-display, video::-webkit-media-controls-time-remaining-display { + -webkit-user-select: none; + display: -webkit-box; + -webkit-box-flex: 0; + -webkit-box-pack: center; + -webkit-box-align: center; + cursor: default; + font: -webkit-small-control; + font-size: 9px; + overflow: hidden; + width: 45px; + color: white; + text-shadow: black 0px 1px 1px; + + letter-spacing: normal; + word-spacing: normal; + line-height: normal; + text-transform: none; + text-indent: 0; + text-decoration: none; +} + +audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { + display: -webkit-box; + -webkit-box-flex: 1; + height: 13px; + padding: 0px; + margin: 0px; + margin-top: 2px; +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + display: none; + width: 0px; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + display: none; + width: 0px; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + width: 16px; + height: 16px; + margin-left: 7px; + margin-right: 7px; + -webkit-box-ordinal-group: 4; /* At the very end */ +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: -webkit-box; + -webkit-appearance: media-rewind-button; + width: 18px; + height: 18px; + margin-bottom: 1px; + margin-left: 6px; + margin-right: 2px; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; + -webkit-appearance: media-return-to-realtime-button; + width: 16px; + height: 11px; + margin-left: 6px; + margin-right: 2px; +} + +audio::-webkit-media-controls-status-display, video::-webkit-media-controls-status-display { + -webkit-user-select: none; + cursor: default; + display: -webkit-box; + -webkit-box-flex: 1; + font: -webkit-small-control; + color: white; + font-size: 10px; + line-height: 13px; + overflow: hidden; + text-shadow: black 0px 1px 1px; + margin-left: 10px; + margin-right: 10px; + + letter-spacing: normal; + word-spacing: normal; + line-height: normal; + text-transform: none; + text-indent: 0; + text-decoration: none; +} + +audio::-webkit-media-controls-toggle-closed-captions-button, video::-webkit-media-controls-toggle-closed-captions-button { + -webkit-appearance: media-toggle-closed-captions-button; + display: -webkit-box; + width: 16px; + height: 16px; + margin-left: 7px; + margin-right: 7px; + -webkit-box-ordinal-group: 3; /* between mute and fullscreen */ +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + position: absolute; + + top: 0; + left: 0; + + width: 22px; + height: 114px; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + + top: 7px; + left: 6px; + + width: 10px; + height: 80px; +} + +audio::-webkit-media-controls-volume-slider-mute-button, video::-webkit-media-controls-volume-slider-mute-button { + -webkit-appearance: media-volume-slider-mute-button; + display: inline; + position: absolute; + + bottom: 5px; + left: 4px; + + width: 14px; + height: 12px; +} diff --git a/Source/WebCore/css/quirks.css b/Source/WebCore/css/quirks.css new file mode 100644 index 0000000..52d07e6 --- /dev/null +++ b/Source/WebCore/css/quirks.css @@ -0,0 +1,54 @@ +/* + * Additonal style sheet used to render HTML pages in quirks mode. + * + * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2006, 2007 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. + * + */ + +/* Give floated images margins of 3px */ +img[align="left"] { + margin-right: 3px; +} +img[align="right"] { + margin-left: 3px; +} + +/* Tables reset both line-height and white-space in quirks mode. */ +/* Compatible with WinIE. Note that font-family is *not* reset. */ +table { + white-space: normal; + line-height: normal; + font-weight: normal; + font-size: medium; + font-variant: normal; + font-style: normal; + color: -webkit-text; + text-align: -webkit-auto +} + +/* This will apply only to text fields, since all other inputs already use border box sizing */ +input:not([type=image]), textarea { + box-sizing: border-box; +} + +/* Set margin-bottom for form element in quirks mode. */ +/* Compatible with Gecko. (Doing this only for quirks mode is a fix for bug 17696.) */ +form { + margin-bottom: 1em +} diff --git a/Source/WebCore/css/svg.css b/Source/WebCore/css/svg.css new file mode 100644 index 0000000..171c1c4 --- /dev/null +++ b/Source/WebCore/css/svg.css @@ -0,0 +1,70 @@ +/* + * The default style sheet used to render SVG. + * + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +@namespace "http://www.w3.org/2000/svg"; + +/* + When an outermost SVG 'svg' element is stand-alone or embedded inline within a parent XML grammar + which does not use CSS layout [CSS2-LAYOUT] or XSL formatting [XSL], the 'overflow' property on the + outermost 'svg' element is ignored for the purposes of visual rendering and the initial clipping path is set + to the bounds of the initial viewport. + + When an outermost 'svg' element is embedded inline within a parent XML grammar which uses CSS layout + [CSS2-LAYOUT] or XSL formatting [XSL], if the 'overflow' property has the value hidden or scroll, then + the user agent will establish an initial clipping path equal to the bounds of the initial viewport; otherwise, + the initial clipping path is set according to the clipping rules as defined in [CSS2-overflow]. + + Opera/Firefox & WebKit agreed on NOT setting "overflow: hidden" for the outermost svg element - SVG 1.1 Errata + contains these changes as well as all future SVG specifications: see http://lists.w3.org/Archives/Public/public-svg-wg/2008JulSep/0347.html +*/ + +svg:not(:root), symbol, image, marker, pattern, foreignObject { + overflow: hidden +} + +svg { + width: 100%; + height: 100%; +} + +text, foreignObject { + display: block +} + +text, tspan, textPath { + white-space: nowrap +} + +text, tspan, tref { + -webkit-text-size-adjust: none; +} + +/* states */ + +:focus { + outline: auto 5px -webkit-focus-ring-color +} diff --git a/Source/WebCore/css/themeChromiumLinux.css b/Source/WebCore/css/themeChromiumLinux.css new file mode 100644 index 0000000..f8210c3 --- /dev/null +++ b/Source/WebCore/css/themeChromiumLinux.css @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* These styles override other user-agent styles for Chromium on Linux. */ + +select { + background-color: #dddddd; + border: 0px; +} diff --git a/Source/WebCore/css/themeChromiumSkia.css b/Source/WebCore/css/themeChromiumSkia.css new file mode 100644 index 0000000..bcd05f0 --- /dev/null +++ b/Source/WebCore/css/themeChromiumSkia.css @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* These styles override other user-agent styles for Chromium using Skia. */ + +/* Option elements inherit their font (see themeWin.css). However, their + * font weight should always be normal, to distinguish from optgroup labels. */ +option { + font-weight: normal !important; +} diff --git a/Source/WebCore/css/themeQtMobile.css b/Source/WebCore/css/themeQtMobile.css new file mode 100644 index 0000000..f6327a9 --- /dev/null +++ b/Source/WebCore/css/themeQtMobile.css @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +input[type="button"], +input[type="submit"], +input[type="reset"], +input[type="file"]::-webkit-file-upload-button, button, +select { + padding: 2px 18px 3px 18px; + border: 1px solid gray; + -webkit-border-radius:5px; + background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, rgba(0, 0, 0, 0.35)), color-stop(0.4, rgba(0, 0, 0, 0.0))); + background-color: #ffffff; + color: #3e3e3e; +} + +input[type="button"]:disabled, +input[type="submit"]:disabled, +input[type="reset"]:disabled, +input[type="file"]:disabled::-webkit-file-upload-button, +button:disabled, +select:disabled { + border: 1px solid gray; +} + +input[type="button"]:active, +input[type="submit"]:active, +input[type="reset"]:active, +input[type="file"]:active::-webkit-file-upload-button, +button:active, +select:active { + background: ButtonShadow; +} + +input[type="button"]:active:disabled, +input[type="submit"]:active:disabled, +input[type="reset"]:active:disabled, +input[type="file"]:active:disabled::-webkit-file-upload-button, +button:active:disabled, +select:active:disabled { + border: 1px solid gray; +} + +input:not([type]), +input[type="text"], +input[type="password"], +input[type="email"], +input[type="tel"], +input[type="color"], +input[type="search"], +input[type="date"], +input[type="datetime"], +input[type="datetime-local"], +input[type="month"], +input[type="week"], +input[type="time"], +input[type="number"], +input[type="url"], +textarea { + border: 1px solid gray; + background: -webkit-gradient(linear, left top, left 30, color-stop(0.0, rgba(0, 0, 0, 0.35)), color-stop(0.2, rgba(0, 0, 0, 0.0))); + background-color: #ffffff; + color: #3e3e3e; + -webkit-border-radius:5px; +} + +input:not([type]):disabled, +input[type="text"]:disabled, +input[type="password"]:disabled, +input[type="email"]:disabled, +input[type="tel"]:disabled, +input[type="color"]:disabled, +input[type="search"]:disabled, +input[type="date"]:disabled, +input[type="datetime"]:disabled, +input[type="datetime-local"]:disabled, +input[type="month"]:disabled, +input[type="week"]:disabled, +input[type="time"]:disabled, +input[type="number"]:disabled, +input[type="url"]:disabled, +textarea:disabled { + border: 1px solid gray; + background: -webkit-gradient(linear, left top, left 30, color-stop(0.0, rgba(0, 0, 0, 0.3)), color-stop(0.2, rgba(0, 0, 0, 0.0))); + background-color: #ffffff; + color: #e5e5e5; +} + +input:not([type]):active, +input[type="text"]:active, +input[type="password"]:active, +input[type="email"]:active, +input[type="tel"]:active, +input[type="color"]:active, +input[type="search"]:active, +input[type="date"]:active, +input[type="datetime"]:active, +input[type="datetime-local"]:active, +input[type="month"]:active, +input[type="week"]:active, +input[type="time"]:active, +input[type="number"]:active, +input[type="url"]:active, +textarea:active { + background: ButtonShadow; +} diff --git a/Source/WebCore/css/themeQtNoListboxes.css b/Source/WebCore/css/themeQtNoListboxes.css new file mode 100644 index 0000000..4c5e44a --- /dev/null +++ b/Source/WebCore/css/themeQtNoListboxes.css @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +select[size], +select[multiple], +select[size][multiple] { + -webkit-appearance: menulist; + -webkit-box-align: center; + border: 1px solid; + -webkit-border-radius: 5px; + white-space: pre; +} diff --git a/Source/WebCore/css/themeWin.css b/Source/WebCore/css/themeWin.css new file mode 100644 index 0000000..f2ad669 --- /dev/null +++ b/Source/WebCore/css/themeWin.css @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* These styles override the default styling for HTML elements as defined in + WebCore/css/html.css. So far we have used this file exclusively for + making our form elements match Firefox's. */ + +input:not([type]), +input[type="text"], +input[type="password"] { + padding:1px 0; +} + +input[type="search"] { + padding:1px; +} + +input[type="checkbox"] { + margin:3px 3px 3px 4px; +} + +input[type="radio"] { + margin:3px 3px 0 5px; +} + +/* Not sure this is the right color. #EBEBE4 is what Firefox uses. + FIXME: Figure out how to support legacy input rendering. + FIXME: Add input[type="file"] once we figure out our file inputs. + FIXME: Add input[type="image"] once we figure out our image inputs. + FIXME: We probably do the wrong thing if you put an invalid input type. + do we care? +*/ +textarea:disabled, +input:not([type]):disabled, +input[type="text"]:disabled, +input[type="password"]:disabled, +input[type="search"]:disabled { + background-color: #EBEBE4; +} + +input[type="search"]::-webkit-search-cancel-button { + margin-right: 3px; +} + +input[type="search"]::-webkit-search-results-decoration { + margin: 0 3px 0 2px; +} + +input[type="search"]::-webkit-search-results-button { + margin: 0 3px 0 2px; +} + +input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button, button { + padding: 1px 6px; +} + +/* Windows selects are not rounded. Custom borders for them shouldn't be either. */ +keygen, +select, +select[size="0"], +select[size="1"] { + -webkit-border-radius: 0; +} + +/* Option font must be inherited because we depend on computing the size of the + <select> based on the size of the options, and they must use the same font + for that computation to be correct */ +option { + font: inherit !important; +} + +textarea { + font-family: monospace; +} diff --git a/Source/WebCore/css/themeWinQuirks.css b/Source/WebCore/css/themeWinQuirks.css new file mode 100644 index 0000000..c69b74c --- /dev/null +++ b/Source/WebCore/css/themeWinQuirks.css @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* These styles override the default styling for HTML elements in quirks-mode + as defined in WebCore/css/quirks.css. So far we have used this file exclusively for + making our form elements match Firefox's. */ + +textarea { + /* Matches IE's text offsets in quirksmode (causes text to wrap the same as IE). */ + padding: 2px 0 0 2px; +} diff --git a/Source/WebCore/css/tokenizer.flex b/Source/WebCore/css/tokenizer.flex new file mode 100644 index 0000000..eb18cb9 --- /dev/null +++ b/Source/WebCore/css/tokenizer.flex @@ -0,0 +1,121 @@ +%option case-insensitive +%option noyywrap +%option 8bit +%option stack +%s mediaquery +%s forkeyword + +h [0-9a-fA-F] +nonascii [\200-\377] +unicode \\{h}{1,6}[ \t\r\n\f]? +escape {unicode}|\\[ -~\200-\377] +nmstart [_a-zA-Z]|{nonascii}|{escape} +nmchar [_a-zA-Z0-9-]|{nonascii}|{escape} +string1 \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" +string2 \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' + +ident -?{nmstart}{nmchar}* +name {nmchar}+ +num [0-9]+|[0-9]*"."[0-9]+ +intnum [0-9]+ +string {string1}|{string2} +url ([!#$%&*-~]|{nonascii}|{escape})* +w [ \t\r\n\f]* +nl \n|\r\n|\r|\f +range \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h}))))) +nth [\+-]?{intnum}*n([\t\r\n ]*[\+-][\t\r\n ]*{intnum})? + +%% + +\/\*[^*]*\*+([^/*][^*]*\*+)*\/ {countLines(); /* ignore comments */ } + +[ \t\r\n\f]+ {countLines(); yyTok = WHITESPACE; return yyTok;} + +"<!--" {yyTok = SGML_CD; return yyTok;} +"-->" {yyTok = SGML_CD; return yyTok;} +"~=" {yyTok = INCLUDES; return yyTok;} +"|=" {yyTok = DASHMATCH; return yyTok;} +"^=" {yyTok = BEGINSWITH; return yyTok;} +"$=" {yyTok = ENDSWITH; return yyTok;} +"*=" {yyTok = CONTAINS; return yyTok;} +<mediaquery>"not" {yyTok = MEDIA_NOT; return yyTok;} +<mediaquery>"only" {yyTok = MEDIA_ONLY; return yyTok;} +<mediaquery>"and" {yyTok = MEDIA_AND; return yyTok;} + +{string} {yyTok = STRING; return yyTok;} +{ident} {yyTok = IDENT; return yyTok;} +{nth} {yyTok = NTH; return yyTok;} + +"#"{ident} {yyTok = IDSEL; return yyTok;} +"#"{name} {yyTok = HEX; return yyTok;} + +"@import" {BEGIN(mediaquery); yyTok = IMPORT_SYM; return yyTok;} +"@page" {yyTok = PAGE_SYM; return yyTok;} +"@top-left-corner" {yyTok = TOPLEFTCORNER_SYM; return yyTok;} +"@top-left" {yyTok = TOPLEFT_SYM; return yyTok;} +"@top-center" {yyTok = TOPCENTER_SYM; return yyTok;} +"@top-right" {yyTok = TOPRIGHT_SYM; return yyTok;} +"@top-right-corner" {yyTok = TOPRIGHTCORNER_SYM; return yyTok;} +"@bottom-left-corner" {yyTok = BOTTOMLEFTCORNER_SYM; return yyTok;} +"@bottom-left" {yyTok = BOTTOMLEFT_SYM; return yyTok;} +"@bottom-center" {yyTok = BOTTOMCENTER_SYM; return yyTok;} +"@bottom-right" {yyTok = BOTTOMRIGHT_SYM; return yyTok;} +"@bottom-right-corner" {yyTok = BOTTOMRIGHTCORNER_SYM; return yyTok;} +"@left-top" {yyTok = LEFTTOP_SYM; return yyTok;} +"@left-middle" {yyTok = LEFTMIDDLE_SYM; return yyTok;} +"@left-bottom" {yyTok = LEFTBOTTOM_SYM; return yyTok;} +"@right-top" {yyTok = RIGHTTOP_SYM; return yyTok;} +"@right-middle" {yyTok = RIGHTMIDDLE_SYM; return yyTok;} +"@right-bottom" {yyTok = RIGHTBOTTOM_SYM; return yyTok;} +"@media" {BEGIN(mediaquery); yyTok = MEDIA_SYM; return yyTok;} +"@font-face" {yyTok = FONT_FACE_SYM; return yyTok;} +"@charset" {yyTok = CHARSET_SYM; return yyTok;} +"@namespace" {yyTok = NAMESPACE_SYM; return yyTok; } +"@-webkit-rule" {yyTok = WEBKIT_RULE_SYM; return yyTok; } +"@-webkit-decls" {yyTok = WEBKIT_DECLS_SYM; return yyTok; } +"@-webkit-value" {yyTok = WEBKIT_VALUE_SYM; return yyTok; } +"@-webkit-mediaquery" {BEGIN(mediaquery); yyTok = WEBKIT_MEDIAQUERY_SYM; return yyTok; } +"@-webkit-selector" {yyTok = WEBKIT_SELECTOR_SYM; return yyTok; } +"@-webkit-keyframes" {yyTok = WEBKIT_KEYFRAMES_SYM; return yyTok; } +"@-webkit-keyframe-rule" {yyTok = WEBKIT_KEYFRAME_RULE_SYM; return yyTok; } + +"@"{ident} {yyTok = ATKEYWORD; return yyTok; } + +"!"{w}"important" {yyTok = IMPORTANT_SYM; return yyTok;} + +{num}em {yyTok = EMS; return yyTok;} +{num}rem {yyTok = REMS; return yyTok;} +{num}__qem {yyTok = QEMS; return yyTok;} /* quirky ems */ +{num}ex {yyTok = EXS; return yyTok;} +{num}px {yyTok = PXS; return yyTok;} +{num}cm {yyTok = CMS; return yyTok;} +{num}mm {yyTok = MMS; return yyTok;} +{num}in {yyTok = INS; return yyTok;} +{num}pt {yyTok = PTS; return yyTok;} +{num}pc {yyTok = PCS; return yyTok;} +{num}deg {yyTok = DEGS; return yyTok;} +{num}rad {yyTok = RADS; return yyTok;} +{num}grad {yyTok = GRADS; return yyTok;} +{num}turn {yyTok = TURNS; return yyTok;} +{num}ms {yyTok = MSECS; return yyTok;} +{num}s {yyTok = SECS; return yyTok;} +{num}Hz {yyTok = HERTZ; return yyTok;} +{num}kHz {yyTok = KHERTZ; return yyTok;} +{num}{ident} {yyTok = DIMEN; return yyTok;} +{num}%+ {yyTok = PERCENTAGE; return yyTok;} +{intnum} {yyTok = INTEGER; return yyTok;} +{num} {yyTok = FLOATTOKEN; return yyTok;} + +"not(" {yyTok = NOTFUNCTION; return yyTok;} +"url("{w}{string}{w}")" {yyTok = URI; return yyTok;} +"url("{w}{url}{w}")" {yyTok = URI; return yyTok;} +{ident}"(" {yyTok = FUNCTION; return yyTok;} + +U\+{range} {yyTok = UNICODERANGE; return yyTok;} +U\+{h}{1,6}-{h}{1,6} {yyTok = UNICODERANGE; return yyTok;} + +<mediaquery>"{" | +<mediaquery>";" {BEGIN(INITIAL); yyTok = *yytext; return yyTok; } +. {yyTok = *yytext; return yyTok;} + +%% diff --git a/Source/WebCore/css/view-source.css b/Source/WebCore/css/view-source.css new file mode 100644 index 0000000..afceef5 --- /dev/null +++ b/Source/WebCore/css/view-source.css @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +body { + margin: 0 +} + +table { + width: 100%; + border-spacing: 0; + counter-reset: lines; + white-space: pre-wrap !important; + margin: 0; + word-break: break-word; + font-size: initial; + font-family: monospace; +} + +td { + padding: 0 !important; + vertical-align: baseline +} + +.webkit-line-gutter-backdrop, .webkit-line-number { + /* Keep this in sync with inspector.css (.webkit-line-gutter-backdrop) */ + box-sizing: border-box; + padding: 0 4px !important; + width: 31px; + background-color: rgb(240, 240, 240); + border-right: 1px solid rgb(187, 187, 187) !important; + -webkit-user-select: none; +} + +.webkit-line-gutter-backdrop { + /* Keep this in sync with inspector.css (.webkit-line-gutter-backdrop) */ + position: absolute; + z-index: -1; + left: 0; + top: 0; + height: 100% +} + +.webkit-line-number { + text-align: right; + color: rgb(128, 128, 128); + word-break: normal; + white-space: nowrap; + font-size: 9px; + font-family: Helvetica +} + +.webkit-line-number::before { + content: counter(lines); + counter-increment: lines; + -webkit-user-select: none +} + +.webkit-line-content { + padding: 0 5px !important; +} + +.webkit-html-tag { + /* Keep this in sync with inspector.css (.webkit-html-tag) */ + color: rgb(136, 18, 128); +} + +.webkit-html-attribute-name { + /* Keep this in sync with inspector.css (.webkit-html-attribute-name) */ + color: rgb(153, 69, 0); +} + +.webkit-html-attribute-value { + /* Keep this in sync with inspector.css (.webkit-html-attribute-value) */ + color: rgb(26, 26, 166); +} + +.webkit-html-external-link, .webkit-html-resource-link { + /* Keep this in sync with inspector.css (.webkit-html-external-link, .webkit-html-resource-link) */ + color: #00e; +} + +.webkit-html-external-link { + /* Keep this in sync with inspector.css (.webkit-html-external-link) */ + text-decoration: none; +} + +.webkit-html-external-link:hover { + /* Keep this in sync with inspector.css (.webkit-html-external-link:hover) */ + text-decoration: underline; +} + +.webkit-html-comment { + /* Keep this in sync with inspector.css (.webkit-html-comment) */ + color: rgb(35, 110, 37); +} + +.webkit-html-doctype { + /* Keep this in sync with inspector.css (.webkit-html-doctype) */ + color: rgb(192, 192, 192); +} + +.webkit-html-entity { + rgb(136, 18, 128); +} + +.webkit-html-message-bubble { + -webkit-box-shadow: black 0px 2px 5px; + -webkit-border-radius: 9px; + -webkit-border-fit: lines; + min-height: 13px; + font-size: 9px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + margin: 6px 25px; + padding: 0 7px 1px; +} + +.webkit-html-warning-message { + background-color: rgb(100%, 62%, 42%); + border: 2px solid rgb(100%, 52%, 21%); +} + +.webkit-html-error-message { + background-color: rgb(100%, 42%, 42%); + border: 2px solid rgb(100%, 31%, 31%); +} + +.webkit-html-message-line { + padding-left: 23px; + text-indent: -20px; +} + +.webkit-html-message-icon { + position: relative; + top: 2px; + margin: 0 4px; +} diff --git a/Source/WebCore/css/wml.css b/Source/WebCore/css/wml.css new file mode 100644 index 0000000..4bcf08f --- /dev/null +++ b/Source/WebCore/css/wml.css @@ -0,0 +1,256 @@ +/* + * The default style sheet used to render WML. + * + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * 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. + * + */ + +@namespace "http://www.wapforum.org/DTD/wml_1.1.xml" + +wml { + display: block +} + +/* children of the <head> element all have display:none */ +head { + display: none +} + +meta { + display: none +} + +access { + display: none +} + +/* generic block-level elements */ + +card { + display: block; + margin: 8px +} + +p { + display: block; + margin: 1.0__qem 0px +} + +/* tables */ + +table { + display: table; + border-collapse: separate; + border-spacing: 2px; + border-color: gray +} + +/* for tables without table section elements (can happen with XHTML or dynamically created tables) */ +table > tr { + vertical-align: middle; +} + +tr { + display: table-row; + vertical-align: inherit; + border-color: inherit +} + +td { + display: table-cell; + vertical-align: inherit +} + +/* form elements */ + +go { + display: block; + margin-top: 0__qem +} + +insertedLegend { + display: block; + padding-left: 2px; + padding-right: 2px; + border: none +} + +fieldset { + display: block; + margin-left: 2px; + margin-right: 2px; + padding: 0.35em 0.75em 0.625em; + border: 2px groove ThreeDFace +} + +do { + -webkit-appearance: button; + -webkit-box-align: center; + text-align: center; + cursor: default; + color: ButtonText; + padding: 2px 6px 3px 6px; + border: 2px outset ButtonFace; + background-color: ButtonFace; + box-sizing: border-box +} + +input, select, do { + margin: 0__qem; + font: -webkit-small-control; + color: initial; + letter-spacing: normal; + word-spacing: normal; + line-height: normal; + text-transform: none; + text-indent: 0; + text-shadow: none; + display: inline-block; + text-align: -webkit-auto; +} + +input, input[type="password"] { + -webkit-appearance: textfield; + padding: 1px; + background-color: white; + border: 2px inset; + -webkit-rtl-ordering: logical; + -webkit-user-select: text; + cursor: auto; +} + +input::-webkit-input-placeholder { + color: darkGray; +} + +input[type="password"] { + -webkit-text-security: disc !important; +} + +input:-webkit-autofill { + background-color: #FAFFBD !important; + background-image:none !important; +} + +do:disabled, select:disabled, optgroup:disabled, option:disabled { + color: GrayText +} + +do:active { + border-style: inset +} + +do:active:disabled { + border-style: outset +} + +select { + -webkit-appearance: menulist; + box-sizing: border-box; + -webkit-box-align: center; + border: 1px solid; + -webkit-border-radius: 5px; + white-space: pre; + -webkit-rtl-ordering: logical; + color: black; + background-color: white; + cursor: default; +} + +select[size], +select[multiple], +select[size][multiple] { + -webkit-appearance: listbox; + -webkit-box-align: start; + border: 1px inset gray; + -webkit-border-radius: initial; + white-space: initial; +} + +select[size="0"], +select[size="1"] { + -webkit-appearance: menulist; + -webkit-box-align: center; + border: 1px solid; + -webkit-border-radius: 5px; + white-space: pre; +} + +optgroup { + font-weight: bolder; +} + +option { + font-weight: normal; +} + +/* inline elements */ + +u { + text-decoration: underline +} + +strong, b { + font-weight: bolder +} + +i, em { + font-style: italic +} + +big { + font-size: larger +} + +small { + font-size: smaller +} + +pre { + display: block; + font-family: monospace; + white-space: pre; + margin: 1__qem 0 +} + +/* states */ + +:focus { + outline: auto 5px -webkit-focus-ring-color +} + +/* Read-only text fields do not show a focus ring but do still receive focus */ +wml:focus, card:focus { + outline: none +} + +input:focus, select:focus { + outline-offset: -2px +} + +a:-webkit-any-link, anchor:-webkit-any-link { + color: -webkit-link; + text-decoration: underline; + cursor: auto; +} + +a:-webkit-any-link:active, anchor:-webkit-any-link:active { + color: -webkit-activelink +} |