diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
| commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
| tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebCore/css | |
| download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz | |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebCore/css')
224 files changed, 53631 insertions, 0 deletions
diff --git a/Source/WebCore/css/CSSAllInOne.cpp b/Source/WebCore/css/CSSAllInOne.cpp new file mode 100644 index 000000000..50901aac7 --- /dev/null +++ b/Source/WebCore/css/CSSAllInOne.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "CSSAspectRatioValue.cpp" +#include "CSSBorderImageSliceValue.cpp" +#include "CSSBorderImageValue.cpp" +#include "CSSCanvasValue.cpp" +#include "CSSCharsetRule.cpp" +#include "CSSComputedStyleDeclaration.cpp" +#include "CSSCrossfadeValue.cpp" +#include "CSSCursorImageValue.cpp" +#include "CSSElementStyleDeclaration.cpp" +#include "CSSFlexValue.cpp" +#include "CSSFontFace.cpp" +#include "CSSFontFaceRule.cpp" +#include "CSSFontFaceSource.cpp" +#include "CSSFontFaceSrcValue.cpp" +#include "CSSFontSelector.cpp" +#include "CSSFunctionValue.cpp" +#include "CSSGradientValue.cpp" +#include "CSSImageGeneratorValue.cpp" +#include "CSSImageValue.cpp" +#include "CSSImportRule.cpp" +#include "CSSInheritedValue.cpp" +#include "CSSInitialValue.cpp" +#include "CSSLineBoxContainValue.cpp" +#include "CSSMediaRule.cpp" +#include "CSSMutableStyleDeclaration.cpp" +#include "CSSOMUtils.cpp" +#include "CSSPageRule.cpp" +#include "CSSParser.cpp" +#include "CSSParserValues.cpp" +#include "CSSPropertyLonghand.cpp" +#include "CSSPropertySourceData.cpp" +#include "CSSReflectValue.cpp" +#include "CSSRule.cpp" +#include "CSSRuleList.cpp" +#include "CSSSegmentedFontFace.cpp" +#include "CSSSelector.cpp" +#include "CSSSelectorList.cpp" +#include "CSSStyleApplyProperty.cpp" +#include "CSSStyleDeclaration.cpp" +#include "CSSStyleRule.cpp" +#include "CSSStyleSelector.cpp" +#include "CSSStyleSheet.cpp" +#include "CSSTimingFunctionValue.cpp" +#include "CSSUnicodeRangeValue.cpp" +#include "CSSValue.cpp" +#include "CSSValueList.cpp" +#include "CSSValuePool.cpp" +#include "CSSWrapShapes.cpp" diff --git a/Source/WebCore/css/CSSAspectRatioValue.cpp b/Source/WebCore/css/CSSAspectRatioValue.cpp new file mode 100644 index 000000000..18b0ded67 --- /dev/null +++ b/Source/WebCore/css/CSSAspectRatioValue.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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. + * 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. + */ + +#include "config.h" +#include "CSSAspectRatioValue.h" + +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +String CSSAspectRatioValue::customCssText() const +{ + StringBuilder result; + result.append(String::number(m_numeratorValue)); + result.append("/"); + result.append(String::number(m_denominatorValue)); + return result.toString(); +} + +} diff --git a/Source/WebCore/css/CSSAspectRatioValue.h b/Source/WebCore/css/CSSAspectRatioValue.h new file mode 100644 index 000000000..2f6b426d8 --- /dev/null +++ b/Source/WebCore/css/CSSAspectRatioValue.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 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. + * 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. + */ + +#ifndef CSSAspectRatioValue_h +#define CSSAspectRatioValue_h + +#include "CSSPrimitiveValue.h" +#include "CSSValue.h" + +namespace WebCore { + +class CSSAspectRatioValue : public CSSValue { +public: + static PassRefPtr<CSSAspectRatioValue> create(float numeratorValue, float denominatorValue) + { + return adoptRef(new CSSAspectRatioValue(numeratorValue, denominatorValue)); + } + + String customCssText() const; + + float numeratorValue() const { return m_numeratorValue; } + float denominatorValue() const { return m_denominatorValue; } + +private: + CSSAspectRatioValue(float numeratorValue, float denominatorValue) + : CSSValue(AspectRatioClass) + , m_numeratorValue(numeratorValue) + , m_denominatorValue(denominatorValue) + { + } + + float m_numeratorValue; + float m_denominatorValue; +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSBorderImageSliceValue.cpp b/Source/WebCore/css/CSSBorderImageSliceValue.cpp new file mode 100644 index 000000000..04ef2d366 --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageSliceValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 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 "CSSBorderImageSliceValue.h" + +#include "PlatformString.h" +#include "Rect.h" + +namespace WebCore { + +CSSBorderImageSliceValue::CSSBorderImageSliceValue(PassRefPtr<CSSPrimitiveValue> slices, bool fill) + : CSSValue(BorderImageSliceClass) + , m_slices(slices) + , m_fill(fill) +{ +} + +String CSSBorderImageSliceValue::customCssText() const +{ + // Dump the slices first. + String text = m_slices->cssText(); + + // Now the fill keywords if it is present. + if (m_fill) + text += " fill"; + return text; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSBorderImageSliceValue.h b/Source/WebCore/css/CSSBorderImageSliceValue.h new file mode 100644 index 000000000..d8230f474 --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageSliceValue.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 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 CSSBorderImageSliceValue_h +#define CSSBorderImageSliceValue_h + +#include "CSSPrimitiveValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Rect; + +class CSSBorderImageSliceValue : public CSSValue { +public: + static PassRefPtr<CSSBorderImageSliceValue> create(PassRefPtr<CSSPrimitiveValue> slices, bool fill) + { + return adoptRef(new CSSBorderImageSliceValue(slices, fill)); + } + + String customCssText() const; + + Quad* slices() { return m_slices ? m_slices->getQuadValue() : 0; } + + // These four values are used to make "cuts" in the border image. They can be numbers + // or percentages. + RefPtr<CSSPrimitiveValue> m_slices; + bool m_fill; + +private: + CSSBorderImageSliceValue(PassRefPtr<CSSPrimitiveValue> slices, bool fill); +}; + +} // namespace WebCore + +#endif // CSSBorderImageSliceValue_h diff --git a/Source/WebCore/css/CSSBorderImageValue.cpp b/Source/WebCore/css/CSSBorderImageValue.cpp new file mode 100644 index 000000000..846ea6dc5 --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageValue.cpp @@ -0,0 +1,81 @@ +/* + * (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<CSSBorderImageSliceValue> imageSlice, + PassRefPtr<CSSValue> borderSlice, PassRefPtr<CSSValue> outset, PassRefPtr<CSSValue> repeat) + : CSSValue(BorderImageClass) + , m_image(image) + , m_imageSlice(imageSlice) + , m_borderSlice(borderSlice) + , m_outset(outset) + , m_repeat(repeat) +{ +} + +String CSSBorderImageValue::customCssText() const +{ + // Image first. + String text; + + if (m_image) + text += m_image->cssText(); + + // Now the slices. + if (m_imageSlice) { + if (!text.isEmpty()) + text += " "; + text += m_imageSlice->cssText(); + } + + // Now the border widths. + if (m_borderSlice) { + text += " / "; + text += m_borderSlice->cssText(); + } + + if (m_outset) { + text += " / "; + text += m_outset->cssText(); + } + + if (m_repeat) { + // Now the keywords. + if (!text.isEmpty()) + text += " "; + text += m_repeat->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 000000000..675758cc3 --- /dev/null +++ b/Source/WebCore/css/CSSBorderImageValue.h @@ -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. + */ + +#ifndef CSSBorderImageValue_h +#define CSSBorderImageValue_h + +#include "CSSBorderImageSliceValue.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<CSSBorderImageSliceValue> imageSlice, + PassRefPtr<CSSValue> borderSlice, PassRefPtr<CSSValue> outset, PassRefPtr<CSSValue> repeat) + { + return adoptRef(new CSSBorderImageValue(image, imageSlice, borderSlice, outset, repeat)); + } + + String customCssText() const; + + CSSValue* imageValue() const { return m_image.get(); } + + 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<CSSBorderImageSliceValue> m_imageSlice; + + // These four values are used to make "cuts" in the border image drawing area. + // They can be numbers, percentages or lengths. + RefPtr<CSSValue> m_borderSlice; + + // The outset values are used to inflate the border image drawing area. + RefPtr<CSSValue> m_outset; + + // Values for how to handle the scaling/stretching/tiling of the image slices. + RefPtr<CSSValue> m_repeat; + +private: + CSSBorderImageValue(PassRefPtr<CSSValue> image, PassRefPtr<CSSBorderImageSliceValue>, PassRefPtr<CSSValue> borderSlice, + PassRefPtr<CSSValue> outset, PassRefPtr<CSSValue> repeat); +}; + +} // namespace WebCore + +#endif // CSSBorderImageValue_h diff --git a/Source/WebCore/css/CSSCanvasValue.cpp b/Source/WebCore/css/CSSCanvasValue.cpp new file mode 100644 index 000000000..783ceef82 --- /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(&m_canvasObserver); +} + +String CSSCanvasValue::customCssText() 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 = clients().end(); + for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr) + const_cast<RenderObject*>(curr->first)->imageChanged(static_cast<WrappedImagePtr>(this), &imageChangeRect); +} + +void CSSCanvasValue::canvasResized(HTMLCanvasElement*) +{ + RenderObjectSizeCountMap::const_iterator end = clients().end(); + for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr) + const_cast<RenderObject*>(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(&m_canvasObserver); + } + return m_element; +} + +PassRefPtr<Image> CSSCanvasValue::image(RenderObject* renderer, const IntSize& /*size*/) +{ + ASSERT(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 000000000..efad7e692 --- /dev/null +++ b/Source/WebCore/css/CSSCanvasValue.h @@ -0,0 +1,98 @@ +/* + * 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 { +public: + static PassRefPtr<CSSCanvasValue> create() { return adoptRef(new CSSCanvasValue); } + ~CSSCanvasValue(); + + String customCssText() const; + + PassRefPtr<Image> image(RenderObject*, const IntSize&); + bool isFixedSize() const { return true; } + IntSize fixedSize(const RenderObject*); + + bool isPending() const { return false; } + void loadSubimages(CachedResourceLoader*) { } + + void setName(const String& name) { m_name = name; } + +private: + CSSCanvasValue() + : CSSImageGeneratorValue(CanvasClass) + , m_canvasObserver(this) + , m_element(0) + { + } + + // NOTE: We put the CanvasObserver in a member instead of inheriting from it + // to avoid adding a vptr to CSSCanvasValue. + class CanvasObserverProxy : public CanvasObserver { + public: + CanvasObserverProxy(CSSCanvasValue* ownerValue) : m_ownerValue(ownerValue) { } + virtual ~CanvasObserverProxy() { } + virtual void canvasChanged(HTMLCanvasElement* canvas, const FloatRect& changedRect) + { + m_ownerValue->canvasChanged(canvas, changedRect); + } + virtual void canvasResized(HTMLCanvasElement* canvas) + { + m_ownerValue->canvasResized(canvas); + } + virtual void canvasDestroyed(HTMLCanvasElement* canvas) + { + m_ownerValue->canvasDestroyed(canvas); + } + private: + CSSCanvasValue* m_ownerValue; + }; + + void canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect); + void canvasResized(HTMLCanvasElement*); + void canvasDestroyed(HTMLCanvasElement*); + + HTMLCanvasElement* element(Document*); + + CanvasObserverProxy m_canvasObserver; + + // 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 000000000..b7a77ac52 --- /dev/null +++ b/Source/WebCore/css/CSSCharsetRule.cpp @@ -0,0 +1,37 @@ +/* + * 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, CSSRule::CHARSET_RULE) + , m_encoding(encoding) +{ +} + +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 000000000..d08efa7df --- /dev/null +++ b/Source/WebCore/css/CSSCharsetRule.h @@ -0,0 +1,50 @@ +/* + * (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)); + } + + const String& encoding() const { return m_encoding; } + void setEncoding(const String& encoding, ExceptionCode&) { m_encoding = encoding; } + + String cssText() const; + +private: + CSSCharsetRule(CSSStyleSheet* parent, const String& encoding); + + 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 000000000..2b158ff8b --- /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 000000000..3e0dc8c21 --- /dev/null +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -0,0 +1,2464 @@ +/* + * Copyright (C) 2004 Zack Rusin <zack@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> + * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> + * Copyright (C) 2011 Sencha, 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 + */ + +#include "config.h" +#include "CSSComputedStyleDeclaration.h" + +#include "AnimationController.h" +#include "CSSAspectRatioValue.h" +#include "CSSBorderImageValue.h" +#include "CSSLineBoxContainValue.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 "CSSValuePool.h" +#include "ContentData.h" +#include "CounterContent.h" +#include "CursorList.h" +#if ENABLE(CSS_SHADERS) +#include "CustomFilterOperation.h" +#endif +#include "Document.h" +#include "ExceptionCode.h" +#include "FontFeatureSettings.h" +#include "FontFeatureValue.h" +#include "FontValue.h" +#include "Pair.h" +#include "Rect.h" +#include "RenderBox.h" +#include "RenderLayer.h" +#include "RenderStyle.h" +#include "ShadowValue.h" +#if ENABLE(CSS_FILTERS) +#include "WebKitCSSFilterValue.h" +#endif +#include "WebKitCSSTransformValue.h" +#include "WebKitFontFamilyNames.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, + CSSPropertyBorderImageOutset, + CSSPropertyBorderImageRepeat, + CSSPropertyBorderImageSlice, + CSSPropertyBorderImageSource, + CSSPropertyBorderImageWidth, + 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, + CSSPropertyImageRendering, + 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, + CSSPropertyWebkitColumnAxis, + CSSPropertyWebkitColumnCount, + CSSPropertyWebkitColumnGap, + CSSPropertyWebkitColumnRuleColor, + CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleWidth, + CSSPropertyWebkitColumnSpan, + CSSPropertyWebkitColumnWidth, +#if ENABLE(DASHBOARD_SUPPORT) + CSSPropertyWebkitDashboardRegion, +#endif + CSSPropertyWebkitFlexOrder, + CSSPropertyWebkitFlexPack, + CSSPropertyWebkitFlexAlign, + CSSPropertyWebkitFlexDirection, + CSSPropertyWebkitFlexFlow, + CSSPropertyWebkitFlexWrap, + CSSPropertyWebkitFontSmoothing, +#if ENABLE(CSS_GRID_LAYOUT) + CSSPropertyWebkitGridColumns, + CSSPropertyWebkitGridRows, +#endif + CSSPropertyWebkitHighlight, + CSSPropertyWebkitHyphenateCharacter, + CSSPropertyWebkitHyphenateLimitAfter, + CSSPropertyWebkitHyphenateLimitBefore, + CSSPropertyWebkitHyphenateLimitLines, + CSSPropertyWebkitHyphens, + CSSPropertyWebkitLineBoxContain, + CSSPropertyWebkitLineBreak, + CSSPropertyWebkitLineClamp, + CSSPropertyWebkitLineGrid, + CSSPropertyWebkitLineGridSnap, + CSSPropertyWebkitLocale, + CSSPropertyWebkitMarginBeforeCollapse, + CSSPropertyWebkitMarginAfterCollapse, + CSSPropertyWebkitMarqueeDirection, + CSSPropertyWebkitMarqueeIncrement, + CSSPropertyWebkitMarqueeRepetition, + CSSPropertyWebkitMarqueeStyle, + CSSPropertyWebkitMaskAttachment, + CSSPropertyWebkitMaskBoxImage, + CSSPropertyWebkitMaskBoxImageOutset, + CSSPropertyWebkitMaskBoxImageRepeat, + CSSPropertyWebkitMaskBoxImageSlice, + CSSPropertyWebkitMaskBoxImageSource, + CSSPropertyWebkitMaskBoxImageWidth, + CSSPropertyWebkitMaskClip, + CSSPropertyWebkitMaskComposite, + CSSPropertyWebkitMaskImage, + CSSPropertyWebkitMaskOrigin, + CSSPropertyWebkitMaskPosition, + CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskSize, + CSSPropertyWebkitNbspMode, + CSSPropertyWebkitPerspective, + CSSPropertyWebkitPerspectiveOrigin, + CSSPropertyWebkitPrintColorAdjust, + CSSPropertyWebkitRtlOrdering, +#if ENABLE(TOUCH_EVENTS) + CSSPropertyWebkitTapHighlightColor, +#endif + CSSPropertyWebkitTextCombine, + CSSPropertyWebkitTextDecorationsInEffect, + CSSPropertyWebkitTextEmphasisColor, + CSSPropertyWebkitTextEmphasisPosition, + CSSPropertyWebkitTextEmphasisStyle, + CSSPropertyWebkitTextFillColor, + CSSPropertyWebkitTextOrientation, + CSSPropertyWebkitTextSecurity, + CSSPropertyWebkitTextStrokeColor, + CSSPropertyWebkitTextStrokeWidth, + CSSPropertyWebkitTransform, + CSSPropertyWebkitTransformOrigin, + CSSPropertyWebkitTransformStyle, + CSSPropertyWebkitTransitionDelay, + CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionProperty, + CSSPropertyWebkitTransitionTimingFunction, + CSSPropertyWebkitUserDrag, + CSSPropertyWebkitUserModify, + CSSPropertyWebkitUserSelect, + CSSPropertyWebkitWritingMode, + CSSPropertyWebkitFlowInto, + CSSPropertyWebkitFlowFrom, + CSSPropertyWebkitRegionOverflow, + CSSPropertyWebkitRegionBreakAfter, + CSSPropertyWebkitRegionBreakBefore, + CSSPropertyWebkitRegionBreakInside, + CSSPropertyWebkitWrapFlow, + CSSPropertyWebkitWrapMargin, + CSSPropertyWebkitWrapPadding, + CSSPropertyWebkitWrapThrough +#if ENABLE(SVG) + , + CSSPropertyClipPath, + CSSPropertyClipRule, + CSSPropertyMask, + CSSPropertyFilter, + CSSPropertyFloodColor, + CSSPropertyFloodOpacity, + CSSPropertyLightingColor, + CSSPropertyStopColor, + CSSPropertyStopOpacity, + CSSPropertyColorInterpolation, + CSSPropertyColorInterpolationFilters, + CSSPropertyColorRendering, + CSSPropertyFill, + CSSPropertyFillOpacity, + CSSPropertyFillRule, + CSSPropertyMarkerEnd, + CSSPropertyMarkerMid, + CSSPropertyMarkerStart, + CSSPropertyShapeRendering, + CSSPropertyStroke, + CSSPropertyStrokeDasharray, + CSSPropertyStrokeDashoffset, + CSSPropertyStrokeLinecap, + CSSPropertyStrokeLinejoin, + CSSPropertyStrokeMiterlimit, + CSSPropertyStrokeOpacity, + CSSPropertyStrokeWidth, + CSSPropertyAlignmentBaseline, + CSSPropertyBaselineShift, + CSSPropertyDominantBaseline, + CSSPropertyKerning, + CSSPropertyTextAnchor, + CSSPropertyWritingMode, + CSSPropertyGlyphOrientationHorizontal, + CSSPropertyGlyphOrientationVertical, + CSSPropertyWebkitSvgShadow, + CSSPropertyVectorEffect +#endif +}; + +const unsigned numComputedProperties = WTF_ARRAY_LENGTH(computedProperties); + +static int valueForRepeatRule(int rule) +{ + switch (rule) { + case RepeatImageRule: + return CSSValueRepeat; + case RoundImageRule: + return CSSValueRound; + case SpaceImageRule: + return CSSValueSpace; + default: + return CSSValueStretch; + } +} + +static PassRefPtr<CSSBorderImageSliceValue> valueForNinePieceImageSlice(const NinePieceImage& image, CSSValuePool* cssValuePool) +{ + // Create the slices. + RefPtr<CSSPrimitiveValue> top; + RefPtr<CSSPrimitiveValue> right; + RefPtr<CSSPrimitiveValue> bottom; + RefPtr<CSSPrimitiveValue> left; + + if (image.imageSlices().top().isPercent()) + top = cssValuePool->createValue(image.imageSlices().top().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + top = cssValuePool->createValue(image.imageSlices().top().value(), CSSPrimitiveValue::CSS_NUMBER); + + if (image.imageSlices().right() == image.imageSlices().top() && image.imageSlices().bottom() == image.imageSlices().top() + && image.imageSlices().left() == image.imageSlices().top()) { + right = top; + bottom = top; + left = top; + } else { + if (image.imageSlices().right().isPercent()) + right = cssValuePool->createValue(image.imageSlices().right().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + right = cssValuePool->createValue(image.imageSlices().right().value(), CSSPrimitiveValue::CSS_NUMBER); + + if (image.imageSlices().bottom() == image.imageSlices().top() && image.imageSlices().right() == image.imageSlices().left()) { + bottom = top; + left = right; + } else { + if (image.imageSlices().bottom().isPercent()) + bottom = cssValuePool->createValue(image.imageSlices().bottom().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + bottom = cssValuePool->createValue(image.imageSlices().bottom().value(), CSSPrimitiveValue::CSS_NUMBER); + + if (image.imageSlices().left() == image.imageSlices().right()) + left = right; + else { + if (image.imageSlices().left().isPercent()) + left = cssValuePool->createValue(image.imageSlices().left().value(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + left = cssValuePool->createValue(image.imageSlices().left().value(), CSSPrimitiveValue::CSS_NUMBER); + } + } + } + + RefPtr<Quad> quad = Quad::create(); + quad->setTop(top); + quad->setRight(right); + quad->setBottom(bottom); + quad->setLeft(left); + + return CSSBorderImageSliceValue::create(cssValuePool->createValue(quad.release()), image.fill()); +} + +static PassRefPtr<CSSPrimitiveValue> valueForNinePieceImageQuad(const LengthBox& box, CSSValuePool* cssValuePool) +{ + // Create the slices. + RefPtr<CSSPrimitiveValue> top; + RefPtr<CSSPrimitiveValue> right; + RefPtr<CSSPrimitiveValue> bottom; + RefPtr<CSSPrimitiveValue> left; + + if (box.top().isRelative()) + top = cssValuePool->createValue(box.top().value(), CSSPrimitiveValue::CSS_NUMBER); + else + top = cssValuePool->createValue(box.top()); + + if (box.right() == box.top() && box.bottom() == box.top() && box.left() == box.top()) { + right = top; + bottom = top; + left = top; + } else { + if (box.right().isRelative()) + right = cssValuePool->createValue(box.right().value(), CSSPrimitiveValue::CSS_NUMBER); + else + right = cssValuePool->createValue(box.right()); + + if (box.bottom() == box.top() && box.right() == box.left()) { + bottom = top; + left = right; + } else { + if (box.bottom().isRelative()) + bottom = cssValuePool->createValue(box.bottom().value(), CSSPrimitiveValue::CSS_NUMBER); + else + bottom = cssValuePool->createValue(box.bottom()); + + if (box.left() == box.right()) + left = right; + else { + if (box.left().isRelative()) + left = cssValuePool->createValue(box.left().value(), CSSPrimitiveValue::CSS_NUMBER); + else + left = cssValuePool->createValue(box.left()); + } + } + } + + RefPtr<Quad> quad = Quad::create(); + quad->setTop(top); + quad->setRight(right); + quad->setBottom(bottom); + quad->setLeft(left); + + return cssValuePool->createValue(quad.release()); +} + +static PassRefPtr<CSSValue> valueForNinePieceImageRepeat(const NinePieceImage& image, CSSValuePool* cssValuePool) +{ + RefPtr<CSSPrimitiveValue> horizontalRepeat; + RefPtr<CSSPrimitiveValue> verticalRepeat; + + horizontalRepeat = cssValuePool->createIdentifierValue(valueForRepeatRule(image.horizontalRule())); + if (image.horizontalRule() == image.verticalRule()) + verticalRepeat = horizontalRepeat; + else + verticalRepeat = cssValuePool->createIdentifierValue(valueForRepeatRule(image.verticalRule())); + return cssValuePool->createValue(Pair::create(horizontalRepeat.release(), verticalRepeat.release())); +} + +static PassRefPtr<CSSValue> valueForNinePieceImage(const NinePieceImage& image, CSSValuePool* cssValuePool) +{ + if (!image.hasImage()) + return cssValuePool->createIdentifierValue(CSSValueNone); + + // Image first. + RefPtr<CSSValue> imageValue; + if (image.image()) + imageValue = image.image()->cssValue(); + + // Create the image slice. + RefPtr<CSSBorderImageSliceValue> imageSlices = valueForNinePieceImageSlice(image, cssValuePool); + + // Create the border area slices. + RefPtr<CSSValue> borderSlices = valueForNinePieceImageQuad(image.borderSlices(), cssValuePool); + + // Create the border outset. + RefPtr<CSSValue> outset = valueForNinePieceImageQuad(image.outset(), cssValuePool); + + // Create the repeat rules. + RefPtr<CSSValue> repeat = valueForNinePieceImageRepeat(image, cssValuePool); + + return CSSBorderImageValue::create(imageValue.release(), imageSlices.release(), borderSlices.release(), outset.release(), repeat); +} + +inline static PassRefPtr<CSSPrimitiveValue> zoomAdjustedPixelValue(int value, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + return cssValuePool->createValue(adjustForAbsoluteZoom(value, style), CSSPrimitiveValue::CSS_PX); +} + +inline static PassRefPtr<CSSPrimitiveValue> zoomAdjustedNumberValue(double value, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + return cssValuePool->createValue(value / style->effectiveZoom(), CSSPrimitiveValue::CSS_NUMBER); +} + +static PassRefPtr<CSSValue> zoomAdjustedPixelValueForLength(const Length& length, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + if (length.isFixed()) + return zoomAdjustedPixelValue(length.value(), style, cssValuePool); + return cssValuePool->createValue(length); +} + +static PassRefPtr<CSSValue> valueForReflection(const StyleReflection* reflection, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + if (!reflection) + return cssValuePool->createIdentifierValue(CSSValueNone); + + RefPtr<CSSPrimitiveValue> offset; + if (reflection->offset().isPercent()) + offset = cssValuePool->createValue(reflection->offset().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + else + offset = zoomAdjustedPixelValue(reflection->offset().value(), style, cssValuePool); + + return CSSReflectValue::create(reflection->direction(), offset.release(), valueForNinePieceImage(reflection->mask(), cssValuePool)); +} + +static PassRefPtr<CSSValue> getPositionOffsetValue(RenderStyle* style, int propertyID, CSSValuePool* cssValuePool) +{ + 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, cssValuePool); + return cssValuePool->createValue(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 cssValuePool->createValue(l); + + return cssValuePool->createIdentifierValue(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. + CSSValuePool* cssValuePool = m_node->document()->cssValuePool().get(); + if (!color.isValid()) + return cssValuePool->createColorValue(style->color().rgb()); + return cssValuePool->createColorValue(color.rgb()); +} + +static PassRefPtr<CSSValue> getBorderRadiusCornerValue(LengthSize radius, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (radius.width() == radius.height()) { + if (radius.width().type() == Percent) + return cssValuePool->createValue(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + return zoomAdjustedPixelValue(radius.width().value(), style, cssValuePool); + } + if (radius.width().type() == Percent) + list->append(cssValuePool->createValue(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); + else + list->append(zoomAdjustedPixelValue(radius.width().value(), style, cssValuePool)); + if (radius.height().type() == Percent) + list->append(cssValuePool->createValue(radius.height().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); + else + list->append(zoomAdjustedPixelValue(radius.height().value(), style, cssValuePool)); + return list.release(); +} + +static LayoutRect sizingBox(RenderObject* renderer) +{ + if (!renderer->isBox()) + return LayoutRect(); + + 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, CSSValuePool* cssValuePool) +{ + if (!renderer || style->transform().operations().isEmpty()) + return cssValuePool->createIdentifierValue(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(cssValuePool->createValue(transform.a(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.b(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.c(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.d(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(zoomAdjustedNumberValue(transform.e(), style, cssValuePool)); + transformVal->append(zoomAdjustedNumberValue(transform.f(), style, cssValuePool)); + } else { + transformVal = WebKitCSSTransformValue::create(WebKitCSSTransformValue::Matrix3DTransformOperation); + + transformVal->append(cssValuePool->createValue(transform.m11(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m12(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m13(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m14(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(cssValuePool->createValue(transform.m21(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m22(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m23(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m24(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(cssValuePool->createValue(transform.m31(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m32(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m33(), CSSPrimitiveValue::CSS_NUMBER)); + transformVal->append(cssValuePool->createValue(transform.m34(), CSSPrimitiveValue::CSS_NUMBER)); + + transformVal->append(zoomAdjustedNumberValue(transform.m41(), style, cssValuePool)); + transformVal->append(zoomAdjustedNumberValue(transform.m42(), style, cssValuePool)); + transformVal->append(zoomAdjustedNumberValue(transform.m43(), style, cssValuePool)); + transformVal->append(cssValuePool->createValue(transform.m44(), CSSPrimitiveValue::CSS_NUMBER)); + } + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(transformVal); + + return list.release(); +} + +#if ENABLE(CSS_FILTERS) +PassRefPtr<CSSValue> CSSComputedStyleDeclaration::valueForFilter(RenderStyle* style) const +{ + CSSValuePool* cssValuePool = m_node->document()->cssValuePool().get(); + + if (style->filter().operations().isEmpty()) + return cssValuePool->createIdentifierValue(CSSValueNone); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + + RefPtr<WebKitCSSFilterValue> filterValue; + + Vector<RefPtr<FilterOperation> >::const_iterator end = style->filter().operations().end(); + for (Vector<RefPtr<FilterOperation> >::const_iterator it = style->filter().operations().begin(); it != end; ++it) { + FilterOperation* filterOperation = (*it).get(); + switch (filterOperation->getOperationType()) { + case FilterOperation::REFERENCE: { + ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation); + filterValue->append(cssValuePool->createValue(referenceOperation->reference(), CSSPrimitiveValue::CSS_STRING)); + break; + } + case FilterOperation::GRAYSCALE: { + BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::GrayscaleFilterOperation); + filterValue->append(cssValuePool->createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::SEPIA: { + BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::SepiaFilterOperation); + filterValue->append(cssValuePool->createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::SATURATE: { + BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::SaturateFilterOperation); + filterValue->append(cssValuePool->createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::HUE_ROTATE: { + BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::HueRotateFilterOperation); + filterValue->append(cssValuePool->createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_DEG)); + break; + } + case FilterOperation::INVERT: { + BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::InvertFilterOperation); + filterValue->append(cssValuePool->createValue(componentTransferOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::OPACITY: { + BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::OpacityFilterOperation); + filterValue->append(cssValuePool->createValue(componentTransferOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::BRIGHTNESS: { + BasicComponentTransferFilterOperation* brightnessOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::BrightnessFilterOperation); + filterValue->append(cssValuePool->createValue(brightnessOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::CONTRAST: { + BasicComponentTransferFilterOperation* contrastOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ContrastFilterOperation); + filterValue->append(cssValuePool->createValue(contrastOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::BLUR: { + BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::BlurFilterOperation); + filterValue->append(zoomAdjustedPixelValue(blurOperation->stdDeviation().value(), style, cssValuePool)); + break; + } + case FilterOperation::DROP_SHADOW: { + DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::DropShadowFilterOperation); + // We want our computed style to look like that of a text shadow (has neither spread nor inset style). + ShadowData shadowData = ShadowData(dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->stdDeviation(), 0, Normal, false, dropShadowOperation->color()); + filterValue->append(valueForShadow(&shadowData, CSSPropertyTextShadow, style)); + break; + } +#if ENABLE(CSS_SHADERS) + case FilterOperation::CUSTOM: { + CustomFilterOperation* customOperation = static_cast<CustomFilterOperation*>(filterOperation); + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation); + + // The output should be verbose, even if the values are the default ones. + + RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated(); + if (customOperation->vertexShader()) + shadersList->append(customOperation->vertexShader()->cssValue()); + else + shadersList->append(cssValuePool->createIdentifierValue(CSSValueNone)); + if (customOperation->fragmentShader()) + shadersList->append(customOperation->fragmentShader()->cssValue()); + else + shadersList->append(cssValuePool->createIdentifierValue(CSSValueNone)); + filterValue->append(shadersList.release()); + + RefPtr<CSSValueList> meshParameters = CSSValueList::createSpaceSeparated(); + meshParameters->append(cssValuePool->createValue(customOperation->meshRows(), CSSPrimitiveValue::CSS_NUMBER)); + meshParameters->append(cssValuePool->createValue(customOperation->meshColumns(), CSSPrimitiveValue::CSS_NUMBER)); + meshParameters->append(cssValuePool->createValue(customOperation->meshBoxType())); + + // FIXME: The specification doesn't have any "attached" identifier. Should we add one? + // https://bugs.webkit.org/show_bug.cgi?id=72700 + if (customOperation->meshType() == CustomFilterOperation::DETACHED) + meshParameters->append(cssValuePool->createIdentifierValue(CSSValueDetached)); + + filterValue->append(meshParameters.release()); + + break; + } +#endif + default: + filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::UnknownFilterOperation); + break; + } + list->append(filterValue); + } + + return list.release(); +} +#endif + +#if ENABLE(CSS_GRID_LAYOUT) +static PassRefPtr<CSSValue> valueForGridTrackBreadth(const Length& trackLength, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + if (trackLength.isPercent()) + return cssValuePool->createValue(trackLength); + if (trackLength.isAuto()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(trackLength.value(), style, cssValuePool); +} + +static PassRefPtr<CSSValue> valueForGridTrackList(const Vector<Length>& trackLengths, const RenderStyle* style, CSSValuePool* cssValuePool) +{ + // We should have at least an element! + ASSERT(trackLengths.size()); + + // Handle the 'none' case here. + if (trackLengths.size() == 1 && trackLengths[0].isUndefined()) + return cssValuePool->createIdentifierValue(CSSValueNone); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (size_t i = 0; i < trackLengths.size(); ++i) + list->append(valueForGridTrackBreadth(trackLengths[i], style, cssValuePool)); + return list.release(); +} +#endif + +static PassRefPtr<CSSValue> getDelayValue(const AnimationList* animList, CSSValuePool* cssValuePool) +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + if (animList) { + for (size_t i = 0; i < animList->size(); ++i) + list->append(cssValuePool->createValue(animList->animation(i)->delay(), CSSPrimitiveValue::CSS_S)); + } else { + // Note that initialAnimationDelay() is used for both transitions and animations + list->append(cssValuePool->createValue(Animation::initialAnimationDelay(), CSSPrimitiveValue::CSS_S)); + } + return list.release(); +} + +static PassRefPtr<CSSValue> getDurationValue(const AnimationList* animList, CSSValuePool* cssValuePool) +{ + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + if (animList) { + for (size_t i = 0; i < animList->size(); ++i) + list->append(cssValuePool->createValue(animList->animation(i)->duration(), CSSPrimitiveValue::CSS_S)); + } else { + // Note that initialAnimationDuration() is used for both transitions and animations + list->append(cssValuePool->createValue(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(); +} + +static PassRefPtr<CSSValue> createLineBoxContainValue(CSSValuePool* cssValuePool, unsigned lineBoxContain) +{ + if (!lineBoxContain) + return cssValuePool->createIdentifierValue(CSSValueNone); + return CSSLineBoxContainValue::create(lineBoxContain); +} + +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; + + CSSValuePool* cssValuePool = m_node->document()->cssValuePool().get(); + + if (int keywordSize = style->fontDescription().keywordSize()) + return cssValuePool->createIdentifierValue(cssIdentifierForFontSizeKeyword(keywordSize)); + + + return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style.get(), cssValuePool); +} + +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 +{ + CSSValuePool* cssValuePool = m_node->document()->cssValuePool().get(); + if (!shadow) + return cssValuePool->createIdentifierValue(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, cssValuePool); + RefPtr<CSSPrimitiveValue> y = zoomAdjustedPixelValue(s->y(), style, cssValuePool); + RefPtr<CSSPrimitiveValue> blur = zoomAdjustedPixelValue(s->blur(), style, cssValuePool); + RefPtr<CSSPrimitiveValue> spread = propertyID == CSSPropertyTextShadow ? PassRefPtr<CSSPrimitiveValue>() : zoomAdjustedPixelValue(s->spread(), style, cssValuePool); + RefPtr<CSSPrimitiveValue> style = propertyID == CSSPropertyTextShadow || s->style() == Normal ? PassRefPtr<CSSPrimitiveValue>() : cssValuePool->createIdentifierValue(CSSValueInset); + RefPtr<CSSPrimitiveValue> color = cssValuePool->createColorValue(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) +{ + if (family == cursiveFamily) + return CSSValueCursive; + if (family == fantasyFamily) + return CSSValueFantasy; + if (family == monospaceFamily) + return CSSValueMonospace; + if (family == pictographFamily) + return CSSValueWebkitPictograph; + if (family == sansSerifFamily) + return CSSValueSansSerif; + if (family == serifFamily) + return CSSValueSerif; + return 0; +} + +static PassRefPtr<CSSPrimitiveValue> valueForFamily(const AtomicString& family, CSSValuePool* cssValuePool) +{ + if (int familyIdentifier = identifierForFamily(family)) + return cssValuePool->createIdentifierValue(familyIdentifier); + return cssValuePool->createValue(family.string(), CSSPrimitiveValue::CSS_STRING); +} + +static PassRefPtr<CSSValue> renderTextDecorationFlagsToCSSValue(int textDecoration, CSSValuePool* cssValuePool) +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (textDecoration & UNDERLINE) + list->append(cssValuePool->createIdentifierValue(CSSValueUnderline)); + if (textDecoration & OVERLINE) + list->append(cssValuePool->createIdentifierValue(CSSValueOverline)); + if (textDecoration & LINE_THROUGH) + list->append(cssValuePool->createIdentifierValue(CSSValueLineThrough)); + if (textDecoration & BLINK) + list->append(cssValuePool->createIdentifierValue(CSSValueBlink)); + + if (!list->length()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return list; +} + +static PassRefPtr<CSSValue> fillRepeatToCSSValue(EFillRepeat xRepeat, EFillRepeat yRepeat, CSSValuePool* cssValuePool) +{ + // 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 cssValuePool->createValue(xRepeat); + if (xRepeat == RepeatFill && yRepeat == NoRepeatFill) + return cssValuePool->createIdentifierValue(CSSValueRepeatX); + if (xRepeat == NoRepeatFill && yRepeat == RepeatFill) + return cssValuePool->createIdentifierValue(CSSValueRepeatY); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(cssValuePool->createValue(xRepeat)); + list->append(cssValuePool->createValue(yRepeat)); + return list.release(); +} + +static PassRefPtr<CSSValue> fillSizeToCSSValue(const FillSize& fillSize, CSSValuePool* cssValuePool) +{ + if (fillSize.type == Contain) + return cssValuePool->createIdentifierValue(CSSValueContain); + + if (fillSize.type == Cover) + return cssValuePool->createIdentifierValue(CSSValueCover); + + if (fillSize.size.height().isAuto()) + return cssValuePool->createValue(fillSize.size.width()); + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(cssValuePool->createValue(fillSize.size.width())); + list->append(cssValuePool->createValue(fillSize.size.height())); + return list.release(); +} + +static PassRefPtr<CSSValue> contentToCSSValue(const RenderStyle* style, CSSValuePool* cssValuePool) +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (const ContentData* contentData = style->contentData(); contentData; contentData = contentData->next()) { + if (contentData->isCounter()) { + const CounterContent* counter = static_cast<const CounterContentData*>(contentData)->counter(); + ASSERT(counter); + list->append(cssValuePool->createValue(counter->identifier(), CSSPrimitiveValue::CSS_COUNTER_NAME)); + } else if (contentData->isImage()) { + const StyleImage* image = static_cast<const ImageContentData*>(contentData)->image(); + ASSERT(image); + list->append(image->cssValue()); + } else if (contentData->isText()) + list->append(cssValuePool->createValue(static_cast<const TextContentData*>(contentData)->text(), CSSPrimitiveValue::CSS_STRING)); + } + if (!style->regionThread().isNull()) + list->append(cssValuePool->createValue(style->regionThread(), CSSPrimitiveValue::CSS_STRING)); + return list.release(); +} + +static PassRefPtr<CSSValue> counterToCSSValue(const RenderStyle* style, int propertyID, CSSValuePool* cssValuePool) +{ + const CounterDirectiveMap* map = style->counterDirectives(); + if (!map) + return 0; + + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (CounterDirectiveMap::const_iterator it = map->begin(); it != map->end(); ++it) { + list->append(cssValuePool->createValue(it->first.get(), CSSPrimitiveValue::CSS_STRING)); + short number = propertyID == CSSPropertyCounterIncrement ? it->second.m_incrementValue : it->second.m_resetValue; + list->append(cssValuePool->createValue((double)number, CSSPrimitiveValue::CSS_NUMBER)); + } + 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))); +} + +static PassRefPtr<CSSValueList> fontFamilyFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + const FontFamily& firstFamily = style->fontDescription().family(); + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FontFamily* family = &firstFamily; family; family = family->next()) + list->append(valueForFamily(family->family(), cssValuePool)); + return list.release(); +} + +static PassRefPtr<CSSPrimitiveValue> lineHeightFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + Length length = style->lineHeight(); + if (length.isNegative()) + return cssValuePool->createIdentifierValue(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, cssValuePool); + return zoomAdjustedPixelValue(length.value(), style, cssValuePool); +} + +static PassRefPtr<CSSPrimitiveValue> fontSizeFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style, cssValuePool); +} + +static PassRefPtr<CSSPrimitiveValue> fontStyleFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + if (style->fontDescription().italic()) + return cssValuePool->createIdentifierValue(CSSValueItalic); + return cssValuePool->createIdentifierValue(CSSValueNormal); +} + +static PassRefPtr<CSSPrimitiveValue> fontVariantFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + if (style->fontDescription().smallCaps()) + return cssValuePool->createIdentifierValue(CSSValueSmallCaps); + return cssValuePool->createIdentifierValue(CSSValueNormal); +} + +static PassRefPtr<CSSPrimitiveValue> fontWeightFromStyle(RenderStyle* style, CSSValuePool* cssValuePool) +{ + switch (style->fontDescription().weight()) { + case FontWeight100: + return cssValuePool->createIdentifierValue(CSSValue100); + case FontWeight200: + return cssValuePool->createIdentifierValue(CSSValue200); + case FontWeight300: + return cssValuePool->createIdentifierValue(CSSValue300); + case FontWeightNormal: + return cssValuePool->createIdentifierValue(CSSValueNormal); + case FontWeight500: + return cssValuePool->createIdentifierValue(CSSValue500); + case FontWeight600: + return cssValuePool->createIdentifierValue(CSSValue600); + case FontWeightBold: + return cssValuePool->createIdentifierValue(CSSValueBold); + case FontWeight800: + return cssValuePool->createIdentifierValue(CSSValue800); + case FontWeight900: + return cssValuePool->createIdentifierValue(CSSValue900); + } + ASSERT_NOT_REACHED(); + return cssValuePool->createIdentifierValue(CSSValueNormal); +} + +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; + + CSSValuePool* cssValuePool = node->document()->cssValuePool().get(); + + propertyID = CSSProperty::resolveDirectionAwareProperty(propertyID, style->direction(), style->writingMode()); + + switch (static_cast<CSSPropertyID>(propertyID)) { + case CSSPropertyInvalid: + break; + + case CSSPropertyBackgroundColor: + return cssValuePool->createColorValue(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 cssValuePool->createIdentifierValue(CSSValueNone); + + if (!layers->next()) { + if (layers->image()) + return layers->image()->cssValue(); + + return cssValuePool->createIdentifierValue(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(cssValuePool->createIdentifierValue(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(), cssValuePool); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(fillSizeToCSSValue(currLayer->size(), cssValuePool)); + + 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(), cssValuePool); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(fillRepeatToCSSValue(currLayer->repeatX(), currLayer->repeatY(), cssValuePool)); + + return list.release(); + } + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyWebkitMaskComposite: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskComposite ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return cssValuePool->createValue(layers->composite()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool->createValue(currLayer->composite())); + + return list.release(); + } + case CSSPropertyBackgroundAttachment: + case CSSPropertyWebkitMaskAttachment: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskAttachment ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return cssValuePool->createValue(layers->attachment()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool->createValue(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 cssValuePool->createValue(box); + } + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { + EFillBox box = isClip ? currLayer->clip() : currLayer->origin(); + list->append(cssValuePool->createValue(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(cssValuePool->createValue(layers->xPosition())); + list->append(cssValuePool->createValue(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(cssValuePool->createValue(currLayer->xPosition())); + positionList->append(cssValuePool->createValue(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 cssValuePool->createValue(layers->xPosition()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool->createValue(currLayer->xPosition())); + + return list.release(); + } + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: { + const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPositionY ? style->maskLayers() : style->backgroundLayers(); + if (!layers->next()) + return cssValuePool->createValue(layers->yPosition()); + + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool->createValue(currLayer->yPosition())); + + return list.release(); + } + case CSSPropertyBorderCollapse: + if (style->borderCollapse()) + return cssValuePool->createIdentifierValue(CSSValueCollapse); + return cssValuePool->createIdentifierValue(CSSValueSeparate); + case CSSPropertyBorderSpacing: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get(), cssValuePool)); + list->append(zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get(), cssValuePool)); + return list.release(); + } + case CSSPropertyWebkitBorderHorizontalSpacing: + return zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get(), cssValuePool); + case CSSPropertyWebkitBorderVerticalSpacing: + return zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get(), cssValuePool); + case CSSPropertyBorderImageSource: + if (style->borderImageSource()) + return style->borderImageSource()->cssValue(); + return cssValuePool->createIdentifierValue(CSSValueNone); + case CSSPropertyBorderTopColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyBorderTopColor).rgb()) : currentColorOrValidColor(style.get(), style->borderTopColor()); + case CSSPropertyBorderRightColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyBorderRightColor).rgb()) : currentColorOrValidColor(style.get(), style->borderRightColor()); + case CSSPropertyBorderBottomColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyBorderBottomColor).rgb()) : currentColorOrValidColor(style.get(), style->borderBottomColor()); + case CSSPropertyBorderLeftColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyBorderLeftColor).rgb()) : currentColorOrValidColor(style.get(), style->borderLeftColor()); + case CSSPropertyBorderTopStyle: + return cssValuePool->createValue(style->borderTopStyle()); + case CSSPropertyBorderRightStyle: + return cssValuePool->createValue(style->borderRightStyle()); + case CSSPropertyBorderBottomStyle: + return cssValuePool->createValue(style->borderBottomStyle()); + case CSSPropertyBorderLeftStyle: + return cssValuePool->createValue(style->borderLeftStyle()); + case CSSPropertyBorderTopWidth: + return zoomAdjustedPixelValue(style->borderTopWidth(), style.get(), cssValuePool); + case CSSPropertyBorderRightWidth: + return zoomAdjustedPixelValue(style->borderRightWidth(), style.get(), cssValuePool); + case CSSPropertyBorderBottomWidth: + return zoomAdjustedPixelValue(style->borderBottomWidth(), style.get(), cssValuePool); + case CSSPropertyBorderLeftWidth: + return zoomAdjustedPixelValue(style->borderLeftWidth(), style.get(), cssValuePool); + case CSSPropertyBottom: + return getPositionOffsetValue(style.get(), CSSPropertyBottom, cssValuePool); + case CSSPropertyWebkitBoxAlign: + return cssValuePool->createValue(style->boxAlign()); + case CSSPropertyWebkitBoxDirection: + return cssValuePool->createValue(style->boxDirection()); + case CSSPropertyWebkitBoxFlex: + return cssValuePool->createValue(style->boxFlex(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxFlexGroup: + return cssValuePool->createValue(style->boxFlexGroup(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxLines: + return cssValuePool->createValue(style->boxLines()); + case CSSPropertyWebkitBoxOrdinalGroup: + return cssValuePool->createValue(style->boxOrdinalGroup(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBoxOrient: + return cssValuePool->createValue(style->boxOrient()); + case CSSPropertyWebkitBoxPack: + return cssValuePool->createValue(style->boxPack()); + case CSSPropertyWebkitBoxReflect: + return valueForReflection(style->boxReflect(), style.get(), cssValuePool); + case CSSPropertyBoxShadow: + case CSSPropertyWebkitBoxShadow: + return valueForShadow(style->boxShadow(), propertyID, style.get()); + case CSSPropertyCaptionSide: + return cssValuePool->createValue(style->captionSide()); + case CSSPropertyClear: + return cssValuePool->createValue(style->clear()); + case CSSPropertyColor: + return cssValuePool->createColorValue(m_allowVisitedStyle ? style->visitedDependentColor(CSSPropertyColor).rgb() : style->color().rgb()); + case CSSPropertyWebkitPrintColorAdjust: + return cssValuePool->createValue(style->printColorAdjust()); + case CSSPropertyWebkitColumnAxis: + return cssValuePool->createValue(style->columnAxis()); + case CSSPropertyWebkitColumnCount: + if (style->hasAutoColumnCount()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->columnCount(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitColumnGap: + if (style->hasNormalColumnGap()) + return cssValuePool->createIdentifierValue(CSSValueNormal); + return zoomAdjustedPixelValue(style->columnGap(), style.get(), cssValuePool); + case CSSPropertyWebkitColumnRuleColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->columnRuleColor()); + case CSSPropertyWebkitColumnRuleStyle: + return cssValuePool->createValue(style->columnRuleStyle()); + case CSSPropertyWebkitColumnRuleWidth: + return zoomAdjustedPixelValue(style->columnRuleWidth(), style.get(), cssValuePool); + case CSSPropertyWebkitColumnSpan: + if (style->columnSpan()) + return cssValuePool->createIdentifierValue(CSSValueAll); + return cssValuePool->createValue(1, CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitColumnBreakAfter: + return cssValuePool->createValue(style->columnBreakAfter()); + case CSSPropertyWebkitColumnBreakBefore: + return cssValuePool->createValue(style->columnBreakBefore()); + case CSSPropertyWebkitColumnBreakInside: + return cssValuePool->createValue(style->columnBreakInside()); + case CSSPropertyWebkitColumnWidth: + if (style->hasAutoColumnWidth()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(style->columnWidth(), style.get(), cssValuePool); + case CSSPropertyWebkitRegionBreakAfter: + return cssValuePool->createValue(style->regionBreakAfter()); + case CSSPropertyWebkitRegionBreakBefore: + return cssValuePool->createValue(style->regionBreakBefore()); + case CSSPropertyWebkitRegionBreakInside: + return cssValuePool->createValue(style->regionBreakInside()); + 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 = cssValuePool->createValue(style->cursor()); + if (list) { + list->append(value); + return list.release(); + } + return value.release(); + } + case CSSPropertyDirection: + return cssValuePool->createValue(style->direction()); + case CSSPropertyDisplay: + return cssValuePool->createValue(style->display()); + case CSSPropertyEmptyCells: + return cssValuePool->createValue(style->emptyCells()); + case CSSPropertyWebkitFlexOrder: + return cssValuePool->createValue(style->flexOrder(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitFlexPack: + return cssValuePool->createValue(style->flexPack()); + case CSSPropertyWebkitFlexAlign: + return cssValuePool->createValue(style->flexAlign()); + case CSSPropertyWebkitFlexDirection: + return cssValuePool->createValue(style->flexDirection()); + case CSSPropertyWebkitFlexWrap: + return cssValuePool->createValue(style->flexWrap()); + case CSSPropertyWebkitFlexFlow: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(cssValuePool->createValue(style->flexDirection())); + list->append(cssValuePool->createValue(style->flexWrap())); + return list.release(); + } + case CSSPropertyFloat: + return cssValuePool->createValue(style->floating()); + case CSSPropertyFont: { + RefPtr<FontValue> computedFont = FontValue::create(); + computedFont->style = fontStyleFromStyle(style.get(), cssValuePool); + computedFont->variant = fontVariantFromStyle(style.get(), cssValuePool); + computedFont->weight = fontWeightFromStyle(style.get(), cssValuePool); + computedFont->size = fontSizeFromStyle(style.get(), cssValuePool); + computedFont->lineHeight = lineHeightFromStyle(style.get(), cssValuePool); + computedFont->family = fontFamilyFromStyle(style.get(), cssValuePool); + return computedFont.release(); + } + case CSSPropertyFontFamily: { + RefPtr<CSSValueList> fontFamilyList = fontFamilyFromStyle(style.get(), cssValuePool); + // If there's only a single family, return that as a CSSPrimitiveValue. + // NOTE: Gecko always returns this as a comma-separated CSSPrimitiveValue string. + if (fontFamilyList->length() == 1) + return fontFamilyList->item(0); + return fontFamilyList.release(); + } + case CSSPropertyFontSize: + return fontSizeFromStyle(style.get(), cssValuePool); + case CSSPropertyFontStyle: + return fontStyleFromStyle(style.get(), cssValuePool); + case CSSPropertyFontVariant: + return fontVariantFromStyle(style.get(), cssValuePool); + case CSSPropertyFontWeight: + return fontWeightFromStyle(style.get(), cssValuePool); + case CSSPropertyWebkitFontFeatureSettings: { + const FontFeatureSettings* featureSettings = style->fontDescription().featureSettings(); + if (!featureSettings || !featureSettings->size()) + return cssValuePool->createIdentifierValue(CSSValueNormal); + RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + for (unsigned i = 0; i < featureSettings->size(); ++i) { + const FontFeature& feature = featureSettings->at(i); + RefPtr<FontFeatureValue> featureValue = FontFeatureValue::create(feature.tag(), feature.value()); + list->append(featureValue.release()); + } + return list.release(); + } +#if ENABLE(CSS_GRID_LAYOUT) + case CSSPropertyWebkitGridColumns: { + return valueForGridTrackList(style->gridColumns(), style.get(), cssValuePool); + } + case CSSPropertyWebkitGridRows: { + return valueForGridTrackList(style->gridRows(), style.get(), cssValuePool); + } +#endif + case CSSPropertyHeight: + if (renderer) { + // According to http://www.w3.org/TR/CSS2/visudet.html#the-height-property, + // the "height" property does not apply for non-replaced inline elements. + if (!renderer->isReplaced() && renderer->isInline()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(sizingBox(renderer).height(), style.get(), cssValuePool); + } + return zoomAdjustedPixelValueForLength(style->height(), style.get(), cssValuePool); + case CSSPropertyWebkitHighlight: + if (style->highlight() == nullAtom) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(style->highlight(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitHyphens: + return cssValuePool->createValue(style->hyphens()); + case CSSPropertyWebkitHyphenateCharacter: + if (style->hyphenationString().isNull()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->hyphenationString(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitHyphenateLimitAfter: + if (style->hyphenationLimitAfter() < 0) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->hyphenationLimitAfter(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitHyphenateLimitBefore: + if (style->hyphenationLimitBefore() < 0) + return CSSPrimitiveValue::createIdentifier(CSSValueAuto); + return CSSPrimitiveValue::create(style->hyphenationLimitBefore(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitHyphenateLimitLines: + if (style->hyphenationLimitLines() < 0) + return CSSPrimitiveValue::createIdentifier(CSSValueNoLimit); + return CSSPrimitiveValue::create(style->hyphenationLimitLines(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitBorderFit: + if (style->borderFit() == BorderFitBorder) + return cssValuePool->createIdentifierValue(CSSValueBorder); + return cssValuePool->createIdentifierValue(CSSValueLines); + case CSSPropertyImageRendering: + return CSSPrimitiveValue::create(style->imageRendering()); + case CSSPropertyLeft: + return getPositionOffsetValue(style.get(), CSSPropertyLeft, cssValuePool); + case CSSPropertyLetterSpacing: + if (!style->letterSpacing()) + return cssValuePool->createIdentifierValue(CSSValueNormal); + return zoomAdjustedPixelValue(style->letterSpacing(), style.get(), cssValuePool); + case CSSPropertyWebkitLineClamp: + if (style->lineClamp().isNone()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(style->lineClamp().value(), style->lineClamp().isPercentage() ? CSSPrimitiveValue::CSS_PERCENTAGE : CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyLineHeight: + return lineHeightFromStyle(style.get(), cssValuePool); + case CSSPropertyListStyleImage: + if (style->listStyleImage()) + return style->listStyleImage()->cssValue(); + return cssValuePool->createIdentifierValue(CSSValueNone); + case CSSPropertyListStylePosition: + return cssValuePool->createValue(style->listStylePosition()); + case CSSPropertyListStyleType: + return cssValuePool->createValue(style->listStyleType()); + case CSSPropertyWebkitLocale: + if (style->locale().isNull()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->locale(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyMarginTop: { + Length marginTop = style->marginTop(); + if (marginTop.isFixed() || !renderer || !renderer->isBox()) + return zoomAdjustedPixelValueForLength(marginTop, style.get(), cssValuePool); + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginTop(), style.get(), cssValuePool); + } + case CSSPropertyMarginRight: { + Length marginRight = style->marginRight(); + if (marginRight.isFixed() || !renderer || !renderer->isBox()) + return zoomAdjustedPixelValueForLength(marginRight, style.get(), cssValuePool); + int value; + if (marginRight.isPercent()) + // RenderBox gives a marginRight() that is the distance between the right-edge of the child box + // and the right-edge of the containing box, when display == BLOCK. Let's calculate the absolute + // value of the specified margin-right % instead of relying on RenderBox's marginRight() value. + value = marginRight.calcMinValue(toRenderBox(renderer)->containingBlockLogicalWidthForContent()); + else + value = toRenderBox(renderer)->marginRight(); + return zoomAdjustedPixelValue(value, style.get(), cssValuePool); + } + case CSSPropertyMarginBottom: { + Length marginBottom = style->marginBottom(); + if (marginBottom.isFixed() || !renderer || !renderer->isBox()) + return zoomAdjustedPixelValueForLength(marginBottom, style.get(), cssValuePool); + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginBottom(), style.get(), cssValuePool); + } + case CSSPropertyMarginLeft: { + Length marginLeft = style->marginLeft(); + if (marginLeft.isFixed() || !renderer || !renderer->isBox()) + return zoomAdjustedPixelValueForLength(marginLeft, style.get(), cssValuePool); + return zoomAdjustedPixelValue(toRenderBox(renderer)->marginLeft(), style.get(), cssValuePool); + } + case CSSPropertyWebkitMarqueeDirection: + return cssValuePool->createValue(style->marqueeDirection()); + case CSSPropertyWebkitMarqueeIncrement: + return cssValuePool->createValue(style->marqueeIncrement()); + case CSSPropertyWebkitMarqueeRepetition: + if (style->marqueeLoopCount() < 0) + return cssValuePool->createIdentifierValue(CSSValueInfinite); + return cssValuePool->createValue(style->marqueeLoopCount(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWebkitMarqueeStyle: + return cssValuePool->createValue(style->marqueeBehavior()); + case CSSPropertyWebkitUserModify: + return cssValuePool->createValue(style->userModify()); + case CSSPropertyMaxHeight: { + const Length& maxHeight = style->maxHeight(); + if (maxHeight.isUndefined()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(maxHeight); + } + case CSSPropertyMaxWidth: { + const Length& maxWidth = style->maxWidth(); + if (maxWidth.isUndefined()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(maxWidth); + } + case CSSPropertyMinHeight: + return cssValuePool->createValue(style->minHeight()); + case CSSPropertyMinWidth: + return cssValuePool->createValue(style->minWidth()); + case CSSPropertyOpacity: + return cssValuePool->createValue(style->opacity(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyOrphans: + return cssValuePool->createValue(style->orphans(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyOutlineColor: + return m_allowVisitedStyle ? cssValuePool->createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->outlineColor()); + case CSSPropertyOutlineOffset: + return zoomAdjustedPixelValue(style->outlineOffset(), style.get(), cssValuePool); + case CSSPropertyOutlineStyle: + if (style->outlineStyleIsAuto()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->outlineStyle()); + case CSSPropertyOutlineWidth: + return zoomAdjustedPixelValue(style->outlineWidth(), style.get(), cssValuePool); + case CSSPropertyOverflow: + return cssValuePool->createValue(max(style->overflowX(), style->overflowY())); + case CSSPropertyOverflowX: + return cssValuePool->createValue(style->overflowX()); + case CSSPropertyOverflowY: + return cssValuePool->createValue(style->overflowY()); + case CSSPropertyPaddingTop: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingTop(false), style.get(), cssValuePool); + return cssValuePool->createValue(style->paddingTop()); + case CSSPropertyPaddingRight: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingRight(false), style.get(), cssValuePool); + return cssValuePool->createValue(style->paddingRight()); + case CSSPropertyPaddingBottom: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingBottom(false), style.get(), cssValuePool); + return cssValuePool->createValue(style->paddingBottom()); + case CSSPropertyPaddingLeft: + if (renderer && renderer->isBox()) + return zoomAdjustedPixelValue(toRenderBox(renderer)->paddingLeft(false), style.get(), cssValuePool); + return cssValuePool->createValue(style->paddingLeft()); + case CSSPropertyPageBreakAfter: + return cssValuePool->createValue(style->pageBreakAfter()); + case CSSPropertyPageBreakBefore: + return cssValuePool->createValue(style->pageBreakBefore()); + case CSSPropertyPageBreakInside: { + EPageBreak pageBreak = style->pageBreakInside(); + ASSERT(pageBreak != PBALWAYS); + if (pageBreak == PBALWAYS) + return 0; + return cssValuePool->createValue(style->pageBreakInside()); + } + case CSSPropertyPosition: + return cssValuePool->createValue(style->position()); + case CSSPropertyRight: + return getPositionOffsetValue(style.get(), CSSPropertyRight, cssValuePool); + case CSSPropertyTableLayout: + return cssValuePool->createValue(style->tableLayout()); + case CSSPropertyTextAlign: + return cssValuePool->createValue(style->textAlign()); + case CSSPropertyTextDecoration: + return renderTextDecorationFlagsToCSSValue(style->textDecoration(), cssValuePool); + case CSSPropertyWebkitTextDecorationsInEffect: + return renderTextDecorationFlagsToCSSValue(style->textDecorationsInEffect(), cssValuePool); + case CSSPropertyWebkitTextFillColor: + return currentColorOrValidColor(style.get(), style->textFillColor()); + case CSSPropertyWebkitTextEmphasisColor: + return currentColorOrValidColor(style.get(), style->textEmphasisColor()); + case CSSPropertyWebkitTextEmphasisPosition: + return cssValuePool->createValue(style->textEmphasisPosition()); + case CSSPropertyWebkitTextEmphasisStyle: + switch (style->textEmphasisMark()) { + case TextEmphasisMarkNone: + return cssValuePool->createIdentifierValue(CSSValueNone); + case TextEmphasisMarkCustom: + return cssValuePool->createValue(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(cssValuePool->createValue(style->textEmphasisFill())); + list->append(cssValuePool->createValue(style->textEmphasisMark())); + return list.release(); + } + } + case CSSPropertyTextIndent: + return cssValuePool->createValue(style->textIndent()); + case CSSPropertyTextShadow: + return valueForShadow(style->textShadow(), propertyID, style.get()); + case CSSPropertyTextRendering: + return cssValuePool->createValue(style->fontDescription().textRenderingMode()); + case CSSPropertyTextOverflow: + if (style->textOverflow()) + return cssValuePool->createIdentifierValue(CSSValueEllipsis); + return cssValuePool->createIdentifierValue(CSSValueClip); + case CSSPropertyWebkitTextSecurity: + return cssValuePool->createValue(style->textSecurity()); + case CSSPropertyWebkitTextSizeAdjust: + if (style->textSizeAdjust()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createIdentifierValue(CSSValueNone); + case CSSPropertyWebkitTextStrokeColor: + return currentColorOrValidColor(style.get(), style->textStrokeColor()); + case CSSPropertyWebkitTextStrokeWidth: + return zoomAdjustedPixelValue(style->textStrokeWidth(), style.get(), cssValuePool); + case CSSPropertyTextTransform: + return cssValuePool->createValue(style->textTransform()); + case CSSPropertyTop: + return getPositionOffsetValue(style.get(), CSSPropertyTop, cssValuePool); + case CSSPropertyUnicodeBidi: + return cssValuePool->createValue(style->unicodeBidi()); + case CSSPropertyVerticalAlign: + switch (style->verticalAlign()) { + case BASELINE: + return cssValuePool->createIdentifierValue(CSSValueBaseline); + case MIDDLE: + return cssValuePool->createIdentifierValue(CSSValueMiddle); + case SUB: + return cssValuePool->createIdentifierValue(CSSValueSub); + case SUPER: + return cssValuePool->createIdentifierValue(CSSValueSuper); + case TEXT_TOP: + return cssValuePool->createIdentifierValue(CSSValueTextTop); + case TEXT_BOTTOM: + return cssValuePool->createIdentifierValue(CSSValueTextBottom); + case TOP: + return cssValuePool->createIdentifierValue(CSSValueTop); + case BOTTOM: + return cssValuePool->createIdentifierValue(CSSValueBottom); + case BASELINE_MIDDLE: + return cssValuePool->createIdentifierValue(CSSValueWebkitBaselineMiddle); + case LENGTH: + return cssValuePool->createValue(style->verticalAlignLength()); + } + ASSERT_NOT_REACHED(); + return 0; + case CSSPropertyVisibility: + return cssValuePool->createValue(style->visibility()); + case CSSPropertyWhiteSpace: + return cssValuePool->createValue(style->whiteSpace()); + case CSSPropertyWidows: + return cssValuePool->createValue(style->widows(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyWidth: + if (renderer) { + // According to http://www.w3.org/TR/CSS2/visudet.html#the-width-property, + // the "width" property does not apply for non-replaced inline elements. + if (!renderer->isReplaced() && renderer->isInline()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(sizingBox(renderer).width(), style.get(), cssValuePool); + } + return zoomAdjustedPixelValueForLength(style->width(), style.get(), cssValuePool); + case CSSPropertyWordBreak: + return cssValuePool->createValue(style->wordBreak()); + case CSSPropertyWordSpacing: + return zoomAdjustedPixelValue(style->wordSpacing(), style.get(), cssValuePool); + case CSSPropertyWordWrap: + return cssValuePool->createValue(style->wordWrap()); + case CSSPropertyWebkitLineBreak: + return cssValuePool->createValue(style->khtmlLineBreak()); + case CSSPropertyWebkitNbspMode: + return cssValuePool->createValue(style->nbspMode()); + case CSSPropertyWebkitMatchNearestMailBlockquoteColor: + return cssValuePool->createValue(style->matchNearestMailBlockquoteColor()); + case CSSPropertyResize: + return cssValuePool->createValue(style->resize()); + case CSSPropertyWebkitFontSmoothing: + return cssValuePool->createValue(style->fontDescription().fontSmoothing()); + case CSSPropertyZIndex: + if (style->hasAutoZIndex()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->zIndex(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyZoom: + return cssValuePool->createValue(style->zoom(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyBoxSizing: + if (style->boxSizing() == CONTENT_BOX) + return cssValuePool->createIdentifierValue(CSSValueContentBox); + return cssValuePool->createIdentifierValue(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 cssValuePool->createIdentifierValue(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(), cssValuePool)); + region->setRight(zoomAdjustedPixelValue(offset.right().value(), style.get(), cssValuePool)); + region->setBottom(zoomAdjustedPixelValue(offset.bottom().value(), style.get(), cssValuePool)); + region->setLeft(zoomAdjustedPixelValue(offset.left().value(), style.get(), cssValuePool)); + 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 cssValuePool->createValue(firstRegion.release()); + } +#endif + case CSSPropertyWebkitAnimationDelay: + return getDelayValue(style->animations(), cssValuePool); + 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(cssValuePool->createIdentifierValue(CSSValueAlternate)); + else + list->append(cssValuePool->createIdentifierValue(CSSValueNormal)); + } + } else + list->append(cssValuePool->createIdentifierValue(CSSValueNormal)); + return list.release(); + } + case CSSPropertyWebkitAnimationDuration: + return getDurationValue(style->animations(), cssValuePool); + 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(cssValuePool->createIdentifierValue(CSSValueNone)); + break; + case AnimationFillModeForwards: + list->append(cssValuePool->createIdentifierValue(CSSValueForwards)); + break; + case AnimationFillModeBackwards: + list->append(cssValuePool->createIdentifierValue(CSSValueBackwards)); + break; + case AnimationFillModeBoth: + list->append(cssValuePool->createIdentifierValue(CSSValueBoth)); + break; + } + } + } else + list->append(cssValuePool->createIdentifierValue(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(cssValuePool->createIdentifierValue(CSSValueInfinite)); + else + list->append(cssValuePool->createValue(iterationCount, CSSPrimitiveValue::CSS_NUMBER)); + } + } else + list->append(cssValuePool->createValue(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(cssValuePool->createValue(t->animation(i)->name(), CSSPrimitiveValue::CSS_STRING)); + } else + list->append(cssValuePool->createIdentifierValue(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(cssValuePool->createIdentifierValue(CSSValueRunning)); + else + list->append(cssValuePool->createIdentifierValue(CSSValuePaused)); + } + } else + list->append(cssValuePool->createIdentifierValue(CSSValueRunning)); + return list.release(); + } + case CSSPropertyWebkitAnimationTimingFunction: + return getTimingFunctionValue(style->animations()); + case CSSPropertyWebkitAppearance: + return cssValuePool->createValue(style->appearance()); + case CSSPropertyWebkitAspectRatio: + if (!style->hasAspectRatio()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return CSSAspectRatioValue::create(style->aspectRatioNumerator(), style->aspectRatioDenominator()); + case CSSPropertyWebkitBackfaceVisibility: + return cssValuePool->createIdentifierValue((style->backfaceVisibility() == BackfaceVisibilityHidden) ? CSSValueHidden : CSSValueVisible); + case CSSPropertyWebkitBorderImage: + return valueForNinePieceImage(style->borderImage(), cssValuePool); + case CSSPropertyBorderImageOutset: + return valueForNinePieceImageQuad(style->borderImage().outset(), cssValuePool); + case CSSPropertyBorderImageRepeat: + return valueForNinePieceImageRepeat(style->borderImage(), cssValuePool); + case CSSPropertyBorderImageSlice: + return valueForNinePieceImageSlice(style->borderImage(), cssValuePool); + case CSSPropertyBorderImageWidth: + return valueForNinePieceImageQuad(style->borderImage().borderSlices(), cssValuePool); + case CSSPropertyWebkitMaskBoxImage: + return valueForNinePieceImage(style->maskBoxImage(), cssValuePool); + case CSSPropertyWebkitMaskBoxImageOutset: + return valueForNinePieceImageQuad(style->maskBoxImage().outset(), cssValuePool); + case CSSPropertyWebkitMaskBoxImageRepeat: + return valueForNinePieceImageRepeat(style->maskBoxImage(), cssValuePool); + case CSSPropertyWebkitMaskBoxImageSlice: + return valueForNinePieceImageSlice(style->maskBoxImage(), cssValuePool); + case CSSPropertyWebkitMaskBoxImageWidth: + return valueForNinePieceImageQuad(style->maskBoxImage().borderSlices(), cssValuePool); + case CSSPropertyWebkitMaskBoxImageSource: + if (style->maskBoxImageSource()) + return style->maskBoxImageSource()->cssValue(); + return cssValuePool->createIdentifierValue(CSSValueNone); + case CSSPropertyWebkitFontSizeDelta: + // Not a real style property -- used by the editing engine -- so has no computed value. + break; + case CSSPropertyWebkitMarginBottomCollapse: + case CSSPropertyWebkitMarginAfterCollapse: + return cssValuePool->createValue(style->marginAfterCollapse()); + case CSSPropertyWebkitMarginTopCollapse: + case CSSPropertyWebkitMarginBeforeCollapse: + return cssValuePool->createValue(style->marginBeforeCollapse()); + case CSSPropertyWebkitPerspective: + if (!style->hasPerspective()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return zoomAdjustedPixelValue(style->perspective(), style.get(), cssValuePool); + case CSSPropertyWebkitPerspectiveOrigin: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (renderer) { + IntRect box = sizingBox(renderer); + list->append(zoomAdjustedPixelValue(style->perspectiveOriginX().calcMinValue(box.width()), style.get(), cssValuePool)); + list->append(zoomAdjustedPixelValue(style->perspectiveOriginY().calcMinValue(box.height()), style.get(), cssValuePool)); + } + else { + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginX(), style.get(), cssValuePool)); + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginY(), style.get(), cssValuePool)); + + } + return list.release(); + } + case CSSPropertyWebkitRtlOrdering: + return cssValuePool->createIdentifierValue(style->rtlOrdering() ? CSSValueVisual : CSSValueLogical); +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyWebkitTapHighlightColor: + return currentColorOrValidColor(style.get(), style->tapHighlightColor()); +#endif + case CSSPropertyWebkitUserDrag: + return cssValuePool->createValue(style->userDrag()); + case CSSPropertyWebkitUserSelect: + return cssValuePool->createValue(style->userSelect()); + case CSSPropertyBorderBottomLeftRadius: + return getBorderRadiusCornerValue(style->borderBottomLeftRadius(), style.get(), cssValuePool); + case CSSPropertyBorderBottomRightRadius: + return getBorderRadiusCornerValue(style->borderBottomRightRadius(), style.get(), cssValuePool); + case CSSPropertyBorderTopLeftRadius: + return getBorderRadiusCornerValue(style->borderTopLeftRadius(), style.get(), cssValuePool); + case CSSPropertyBorderTopRightRadius: + return getBorderRadiusCornerValue(style->borderTopRightRadius(), style.get(), cssValuePool); + case CSSPropertyClip: { + if (!style->hasClip()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + RefPtr<Rect> rect = Rect::create(); + rect->setTop(zoomAdjustedPixelValue(style->clip().top().value(), style.get(), cssValuePool)); + rect->setRight(zoomAdjustedPixelValue(style->clip().right().value(), style.get(), cssValuePool)); + rect->setBottom(zoomAdjustedPixelValue(style->clip().bottom().value(), style.get(), cssValuePool)); + rect->setLeft(zoomAdjustedPixelValue(style->clip().left().value(), style.get(), cssValuePool)); + return cssValuePool->createValue(rect.release()); + } + case CSSPropertySpeak: + return cssValuePool->createValue(style->speak()); + case CSSPropertyWebkitTransform: + return computedTransform(renderer, style.get(), cssValuePool); + case CSSPropertyWebkitTransformOrigin: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + if (renderer) { + IntRect box = sizingBox(renderer); + list->append(zoomAdjustedPixelValue(style->transformOriginX().calcMinValue(box.width()), style.get(), cssValuePool)); + list->append(zoomAdjustedPixelValue(style->transformOriginY().calcMinValue(box.height()), style.get(), cssValuePool)); + if (style->transformOriginZ() != 0) + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get(), cssValuePool)); + } else { + list->append(zoomAdjustedPixelValueForLength(style->transformOriginX(), style.get(), cssValuePool)); + list->append(zoomAdjustedPixelValueForLength(style->transformOriginY(), style.get(), cssValuePool)); + if (style->transformOriginZ() != 0) + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get(), cssValuePool)); + } + return list.release(); + } + case CSSPropertyWebkitTransformStyle: + return cssValuePool->createIdentifierValue((style->transformStyle3D() == TransformStyle3DPreserve3D) ? CSSValuePreserve3d : CSSValueFlat); + case CSSPropertyWebkitTransitionDelay: + return getDelayValue(style->transitions(), cssValuePool); + case CSSPropertyWebkitTransitionDuration: + return getDurationValue(style->transitions(), cssValuePool); + 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 = cssValuePool->createIdentifierValue(CSSValueNone); + else if (prop == cAnimateAll) + propertyValue = cssValuePool->createIdentifierValue(CSSValueAll); + else + propertyValue = cssValuePool->createValue(getPropertyName(static_cast<CSSPropertyID>(prop)), CSSPrimitiveValue::CSS_STRING); + list->append(propertyValue); + } + } else + list->append(cssValuePool->createIdentifierValue(CSSValueAll)); + return list.release(); + } + case CSSPropertyWebkitTransitionTimingFunction: + return getTimingFunctionValue(style->transitions()); + case CSSPropertyPointerEvents: + return cssValuePool->createValue(style->pointerEvents()); + case CSSPropertyWebkitColorCorrection: + return cssValuePool->createValue(style->colorSpace()); + case CSSPropertyWebkitLineGrid: + if (style->lineGrid().isNull()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(style->lineGrid(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitLineGridSnap: + return CSSPrimitiveValue::create(style->lineGridSnap()); + case CSSPropertyWebkitWritingMode: + return cssValuePool->createValue(style->writingMode()); + case CSSPropertyWebkitTextCombine: + return cssValuePool->createValue(style->textCombine()); + case CSSPropertyWebkitTextOrientation: + return CSSPrimitiveValue::create(style->fontDescription().textOrientation()); + case CSSPropertyWebkitLineBoxContain: + return createLineBoxContainValue(cssValuePool, style->lineBoxContain()); + case CSSPropertyContent: + return contentToCSSValue(style.get(), cssValuePool); + case CSSPropertyCounterIncrement: + return counterToCSSValue(style.get(), propertyID, cssValuePool); + case CSSPropertyCounterReset: + return counterToCSSValue(style.get(), propertyID, cssValuePool); + case CSSPropertyWebkitFlowInto: + if (style->flowThread().isNull()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->flowThread(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitFlowFrom: + if (style->regionThread().isNull()) + return cssValuePool->createIdentifierValue(CSSValueNone); + return cssValuePool->createValue(style->regionThread(), CSSPrimitiveValue::CSS_STRING); + case CSSPropertyWebkitRegionOverflow: + return cssValuePool->createValue(style->regionOverflow()); + case CSSPropertyWebkitWrapFlow: + return cssValuePool->createValue(style->wrapFlow()); + case CSSPropertyWebkitWrapMargin: + return cssValuePool->createValue(style->wrapMargin()); + case CSSPropertyWebkitWrapPadding: + return cssValuePool->createValue(style->wrapPadding()); + case CSSPropertyWebkitWrapShapeInside: + if (!style->wrapShapeInside()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->wrapShapeInside()); + case CSSPropertyWebkitWrapShapeOutside: + if (!style->wrapShapeOutside()) + return cssValuePool->createIdentifierValue(CSSValueAuto); + return cssValuePool->createValue(style->wrapShapeOutside()); + case CSSPropertyWebkitWrapThrough: + return cssValuePool->createValue(style->wrapThrough()); +#if ENABLE(CSS_FILTERS) + case CSSPropertyWebkitFilter: + return valueForFilter(style.get()); +#endif + /* Shorthand properties, currently not supported see bug 13658*/ + case CSSPropertyBackground: { + const int properties[5] = { CSSPropertyBackgroundColor, CSSPropertyBackgroundImage, + CSSPropertyBackgroundRepeat, CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundPosition }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyBorder: { + RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyBorderTop, DoNotUpdateLayout); + const int properties[3] = { CSSPropertyBorderRight, CSSPropertyBorderBottom, + CSSPropertyBorderLeft }; + for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { + if (value->cssText() != getPropertyCSSValue(properties[i], DoNotUpdateLayout)->cssText()) + return 0; + } + return value.release(); + } + case CSSPropertyBorderBottom: { + const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, + CSSPropertyBorderBottomColor }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyBorderColor: { + const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, + CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; + return getCSSPropertyValuesForSidesShorthand(properties); + } + case CSSPropertyBorderLeft: { + const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, + CSSPropertyBorderLeftColor }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyBorderImage: + return valueForNinePieceImage(style->borderImage(), cssValuePool); + case CSSPropertyBorderRadius: + break; + case CSSPropertyBorderRight: { + const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, + CSSPropertyBorderRightColor }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyBorderStyle: { + const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, + CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; + return getCSSPropertyValuesForSidesShorthand(properties); + } + case CSSPropertyBorderTop: { + const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, + CSSPropertyBorderTopColor }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyBorderWidth: { + const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, + CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; + return getCSSPropertyValuesForSidesShorthand(properties); + } + case CSSPropertyListStyle: { + const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition, + CSSPropertyListStyleImage }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyMargin: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, + CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return getCSSPropertyValuesForSidesShorthand(properties); + } + case CSSPropertyOutline: { + const int properties[3] = { CSSPropertyOutlineColor, CSSPropertyOutlineStyle, + CSSPropertyOutlineWidth }; + return getCSSPropertyValuesForShorthandProperties(properties, WTF_ARRAY_LENGTH(properties)); + } + case CSSPropertyPadding: { + const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, + CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; + return getCSSPropertyValuesForSidesShorthand(properties); + } + /* Individual properties not part of the spec */ + case CSSPropertyBackgroundRepeatX: + case CSSPropertyBackgroundRepeatY: + 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 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: + case CSSPropertyWebkitWrap: + break; + +#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 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(); +} + +PassRefPtr<CSSValueList> CSSComputedStyleDeclaration::getCSSPropertyValuesForShorthandProperties(const int* properties, size_t size) const +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (size_t i = 0; i < size; ++i) { + RefPtr<CSSValue> value = getPropertyCSSValue(properties[i], DoNotUpdateLayout); + list->append(value); + } + return list.release(); +} + +PassRefPtr<CSSValueList> CSSComputedStyleDeclaration::getCSSPropertyValuesForSidesShorthand(const int* properties) const +{ + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + // Assume the properties are in the usual order top, right, bottom, left. + RefPtr<CSSValue> topValue = getPropertyCSSValue(properties[0], DoNotUpdateLayout); + RefPtr<CSSValue> rightValue = getPropertyCSSValue(properties[1], DoNotUpdateLayout); + RefPtr<CSSValue> bottomValue = getPropertyCSSValue(properties[2], DoNotUpdateLayout); + RefPtr<CSSValue> leftValue = getPropertyCSSValue(properties[3], DoNotUpdateLayout); + + // All 4 properties must be specified. + if (!topValue || !rightValue || !bottomValue || !leftValue) + return 0; + + bool showLeft = rightValue->cssText() != leftValue->cssText(); + bool showBottom = (topValue->cssText() != bottomValue->cssText()) || showLeft; + bool showRight = (topValue->cssText() != rightValue->cssText()) || showBottom; + + list->append(topValue); + if (showRight) + list->append(rightValue); + if (showBottom) + list->append(bottomValue); + if (showLeft) + list->append(leftValue); + + return list.release(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.h b/Source/WebCore/css/CSSComputedStyleDeclaration.h new file mode 100644 index 000000000..6ef90af6e --- /dev/null +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.h @@ -0,0 +1,105 @@ +/* + * 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 "RenderStyleConstants.h" +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class Color; +class CSSMutableStyleDeclaration; +class CSSPrimitiveValue; +class CSSValueList; +class CSSValuePool; +class Node; +class RenderStyle; +class ShadowData; +class SVGPaint; + +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; +#if ENABLE(SVG) + PassRefPtr<SVGPaint> adjustSVGPaintForCurrentColor(PassRefPtr<SVGPaint>, RenderStyle*) const; +#endif + +#if ENABLE(CSS_FILTERS) + PassRefPtr<CSSValue> valueForFilter(RenderStyle*) const; +#endif + + PassRefPtr<CSSValueList> getCSSPropertyValuesForShorthandProperties(const int* properties, size_t) const; + PassRefPtr<CSSValueList> getCSSPropertyValuesForSidesShorthand(const int* properties) 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/CSSCrossfadeValue.cpp b/Source/WebCore/css/CSSCrossfadeValue.cpp new file mode 100644 index 000000000..4ff08afca --- /dev/null +++ b/Source/WebCore/css/CSSCrossfadeValue.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2011 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 "CSSCrossfadeValue.h" + +#include "CSSImageValue.h" +#include "CachedImage.h" +#include "CachedResourceLoader.h" +#include "CrossfadeGeneratedImage.h" +#include "ImageBuffer.h" +#include "RenderObject.h" +#include "StyleCachedImage.h" +#include "StyleGeneratedImage.h" + +namespace WebCore { + +static bool subimageIsPending(CSSValue* value) +{ + if (value->isImageValue()) + return static_cast<CSSImageValue*>(value)->cachedOrPendingImage()->isPendingImage(); + + if (value->isImageGeneratorValue()) + return static_cast<CSSImageGeneratorValue*>(value)->isPending(); + + ASSERT_NOT_REACHED(); + + return false; +} + +static CachedImage* cachedImageForCSSValue(CSSValue* value, CachedResourceLoader* cachedResourceLoader) +{ + if (!value) + return 0; + + if (value->isImageValue()) { + StyleCachedImage* styleCachedImage = static_cast<CSSImageValue*>(value)->cachedImage(cachedResourceLoader); + if (!styleCachedImage) + return 0; + + return styleCachedImage->cachedImage(); + } + + if (value->isImageGeneratorValue()) { + static_cast<CSSImageGeneratorValue*>(value)->loadSubimages(cachedResourceLoader); + // FIXME: Handle CSSImageGeneratorValue (and thus cross-fades with gradients and canvas). + return 0; + } + + ASSERT_NOT_REACHED(); + + return 0; +} + +CSSCrossfadeValue::~CSSCrossfadeValue() +{ + if (m_cachedFromImage) + m_cachedFromImage->removeClient(&m_crossfadeSubimageObserver); + if (m_cachedToImage) + m_cachedToImage->removeClient(&m_crossfadeSubimageObserver); +} + +String CSSCrossfadeValue::customCssText() const +{ + String result = "-webkit-cross-fade("; + result += m_fromValue->cssText() + ", "; + result += m_toValue->cssText() + ", "; + result += m_percentageValue->cssText(); + result += ")"; + return result; +} + +IntSize CSSCrossfadeValue::fixedSize(const RenderObject* renderer) +{ + float percentage = m_percentageValue->getFloatValue(); + float inversePercentage = 1 - percentage; + + CachedResourceLoader* cachedResourceLoader = renderer->document()->cachedResourceLoader(); + CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); + CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + + if (!cachedFromImage || !cachedToImage) + return IntSize(); + + IntSize fromImageSize = cachedFromImage->imageForRenderer(renderer)->size(); + IntSize toImageSize = cachedToImage->imageForRenderer(renderer)->size(); + + // Rounding issues can cause transitions between images of equal size to return + // a different fixed size; avoid performing the interpolation if the images are the same size. + if (fromImageSize == toImageSize) + return fromImageSize; + + return IntSize(fromImageSize.width() * inversePercentage + toImageSize.width() * percentage, + fromImageSize.height() * inversePercentage + toImageSize.height() * percentage); +} + +bool CSSCrossfadeValue::isPending() const +{ + return subimageIsPending(m_fromValue.get()) || subimageIsPending(m_toValue.get()); +} + +void CSSCrossfadeValue::loadSubimages(CachedResourceLoader* cachedResourceLoader) +{ + m_cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); + m_cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + + if (m_cachedFromImage) + m_cachedFromImage->addClient(&m_crossfadeSubimageObserver); + if (m_cachedToImage) + m_cachedToImage->addClient(&m_crossfadeSubimageObserver); + + m_crossfadeSubimageObserver.setReady(true); +} + +PassRefPtr<Image> CSSCrossfadeValue::image(RenderObject* renderer, const IntSize& size) +{ + if (size.isEmpty()) + return 0; + + CachedResourceLoader* cachedResourceLoader = renderer->document()->cachedResourceLoader(); + CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); + CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + + if (!cachedFromImage || !cachedToImage) + return Image::nullImage(); + + Image* fromImage = cachedFromImage->imageForRenderer(renderer); + Image* toImage = cachedToImage->imageForRenderer(renderer); + + if (!fromImage || !toImage) + return Image::nullImage(); + + m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); + + return m_generatedImage.release(); +} + +void CSSCrossfadeValue::crossfadeChanged(const IntRect&) +{ + RenderObjectSizeCountMap::const_iterator end = clients().end(); + for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr) { + RenderObject* client = const_cast<RenderObject*>(curr->first); + client->imageChanged(static_cast<WrappedImagePtr>(this)); + } +} + +void CSSCrossfadeValue::CrossfadeSubimageObserverProxy::imageChanged(CachedImage*, const IntRect* rect) +{ + if (m_ready) + m_ownerValue->crossfadeChanged(*rect); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSCrossfadeValue.h b/Source/WebCore/css/CSSCrossfadeValue.h new file mode 100644 index 000000000..be6066037 --- /dev/null +++ b/Source/WebCore/css/CSSCrossfadeValue.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2011 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 CSSCrossfadeValue_h +#define CSSCrossfadeValue_h + +#include "CachedImage.h" +#include "CSSImageGeneratorValue.h" +#include "CSSPrimitiveValue.h" +#include "Image.h" +#include "ImageObserver.h" + +namespace WebCore { + +class CachedImage; +class CrossfadeSubimageObserverProxy; +class RenderObject; +class Document; + +class CSSCrossfadeValue : public CSSImageGeneratorValue { + friend class CrossfadeSubimageObserverProxy; +public: + static PassRefPtr<CSSCrossfadeValue> create(PassRefPtr<CSSValue> fromValue, PassRefPtr<CSSValue> toValue) + { + return adoptRef(new CSSCrossfadeValue(fromValue, toValue)); + } + + ~CSSCrossfadeValue(); + + String customCssText() const; + + PassRefPtr<Image> image(RenderObject*, const IntSize&); + bool isFixedSize() const { return true; } + IntSize fixedSize(const RenderObject*); + + bool isPending() const; + void loadSubimages(CachedResourceLoader*); + + void setPercentage(PassRefPtr<CSSPrimitiveValue> percentageValue) { m_percentageValue = percentageValue; } + +private: + CSSCrossfadeValue(PassRefPtr<CSSValue> fromValue, PassRefPtr<CSSValue> toValue) + : CSSImageGeneratorValue(CrossfadeClass) + , m_fromValue(fromValue) + , m_toValue(toValue) + , m_cachedFromImage(0) + , m_cachedToImage(0) + , m_crossfadeSubimageObserver(this) { } + + class CrossfadeSubimageObserverProxy : public CachedImageClient { + public: + CrossfadeSubimageObserverProxy(CSSCrossfadeValue* ownerValue) + : m_ownerValue(ownerValue) + , m_ready(false) { } + + virtual ~CrossfadeSubimageObserverProxy() { } + virtual void imageChanged(CachedImage*, const IntRect* = 0) OVERRIDE; + void setReady(bool ready) { m_ready = ready; } + private: + CSSCrossfadeValue* m_ownerValue; + bool m_ready; + }; + + void crossfadeChanged(const IntRect&); + + RefPtr<CSSValue> m_fromValue; + RefPtr<CSSValue> m_toValue; + RefPtr<CSSPrimitiveValue> m_percentageValue; + + CachedImage* m_cachedFromImage; + CachedImage* m_cachedToImage; + + RefPtr<Image> m_generatedImage; + + CrossfadeSubimageObserverProxy m_crossfadeSubimageObserver; +}; + +} // namespace WebCore + +#endif // CSSCrossfadeValue_h diff --git a/Source/WebCore/css/CSSCursorImageValue.cpp b/Source/WebCore/css/CSSCursorImageValue.cpp new file mode 100644 index 000000000..f41276b21 --- /dev/null +++ b/Source/WebCore/css/CSSCursorImageValue.cpp @@ -0,0 +1,139 @@ +/* + * 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 "TreeScope.h" +#include "PlatformString.h" +#include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> + +#if ENABLE(SVG) +#include "SVGCursorElement.h" +#include "SVGLengthContext.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& url, Document* document) +{ + Element* element = SVGURIReference::targetElementFromIRIString(url, document); + if (element && element->hasTagName(SVGNames::cursorTag)) + return static_cast<SVGCursorElement*>(element); + + return 0; +} +#endif + +CSSCursorImageValue::CSSCursorImageValue(const String& url, const IntPoint& hotSpot) + : CSSImageValue(CursorImageClass, 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. + SVGLengthContext lengthContext(0); + float x = roundf(cursorElement->x().value(lengthContext)); + m_hotSpot.setX(static_cast<int>(x)); + + float y = roundf(cursorElement->y().value(lengthContext)); + 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()) { + // FIXME: This will fail if the <cursor> element is in a shadow DOM (bug 59827) + 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 000000000..cb26919e4 --- /dev/null +++ b/Source/WebCore/css/CSSCursorImageValue.h @@ -0,0 +1,63 @@ +/* + * 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)); + } + + ~CSSCursorImageValue(); + + IntPoint hotSpot() const { return m_hotSpot; } + + bool updateIfSVGCursorIsUsed(Element*); + StyleCachedImage* cachedImage(CachedResourceLoader*); + +#if ENABLE(SVG) + void removeReferencedElement(SVGElement*); +#endif + +private: + CSSCursorImageValue(const String& url, const IntPoint& hotSpot); + + IntPoint m_hotSpot; + +#if ENABLE(SVG) + HashSet<SVGElement*> m_referencedElements; +#endif +}; + +} // namespace WebCore + +#endif // CSSCursorImageValue_h diff --git a/Source/WebCore/css/CSSElementStyleDeclaration.cpp b/Source/WebCore/css/CSSElementStyleDeclaration.cpp new file mode 100644 index 000000000..81782619c --- /dev/null +++ b/Source/WebCore/css/CSSElementStyleDeclaration.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#include "config.h" +#include "CSSElementStyleDeclaration.h" + +#include "StyledElement.h" + +namespace WebCore { + +CSSStyleSheet* CSSElementStyleDeclaration::styleSheet() const +{ + if (m_element && m_element->document()) + return m_element->document()->elementSheet(); + return 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSElementStyleDeclaration.h b/Source/WebCore/css/CSSElementStyleDeclaration.h new file mode 100644 index 000000000..71ca518d5 --- /dev/null +++ b/Source/WebCore/css/CSSElementStyleDeclaration.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#ifndef CSSElementStyleDeclaration_h +#define CSSElementStyleDeclaration_h + +#include "CSSMutableStyleDeclaration.h" + +namespace WebCore { + +class StyledElement; + +// Base class for CSSInlineStyleDeclaration and FontFaceStyleDeclaration (SVG). + +class CSSElementStyleDeclaration : public CSSMutableStyleDeclaration { +public: + StyledElement* element() const { return m_element; } + void clearElement() { m_element = 0; } + + virtual CSSStyleSheet* styleSheet() const; + +protected: + CSSElementStyleDeclaration(StyledElement* element, bool isInline) + : CSSMutableStyleDeclaration() + , m_element(element) + { + m_isElementStyleDeclaration = true; + m_isInlineStyleDeclaration = isInline; + } + + virtual ~CSSElementStyleDeclaration() { } + +private: + StyledElement* m_element; +}; + +} // namespace WebCore + +#endif // CSSElementStyleDeclaration_h diff --git a/Source/WebCore/css/CSSFlexValue.cpp b/Source/WebCore/css/CSSFlexValue.cpp new file mode 100644 index 000000000..3594507c4 --- /dev/null +++ b/Source/WebCore/css/CSSFlexValue.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 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. + * 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. + */ + +#include "config.h" +#include "CSSFlexValue.h" + +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +String CSSFlexValue::customCssText() const +{ + StringBuilder result; + result.append("-webkit-flex("); + result.append(String::number(m_positiveFlex)); + result.append(" "); + result.append(String::number(m_negativeFlex)); + result.append(" "); + result.append(m_preferredSize->cssText()); + result.append(")"); + return result.toString(); +} + +} diff --git a/Source/WebCore/css/CSSFlexValue.h b/Source/WebCore/css/CSSFlexValue.h new file mode 100644 index 000000000..58c6cce5a --- /dev/null +++ b/Source/WebCore/css/CSSFlexValue.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 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. + * 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. + */ + +#ifndef CSSFlexValue_h +#define CSSFlexValue_h + +#include "CSSPrimitiveValue.h" +#include "CSSValue.h" + +namespace WebCore { + +class CSSFlexValue : public CSSValue { +public: + static PassRefPtr<CSSFlexValue> create(float positiveFlex, float negativeFlex, PassRefPtr<CSSPrimitiveValue> preferredSize) + { + return adoptRef(new CSSFlexValue(positiveFlex, negativeFlex, preferredSize)); + } + + String customCssText() const; + + float positiveFlex() { return m_positiveFlex; } + float negativeFlex() { return m_negativeFlex; } + CSSPrimitiveValue* preferredSize() { return m_preferredSize.get(); } + +private: + CSSFlexValue(float positiveFlex, float negativeFlex, PassRefPtr<CSSPrimitiveValue> preferredSize) + : CSSValue(FlexClass) + , m_positiveFlex(positiveFlex) + , m_negativeFlex(negativeFlex) + , m_preferredSize(preferredSize) + { + } + + float m_positiveFlex; + float m_negativeFlex; + RefPtr<CSSPrimitiveValue> m_preferredSize; +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSFontFace.cpp b/Source/WebCore/css/CSSFontFace.cpp new file mode 100644 index 000000000..67a7f7038 --- /dev/null +++ b/Source/WebCore/css/CSSFontFace.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2007, 2008, 2011 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 { + +bool CSSFontFace::isLoaded() const +{ + size_t size = m_sources.size(); + for (size_t i = 0; i < size; i++) { + if (!m_sources[i]->isLoaded()) + return false; + } + return true; +} + +bool CSSFontFace::isValid() const +{ + size_t size = m_sources.size(); + for (size_t 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(PassOwnPtr<CSSFontFaceSource> source) +{ + source->setFontFace(this); + m_sources.append(source); +} + +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].get(); + return result; + } + } + + return 0; +} + +#if ENABLE(SVG_FONTS) +bool CSSFontFace::hasSVGFontFaceSource() const +{ + size_t size = m_sources.size(); + for (size_t i = 0; i < 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 000000000..7fbbf0a5f --- /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/Forward.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)); } + + 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(PassOwnPtr<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<OwnPtr<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 000000000..b4c697662 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceRule.cpp @@ -0,0 +1,55 @@ +/* + * (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, CSSRule::FONT_FACE_RULE) +{ +} + +CSSFontFaceRule::~CSSFontFaceRule() +{ + if (m_style) + m_style->clearParentRule(); +} + +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 000000000..3d1f76cf3 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceRule.h @@ -0,0 +1,61 @@ +/* + * (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 "CSSMutableStyleDeclaration.h" +#include "CSSRule.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +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)); + } + + ~CSSFontFaceRule(); + + CSSMutableStyleDeclaration* style() const { return m_style.get(); } + + String cssText() const; + + void setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) { m_style = style; } + + void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + +private: + CSSFontFaceRule(CSSStyleSheet* parent); + + 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 000000000..bd38a6137 --- /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 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 000000000..e36735afb --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSource.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2007, 2008, 2010, 2011 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 "Document.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_hasExternalSVGFont(false) +#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; + + 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 (!m_font +#if ENABLE(SVG_FONTS) + && !m_svgFontFaceElement +#endif + ) { + // We're local. Just return a SimpleFontData from the normal cache. + return fontCache()->getCachedFontData(fontDescription, m_string); + } + + // See if we have a mapping in our FontData cache. + unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 6 | fontDescription.widthVariant() << 4 + | (fontDescription.textOrientation() == TextOrientationUpright ? 8 : 0) | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); + + SimpleFontData*& cachedData = m_fontDataTable.add(hashKey, 0).first->second; + if (cachedData) + 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_hasExternalSVGFont) { + // For SVG fonts parse the external SVG document, and extract the <font> element. + if (!m_font->ensureSVGFontData()) + return 0; + + if (!m_externalSVGFontElement) { + String fragmentIdentifier; + size_t start = m_string.find('#'); + if (start != notFound) + fragmentIdentifier = m_string.string().substring(start + 1); + m_externalSVGFontElement = m_font->getSVGFontById(fragmentIdentifier); + } + + 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 = adoptPtr(new SimpleFontData(SVGFontData::create(fontFaceElement), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); + } + } else +#endif + { + // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef. + if (!m_font->ensureCustomFontData()) + return 0; + + fontData = adoptPtr(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.orientation(), + fontDescription.textOrientation(), fontDescription.widthVariant(), fontDescription.renderingMode()), true, false)); + } + } else { +#if ENABLE(SVG_FONTS) + // In-Document SVG Fonts + if (m_svgFontFaceElement) + fontData = adoptPtr(new SimpleFontData(SVGFontData::create(m_svgFontFaceElement.get()), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); +#endif + } + } else { + // Kick off the load. Do it soon rather than now, because we may be in the middle of layout, + // and the loader may invoke arbitrary delegate or event handler code. + fontSelector->beginLoadingFontSoon(m_font.get()); + + // This temporary font is not retained and should not be returned. + FontCachePurgePreventer fontCachePurgePreventer; + SimpleFontData* temporaryFont = fontCache()->getNonRetainedLastResortFallbackFont(fontDescription); + fontData = adoptPtr(new SimpleFontData(temporaryFont->platformData(), true, true)); + } + + if (Document* document = fontSelector->document()) { + cachedData = fontData.get(); + document->registerCustomFont(fontData.release()); + } + + return cachedData; +} + +#if ENABLE(SVG_FONTS) +SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const +{ + return m_svgFontFaceElement.get(); +} + +void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element) +{ + m_svgFontFaceElement = element; +} + +bool CSSFontFaceSource::isSVGFontFaceSource() const +{ + return m_svgFontFaceElement || m_hasExternalSVGFont; +} +#endif + +} diff --git a/Source/WebCore/css/CSSFontFaceSource.h b/Source/WebCore/css/CSSFontFaceSource.h new file mode 100644 index 000000000..e36fe4542 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSource.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007, 2008, 2011 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 "CachedFont.h" +#include "CachedResourceHandle.h" +#include "Timer.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 CachedFontClient { +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; + void setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement>); + bool isSVGFontFaceSource() const; + void setHasExternalSVGFont(bool value) { m_hasExternalSVGFont = value; } +#endif + +private: + void startLoadingTimerFired(Timer<CSSFontFaceSource>*); + + 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) + RefPtr<SVGFontFaceElement> m_svgFontFaceElement; + RefPtr<SVGFontElement> m_externalSVGFontElement; + bool m_hasExternalSVGFont; +#endif +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSFontFaceSrcValue.cpp b/Source/WebCore/css/CSSFontFaceSrcValue.cpp new file mode 100644 index 000000000..57300ef71 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSrcValue.cpp @@ -0,0 +1,80 @@ +/* + * 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 { + +#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::customCssText() 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 000000000..121f4d4e1 --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSrcValue.h @@ -0,0 +1,89 @@ +/* + * 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> + +namespace WebCore { + +class SVGFontFaceElement; + +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)); + } + + 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 + + String customCssText() const; + + void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +private: + CSSFontFaceSrcValue(const String& resource, bool local) + : CSSValue(FontFaceSrcClass) + , 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 000000000..ed715038a --- /dev/null +++ b/Source/WebCore/css/CSSFontSelector.cpp @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2007, 2008, 2011 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 "CSSStyleSelector.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 "WebKitFontFamilyNames.h" +#include <wtf/text/AtomicString.h> + +#if ENABLE(SVG) +#include "SVGFontFaceElement.h" +#include "SVGNames.h" +#endif + +using namespace std; + +namespace WebCore { + +CSSFontSelector::CSSFontSelector(Document* document) + : m_document(document) + , m_beginLoadingTimer(this, &CSSFontSelector::beginLoadTimerFired) +{ + // 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() +{ + clearDocument(); + fontCache()->removeClient(this); +} + +bool CSSFontSelector::isEmpty() const +{ + return m_fonts.isEmpty(); +} + +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)); + OwnPtr<CSSFontFaceSource> source; + +#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) { + ResourceRequest request(m_document->completeURL(item->resource())); + CachedFont* cachedFont = m_document->cachedResourceLoader()->requestFont(request); + if (cachedFont) { + source = adoptPtr(new CSSFontFaceSource(item->resource(), cachedFont)); +#if ENABLE(SVG_FONTS) + if (foundSVGFont) + source->setHasExternalSVGFont(true); +#endif + } + } + } else { + source = adoptPtr(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.release()); + } + } + + 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 = serifFamily; + break; + case CSSValueSansSerif: + familyName = sansSerifFamily; + break; + case CSSValueCursive: + familyName = cursiveFamily; + break; + case CSSValueFantasy: + familyName = fantasyFamily; + break; + case CSSValueMonospace: + familyName = monospaceFamily; + break; + case CSSValueWebkitPictograph: + familyName = pictographFamily; + break; + default: + break; + } + } + + if (familyName.isEmpty()) + continue; + + OwnPtr<Vector<RefPtr<CSSFontFace> > >& familyFontFaces = m_fontFaces.add(familyName, nullptr).first->second; + if (!familyFontFaces) { + familyFontFaces = adoptPtr(new Vector<RefPtr<CSSFontFace> >); + + ASSERT(!m_locallyInstalledFontFaces.contains(familyName)); + + Vector<unsigned> locallyInstalledFontsTraitsMasks; + fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks); + if (unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size()) { + OwnPtr<Vector<RefPtr<CSSFontFace> > > familyLocallyInstalledFaces = adoptPtr(new Vector<RefPtr<CSSFontFace> >); + + for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) { + RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), true); + locallyInstalledFontFace->addSource(adoptPtr(new CSSFontFaceSource(familyName))); + ASSERT(locallyInstalledFontFace->isValid()); + familyLocallyInstalledFaces->append(locallyInstalledFontFace); + } + + m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces.release()); + } + } + + familyFontFaces->append(fontFace); + } +} + +void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client) +{ + m_clients.add(client); +} + +void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client) +{ + m_clients.remove(client); +} + +void CSSFontSelector::dispatchInvalidationCallbacks() +{ + Vector<FontSelectorClient*> clients; + copyToVector(m_clients, clients); + for (size_t i = 0; i < clients.size(); ++i) + clients[i]->fontsNeedUpdate(this); + + // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks. + if (!m_document) + return; + if (CSSStyleSelector* styleSelector = m_document->styleSelectorIfExists()) + styleSelector->invalidateMatchedDeclarationCache(); + if (m_document->inPageCache() || !m_document->renderer()) + return; + m_document->scheduleForcedStyleRecalc(); +} + +void CSSFontSelector::fontLoaded() +{ + dispatchInvalidationCallbacks(); +} + +void CSSFontSelector::fontCacheInvalidated() +{ + dispatchInvalidationCallbacks(); +} + +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; + UScriptCode script = fontDescription.script(); + + if (familyName == serifFamily) + genericFamily = settings->serifFontFamily(script); + else if (familyName == sansSerifFamily) + genericFamily = settings->sansSerifFontFamily(script); + else if (familyName == cursiveFamily) + genericFamily = settings->cursiveFontFamily(script); + else if (familyName == fantasyFamily) + genericFamily = settings->fantasyFontFamily(script); + else if (familyName == monospaceFamily) + genericFamily = settings->fixedFontFamily(script); + else if (familyName == pictographFamily) + genericFamily = settings->pictographFontFamily(script); + else if (familyName == standardFamily) + genericFamily = settings->standardFontFamily(script); + + 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); + if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) + return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard"); + 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. + if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) + return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard"); + return fontDataForGenericFamily(m_document, fontDescription, familyName); + } + + OwnPtr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace> > >& segmentedFontFaceCache = m_fonts.add(family, nullptr).first->second; + if (!segmentedFontFaceCache) + segmentedFontFaceCache = adoptPtr(new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >); + + FontTraitsMask traitsMask = fontDescription.traitsMask(); + + RefPtr<CSSSegmentedFontFace>& face = segmentedFontFaceCache->add(traitsMask, 0).first->second; + if (!face) { + face = CSSSegmentedFontFace::create(this); + + // 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; + 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); +} + +void CSSFontSelector::clearDocument() +{ + if (!m_document) { + ASSERT(!m_beginLoadingTimer.isActive()); + ASSERT(m_fontsToBeginLoading.isEmpty()); + return; + } + + m_beginLoadingTimer.stop(); + + CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader(); + for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) { + // Balances incrementRequestCount() in beginLoadingFontSoon(). + cachedResourceLoader->decrementRequestCount(m_fontsToBeginLoading[i].get()); + } + + m_fontsToBeginLoading.clear(); + + m_document = 0; +} + +void CSSFontSelector::beginLoadingFontSoon(CachedFont* font) +{ + if (!m_document) + return; + + m_fontsToBeginLoading.append(font); + // Increment the request count now, in order to prevent didFinishLoad from being dispatched + // after this font has been requested but before it began loading. Balanced by + // decrementRequestCount() in beginLoadTimerFired() and in clearDocument(). + m_document->cachedResourceLoader()->incrementRequestCount(font); + m_beginLoadingTimer.startOneShot(0); +} + +void CSSFontSelector::beginLoadTimerFired(Timer<WebCore::CSSFontSelector>*) +{ + Vector<CachedResourceHandle<CachedFont> > fontsToBeginLoading; + fontsToBeginLoading.swap(m_fontsToBeginLoading); + + CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader(); + for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) { + fontsToBeginLoading[i]->beginLoadIfNeeded(cachedResourceLoader); + // Balances incrementRequestCount() in beginLoadingFontSoon(). + cachedResourceLoader->decrementRequestCount(fontsToBeginLoading[i].get()); + } +} + +} diff --git a/Source/WebCore/css/CSSFontSelector.h b/Source/WebCore/css/CSSFontSelector.h new file mode 100644 index 000000000..3e992cc74 --- /dev/null +++ b/Source/WebCore/css/CSSFontSelector.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007, 2008, 2011 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 "CachedResourceHandle.h" +#include "FontSelector.h" +#include "Timer.h" +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/RefPtr.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +class CSSFontFace; +class CSSFontFaceRule; +class CSSSegmentedFontFace; +class CachedFont; +class Document; +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(); + + void addFontFaceRule(const CSSFontFaceRule*); + + void fontLoaded(); + virtual void fontCacheInvalidated(); + + bool isEmpty() const; + + virtual void registerForInvalidationCallbacks(FontSelectorClient*); + virtual void unregisterForInvalidationCallbacks(FontSelectorClient*); + + Document* document() const { return m_document; } + + void beginLoadingFontSoon(CachedFont*); + +private: + CSSFontSelector(Document*); + + void dispatchInvalidationCallbacks(); + + void beginLoadTimerFired(Timer<CSSFontSelector>*); + + Document* m_document; + HashMap<String, OwnPtr<Vector<RefPtr<CSSFontFace> > >, CaseFoldingHash> m_fontFaces; + HashMap<String, OwnPtr<Vector<RefPtr<CSSFontFace> > >, CaseFoldingHash> m_locallyInstalledFontFaces; + HashMap<String, OwnPtr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace> > >, CaseFoldingHash> m_fonts; + HashSet<FontSelectorClient*> m_clients; + + Vector<CachedResourceHandle<CachedFont> > m_fontsToBeginLoading; + Timer<CSSFontSelector> m_beginLoadingTimer; +}; + +} // namespace WebCore + +#endif // CSSFontSelector_h diff --git a/Source/WebCore/css/CSSFunctionValue.cpp b/Source/WebCore/css/CSSFunctionValue.cpp new file mode 100644 index 000000000..522ad9fd1 --- /dev/null +++ b/Source/WebCore/css/CSSFunctionValue.cpp @@ -0,0 +1,52 @@ +/* + * 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 "CSSParserValues.h" +#include "CSSValueList.h" +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +CSSFunctionValue::CSSFunctionValue(CSSParserFunction* function) + : CSSValue(FunctionClass) + , m_name(function->name) +{ + if (function->args) + m_args = CSSValueList::createFromParserValueList(function->args.get()); +} + +String CSSFunctionValue::customCssText() const +{ + String result = m_name; // Includes the '(' + if (m_args) + result += m_args->cssText(); + result += ")"; + return result; +} + +} diff --git a/Source/WebCore/css/CSSFunctionValue.h b/Source/WebCore/css/CSSFunctionValue.h new file mode 100644 index 000000000..a35a1b17b --- /dev/null +++ b/Source/WebCore/css/CSSFunctionValue.h @@ -0,0 +1,54 @@ +/* + * 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)); + } + + String customCssText() 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 000000000..41977fb03 --- /dev/null +++ b/Source/WebCore/css/CSSGradientValue.cpp @@ -0,0 +1,868 @@ +/* + * 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 "CSSStyleSelector.h" +#include "CSSValueKeywords.h" +#include "GeneratorGeneratedImage.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 { + +PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize& size) +{ + if (size.isEmpty()) + return 0; + + bool cacheable = isCacheable(); + if (cacheable) { + if (!clients().contains(renderer)) + return 0; + + // Need to look up our size. Create a string of width*height to use as a hash key. + Image* result = getImage(renderer, size); + if (result) + return result; + } + + // We need to create an image. + RefPtr<Gradient> gradient; + + if (isLinearGradient()) + gradient = static_cast<CSSLinearGradientValue*>(this)->createGradient(renderer, size); + else { + ASSERT(isRadialGradient()); + gradient = static_cast<CSSRadialGradientValue*>(this)->createGradient(renderer, size); + } + + RefPtr<Image> newImage = GeneratorGeneratedImage::create(gradient, size); + if (cacheable) + putImage(size, newImage); + + return newImage.release(); +} + +// 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; + } +} + +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()->colorFromPrimitiveValue(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()->colorFromPrimitiveValue(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->computeLength<float>(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) { + // If the difference in the positions of the first and last color-stops is 0, + // the gradient defines a solid-color image with the color of the last color-stop in the rule. + float gradientRange = stops[numStops - 1].offset - stops[0].offset; + if (!gradientRange) { + stops.first().offset = 0; + stops.first().color = stops.last().color; + stops.shrink(1); + numStops = 1; + } else { + 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) { + size_t srcStopIndex = originalFirstStopIndex + srcStopOrdinal; + GradientStop newStop = stops[srcStopIndex]; + newStop.offset = currOffset; + stops.append(newStop); + if (currOffset > maxExtent) + break; + if (srcStopOrdinal < originalNumStops - 1) + currOffset += stops[srcStopIndex + 1].offset - stops[srcStopIndex].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); + // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication. + 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->computeLength<float>(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; +} + +bool CSSGradientValue::isCacheable() const +{ + for (size_t i = 0; i < m_stops.size(); ++i) { + const CSSGradientColorStop& stop = m_stops[i]; + + CSSPrimitiveValue* color = stop.m_color.get(); + if (color->getIdent() == CSSValueCurrentcolor) + return false; + + if (!stop.m_position) + continue; + + unsigned short unitType = stop.m_position->primitiveType(); + if (unitType == CSSPrimitiveValue::CSS_EMS || unitType == CSSPrimitiveValue::CSS_EXS || unitType == CSSPrimitiveValue::CSS_REMS) + return false; + } + + return true; +} + +String CSSLinearGradientValue::customCssText() 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; + } + + if (angleDeg == 270) { + firstPoint.set(0, 0); + secondPoint.set(0, size.height()); + 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::customCssText() 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->computeLength<float>(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 000000000..ea10eb8c2 --- /dev/null +++ b/Source/WebCore/css/CSSGradientValue.h @@ -0,0 +1,173 @@ +/* + * 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: + PassRefPtr<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(); + + bool isLinearGradient() const { return classType() == LinearGradientClass; } + bool isRadialGradient() const { return classType() == RadialGradientClass; } + + bool isRepeating() const { return m_repeating; } + + bool deprecatedType() const { return m_deprecatedType; } // came from -webkit-gradient + + bool isFixedSize() const { return false; } + IntSize fixedSize(const RenderObject*) const { return IntSize(); } + + bool isPending() const { return false; } + void loadSubimages(CachedResourceLoader*) { } + +protected: + CSSGradientValue(ClassType classType, CSSGradientRepeat repeat, bool deprecatedType = false) + : CSSImageGeneratorValue(classType) + , m_stopsSorted(false) + , m_deprecatedType(deprecatedType) + , m_repeating(repeat == Repeating) + { + } + + void addStops(Gradient*, RenderObject*, RenderStyle* rootStyle, float maxLengthForRepeat = 0); + + // Resolve points/radii to front end values. + FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, const IntSize&); + + bool isCacheable() const; + + // 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; } + + String customCssText() const; + + // Create the gradient for a given size. + PassRefPtr<Gradient> createGradient(RenderObject*, const IntSize&); + +private: + CSSLinearGradientValue(CSSGradientRepeat repeat, bool deprecatedType = false) + : CSSGradientValue(LinearGradientClass, repeat, deprecatedType) + { + } + + 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)); + } + + String customCssText() 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; } + + // Create the gradient for a given size. + PassRefPtr<Gradient> createGradient(RenderObject*, const IntSize&); + +private: + CSSRadialGradientValue(CSSGradientRepeat repeat, bool deprecatedType = false) + : CSSGradientValue(RadialGradientClass, repeat, deprecatedType) + { + } + + // 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 000000000..705c36be0 --- /dev/null +++ b/Source/WebCore/css/CSSGrammar.y @@ -0,0 +1,1704 @@ +%{ + +/* + * 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 "CSSSelectorList.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; + CSSParserSelector* selector; + Vector<OwnPtr<CSSParserSelector> >* 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 55 + +%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 WEBKIT_REGION_RULE_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 <string> INVALIDDIMEN +%token <number> PERCENTAGE +%token <number> FLOATTOKEN +%token <number> INTEGER + +%token <string> URI +%token <string> FUNCTION +%token <string> ANYFUNCTION +%token <string> NOTFUNCTION +%token <string> CALCFUNCTION +%token <string> MINFUNCTION +%token <string> MAXFUNCTION + +%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 <rule> region + +%type <string> maybe_ns_prefix + +%type <string> namespace_selector + +%type <string> string_or_uri +%type <string> ident_or_string +%type <string> medium +%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 <selectorList> simple_selector_list +%type <selectorList> region_selector +%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 <value> calc_func_term +%type <character> calc_func_operator +%type <valueList> calc_func_expr +%type <valueList> calc_func_expr_list +%type <valueList> calc_func_paren_expr +%type <value> calc_function +%type <string> min_or_max +%type <value> min_or_max_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); + p->m_valueList = nullptr; + } + } +; + +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 + | region + ; + +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)); + p->updateLastMediaLine($$); + } + | media_list ',' maybe_space media_query { + $$ = $1; + if ($$) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$->appendMediaQuery(p->sinkFloatingMediaQuery($4)); + p->updateLastMediaLine($$); + } + } + | 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(); + $$->setTag(QualifiedName(nullAtom, $1, p->m_defaultNamespace)); + $$->setForPage(); + } + | IDENT pseudo_page { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $2; + if ($$) { + $$->setTag(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; + } +; + +region_selector: + selector_list { + if ($1) { + static_cast<CSSParser*>(parser)->setReusableRegionSelectorVector($1); + $$ = static_cast<CSSParser*>(parser)->reusableRegionSelectorVector(); + } + else + $$ = 0; + } +; + +region: + WEBKIT_REGION_RULE_SYM WHITESPACE region_selector '{' maybe_space block_rule_list save_block { + if ($3) + $$ = static_cast<CSSParser*>(parser)->createRegionRule($3, $6); + else + $$ = 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(); + $$->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); + CSSParserSelector* end = $$; + while (end->tagHistory()) + end = end->tagHistory(); + end->setRelation(CSSSelector::Descendant); + end->setTagHistory(p->sinkFloatingSelector($1)); + } + } + | selector combinator simple_selector { + $$ = $3; + if (!$1) + $$ = 0; + else if ($$) { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSParserSelector* end = $$; + while (end->tagHistory()) + end = end->tagHistory(); + end->setRelation($2); + end->setTagHistory(p->sinkFloatingSelector($1)); + } + } + | 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(); + $$->setTag(QualifiedName(nullAtom, $1, p->m_defaultNamespace)); + } + | element_name specifier_list { + $$ = $2; + if ($$) + static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName(nullAtom, $1, $$); + } + | specifier_list { + $$ = $1; + if ($$) + static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName(nullAtom, starAtom, $$); + } + | namespace_selector element_name { + AtomicString namespacePrefix = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + if (p->m_styleSheet) + $$->setTag(QualifiedName(namespacePrefix, $2, + p->m_styleSheet->determineNamespace(namespacePrefix))); + else // FIXME: Shouldn't this case be an error? + $$->setTag(QualifiedName(nullAtom, $2, p->m_defaultNamespace)); + } + | namespace_selector element_name specifier_list { + $$ = $3; + if ($$) + static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName($1, $2, $$); + } + | namespace_selector specifier_list { + $$ = $2; + if ($$) + static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName($1, starAtom, $$); + } + ; + +simple_selector_list: + simple_selector %prec UNIMPORTANT_TOK { + if ($1) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelectorVector(); + $$->append(p->sinkFloatingSelector($1)); + } else + $$ = 0; + } + | simple_selector_list maybe_space ',' maybe_space simple_selector %prec UNIMPORTANT_TOK { + if ($1 && $5) { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = $1; + $$->append(p->sinkFloatingSelector($5)); + } else + $$ = 0; + } + | simple_selector_list error { + $$ = 0; + } + ; + +element_name: + IDENT { + CSSParserString& str = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + Document* doc = p->findDocument(); + 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) + $$ = static_cast<CSSParser*>(parser)->updateSpecifiers($1, $2); + } + | specifier_list error { + $$ = 0; + } +; + +specifier: + IDSEL { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::Id); + if (!p->m_strict) + $1.lower(); + $$->setValue($1); + } + | HEX { + if ($1.characters[0] >= '0' && $1.characters[0] <= '9') { + $$ = 0; + } else { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::Id); + if (!p->m_strict) + $1.lower(); + $$->setValue($1); + } + } + | class + | attrib + | pseudo + ; + +class: + '.' IDENT { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::Class); + if (!p->m_strict) + $2.lower(); + $$->setValue($2); + } + ; + +attr_name: + IDENT maybe_space { + CSSParserString& str = $1; + CSSParser* p = static_cast<CSSParser*>(parser); + Document* doc = p->findDocument(); + if (doc && doc->isHTMLDocument()) + str.lower(); + $$ = str; + } + ; + +attrib: + '[' maybe_space attr_name ']' { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); + $$->setMatch(CSSSelector::Set); + } + | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); + $$->setMatch((CSSSelector::Match)$4); + $$->setValue($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))); + $$->setMatch(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))); + $$->setMatch((CSSSelector::Match)$5); + $$->setValue($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(); + $$->setMatch(CSSSelector::PagePseudoClass); + $2.lower(); + $$->setValue($2); + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + } + +pseudo: + ':' IDENT { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoClass); + $2.lower(); + $$->setValue($2); + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + } + | ':' ':' IDENT { + $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoElement); + $3.lower(); + $$->setValue($3); + // FIXME: This call is needed to force selector to compute the pseudoType early enough. + $$->pseudoType(); + } + // use by :-webkit-any. + // FIXME: should we support generic selectors here or just simple_selectors? + // Use simple_selector_list for now to match -moz-any. + // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0566.html for some + // related discussion with respect to :not. + | ':' ANYFUNCTION maybe_space simple_selector_list maybe_space ')' { + if ($4) { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoClass); + $$->adoptSelectorVector(*p->sinkFloatingSelectorVector($4)); + $2.lower(); + $$->setValue($2); + CSSSelector::PseudoType type = $$->pseudoType(); + if (type != CSSSelector::PseudoAny) + $$ = 0; + } else + $$ = 0; + } + // used by :nth-*(ax+b) + | ':' FUNCTION maybe_space NTH maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoClass); + $$->setArgument($4); + $$->setValue($2); + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + } + // used by :nth-* + | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoClass); + $$->setArgument(String::number($4 * $5)); + $$->setValue($2); + CSSSelector::PseudoType type = $$->pseudoType(); + if (type == CSSSelector::PseudoUnknown) + $$ = 0; + } + // used by :nth-*(odd/even) and :lang + | ':' FUNCTION maybe_space IDENT maybe_space ')' { + CSSParser *p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingSelector(); + $$->setMatch(CSSSelector::PseudoClass); + $$->setArgument($4); + $2.lower(); + $$->setValue($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)) + $$ = 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(); + $$->setMatch(CSSSelector::PseudoClass); + + Vector<OwnPtr<CSSParserSelector> > selectorVector; + selectorVector.append(p->sinkFloatingSelector($4)); + $$->adoptSelectorVector(selectorVector); + + $2.lower(); + $$->setValue($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; + p->m_valueList = nullptr; + } + 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; } + | HEX maybe_space { $$.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; + } + | calc_function { + $$ = $1; + } + | min_or_max_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->findDocument()) + 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 expr TOKEN_EOF { + 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 ')' maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + CSSParserFunction* f = p->createFloatingFunction(); + f->name = $1; + CSSParserValueList* valueList = p->createFloatingValueList(); + f->args = p->sinkFloatingValueList(valueList); + $$.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 = nullptr; + $$.id = 0; + $$.unit = CSSParserValue::Function; + $$.function = f; + } + ; + +calc_func_term: + unary_term { $$ = $1; } + | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } + ; + +calc_func_operator: + '+' WHITESPACE { + $$ = '+'; + } + | '-' WHITESPACE { + $$ = '-'; + } + | '*' maybe_space { + $$ = '*'; + } + | '/' maybe_space { + $$ = '/'; + } + | IDENT maybe_space { + if (equalIgnoringCase("mod", $1.characters, $1.length)) + $$ = '%'; + else + $$ = 0; + } + ; + +calc_func_paren_expr: + '(' maybe_space calc_func_expr maybe_space ')' maybe_space { + if ($3) { + $$ = $3; + CSSParserValue v; + v.id = 0; + v.unit = CSSParserValue::Operator; + v.iValue = '('; + $$->insertValueAt(0, v); + v.iValue = ')'; + $$->addValue(v); + } else + $$ = 0; + } + +calc_func_expr: + calc_func_term maybe_space { + CSSParser* p = static_cast<CSSParser*>(parser); + $$ = p->createFloatingValueList(); + $$->addValue(p->sinkFloatingValue($1)); + } + | calc_func_expr calc_func_operator calc_func_term { + CSSParser* p = static_cast<CSSParser*>(parser); + if ($1 && $2) { + $$ = $1; + CSSParserValue v; + v.id = 0; + v.unit = CSSParserValue::Operator; + v.iValue = $2; + $$->addValue(v); + $$->addValue(p->sinkFloatingValue($3)); + } else + $$ = 0; + + } + | calc_func_expr calc_func_operator calc_func_paren_expr { + if ($1 && $2 && $3) { + $$ = $1; + CSSParserValue v; + v.id = 0; + v.unit = CSSParserValue::Operator; + v.iValue = $2; + $$->addValue(v); + $$->extend(*($3)); + } else + $$ = 0; + } + | calc_func_paren_expr + | calc_func_expr error { + $$ = 0; + } + ; + +calc_func_expr_list: + calc_func_expr { + $$ = $1; + } + | calc_func_expr_list ',' maybe_space calc_func_expr { + if ($1 && $4) { + $$ = $1; + CSSParserValue v; + v.id = 0; + v.unit = CSSParserValue::Operator; + v.iValue = ','; + $$->addValue(v); + $$->extend(*($4)); + } else + $$ = 0; + } + + +calc_function: + CALCFUNCTION maybe_space calc_func_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; + } + | CALCFUNCTION maybe_space error { + YYERROR; + } + ; + + +min_or_max: + MINFUNCTION { + $$ = $1; + } + | MAXFUNCTION { + $$ = $1; + } + ; + +min_or_max_function: + min_or_max maybe_space calc_func_expr_list ')' 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; + } + | min_or_max maybe_space error { + YYERROR; + } + ; + +/* 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 000000000..6f2ffca9b --- /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 000000000..9be446bd0 --- /dev/null +++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp @@ -0,0 +1,199 @@ +/* + * 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 "CSSCanvasValue.h" +#include "CSSCrossfadeValue.h" +#include "CSSGradientValue.h" +#include "Image.h" +#include "RenderObject.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType classType) + : CSSValue(classType) +{ +} + +CSSImageGeneratorValue::~CSSImageGeneratorValue() +{ +} + +void CSSImageGeneratorValue::addClient(RenderObject* renderer, const IntSize& size) +{ + ref(); + + ASSERT(renderer); + if (!size.isEmpty()) + m_sizes.add(size); + + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + if (it == m_clients.end()) + m_clients.add(renderer, SizeAndCount(size, 1)); + else { + SizeAndCount& sizeCount = it->second; + ++sizeCount.count; + } +} + +void CSSImageGeneratorValue::removeClient(RenderObject* renderer) +{ + ASSERT(renderer); + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + ASSERT(it != m_clients.end()); + + IntSize removedImageSize; + SizeAndCount& sizeCount = it->second; + IntSize size = sizeCount.size; + if (!size.isEmpty()) { + m_sizes.remove(size); + if (!m_sizes.contains(size)) + m_images.remove(size); + } + + if (!--sizeCount.count) + m_clients.remove(renderer); + + deref(); +} + +Image* CSSImageGeneratorValue::getImage(RenderObject* renderer, const IntSize& size) +{ + RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); + if (it != m_clients.end()) { + SizeAndCount& sizeCount = it->second; + IntSize oldSize = sizeCount.size; + if (oldSize != size) { + 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); +} + +PassRefPtr<Image> CSSImageGeneratorValue::image(RenderObject* renderer, const IntSize& size) +{ + switch (classType()) { + case CanvasClass: + return static_cast<CSSCanvasValue*>(this)->image(renderer, size); + case CrossfadeClass: + return static_cast<CSSCrossfadeValue*>(this)->image(renderer, size); + case LinearGradientClass: + return static_cast<CSSLinearGradientValue*>(this)->image(renderer, size); + case RadialGradientClass: + return static_cast<CSSRadialGradientValue*>(this)->image(renderer, size); + default: + ASSERT_NOT_REACHED(); + } + return 0; +} + +bool CSSImageGeneratorValue::isFixedSize() const +{ + switch (classType()) { + case CanvasClass: + return static_cast<const CSSCanvasValue*>(this)->isFixedSize(); + case CrossfadeClass: + return static_cast<const CSSCrossfadeValue*>(this)->isFixedSize(); + case LinearGradientClass: + return static_cast<const CSSLinearGradientValue*>(this)->isFixedSize(); + case RadialGradientClass: + return static_cast<const CSSRadialGradientValue*>(this)->isFixedSize(); + default: + ASSERT_NOT_REACHED(); + } + return false; +} + +IntSize CSSImageGeneratorValue::fixedSize(const RenderObject* renderer) +{ + switch (classType()) { + case CanvasClass: + return static_cast<CSSCanvasValue*>(this)->fixedSize(renderer); + case CrossfadeClass: + return static_cast<CSSCrossfadeValue*>(this)->fixedSize(renderer); + case LinearGradientClass: + return static_cast<CSSLinearGradientValue*>(this)->fixedSize(renderer); + case RadialGradientClass: + return static_cast<CSSRadialGradientValue*>(this)->fixedSize(renderer); + default: + ASSERT_NOT_REACHED(); + } + return IntSize(); +} + +bool CSSImageGeneratorValue::isPending() const +{ + switch (classType()) { + case CrossfadeClass: + return static_cast<const CSSCrossfadeValue*>(this)->isPending(); + case CanvasClass: + return static_cast<const CSSCanvasValue*>(this)->isPending(); + case LinearGradientClass: + return static_cast<const CSSLinearGradientValue*>(this)->isPending(); + case RadialGradientClass: + return static_cast<const CSSRadialGradientValue*>(this)->isPending(); + default: + ASSERT_NOT_REACHED(); + } + return false; +} + +void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader* cachedResourceLoader) +{ + switch (classType()) { + case CrossfadeClass: + static_cast<CSSCrossfadeValue*>(this)->loadSubimages(cachedResourceLoader); + break; + case CanvasClass: + static_cast<CSSCanvasValue*>(this)->loadSubimages(cachedResourceLoader); + break; + case LinearGradientClass: + static_cast<CSSLinearGradientValue*>(this)->loadSubimages(cachedResourceLoader); + break; + case RadialGradientClass: + static_cast<CSSRadialGradientValue*>(this)->loadSubimages(cachedResourceLoader); + break; + default: + ASSERT_NOT_REACHED(); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSImageGeneratorValue.h b/Source/WebCore/css/CSSImageGeneratorValue.h new file mode 100644 index 000000000..877969a90 --- /dev/null +++ b/Source/WebCore/css/CSSImageGeneratorValue.h @@ -0,0 +1,82 @@ +/* + * 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/HashCountedSet.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CachedResourceLoader; +class Image; +class RenderObject; + +struct SizeAndCount { + SizeAndCount(IntSize newSize = IntSize(), int newCount = 0) + : size(newSize) + , count(newCount) + { + } + + IntSize size; + int count; +}; + +typedef HashMap<const RenderObject*, SizeAndCount> RenderObjectSizeCountMap; + +class CSSImageGeneratorValue : public CSSValue { +public: + ~CSSImageGeneratorValue(); + + void addClient(RenderObject*, const IntSize&); + void removeClient(RenderObject*); + PassRefPtr<Image> image(RenderObject*, const IntSize&); + + bool isFixedSize() const; + IntSize fixedSize(const RenderObject*); + + bool isPending() const; + + void loadSubimages(CachedResourceLoader*); + +protected: + CSSImageGeneratorValue(ClassType); + + Image* getImage(RenderObject*, const IntSize&); + void putImage(const IntSize&, PassRefPtr<Image>); + const RenderObjectSizeCountMap& clients() const { return m_clients; } + + 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. +}; + +} // namespace WebCore + +#endif // CSSImageGeneratorValue_h diff --git a/Source/WebCore/css/CSSImageValue.cpp b/Source/WebCore/css/CSSImageValue.cpp new file mode 100644 index 000000000..8437f3ec0 --- /dev/null +++ b/Source/WebCore/css/CSSImageValue.cpp @@ -0,0 +1,110 @@ +/* + * (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 "CSSCursorImageValue.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "MemoryCache.h" +#include "CachedImage.h" +#include "CachedResourceLoader.h" +#include "StyleCachedImage.h" +#include "StylePendingImage.h" + +namespace WebCore { + +CSSImageValue::CSSImageValue(ClassType classType, const String& url) + : CSSPrimitiveValue(classType, url, CSS_URI) + , m_accessedImage(false) +{ +} + +CSSImageValue::CSSImageValue() + : CSSPrimitiveValue(ImageClass, CSSValueNone) + , m_accessedImage(true) +{ +} + +CSSImageValue::CSSImageValue(const String& url) + : CSSPrimitiveValue(ImageClass, url, CSS_URI) + , m_accessedImage(false) +{ +} + +CSSImageValue::CSSImageValue(const String& url, StyleImage* image) + : CSSPrimitiveValue(ImageClass, url, CSS_URI) + , m_image(image) + , m_accessedImage(true) +{ +} + +CSSImageValue::~CSSImageValue() +{ +} + +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) +{ + if (isCursorImageValue()) + return static_cast<CSSCursorImageValue*>(this)->cachedImage(loader); + return cachedImage(loader, getStringValue()); +} + +StyleCachedImage* CSSImageValue::cachedImage(CachedResourceLoader* loader, const String& url) +{ + ASSERT(loader); + + if (!m_accessedImage) { + m_accessedImage = true; + + ResourceRequest request(loader->document()->completeURL(url)); + if (CachedImage* cachedImage = loader->requestImage(request)) + 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() +{ + 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 000000000..82e34de4d --- /dev/null +++ b/Source/WebCore/css/CSSImageValue.h @@ -0,0 +1,62 @@ +/* + * (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 <wtf/RefPtr.h> + +namespace WebCore { + +class CachedResourceLoader; +class StyleCachedImage; +class StyleImage; + +class CSSImageValue : public CSSPrimitiveValue { +public: + static PassRefPtr<CSSImageValue> create() { return adoptRef(new CSSImageValue); } + static PassRefPtr<CSSImageValue> create(const String& url) { return adoptRef(new CSSImageValue(url)); } + static PassRefPtr<CSSImageValue> create(const String& url, StyleImage* image) { return adoptRef(new CSSImageValue(url, image)); } + ~CSSImageValue(); + + StyleCachedImage* cachedImage(CachedResourceLoader*); + // Returns a StyleCachedImage if the image is cached already, otherwise a StylePendingImage. + StyleImage* cachedOrPendingImage(); + +protected: + CSSImageValue(ClassType, const String& url); + + StyleCachedImage* cachedImage(CachedResourceLoader*, const String& url); + String cachedImageURL(); + void clearCachedImage(); + +private: + CSSImageValue(); + explicit CSSImageValue(const String& url); + explicit CSSImageValue(const String& url, StyleImage*); + + 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 000000000..7e210a82c --- /dev/null +++ b/Source/WebCore/css/CSSImportRule.cpp @@ -0,0 +1,180 @@ +/* + * (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, CSSRule::IMPORT_RULE) + , m_styleSheetClient(this) + , m_strHref(href) + , m_lstMedia(media) + , m_cachedSheet(0) + , m_loading(false) +{ + ASSERT(parent); + if (m_lstMedia) + m_lstMedia->setParentStyleSheet(parent); + else + m_lstMedia = MediaList::create(parent, String()); +} + +CSSImportRule::~CSSImportRule() +{ + if (m_lstMedia) + m_lstMedia->setParentStyleSheet(0); + if (m_styleSheet) + m_styleSheet->clearOwnerRule(); + if (m_cachedSheet) + m_cachedSheet->removeClient(&m_styleSheetClient); +} + +void CSSImportRule::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet) +{ + if (m_styleSheet) + m_styleSheet->clearOwnerRule(); + 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; + Document* document = parent ? parent->findDocument() : 0; + bool needsSiteSpecificQuirks = document && document->settings() && document->settings()->needsSiteSpecificQuirks(); + +#ifdef 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 (!document || !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::requestStyleSheet() +{ + CSSStyleSheet* parentSheet = parentStyleSheet(); + if (!parentSheet) + return; + Document* document = parentSheet->findDocument(); + if (!document) + return; + + CachedResourceLoader* cachedResourceLoader = 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. + CSSStyleSheet* rootSheet = parentSheet; + for (CSSStyleSheet* sheet = parentSheet; sheet; sheet = sheet->parentStyleSheet()) { + // FIXME: This is wrong if the finalURL was updated via document::updateBaseURL. + if (absHref == sheet->finalURL().string()) + return; + rootSheet = sheet; + } + + ResourceRequest request(document->completeURL(absHref)); + if (parentSheet->isUserStyleSheet()) + m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(request, parentSheet->charset()); + else + m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(request, 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() && rootSheet == parentSheet) + parentSheet->startLoadingDynamicSheet(); + m_loading = true; + m_cachedSheet->addClient(&m_styleSheetClient); + } +} + +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()); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSImportRule.h b/Source/WebCore/css/CSSImportRule.h new file mode 100644 index 000000000..ad15087ba --- /dev/null +++ b/Source/WebCore/css/CSSImportRule.h @@ -0,0 +1,88 @@ +/* + * (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 "CachedResourceHandle.h" +#include "CachedStyleSheetClient.h" +#include "MediaList.h" +#include "PlatformString.h" + +namespace WebCore { + +class CachedCSSStyleSheet; +class MediaList; + +class CSSImportRule : public CSSRule { +public: + static PassRefPtr<CSSImportRule> create(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaList> media) + { + return adoptRef(new CSSImportRule(parent, href, media)); + } + + ~CSSImportRule(); + + String href() const { return m_strHref; } + MediaList* media() const { return m_lstMedia.get(); } + CSSStyleSheet* styleSheet() const { return m_styleSheet.get(); } + + String cssText() const; + + // Not part of the CSSOM + bool isLoading() const; + + void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + + void requestStyleSheet(); + +private: + // NOTE: We put the CachedStyleSheetClient in a member instead of inheriting from it + // to avoid adding a vptr to CSSImportRule. + class ImportedStyleSheetClient : public CachedStyleSheetClient { + public: + ImportedStyleSheetClient(CSSImportRule* ownerRule) : m_ownerRule(ownerRule) { } + virtual ~ImportedStyleSheetClient() { } + virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet) + { + m_ownerRule->setCSSStyleSheet(href, baseURL, charset, sheet); + } + private: + CSSImportRule* m_ownerRule; + }; + + void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*); + friend class ImportedStyleSheetClient; + + CSSImportRule(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaList>); + + ImportedStyleSheetClient m_styleSheetClient; + 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 000000000..05654fe27 --- /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 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 000000000..8c4be6d4b --- /dev/null +++ b/Source/WebCore/css/CSSInheritedValue.cpp @@ -0,0 +1,33 @@ +/** + * (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 { + +String CSSInheritedValue::customCssText() const +{ + return "inherit"; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSInheritedValue.h b/Source/WebCore/css/CSSInheritedValue.h new file mode 100644 index 000000000..5aa906367 --- /dev/null +++ b/Source/WebCore/css/CSSInheritedValue.h @@ -0,0 +1,47 @@ +/* + * (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); + } + + String customCssText() const; + +private: + CSSInheritedValue() + : CSSValue(InheritedClass) + { + } +}; + +} // namespace WebCore + +#endif // CSSInheritedValue_h diff --git a/Source/WebCore/css/CSSInitialValue.cpp b/Source/WebCore/css/CSSInitialValue.cpp new file mode 100644 index 000000000..8de3f3182 --- /dev/null +++ b/Source/WebCore/css/CSSInitialValue.cpp @@ -0,0 +1,33 @@ +/** + * (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 { + +String CSSInitialValue::customCssText() const +{ + return "initial"; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSInitialValue.h b/Source/WebCore/css/CSSInitialValue.h new file mode 100644 index 000000000..f5888903b --- /dev/null +++ b/Source/WebCore/css/CSSInitialValue.h @@ -0,0 +1,52 @@ +/* + * (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() + { + return adoptRef(new CSSInitialValue(/* implicit */ false)); + } + static PassRefPtr<CSSInitialValue> createImplicit() + { + return adoptRef(new CSSInitialValue(/* implicit */ true)); + } + + String customCssText() const; + +private: + CSSInitialValue(bool implicit) + : CSSValue(InitialClass) + { + m_isImplicitInitialValue = implicit; + } +}; + +} // namespace WebCore + +#endif // CSSInitialValue_h diff --git a/Source/WebCore/css/CSSInlineStyleDeclaration.h b/Source/WebCore/css/CSSInlineStyleDeclaration.h new file mode 100644 index 000000000..718e40959 --- /dev/null +++ b/Source/WebCore/css/CSSInlineStyleDeclaration.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Andreas Kling (kling@webkit.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. + */ + +#ifndef CSSInlineStyleDeclaration_h +#define CSSInlineStyleDeclaration_h + +#include "CSSElementStyleDeclaration.h" + +namespace WebCore { + +class CSSInlineStyleDeclaration : public CSSElementStyleDeclaration { +public: + virtual ~CSSInlineStyleDeclaration() { } + + static PassRefPtr<CSSInlineStyleDeclaration> create(StyledElement* element) + { + return adoptRef(new CSSInlineStyleDeclaration(element)); + } + +private: + CSSInlineStyleDeclaration(StyledElement* element) + : CSSElementStyleDeclaration(element, /* isInline */ true) + { + } +}; + +inline CSSInlineStyleDeclaration* toCSSInlineStyleDeclaration(CSSMutableStyleDeclaration* decl) +{ + ASSERT(!decl || decl->isInlineStyleDeclaration()); + return static_cast<CSSInlineStyleDeclaration*>(decl); +} + +} // namespace WebCore + +#endif // CSSInlineStyleDeclaration_h diff --git a/Source/WebCore/css/CSSLineBoxContainValue.cpp b/Source/WebCore/css/CSSLineBoxContainValue.cpp new file mode 100644 index 000000000..53132eb19 --- /dev/null +++ b/Source/WebCore/css/CSSLineBoxContainValue.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#include "config.h" +#include "CSSLineBoxContainValue.h" + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" + +namespace WebCore { + +CSSLineBoxContainValue::CSSLineBoxContainValue(unsigned value) + : CSSValue(LineBoxContainClass) + , m_value(value) +{ +} + +String CSSLineBoxContainValue::customCssText() const +{ + String text(""); + + if (m_value & LineBoxContainBlock) + text += "block"; + if (m_value & LineBoxContainInline) { + if (!text.isEmpty()) + text += " "; + text += "inline"; + } + if (m_value & LineBoxContainFont) { + if (!text.isEmpty()) + text += " "; + text += "font"; + } + if (m_value & LineBoxContainGlyphs) { + if (!text.isEmpty()) + text += " "; + text += "glyphs"; + } + if (m_value & LineBoxContainReplaced) { + if (!text.isEmpty()) + text += " "; + text += "replaced"; + } + if (m_value & LineBoxContainInlineBox) { + if (!text.isEmpty()) + text += " "; + text += "inline-box"; + } + + return text; +} + +} diff --git a/Source/WebCore/css/CSSLineBoxContainValue.h b/Source/WebCore/css/CSSLineBoxContainValue.h new file mode 100644 index 000000000..ddc0c60f3 --- /dev/null +++ b/Source/WebCore/css/CSSLineBoxContainValue.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#ifndef CSSLineBoxContainValue_h +#define CSSLineBoxContainValue_h + +#include "CSSValue.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSPrimitiveValue; + +enum LineBoxContainFlags { LineBoxContainNone = 0x0, LineBoxContainBlock = 0x1, LineBoxContainInline = 0x2, LineBoxContainFont = 0x4, LineBoxContainGlyphs = 0x8, + LineBoxContainReplaced = 0x10, LineBoxContainInlineBox = 0x20 }; +typedef unsigned LineBoxContain; + +// Used for text-CSSLineBoxContain and box-CSSLineBoxContain +class CSSLineBoxContainValue : public CSSValue { +public: + static PassRefPtr<CSSLineBoxContainValue> create(LineBoxContain value) + { + return adoptRef(new CSSLineBoxContainValue(value)); + } + + String customCssText() const; + + LineBoxContain value() const { return m_value; } + +private: + LineBoxContain m_value; + +private: + CSSLineBoxContainValue(LineBoxContain); +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/CSSMediaRule.cpp b/Source/WebCore/css/CSSMediaRule.cpp new file mode 100644 index 000000000..baf19b69a --- /dev/null +++ b/Source/WebCore/css/CSSMediaRule.cpp @@ -0,0 +1,130 @@ +/** + * (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, CSSRule::MEDIA_RULE) + , m_lstMedia(media) + , m_lstCSSRules(rules) +{ + m_lstMedia->setParentStyleSheet(parent); + int length = m_lstCSSRules->length(); + for (int i = 0; i < length; i++) + m_lstCSSRules->item(i)->setParentRule(this); +} + +CSSMediaRule::~CSSMediaRule() +{ + if (m_lstMedia) + m_lstMedia->setParentStyleSheet(0); + + int length = m_lstCSSRules->length(); + for (int i = 0; i < length; i++) + m_lstCSSRules->item(i)->setParentRule(0); +} + +unsigned CSSMediaRule::append(CSSRule* rule) +{ + if (!rule) + return 0; + + rule->setParentRule(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->setParentRule(this); + unsigned returnedIndex = m_lstCSSRules->insertRule(newRule.get(), index); + + if (CSSStyleSheet* styleSheet = parentStyleSheet()) + 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->item(index)->setParentRule(0); + m_lstCSSRules->deleteRule(index); + + if (CSSStyleSheet* styleSheet = parentStyleSheet()) + styleSheet->styleSheetChanged(); +} + +String CSSMediaRule::cssText() const +{ + String result = "@media "; + if (m_lstMedia) { + result += m_lstMedia->mediaText(); + result += " "; + } + result += "{ \n"; + + if (m_lstCSSRules) + result += m_lstCSSRules->rulesText(); + + result += "}"; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSMediaRule.h b/Source/WebCore/css/CSSMediaRule.h new file mode 100644 index 000000000..a591192a9 --- /dev/null +++ b/Source/WebCore/css/CSSMediaRule.h @@ -0,0 +1,63 @@ +/* + * (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 CSSMediaRule : public CSSRule { +public: + static PassRefPtr<CSSMediaRule> create(CSSStyleSheet* parent, PassRefPtr<MediaList> media, PassRefPtr<CSSRuleList> rules) + { + return adoptRef(new CSSMediaRule(parent, media, rules)); + } + ~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&); + + String cssText() const; + + // Not part of the CSSOM + unsigned append(CSSRule*); + +private: + CSSMediaRule(CSSStyleSheet* parent, PassRefPtr<MediaList>, PassRefPtr<CSSRuleList>); + + 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 000000000..cf1a488b5 --- /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 CSSMediaRule : CSSRule { + readonly attribute MediaList media; + readonly attribute CSSRuleList cssRules; + + [OldStyleObjC] unsigned long insertRule(in [Optional=CallWithDefaultValue] DOMString rule, + in [Optional=CallWithDefaultValue] unsigned long index) + raises(DOMException); + void deleteRule(in [Optional=CallWithDefaultValue] unsigned long index) + raises(DOMException); + }; + +} diff --git a/Source/WebCore/css/CSSMutableStyleDeclaration.cpp b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp new file mode 100644 index 000000000..c831b07df --- /dev/null +++ b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp @@ -0,0 +1,1055 @@ +/* + * (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2011 Research In Motion Limited. 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 "CSSInlineStyleDeclaration.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 "HTMLNames.h" +#include "InspectorInstrumentation.h" +#include "MutationObserverInterestGroup.h" +#include "MutationRecord.h" +#include "StyledElement.h" +#include "WebKitMutationObserver.h" +#include <wtf/text/StringBuilder.h> +#include <wtf/text/WTFString.h> + +using namespace std; + +namespace WebCore { + +namespace { + +class StyleAttributeMutationScope { + WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope); +public: + StyleAttributeMutationScope(CSSMutableStyleDeclaration* decl) + { + ++s_scopeCount; + + if (s_scopeCount != 1) { + ASSERT(s_currentDecl == decl); + return; + } + + ASSERT(!s_currentDecl); + s_currentDecl = decl; + +#if ENABLE(MUTATION_OBSERVERS) + if (!s_currentDecl->isInlineStyleDeclaration()) + return; + + CSSInlineStyleDeclaration* inlineDecl = toCSSInlineStyleDeclaration(s_currentDecl); + if (!inlineDecl->element()) + return; + + m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(inlineDecl->element(), HTMLNames::styleAttr); + if (!m_mutationRecipients) + return; + + AtomicString oldValue = m_mutationRecipients->isOldValueRequested() ? inlineDecl->element()->getAttribute(HTMLNames::styleAttr) : nullAtom; + m_mutation = MutationRecord::createAttributes(inlineDecl->element(), HTMLNames::styleAttr, oldValue); +#endif + } + + ~StyleAttributeMutationScope() + { + --s_scopeCount; + if (s_scopeCount) + return; + +#if ENABLE(MUTATION_OBSERVERS) + if (m_mutation && s_shouldDeliver) + m_mutationRecipients->enqueueMutationRecord(m_mutation); + s_shouldDeliver = false; +#endif + + if (!s_shouldNotifyInspector) { + s_currentDecl = 0; + return; + } + + CSSInlineStyleDeclaration* inlineDecl = toCSSInlineStyleDeclaration(s_currentDecl); + s_currentDecl = 0; + s_shouldNotifyInspector = false; + if (inlineDecl->element() && inlineDecl->element()->document()) + InspectorInstrumentation::didInvalidateStyleAttr(inlineDecl->element()->document(), inlineDecl->element()); + } + +#if ENABLE(MUTATION_OBSERVERS) + void enqueueMutationRecord() + { + s_shouldDeliver = true; + } +#endif + + void didInvalidateStyleAttr() + { + ASSERT(s_currentDecl->isInlineStyleDeclaration()); + s_shouldNotifyInspector = true; + } + +private: + static unsigned s_scopeCount; + static CSSMutableStyleDeclaration* s_currentDecl; + static bool s_shouldNotifyInspector; +#if ENABLE(MUTATION_OBSERVERS) + static bool s_shouldDeliver; + + OwnPtr<MutationObserverInterestGroup> m_mutationRecipients; + RefPtr<MutationRecord> m_mutation; +#endif +}; + +unsigned StyleAttributeMutationScope::s_scopeCount = 0; +CSSMutableStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0; +bool StyleAttributeMutationScope::s_shouldNotifyInspector = false; +#if ENABLE(MUTATION_OBSERVERS) +bool StyleAttributeMutationScope::s_shouldDeliver = false; +#endif + +} // namespace + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration() + : CSSStyleDeclaration(0) +{ + // This constructor is used for various inline style declarations, so disable strict parsing. + m_strictParsing = false; +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent) + : CSSStyleDeclaration(parent) +{ +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const Vector<CSSProperty>& properties) + : CSSStyleDeclaration(parent) + , m_properties(properties) +{ + m_properties.shrinkToFit(); + // FIXME: This allows duplicate properties. +} + +CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const CSSProperty* const * properties, int numProperties) + : CSSStyleDeclaration(parent) +{ + m_properties.reserveInitialCapacity(numProperties); + HashMap<int, bool> candidates; + for (int i = 0; i < numProperties; ++i) { + const CSSProperty *property = properties[i]; + ASSERT(property); + bool important = property->isImportant(); + + HashMap<int, bool>::iterator it = candidates.find(property->id()); + if (it != candidates.end()) { + if (!important && it->second) + continue; + removeProperty(property->id(), false, false); + } + + m_properties.append(*property); + candidates.set(property->id(), important); + } +} + +CSSMutableStyleDeclaration::~CSSMutableStyleDeclaration() +{ +} + +void CSSMutableStyleDeclaration::copyPropertiesFrom(const CSSMutableStyleDeclaration& other) +{ + ASSERT(!m_iteratorCount); + m_properties = other.m_properties; +} + +String CSSMutableStyleDeclaration::getPropertyValue(int propertyID) const +{ + RefPtr<CSSValue> value = getPropertyCSSValue(propertyID); + if (value) + return value->cssText(); + + // Shorthand and 4-values properties + switch (propertyID) { + case CSSPropertyBorderSpacing: { + const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyWebkitBorderVerticalSpacing }; + return borderSpacingValue(properties); + } + case CSSPropertyBackgroundPosition: { + // FIXME: Is this correct? The code in cssparser.cpp is confusing + const int properties[2] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyBackgroundRepeat: { + const int properties[2] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyBackground: { + const int properties[9] = { CSSPropertyBackgroundColor, + CSSPropertyBackgroundImage, + CSSPropertyBackgroundRepeatX, + CSSPropertyBackgroundRepeatY, + CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundPositionX, + CSSPropertyBackgroundPositionY, + CSSPropertyBackgroundClip, + CSSPropertyBackgroundOrigin }; + return getLayeredShorthandValue(properties); + } + 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]); + if (!value.isNull()) { + if (!res.isNull()) + res += " "; + res += value; + } + } + return res; + } + case CSSPropertyBorderTop: { + const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, + CSSPropertyBorderTopColor}; + return getShorthandValue(properties); + } + case CSSPropertyBorderRight: { + const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, + CSSPropertyBorderRightColor}; + return getShorthandValue(properties); + } + case CSSPropertyBorderBottom: { + const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, + CSSPropertyBorderBottomColor}; + return getShorthandValue(properties); + } + case CSSPropertyBorderLeft: { + const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, + CSSPropertyBorderLeftColor}; + return getShorthandValue(properties); + } + case CSSPropertyOutline: { + const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle, + CSSPropertyOutlineColor }; + return getShorthandValue(properties); + } + 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 CSSPropertyWebkitFlexFlow: { + const int properties[] = { CSSPropertyWebkitFlexDirection, CSSPropertyWebkitFlexWrap }; + return getShorthandValue(properties); + } + case CSSPropertyFont: + return fontValue(); + case CSSPropertyMargin: { + const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, + CSSPropertyMarginBottom, CSSPropertyMarginLeft }; + return get4Values(properties); + } + case CSSPropertyOverflow: { + const int properties[2] = { CSSPropertyOverflowX, CSSPropertyOverflowY }; + return getCommonValue(properties); + } + 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); + } + case CSSPropertyWebkitMaskPosition: { + // FIXME: Is this correct? The code in cssparser.cpp is confusing + const int properties[2] = { CSSPropertyWebkitMaskPositionX, CSSPropertyWebkitMaskPositionY }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyWebkitMaskRepeat: { + const int properties[2] = { CSSPropertyWebkitMaskRepeatX, CSSPropertyWebkitMaskRepeatY }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyWebkitMask: { + const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskClip, + CSSPropertyWebkitMaskOrigin }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyWebkitTransformOrigin: { + const int properties[3] = { CSSPropertyWebkitTransformOriginX, + CSSPropertyWebkitTransformOriginY, + CSSPropertyWebkitTransformOriginZ }; + return getShorthandValue(properties); + } + case CSSPropertyWebkitTransition: { + const int properties[4] = { CSSPropertyWebkitTransitionProperty, CSSPropertyWebkitTransitionDuration, + CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitTransitionDelay }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyWebkitAnimation: { + const int properties[7] = { CSSPropertyWebkitAnimationName, CSSPropertyWebkitAnimationDuration, + CSSPropertyWebkitAnimationTimingFunction, CSSPropertyWebkitAnimationDelay, + CSSPropertyWebkitAnimationIterationCount, CSSPropertyWebkitAnimationDirection, + CSSPropertyWebkitAnimationFillMode }; + return getLayeredShorthandValue(properties); + } + case CSSPropertyWebkitWrap: { + const int properties[3] = { CSSPropertyWebkitWrapFlow, CSSPropertyWebkitWrapMargin, + CSSPropertyWebkitWrapPadding }; + return getShorthandValue(properties); + } +#if ENABLE(SVG) + case CSSPropertyMarker: { + RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart); + if (value) + return value->cssText(); + } +#endif + } + return String(); +} + +String CSSMutableStyleDeclaration::borderSpacingValue(const int properties[2]) const +{ + RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(properties[0]); + RefPtr<CSSValue> verticalValue = getPropertyCSSValue(properties[1]); + + if (!horizontalValue) + return String(); + ASSERT(verticalValue); // By <http://www.w3.org/TR/CSS21/tables.html#separated-borders>. + + String horizontalValueCSSText = horizontalValue->cssText(); + String verticalValueCSSText = verticalValue->cssText(); + if (horizontalValueCSSText == verticalValueCSSText) + return horizontalValueCSSText; + return horizontalValueCSSText + ' ' + verticalValueCSSText; +} + +bool CSSMutableStyleDeclaration::appendFontLonghandValueIfExplicit(int propertyId, StringBuilder& result) const +{ + const CSSProperty* property = findPropertyWithId(propertyId); + if (!property) + return false; // All longhands must have at least implicit values if "font" is specified. + if (property->isImplicit()) + return true; + + char prefix = '\0'; + switch (propertyId) { + case CSSPropertyFontStyle: + break; // No prefix. + case CSSPropertyFontFamily: + case CSSPropertyFontVariant: + case CSSPropertyFontWeight: + prefix = ' '; + break; + case CSSPropertyLineHeight: + prefix = '/'; + break; + default: + ASSERT_NOT_REACHED(); + } + + if (prefix && !result.isEmpty()) + result.append(prefix); + result.append(property->value()->cssText()); + + return true; +} + +String CSSMutableStyleDeclaration::fontValue() const +{ + const CSSProperty* fontSizeProperty = findPropertyWithId(CSSPropertyFontSize); + if (!fontSizeProperty || fontSizeProperty->isImplicit()) + return emptyString(); + + StringBuilder result; + bool success = true; + success &= appendFontLonghandValueIfExplicit(CSSPropertyFontStyle, result); + success &= appendFontLonghandValueIfExplicit(CSSPropertyFontVariant, result); + success &= appendFontLonghandValueIfExplicit(CSSPropertyFontWeight, result); + if (!result.isEmpty()) + result.append(' '); + result.append(fontSizeProperty->value()->cssText()); + success &= appendFontLonghandValueIfExplicit(CSSPropertyLineHeight, result); + success &= appendFontLonghandValueIfExplicit(CSSPropertyFontFamily, result); + if (!success) { + // An invalid "font" value has been built (should never happen, as at least implicit values + // for mandatory longhands are always found in the style), report empty value instead. + ASSERT_NOT_REACHED(); + return emptyString(); + } + return result.toString(); +} + +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, size_t size) const +{ + String res; + + // Begin by collecting the properties into an array. + Vector< RefPtr<CSSValue> > values(size); + size_t numLayers = 0; + + for (size_t i = 0; i < size; ++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 < size; 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 < size - 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, size_t size) const +{ + String res; + for (size_t i = 0; i < size; ++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, size_t size) const +{ + String res; + for (size_t i = 0; i < size; ++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()) + return false; + return removePropertiesInSet(longhand.properties(), longhand.length(), notifyChanged); +} + +String CSSMutableStyleDeclaration::removeProperty(int propertyID, bool notifyChanged, bool returnText) +{ + ASSERT(!m_iteratorCount); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + 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 ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + + if (notifyChanged) + setNeedsStyleRecalc(); + + return value; +} + +void CSSMutableStyleDeclaration::setNeedsStyleRecalc() +{ + if (isElementStyleDeclaration() && static_cast<CSSElementStyleDeclaration*>(this)->element()) { + StyledElement* element = static_cast<CSSElementStyleDeclaration*>(this)->element(); + if (!isInlineStyleDeclaration()) + element->setNeedsStyleRecalc(FullStyleChange); + else { + element->setNeedsStyleRecalc(InlineStyleChange); + element->invalidateStyleAttribute(); + StyleAttributeMutationScope(this).didInvalidateStyleAttr(); + } + return; + } + + if (CSSStyleSheet* styleSheet = parentStyleSheet()) { + if (Document* document = styleSheet->findDocument()) + 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); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + // 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. + bool success = CSSParser::parseValue(this, propertyID, value, important, useStrictParsing()); + 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>. + return false; + } + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + + if (notifyChanged) + setNeedsStyleRecalc(); + + return true; +} + +void CSSMutableStyleDeclaration::setPropertyInternal(const CSSProperty& property, CSSProperty* slot) +{ + ASSERT(!m_iteratorCount); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + if (!removeShorthandProperty(property.id(), false)) { + CSSProperty* toReplace = slot ? slot : findPropertyWithId(property.id()); + if (toReplace) { + *toReplace = property; + return; + } + } + m_properties.append(property); + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif +} + +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; +} + +bool CSSMutableStyleDeclaration::setProperty(int propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important, bool notifyChanged) +{ + CSSProperty property(propertyID, CSSPrimitiveValue::create(value, unit), important); + setPropertyInternal(property); + if (notifyChanged) + setNeedsStyleRecalc(); + return true; +} + +void CSSMutableStyleDeclaration::parseDeclaration(const String& styleDeclaration) +{ + ASSERT(!m_iteratorCount); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + m_properties.clear(); + CSSParser parser(useStrictParsing()); + parser.parseDeclaration(this, styleDeclaration); + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + + setNeedsStyleRecalc(); +} + +void CSSMutableStyleDeclaration::addParsedProperties(const CSSProperty* const* properties, int numProperties) +{ + ASSERT(!m_iteratorCount); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + m_properties.reserveCapacity(numProperties); + for (int i = 0; i < numProperties; ++i) + addParsedProperty(*properties[i]); + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + + // 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); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + // Only add properties that have no !important counterpart present + if (!getPropertyPriority(property.id()) || property.isImportant()) { + removeProperty(property.id(), false, false); + m_properties.append(property); + } + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif +} + +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); + 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); + 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) +{ + ec = 0; + // FIXME: Detect syntax errors and set ec. + parseDeclaration(text); +} + +void CSSMutableStyleDeclaration::merge(const CSSMutableStyleDeclaration* other, bool argOverridesOnConflict) +{ + ASSERT(!m_iteratorCount); + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + 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); + } + +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + + // 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 = parentStyleSheet(); + 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 + CSSPropertyWebkitAspectRatio, + CSSPropertyWebkitColumnCount, + CSSPropertyWebkitColumnGap, + CSSPropertyWebkitColumnRuleColor, + CSSPropertyWebkitColumnRuleStyle, + CSSPropertyWebkitColumnRuleWidth, + CSSPropertyWebkitColumnBreakBefore, + CSSPropertyWebkitColumnBreakAfter, + CSSPropertyWebkitColumnBreakInside, + CSSPropertyWebkitColumnWidth, + CSSPropertyPageBreakAfter, + CSSPropertyPageBreakBefore, + CSSPropertyPageBreakInside, + CSSPropertyWebkitRegionBreakAfter, + CSSPropertyWebkitRegionBreakBefore, + CSSPropertyWebkitRegionBreakInside, + 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); +} + +bool CSSMutableStyleDeclaration::removePropertiesInSet(const int* set, unsigned length, bool notifyChanged) +{ + ASSERT(!m_iteratorCount); + + if (m_properties.isEmpty()) + return false; + +#if ENABLE(MUTATION_OBSERVERS) + StyleAttributeMutationScope mutationScope(this); +#endif + + // 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 (notifyChanged) { +#if ENABLE(MUTATION_OBSERVERS) + mutationScope.enqueueMutationRecord(); +#endif + setNeedsStyleRecalc(); + } + + return changed; +} + +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 000000000..54e08edb4 --- /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 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: + virtual ~CSSMutableStyleDeclaration(); + + 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)); + } + + // Used by StyledElement::copyNonAttributeProperties(). + void copyPropertiesFrom(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()); } + + 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) { return setProperty(propertyID, value, important, true); } + bool setProperty(int propertyId, double value, CSSPrimitiveValue::UnitTypes unit, bool important = false) { return setProperty(propertyId, value, unit, important, true); } + bool setProperty(int propertyID, const String& value, bool important = false) { return setProperty(propertyID, value, important, true); } + + void removeProperty(int propertyID) { removeProperty(propertyID, true, 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) { removePropertiesInSet(set, length, 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>&); + + bool propertiesEqual(const CSSMutableStyleDeclaration* o) const { return m_properties == o->m_properties; } + +protected: + CSSMutableStyleDeclaration(CSSRule* parentRule); + CSSMutableStyleDeclaration(); + + void setPropertyInternal(const CSSProperty&, CSSProperty* slot = 0); + String removeProperty(int propertyID, bool notifyChanged, bool returnText); + +private: + 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, size_t) const; + String getCommonValue(const int* properties, size_t) const; + String getLayeredShorthandValue(const int* properties, size_t) const; + String get4Values(const int* properties) const; + String borderSpacingValue(const int properties[2]) const; + String fontValue() const; + bool appendFontLonghandValueIfExplicit(int propertyID, StringBuilder& result) const; + + template<size_t size> String getShorthandValue(const int (&properties)[size]) const { return getShorthandValue(properties, size); } + template<size_t size> String getCommonValue(const int (&properties)[size]) const { return getCommonValue(properties, size); } + template<size_t size> String getLayeredShorthandValue(const int (&properties)[size]) const { return getLayeredShorthandValue(properties, size); } + + bool setProperty(int propertyID, int value, bool important, bool notifyChanged); + bool setProperty(int propertyId, double value, CSSPrimitiveValue::UnitTypes, bool important, bool notifyChanged); + bool setProperty(int propertyID, const String& value, bool important, bool notifyChanged); + bool removeShorthandProperty(int propertyID, bool notifyChanged); + bool removePropertiesInSet(const int* set, unsigned length, bool notifyChanged); + + Vector<CSSProperty>::const_iterator findPropertyWithId(int propertyId) const; + Vector<CSSProperty>::iterator findPropertyWithId(int propertyId); + + Vector<CSSProperty, 4> m_properties; + + 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 000000000..92638f20e --- /dev/null +++ b/Source/WebCore/css/CSSNamespace.h @@ -0,0 +1,55 @@ +/* + * 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 { + WTF_MAKE_NONCOPYABLE(CSSNamespace); WTF_MAKE_FAST_ALLOCATED; + public: + 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 000000000..33642db59 --- /dev/null +++ b/Source/WebCore/css/CSSOMUtils.cpp @@ -0,0 +1,124 @@ +/* + * 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 <wtf/HexNumber.h> +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +static void appendCharacter(UChar32 c, StringBuilder& 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, StringBuilder& appendTo) +{ + appendTo.append('\\'); + appendCharacter(c, appendTo); +} + +void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo) +{ + appendTo.append('\\'); + appendUnsignedAsHex(c, appendTo, Lowercase); + appendTo.append(' '); +} + +void serializeIdentifier(const String& identifier, String& appendTo) +{ + StringBuilder addend; + serializeIdentifier(identifier, addend); + appendTo.append(addend.toString()); +} + +void serializeIdentifier(const String& identifier, StringBuilder& 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) +{ + StringBuilder addend; + serializeString(string, addend); + appendTo.append(addend.toString()); +} + +void serializeString(const String& string, StringBuilder& 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 000000000..878669c37 --- /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, StringBuilder& appendTo); +void serializeCharacterAsCodePoint(UChar32, StringBuilder& appendTo); +void serializeIdentifier(const String& identifier, String& appendTo); +void serializeIdentifier(const String& identifier, StringBuilder& appendTo); +void serializeString(const String&, String& appendTo); +void serializeString(const String&, StringBuilder& 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 000000000..8da1ec448 --- /dev/null +++ b/Source/WebCore/css/CSSPageRule.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, 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, int sourceLine) + : CSSStyleRule(parent, sourceLine, CSSRule::PAGE_RULE) +{ +} + +String CSSPageRule::pageSelectorText() 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 000000000..59e9dcf65 --- /dev/null +++ b/Source/WebCore/css/CSSPageRule.h @@ -0,0 +1,50 @@ +/* + * (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, int sourceLine) + { + return adoptRef(new CSSPageRule(parent, sourceLine)); + } + + String pageSelectorText() const; + +private: + CSSPageRule(CSSStyleSheet* parent, int sourceLine); +}; + +} // namespace WebCore + +#endif // CSSPageRule_h diff --git a/Source/WebCore/css/CSSPageRule.idl b/Source/WebCore/css/CSSPageRule.idl new file mode 100644 index 000000000..989fd8d50 --- /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 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 000000000..7940b2774 --- /dev/null +++ b/Source/WebCore/css/CSSParser.cpp @@ -0,0 +1,8162 @@ +/* + * 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, 2011 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 "CSSAspectRatioValue.h" +#include "CSSBorderImageValue.h" +#include "CSSCanvasValue.h" +#include "CSSCharsetRule.h" +#include "CSSCrossfadeValue.h" +#include "CSSCursorImageValue.h" +#include "CSSFlexValue.h" +#include "CSSFontFaceRule.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSFunctionValue.h" +#include "CSSGradientValue.h" +#include "CSSImageValue.h" +#include "CSSImportRule.h" +#include "CSSInheritedValue.h" +#include "CSSInitialValue.h" +#include "CSSLineBoxContainValue.h" +#include "CSSMediaRule.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPageRule.h" +#include "CSSPrimitiveValue.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSPropertySourceData.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 "CSSValuePool.h" +#include "CSSWrapShapes.h" +#include "Counter.h" +#include "Document.h" +#include "FloatConversion.h" +#include "FontFamilyValue.h" +#include "FontFeatureValue.h" +#include "FontValue.h" +#include "HTMLParserIdioms.h" +#include "HashTools.h" +#include "MediaList.h" +#include "MediaQueryExp.h" +#include "Page.h" +#include "Pair.h" +#include "Rect.h" +#include "RenderTheme.h" +#include "ShadowValue.h" +#if ENABLE(CSS_FILTERS) +#include "WebKitCSSFilterValue.h" +#endif +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSRegionRule.h" +#include "WebKitCSSTransformValue.h" +#if ENABLE(CSS_SHADERS) +#include "WebKitCSSShaderValue.h" +#endif +#include <limits.h> +#include <wtf/HexNumber.h> +#include <wtf/dtoa.h> +#include <wtf/text/StringBuffer.h> +#include <wtf/text/StringBuilder.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; + +namespace { + +enum PropertyType { + PropertyExplicit, + PropertyImplicit +}; + +class ImplicitScope { + WTF_MAKE_NONCOPYABLE(ImplicitScope); +public: + ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType) + : m_parser(parser) + { + m_parser->m_implicitShorthand = propertyType == PropertyImplicit; + } + + ~ImplicitScope() + { + m_parser->m_implicitShorthand = false; + } + +private: + WebCore::CSSParser* m_parser; +}; + +} // namespace + +namespace WebCore { + +static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; +static const double MAX_SCALE = 1000000; + +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; +} + +inline void CSSParser::ensureCSSValuePool() +{ + if (!m_cssValuePool) + m_cssValuePool = CSSValuePool::create(); +} + +// FIXME: Can m_parsedProperties just be a Vector? + +CSSParser::CSSParser(bool strictParsing) + : m_strict(strictParsing) + , m_important(false) + , m_id(0) + , m_styleSheet(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) + , 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); + + fastDeleteAllValues(m_floatingSelectors); + deleteAllValues(m_floatingSelectorVectors); + deleteAllValues(m_floatingValueLists); + deleteAllValues(m_floatingFunctions); +} + +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; + + m_data = adoptArrayPtr(new UChar[length]); + for (unsigned i = 0; i < strlen(prefix); i++) + m_data[i] = prefix[i]; + + memcpy(m_data.get() + 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 = m_data.get(); + yy_c_buf_p = yytext; + yy_hold_char = *yy_c_buf_p; + resetRuleBodyMarks(); +} + +void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRangeMap* ruleRangeMap) +{ + setStyleSheet(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; +} + +PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string) +{ + setStyleSheet(sheet); + m_allowNamespaceDeclarations = false; + setupParser("@-webkit-rule{", string, "} "); + cssyyparse(this); + return m_rule.release(); +} + +PassRefPtr<WebKitCSSKeyframeRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string) +{ + setStyleSheet(sheet); + setupParser("@-webkit-keyframe-rule{ ", string, "} "); + cssyyparse(this); + return m_keyframe.release(); +} + +static inline bool isColorPropertyID(int propertyId) +{ + switch (propertyId) { + case CSSPropertyColor: + case CSSPropertyBackgroundColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderTopColor: + case CSSPropertyOutlineColor: + case CSSPropertyTextLineThroughColor: + case CSSPropertyTextOverlineColor: + case CSSPropertyTextUnderlineColor: + case CSSPropertyWebkitBorderAfterColor: + case CSSPropertyWebkitBorderBeforeColor: + case CSSPropertyWebkitBorderEndColor: + case CSSPropertyWebkitBorderStartColor: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextFillColor: + case CSSPropertyWebkitTextStrokeColor: + return true; + default: + return false; + } +} + +static bool parseColorValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict, CSSStyleSheet* contextStyleSheet = 0) +{ + if (!string.length()) + return false; + if (!isColorPropertyID(propertyId)) + return false; + CSSParserString cssString; + cssString.characters = const_cast<UChar*>(string.characters()); + cssString.length = string.length(); + int valueID = cssValueKeywordID(cssString); + bool validPrimitive = false; + if (valueID == CSSValueWebkitText) + validPrimitive = true; + else if (valueID == CSSValueCurrentcolor) + validPrimitive = true; + else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu + || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) { + validPrimitive = true; + } + + CSSStyleSheet* styleSheet = contextStyleSheet ? contextStyleSheet : declaration->parentStyleSheet(); + if (!styleSheet) + return false; + Document* document = styleSheet->findDocument(); + if (!document) + return false; + if (validPrimitive) { + CSSProperty property(propertyId, document->cssValuePool()->createIdentifierValue(valueID), important); + declaration->addParsedProperty(property); + return true; + } + RGBA32 color; + if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#')) + return false; + CSSProperty property(propertyId, document->cssValuePool()->createColorValue(color), important); + declaration->addParsedProperty(property); + return true; +} + +static inline bool isSimpleLengthPropertyID(int propertyId, bool& acceptsNegativeNumbers) +{ + switch (propertyId) { + case CSSPropertyFontSize: + case CSSPropertyHeight: + case CSSPropertyWidth: + case CSSPropertyMinHeight: + case CSSPropertyMinWidth: + case CSSPropertyPaddingBottom: + case CSSPropertyPaddingLeft: + case CSSPropertyPaddingRight: + case CSSPropertyPaddingTop: + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + case CSSPropertyWebkitPaddingAfter: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitWrapMargin: + case CSSPropertyWebkitWrapPadding: + acceptsNegativeNumbers = false; + return true; + case CSSPropertyBottom: + case CSSPropertyLeft: + case CSSPropertyMarginBottom: + case CSSPropertyMarginLeft: + case CSSPropertyMarginRight: + case CSSPropertyMarginTop: + case CSSPropertyRight: + case CSSPropertyTextIndent: + case CSSPropertyTop: + case CSSPropertyWebkitMarginAfter: + case CSSPropertyWebkitMarginBefore: + case CSSPropertyWebkitMarginEnd: + case CSSPropertyWebkitMarginStart: + acceptsNegativeNumbers = true; + return true; + default: + return false; + } +} + +static bool parseSimpleLengthValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict, CSSStyleSheet* contextStyleSheet = 0) +{ + const UChar* characters = string.characters(); + unsigned length = string.length(); + if (!characters || !length) + return false; + bool acceptsNegativeNumbers; + if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers)) + return false; + + CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER; + if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') { + length -= 2; + unit = CSSPrimitiveValue::CSS_PX; + } else if (length > 1 && characters[length - 1] == '%') { + length -= 1; + unit = CSSPrimitiveValue::CSS_PERCENTAGE; + } + + // We rely on charactersToDouble for validation as well. The function + // will set "ok" to "false" if the entire passed-in character range does + // not represent a double. + bool ok; + double number = charactersToDouble(characters, length, &ok); + if (!ok) + return false; + if (unit == CSSPrimitiveValue::CSS_NUMBER) { + if (number && strict) + return false; + unit = CSSPrimitiveValue::CSS_PX; + } + if (number < 0 && !acceptsNegativeNumbers) + return false; + + CSSStyleSheet* styleSheet = contextStyleSheet ? contextStyleSheet : declaration->parentStyleSheet(); + if (!styleSheet) + return false; + Document* document = styleSheet->findDocument(); + if (!document) + return false; + CSSProperty property(propertyId, document->cssValuePool()->createValue(number, unit), important); + declaration->addParsedProperty(property); + return true; +} + +bool CSSParser::parseMappedAttributeValue(CSSMappedAttributeDeclaration* declaration, StyledElement* element, int propertyId, const String& value) +{ + ASSERT(declaration); + ASSERT(element); + ASSERT(element->document()); + CSSStyleSheet* elementSheet = element->document()->elementSheet(); + if (parseSimpleLengthValue(declaration, propertyId, value, false, false, elementSheet)) + return true; + if (parseColorValue(declaration, propertyId, value, false, false, elementSheet)) + return true; + CSSParser parser(false); + return parser.parseValue(declaration, propertyId, value, false, elementSheet); +} + +bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, bool strict) +{ + if (parseSimpleLengthValue(declaration, propertyId, string, important, strict)) + return true; + if (parseColorValue(declaration, propertyId, string, important, strict)) + return true; + CSSParser parser(strict); + return parser.parseValue(declaration, propertyId, string, important); +} + +bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important, CSSStyleSheet* contextStyleSheet) +{ + if (contextStyleSheet) + setStyleSheet(contextStyleSheet); + else + setStyleSheet(declaration->parentStyleSheet()); + + setupParser("@-webkit-value{", string, "} "); + + m_id = propertyId; + 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(); + } + + return ok; +} + +// The color will only be changed when string contains a valid CSS color, so callers +// can set it to a default color and ignore the boolean result. +bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) +{ + // First try creating a color specified by name, rgba(), rgb() or "#" syntax. + if (fastParseColor(color, string, strict)) + return true; + + CSSParser parser(true); + + // In case the fast-path parser didn't understand the color, try the full parser. + if (!parser.parseColor(string)) + return false; + + CSSValue* value = parser.m_parsedProperties[0]->value(); + if (!value->isPrimitiveValue()) + return false; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_RGBCOLOR) + return false; + + color = primitiveValue->getRGBA32Value(); + return true; +} + +bool CSSParser::parseColor(const String& string) +{ + // This function may be called without a stylesheet set on the parser, so we need to + // make sure that we have a CSSValuePool or we'll crash below cssyyparse(). + ensureCSSValuePool(); + + setupParser("@-webkit-decls{color:", string, "} "); + cssyyparse(this); + m_rule = 0; + + return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor); +} + +bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document) +{ + if (!document || !document->page()) + return false; + + CSSParserString cssColor; + cssColor.characters = const_cast<UChar*>(string.characters()); + cssColor.length = string.length(); + int id = cssValueKeywordID(cssColor); + if (id <= 0) + return false; + + color = document->page()->theme()->systemColor(id).rgb(); + return true; +} + +void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList) +{ + RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc); + + setStyleSheet(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()); +} + +bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string, RefPtr<CSSStyleSourceData>* styleSourceData, CSSStyleSheet* contextStyleSheet) +{ + // Length of the "@-webkit-decls{" prefix. + static const unsigned prefixLength = 15; + + if (contextStyleSheet) + setStyleSheet(contextStyleSheet); + else + setStyleSheet(declaration->parentStyleSheet()); + 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; + } + return ok; +} + +bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) +{ + if (string.isEmpty()) + return true; + + 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()); + } + + return ok; +} + +void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important, bool implicit) +{ + OwnPtr<CSSProperty> prop(adoptPtr(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand || implicit))); + if (m_numParsedProperties >= m_maxParsedProperties) { + if (m_numParsedProperties > (UINT_MAX / sizeof(CSSProperty*)) - 32) + CRASH(); // Avoid inconsistencies with rollbackLastProperties. + m_maxParsedProperties += 32; + 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; +} + +void CSSParser::setStyleSheet(CSSStyleSheet* styleSheet) +{ + m_styleSheet = styleSheet; + Document* document = findDocument(); + m_cssValuePool = document ? document->cssValuePool() : CSSValuePool::create(); +} + +Document* CSSParser::findDocument() const +{ + if (!m_styleSheet) + return 0; + return m_styleSheet->findDocument(); +} + +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; +} + +inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value) +{ + ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) + || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)); + return cssValuePool()->createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); +} + +inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value) +{ + ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT); + return cssValuePool()->createValue(value->string, CSSPrimitiveValue::CSS_STRING); +} + +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; + } +} + +inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(int id, CSSParserValue* value) +{ + if (id) + return cssValuePool()->createIdentifierValue(id); + if (value->unit == CSSPrimitiveValue::CSS_STRING) + return createPrimitiveStringValue(value); + if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) + return createPrimitiveNumericValue(value); + if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS) + return createPrimitiveNumericValue(value); + if (value->unit >= CSSParserValue::Q_EMS) + return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); + return 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, cssValuePool()->createInheritedValue(), important); + return true; + } + else if (id == CSSValueInitial) { + if (num != 1) + return false; + addProperty(propId, cssValuePool()->createExplicitInitialValue(), 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; + else + return parseQuotes(propId, important); + break; + case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | plaintext | inherit + if (id == CSSValueNormal + || id == CSSValueEmbed + || id == CSSValueBidiOverride + || id == CSSValueWebkitIsolate + || id == CSSValueWebkitPlaintext) + 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: + case CSSPropertyWebkitRegionBreakAfter: + case CSSPropertyWebkitRegionBreakBefore: + if (id == CSSValueAuto || + id == CSSValueAlways || + id == CSSValueAvoid || + id == CSSValueLeft || + id == CSSValueRight) + validPrimitive = true; + break; + + case CSSPropertyPageBreakInside: // avoid | auto | inherit + case CSSPropertyWebkitColumnBreakInside: + case CSSPropertyWebkitRegionBreakInside: + 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 | -webkit-box | -webkit-inline-box | none | inherit + // -webkit-flexbox | -webkit-inline-flexbox | -webkit-grid | -webkit-inline-grid + if ((id >= CSSValueInline && id <= CSSValueWebkitInlineFlexbox) || id == CSSValueNone) + validPrimitive = true; +#if ENABLE(CSS_GRID_LAYOUT) + if (id == CSSValueWebkitGrid || id == CSSValueWebkitInlineGrid) + validPrimitive = true; +#endif + 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 | positioned | center (for buggy CSS, maps to none) + if (id == CSSValueLeft || id == CSSValueRight + || id == CSSValueNone || id == CSSValueCenter || id == CSSValueWebkitPositioned) + 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 | webkit_match_parent | + // start | end | <string> | inherit + if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || 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(cssValuePool()->createIdentifierValue(CSSValuePointer)); + else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)) + list->append(cssValuePool()->createIdentifierValue(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 = adoptPtr(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 + case CSSPropertyBorderImageSource: + case CSSPropertyWebkitMaskBoxImageSource: + 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(m_valueList.get(), 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 if (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict)) + // ### handle multilength case where we allow relative units + validPrimitive = true; + else if (value->unit == CSSParserValue::Function) + return parseFlex(propId, important); + 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(cssValuePool()->createIdentifierValue(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 CSSPropertyBorderImage: + case CSSPropertyWebkitBorderImage: + case CSSPropertyWebkitMaskBoxImage: { + RefPtr<CSSValue> result; + if (parseBorderImage(propId, result)) { + addProperty(propId, result, important); + return true; + } + break; + } + case CSSPropertyBorderImageOutset: + case CSSPropertyWebkitMaskBoxImageOutset: { + RefPtr<CSSPrimitiveValue> result; + if (parseBorderImageOutset(result)) { + addProperty(propId, result, important); + return true; + } + break; + } + case CSSPropertyBorderImageRepeat: + case CSSPropertyWebkitMaskBoxImageRepeat: { + RefPtr<CSSValue> result; + if (parseBorderImageRepeat(result)) { + addProperty(propId, result, important); + return true; + } + break; + } + case CSSPropertyBorderImageSlice: + case CSSPropertyWebkitMaskBoxImageSlice: { + RefPtr<CSSBorderImageSliceValue> result; + if (parseBorderImageSlice(propId, result)) { + addProperty(propId, result, important); + return true; + } + break; + } + case CSSPropertyBorderImageWidth: + case CSSPropertyWebkitMaskBoxImageWidth: { + RefPtr<CSSPrimitiveValue> result; + if (parseBorderImageWidth(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 | FNonNeg, m_strict); + if (!validPrimitive) + return false; + RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value); + RefPtr<CSSPrimitiveValue> parsedValue2; + if (num == 2) { + value = m_valueList->next(); + validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, m_strict); + if (!validPrimitive) + return false; + parsedValue2 = createPrimitiveNumericValue(value); + } else + parsedValue2 = parsedValue1; + + RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release()); + RefPtr<CSSPrimitiveValue> val = cssValuePool()->createValue(pair.release()); + addProperty(propId, val.release(), important); + return true; + } + case CSSPropertyWebkitAspectRatio: + return parseAspectRatio(important); + 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 { + RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId); + if (shadowValueList) { + addProperty(propId, shadowValueList.release(), important); + m_valueList->next(); + return true; + } + return false; + } + 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; +#if ENABLE(CSS_FILTERS) + case CSSPropertyWebkitFilter: + if (id == CSSValueNone) + validPrimitive = true; + else { + RefPtr<CSSValue> val = parseFilter(); + if (val) { + addProperty(propId, val, important); + return true; + } + return false; + } + break; +#endif + case CSSPropertyWebkitFlexOrder: + if (validUnit(value, FInteger, true)) { + // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set. + parsedValue = cssValuePool()->createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue), + static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)); + m_valueList->next(); + } + break; + case CSSPropertyWebkitFlexPack: + validPrimitive = id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter || id == CSSValueJustify; + break; + case CSSPropertyWebkitFlexAlign: + validPrimitive = id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter || id == CSSValueBaseline || id == CSSValueStretch; + break; + case CSSPropertyWebkitFlexDirection: + validPrimitive = id == CSSValueRow || id == CSSValueRowReverse || id == CSSValueColumn || id == CSSValueColumnReverse; + break; + case CSSPropertyWebkitFlexWrap: + validPrimitive = id == CSSValueNowrap || id == CSSValueWrap || id == CSSValueWrapReverse; + 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; + case CSSPropertyWebkitFlowInto: + return parseFlowThread(propId, important); + case CSSPropertyWebkitFlowFrom: + return parseRegionThread(propId, important); + case CSSPropertyWebkitRegionOverflow: + if (id == CSSValueAuto || id == CSSValueBreak) + validPrimitive = true; + break; + + 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 CSSPropertyWebkitPrintColorAdjust: + if (value->id == CSSValueExact || value->id == CSSValueEconomy) + 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 = createPrimitiveNumericValue(value); + 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; + } +#if ENABLE(CSS_GRID_LAYOUT) + case CSSPropertyWebkitGridColumns: + case CSSPropertyWebkitGridRows: + return parseGridTrackList(propId, important); +#endif + 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 CSSPropertyWebkitColumnAxis: + if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto) + validPrimitive = true; + 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; + case CSSPropertyImageRendering: // auto | optimizeContrast + if (id == CSSValueAuto || id == CSSValueWebkitOptimizeContrast) + 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 CSSPropertyWebkitHyphenateLimitBefore: + case CSSPropertyWebkitHyphenateLimitAfter: + if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, true)) + validPrimitive = true; + break; + + case CSSPropertyWebkitHyphenateLimitLines: + if (id == CSSValueNoLimit || validUnit(value, FInteger | FNonNeg, true)) + validPrimitive = true; + break; + + case CSSPropertyWebkitLineGrid: + if (id == CSSValueNone) + validPrimitive = true; + else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { + String lineGridValue = String(value->string); + if (!lineGridValue.isEmpty()) { + addProperty(propId, cssValuePool()->createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important); + return true; + } + } + break; + case CSSPropertyWebkitLineGridSnap: + if (id == CSSValueNone || id == CSSValueBaseline || id == CSSValueBounds) + validPrimitive = true; + break; + case CSSPropertyWebkitLocale: + 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 + +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyWebkitTapHighlightColor: + if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu + || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) { + validPrimitive = true; + } else { + parsedValue = parseColor(); + if (parsedValue) + m_valueList->next(); + } + break; +#endif + /* 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, + CSSPropertyBackgroundClip, CSSPropertyBackgroundColor }; + return parseFillShorthand(propId, properties, 7, important); + } + case CSSPropertyWebkitMask: { + const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, + CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, + CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip }; + return parseFillShorthand(propId, properties, 6, important); + } + case CSSPropertyBorder: + // [ 'border-width' || 'border-style' || <color> ] | inherit + { + const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, + CSSPropertyBorderColor }; + if (parseShorthand(propId, properties, 3, important)) { + // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as + // though a value of none was specified for the image. + addProperty(CSSPropertyBorderImage, cssValuePool()->createImplicitInitialValue(), important); + return true; + } + return false; + } + 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 CSSPropertyWebkitFlexFlow: + { + const int properties[] = { CSSPropertyWebkitFlexDirection, CSSPropertyWebkitFlexWrap }; + return parseShorthand(propId, properties, 2, 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; + // 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); + + case CSSPropertyWebkitTextOrientation: + // FIXME: For now just support upright and vertical-right. + if (id == CSSValueVerticalRight || id == CSSValueUpright) + validPrimitive = true; + break; + + case CSSPropertyWebkitLineBoxContain: + if (id == CSSValueNone) + validPrimitive = true; + else + return parseLineBoxContain(important); + break; + case CSSPropertyWebkitFontFeatureSettings: + if (id == CSSValueNormal) + validPrimitive = true; + else + return parseFontFeatureSettings(important); + break; + + case CSSPropertyWebkitWrapShapeInside: + case CSSPropertyWebkitWrapShapeOutside: + if (id == CSSValueAuto) + validPrimitive = true; + else if (value->unit == CSSParserValue::Function) + return parseWrapShape((propId == CSSPropertyWebkitWrapShapeInside), important); + break; + case CSSPropertyWebkitWrapFlow: + if (id == CSSValueAuto || id == CSSValueBoth || id == CSSValueLeft || id == CSSValueRight || id == CSSValueMaximum || id == CSSValueClear) + validPrimitive = true; + break; + + case CSSPropertyWebkitWrapThrough: + if (id == CSSValueWrap || id == CSSValueNone) + validPrimitive = true; + break; + case CSSPropertyWebkitWrapMargin: + case CSSPropertyWebkitWrapPadding: + validPrimitive = (!id && validUnit(value, FLength | FNonNeg, m_strict)); + break; + case CSSPropertyWebkitWrap: { + const int properties[] = { CSSPropertyWebkitWrapFlow, CSSPropertyWebkitWrapMargin, CSSPropertyWebkitWrapPadding }; + return parseShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); + } +#if ENABLE(SVG) + default: + return parseSVGValue(propId, important); +#endif + } + + if (validPrimitive) { + parsedValue = parseValidPrimitive(id, value); + m_valueList->next(); + } + if (parsedValue) { + if (!m_valueList->current() || inShorthand()) { + addProperty(propId, parsedValue.release(), important); + return true; + } + } + return false; +} + +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, CSSValuePool* cssValuePool) +{ + if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox + || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) { + cssValue = cssValuePool->createIdentifierValue(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; + bool foundClip = false; + 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], cssValuePool()->createImplicitInitialValue()); + if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) + addFillValue(positionYValue, cssValuePool()->createImplicitInitialValue()); + if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) + addFillValue(repeatYValue, cssValuePool()->createImplicitInitialValue()); + if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { + // If background-origin wasn't present, then reset background-clip also. + addFillValue(clipValue, cssValuePool()->createImplicitInitialValue()); + } + } + 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, cssValuePool())) + addFillValue(clipValue, val1.release()); // The property parsed successfully. + else + addFillValue(clipValue, cssValuePool()->createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead. + } + if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) { + // Update clipValue + addFillValue(clipValue, val1.release()); + foundClip = 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. + for (i = 0; i < numProperties; ++i) { + if (!parsedProperty[i]) { + addFillValue(values[i], cssValuePool()->createImplicitInitialValue()); + if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) + addFillValue(positionYValue, cssValuePool()->createImplicitInitialValue()); + if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) + addFillValue(repeatYValue, cssValuePool()->createImplicitInitialValue()); + if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { + // If background-origin wasn't present, then reset background-clip also. + addFillValue(clipValue, cssValuePool()->createImplicitInitialValue()); + } + } + } + + // 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 if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip) + // Value is already set while updating origin + continue; + else + addProperty(properties[i], values[i].release(), important); + + // Add in clip values when we hit the corresponding origin property. + if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip) + addProperty(CSSPropertyBackgroundClip, clipValue.release(), important); + else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip) + 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], cssValuePool()->createImplicitInitialValue()); + 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], cssValuePool()->createImplicitInitialValue()); + } + + // 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], cssValuePool()->createImplicitInitialValue()); + 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], cssValuePool()->createImplicitInitialValue()); + } + + // 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. + ImplicitScope implicitScope(this, PropertyImplicit); + for (int i = 0; i < numProperties; ++i) { + if (!fnd[i]) + addProperty(properties[i], cssValuePool()->createImplicitInitialValue(), important); + } + + 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(); + ImplicitScope implicitScope(this, PropertyImplicit); + addProperty(properties[1], value, important); + addProperty(properties[2], value, important); + addProperty(properties[3], value, important); + break; + } + case 2: { + if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) + return false; + CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value(); + ImplicitScope implicitScope(this, PropertyImplicit); + addProperty(properties[2], value, important); + value = m_parsedProperties[m_numParsedProperties-2]->value(); + addProperty(properties[3], value, important); + 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(); + ImplicitScope implicitScope(this, PropertyImplicit); + addProperty(properties[3], value, important); + 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, cssValuePool()->createIdentifierValue(value->id), important); + return true; + } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) { + addProperty(propId, createPrimitiveStringValue(value), 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(cssValuePool()->createIdentifierValue(value->id)); + return Auto; + } + return None; + case CSSValueLandscape: + case CSSValuePortrait: + if (prevParamType == None || prevParamType == PageSize) { + parsedValues->append(cssValuePool()->createIdentifierValue(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(cssValuePool()->createIdentifierValue(value->id)); + return PageSize; + } + return None; + case 0: + if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) { + parsedValues->append(createPrimitiveNumericValue(value)); + return Length; + } + return None; + default: + return None; + } +} + +// [ <string> <string> ]+ | inherit | none +// inherit and none are handled in parseValue. +bool CSSParser::parseQuotes(int propId, bool important) +{ + RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); + while (CSSParserValue* val = m_valueList->current()) { + RefPtr<CSSValue> parsedValue; + if (val->unit == CSSPrimitiveValue::CSS_STRING) + parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); + else + break; + values->append(parsedValue.release()); + m_valueList->next(); + } + if (values->length()) { + addProperty(propId, values.release(), important); + m_valueList->next(); + return true; + } + return false; +} + +// [ <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(m_valueList.get(), 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 = cssValuePool()->createIdentifierValue(val->id); + } + } else if (val->unit == CSSPrimitiveValue::CSS_STRING) { + parsedValue = createPrimitiveStringValue(val); + } + 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; + + Document* document = findDocument(); + if (document && document->isHTMLDocument()) + attrName = attrName.lower(); + + return cssValuePool()->createValue(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 cssValuePool()->createIdentifierValue(id); + return parseColor(); +} + +bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value) +{ + if (valueList->current()->id == CSSValueNone) { + value = CSSImageValue::create(); + return true; + } + if (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(valueList->current()->string)); + return true; + } + + if (isGeneratedImageValue(valueList->current())) + return parseGeneratedImage(valueList, value); + + return false; +} + +PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList) +{ + int id = valueList->current()->id; + if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) { + int percent = 0; + if (id == CSSValueRight) + percent = 100; + else if (id == CSSValueCenter) + percent = 50; + return cssValuePool()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + } + if (validUnit(valueList->current(), FPercent | FLength, m_strict)) + return createPrimitiveNumericValue(valueList->current()); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList) +{ + int id = valueList->current()->id; + if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) { + int percent = 0; + if (id == CSSValueBottom) + percent = 100; + else if (id == CSSValueCenter) + percent = 50; + return cssValuePool()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + } + if (validUnit(valueList->current(), FPercent | FLength, m_strict)) + return createPrimitiveNumericValue(valueList->current()); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag) +{ + 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 (cumulativeFlags & XFillPosition) + return 0; + cumulativeFlags |= XFillPosition; + individualFlag = XFillPosition; + if (id == CSSValueRight) + percent = 100; + } + else if (id == CSSValueTop || id == CSSValueBottom) { + if (cumulativeFlags & YFillPosition) + return 0; + cumulativeFlags |= YFillPosition; + individualFlag = YFillPosition; + 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; + cumulativeFlags |= AmbiguousFillPosition; + individualFlag = AmbiguousFillPosition; + } + return cssValuePool()->createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); + } + if (validUnit(valueList->current(), FPercent | FLength, m_strict)) { + if (!cumulativeFlags) { + cumulativeFlags |= XFillPosition; + individualFlag = XFillPosition; + } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) { + cumulativeFlags |= YFillPosition; + individualFlag = YFillPosition; + } else + return 0; + return createPrimitiveNumericValue(valueList->current()); + } + 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. + unsigned cumulativeFlags = 0; + FillPositionFlag value1Flag = InvalidFillPosition; + FillPositionFlag value2Flag = InvalidFillPosition; + value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag); + 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; + + if (value) { + value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag); + 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 = cssValuePool()->createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE); + + if (value1Flag == YFillPosition || value2Flag == XFillPosition) + 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 = cssValuePool()->createIdentifierValue(CSSValueRepeat); + value2 = cssValuePool()->createIdentifierValue(CSSValueNoRepeat); + m_valueList->next(); + return; + } + if (id == CSSValueRepeatY) { + m_implicitShorthand = true; + value1 = cssValuePool()->createIdentifierValue(CSSValueNoRepeat); + value2 = cssValuePool()->createIdentifierValue(CSSValueRepeat); + m_valueList->next(); + return; + } + if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) + value1 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(id); + m_valueList->next(); + } else { + // If only one value was specified, value2 is the same as value1. + m_implicitShorthand = true; + value2 = cssValuePool()->createIdentifierValue(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 cssValuePool()->createIdentifierValue(value->id); + + RefPtr<CSSPrimitiveValue> parsedValue1; + + if (value->id == CSSValueAuto) + parsedValue1 = cssValuePool()->createIdentifierValue(CSSValueAuto); + else { + if (!validUnit(value, FLength | FPercent, m_strict)) + return 0; + parsedValue1 = createPrimitiveNumericValue(value); + } + + CSSPropertyID property = static_cast<CSSPropertyID>(propId); + RefPtr<CSSPrimitiveValue> parsedValue2; + if ((value = m_valueList->next())) { + if (value->unit == CSSParserValue::Operator && value->iValue == ',') + allowComma = false; + else if (value->id != CSSValueAuto) { + if (!validUnit(value, FLength | FPercent, m_strict)) + return 0; + parsedValue2 = createPrimitiveNumericValue(value); + } + } else if (!parsedValue2 && property == CSSPropertyWebkitBackgroundSize) { + // For backwards compatibility we set the second value to the first if it is omitted. + // We only need to do this for -webkit-background-size. It should be safe to let masks match + // the real property. + parsedValue2 = parsedValue1; + } + + if (!parsedValue2) + return parsedValue1; + return cssValuePool()->createValue(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 = cssValuePool()->createIdentifierValue(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundImage: + case CSSPropertyWebkitMaskImage: + if (parseFillImage(m_valueList.get(), 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 = cssValuePool()->createIdentifierValue(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundClip: + if (parseBackgroundClip(val, currValue, cssValuePool())) + m_valueList->next(); + break; + case CSSPropertyBackgroundOrigin: + if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { + currValue = cssValuePool()->createIdentifierValue(val->id); + m_valueList->next(); + } + break; + case CSSPropertyBackgroundPosition: + case CSSPropertyWebkitMaskPosition: + parseFillPosition(m_valueList.get(), currValue, currValue2); + // parseFillPosition advances the m_valueList pointer + break; + case CSSPropertyBackgroundPositionX: + case CSSPropertyWebkitMaskPositionX: { + currValue = parseFillPositionX(m_valueList.get()); + if (currValue) + m_valueList->next(); + break; + } + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: { + currValue = parseFillPositionY(m_valueList.get()); + if (currValue) + m_valueList->next(); + break; + } + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyWebkitMaskComposite: + if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) { + currValue = cssValuePool()->createIdentifierValue(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 createPrimitiveNumericValue(value); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationDirection() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueNormal || value->id == CSSValueAlternate) + return cssValuePool()->createIdentifierValue(value->id); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationDuration() +{ + CSSParserValue* value = m_valueList->current(); + if (validUnit(value, FTime | FNonNeg, m_strict)) + return createPrimitiveNumericValue(value); + 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 cssValuePool()->createIdentifierValue(value->id); + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueInfinite) + return cssValuePool()->createIdentifierValue(value->id); + if (validUnit(value, FInteger | FNonNeg, m_strict)) + return createPrimitiveNumericValue(value); + 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 cssValuePool()->createIdentifierValue(CSSValueNone); + } else { + return createPrimitiveStringValue(value); + } + } + return 0; +} + +PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState() +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueRunning || value->id == CSSValuePaused) + return cssValuePool()->createIdentifierValue(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 cssValuePool()->createIdentifierValue(result); + if (equalIgnoringCase(value->string, "all")) + return cssValuePool()->createIdentifierValue(CSSValueAll); + if (equalIgnoringCase(value->string, "none")) + return cssValuePool()->createIdentifierValue(CSSValueNone); + return 0; +} + +bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3) +{ + parseFillPosition(m_valueList.get(), value1, value2); + + // now get z + if (m_valueList->current()) { + if (validUnit(m_valueList->current(), FLength, m_strict)) { + value3 = createPrimitiveNumericValue(m_valueList->current()); + 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; + 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 cssValuePool()->createIdentifierValue(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 = clampToInteger(v->fValue); + 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(CSS_GRID_LAYOUT) +bool CSSParser::parseGridTrackList(int propId, bool important) +{ + CSSParserValue* value = m_valueList->current(); + if (value->id == CSSValueNone) { + if (m_valueList->next()) + return false; + + addProperty(propId, cssValuePool()->createIdentifierValue(value->id), important); + return true; + } + + RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated(); + while (value) { + bool valid = validUnit(value, FLength | FPercent, m_strict) || value->id == CSSValueAuto; + if (!valid) + return false; + + RefPtr<CSSPrimitiveValue> primitiveValue = value->id == CSSValueAuto ? cssValuePool()->createIdentifierValue(CSSValueAuto) : createPrimitiveNumericValue(value); + values->append(primitiveValue.release()); + value = m_valueList->next(); + } + addProperty(propId, values.release(), important); + return true; +} +#endif + + + +#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, cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 ? + cssValuePool()->createIdentifierValue(CSSValueAuto) : + createPrimitiveNumericValue(arg); + + 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, cssValuePool()->createValue(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 = createPrimitiveStringValue(i); + + RefPtr<CSSPrimitiveValue> separator; + if (!counters) + separator = cssValuePool()->createValue(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 = createPrimitiveStringValue(i); + } + + RefPtr<CSSPrimitiveValue> listStyle; + i = args->next(); + if (!i) // Make the list style default decimal + listStyle = cssValuePool()->createIdentifierValue(CSSValueDecimal); + else { + if (i->unit != CSSParserValue::Operator || i->iValue != ',') + return 0; + + i = args->next(); + if (i->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + + int listStyleID = 0; + if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)) + listStyleID = i->id; + else + return 0; + + listStyle = cssValuePool()->createIdentifierValue(listStyleID); + } + + return cssValuePool()->createValue(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 ? + cssValuePool()->createIdentifierValue(CSSValueAuto) : + createPrimitiveNumericValue(a); + 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, cssValuePool()->createValue(rect.release()), important); + m_valueList->next(); + return true; + } + return false; +} + +PassRefPtr<CSSWrapShape> CSSParser::parseWrapShapeRect(CSSParserValueList* args) +{ + ASSERT(args); + + // rect(x, y, width, height, [[rx], ry]) + if (args->size() != 7 && args->size() != 9 && args->size() != 11) + return 0; + + RefPtr<CSSWrapShapeRect> shape = CSSWrapShapeRect::create(); + + unsigned argumentNumber = 0; + CSSParserValue* argument = args->current(); + while (argument) { + if (!validUnit(argument, FLength, m_strict)) + return 0; + + RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); + ASSERT(argumentNumber < 6); + switch (argumentNumber) { + case 0: + shape->setLeft(length); + break; + case 1: + shape->setTop(length); + break; + case 2: + shape->setWidth(length); + break; + case 3: + shape->setHeight(length); + break; + case 4: + shape->setRadiusX(length); + break; + case 5: + shape->setRadiusY(length); + break; + } + argument = args->next(); + if (argument) { + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return 0; + + argument = args->next(); + } + argumentNumber++; + } + + if (argumentNumber < 4) + return 0; + return shape; +} + +PassRefPtr<CSSWrapShape> CSSParser::parseWrapShapeCircle(CSSParserValueList* args) +{ + ASSERT(args); + + // circle(x, y, r) + if (args->size() != 5) + return 0; + + RefPtr<CSSWrapShapeCircle> shape = CSSWrapShapeCircle::create(); + + unsigned argumentNumber = 0; + CSSParserValue* argument = args->current(); + while (argument) { + if (!validUnit(argument, FLength, m_strict)) + return 0; + + RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); + ASSERT(argumentNumber < 3); + switch (argumentNumber) { + case 0: + shape->setLeft(length); + break; + case 1: + shape->setTop(length); + break; + case 2: + shape->setRadius(length); + break; + } + + argument = args->next(); + if (argument) { + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return 0; + argument = args->next(); + } + argumentNumber++; + } + + if (argumentNumber < 3) + return 0; + return shape; +} + +PassRefPtr<CSSWrapShape> CSSParser::parseWrapShapeEllipse(CSSParserValueList* args) +{ + ASSERT(args); + + // ellipse(x, y, rx, ry) + if (args->size() != 7) + return 0; + + RefPtr<CSSWrapShapeEllipse> shape = CSSWrapShapeEllipse::create(); + unsigned argumentNumber = 0; + CSSParserValue* argument = args->current(); + while (argument) { + if (!validUnit(argument, FLength, m_strict)) + return 0; + + RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument); + ASSERT(argumentNumber < 4); + switch (argumentNumber) { + case 0: + shape->setLeft(length); + break; + case 1: + shape->setTop(length); + break; + case 2: + shape->setRadiusX(length); + break; + case 3: + shape->setRadiusY(length); + break; + } + + argument = args->next(); + if (argument) { + if (argument->unit != CSSParserValue::Operator || argument->iValue != ',') + return 0; + argument = args->next(); + } + argumentNumber++; + } + + if (argumentNumber < 4) + return 0; + return shape; +} + +PassRefPtr<CSSWrapShape> CSSParser::parseWrapShapePolygon(CSSParserValueList* args) +{ + ASSERT(args); + + unsigned size = args->size(); + if (!size) + return 0; + + RefPtr<CSSWrapShapePolygon> shape = CSSWrapShapePolygon::create(); + + CSSParserValue* argument = args->current(); + if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) { + shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO); + + CSSParserValue* comma = args->next(); + if (!comma || comma->unit != CSSParserValue::Operator || comma->iValue != ',') + return 0; + + argument = args->next(); + size -= 2; + } + + // <length>, <length> ... <length>, <length> -> each pair has 3 elements + if (!size || (size % 3)) + return 0; + + CSSParserValue* argumentX = argument; + while (argumentX) { + if (!validUnit(argumentX, FLength, m_strict)) + return 0; + + CSSParserValue* comma = args->next(); + if (!comma || comma->unit != CSSParserValue::Operator || comma->iValue != ',') + return 0; + + CSSParserValue* argumentY = args->next(); + if (!argumentY || !validUnit(argumentY, FLength, m_strict)) + return 0; + + RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX); + RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY); + + shape->appendPoint(xLength.release(), yLength.release()); + + argumentX = args->next(); + } + + return shape; +} + +bool CSSParser::parseWrapShape(bool shapeInside, bool important) +{ + CSSParserValue* value = m_valueList->current(); + CSSParserValueList* args = value->function->args.get(); + + if (!args) + return false; + + RefPtr<CSSWrapShape> shape; + + if (equalIgnoringCase(value->function->name, "rect(")) + shape = parseWrapShapeRect(args); + else if (equalIgnoringCase(value->function->name, "circle(")) + shape = parseWrapShapeCircle(args); + else if (equalIgnoringCase(value->function->name, "ellipse(")) + shape = parseWrapShapeEllipse(args); + else if (equalIgnoringCase(value->function->name, "polygon(")) + shape = parseWrapShapePolygon(args); + + if (shape) { + addProperty(shapeInside ? CSSPropertyWebkitWrapShapeInside : CSSPropertyWebkitWrapShapeOutside, cssValuePool()->createValue(shape.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; + bool styleImplicit = true; + bool variantImplicit = true; + bool weightImplicit = true; + bool lineHeightImplicit = true; + int valueOrdinal = 0; + + 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) { + // It's the initial value for all three, so mark the corresponding longhand as explicit. + switch (valueOrdinal) { + case 0: + styleImplicit = false; + break; + case 1: + variantImplicit = false; + break; + case 2: + weightImplicit = false; + break; + } + } else if (id == CSSValueItalic || id == CSSValueOblique) { + if (font->style) + return false; + font->style = cssValuePool()->createIdentifierValue(id); + styleImplicit = false; + } else if (id == CSSValueSmallCaps) { + if (font->variant) + return false; + font->variant = cssValuePool()->createIdentifierValue(id); + variantImplicit = false; + } else if (id >= CSSValueBold && id <= CSSValueLighter) { + if (font->weight) + return false; + font->weight = cssValuePool()->createIdentifierValue(id); + weightImplicit = false; + } else + valid = false; + } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) { + int weight = static_cast<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 = cssValuePool()->createIdentifierValue(val); + weightImplicit = false; + } else + valid = false; + } else { + valid = false; + } + if (!valid) + break; + value = m_valueList->next(); + ++valueOrdinal; + } + if (!value) + return false; + + // Set undefined values to default. + if (!font->style) + font->style = cssValuePool()->createIdentifierValue(CSSValueNormal); + if (!font->variant) + font->variant = cssValuePool()->createIdentifierValue(CSSValueNormal); + if (!font->weight) + font->weight = cssValuePool()->createIdentifierValue(CSSValueNormal); + + // Now a font size _must_ come. + // <absolute-size> | <relative-size> | <length> | <percentage> | inherit + if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger) + font->size = cssValuePool()->createIdentifierValue(value->id); + else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict)) + font->size = createPrimitiveNumericValue(value); + value = m_valueList->next(); + if (!font->size || !value) + return false; + + if (value->unit == CSSParserValue::Operator && value->iValue == '/') { + // The line-height property. + value = m_valueList->next(); + if (!value) + return false; + if (value->id == CSSValueNormal) { + // Default value, just mark the property as explicit. + lineHeightImplicit = false; + } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict)) { + font->lineHeight = createPrimitiveNumericValue(value); + lineHeightImplicit = false; + } else + return false; + value = m_valueList->next(); + if (!value) + return false; + } + + if (!font->lineHeight) + font->lineHeight = cssValuePool()->createIdentifierValue(CSSValueNormal); + + // Font family must come now. + font->family = parseFontFamily(); + + if (m_valueList->current() || !font->family) + return false; + + ShorthandScope scope(this, CSSPropertyFont); + addProperty(CSSPropertyFontFamily, font->family, important); + addProperty(CSSPropertyFontSize, font->size, important); + addProperty(CSSPropertyFontStyle, font->style, important, styleImplicit); + addProperty(CSSPropertyFontVariant, font->variant, important, variantImplicit); + addProperty(CSSPropertyFontWeight, font->weight, important, weightImplicit); + addProperty(CSSPropertyLineHeight, font->lineHeight, important, lineHeightImplicit); + + // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that + // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values + // but we don't seem to support them at the moment. They should also be added here once implemented. + + 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(cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(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 = cssValuePool()->createIdentifierValue(val->id); + } + } else if (validUnit(val, FInteger | FNonNeg, false)) { + int weight = static_cast<int>(val->fValue); + if (!(weight % 100) && weight >= 100 && weight <= 900) + parsedValue = cssValuePool()->createIdentifierValue(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; +} + +bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList) +{ + // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue, + // not when creating it. + RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(m_styleSheet->completeURL(m_valueList->current()->string))); + + CSSParserValue* value = m_valueList->next(); + if (!value) { + valueList->append(uriValue.release()); + return true; + } + if (value->unit == CSSParserValue::Operator && value->iValue == ',') { + m_valueList->next(); + valueList->append(uriValue.release()); + return true; + } + + if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format(")) + return false; + + // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings, + // but CSSFontFaceSrcValue stores only one format. Allowing one format for now. + CSSParserValueList* args = value->function->args.get(); + if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT)) + return false; + uriValue->setFormat(args->current()->string); + valueList->append(uriValue.release()); + value = m_valueList->next(); + if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') + m_valueList->next(); + return true; +} + +bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList) +{ + CSSParserValueList* args = m_valueList->current()->function->args.get(); + if (!args || !args->size()) + return false; + + if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING) + valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string)); + else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) { + StringBuilder builder; + for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) { + if (localValue->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + if (!builder.isEmpty()) + builder.append(' '); + builder.append(localValue->string); + } + valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString())); + } else + return false; + + if (CSSParserValue* value = m_valueList->next()) { + if (value->unit == CSSParserValue::Operator && value->iValue == ',') + m_valueList->next(); + } + return true; +} + +bool CSSParser::parseFontFaceSrc() +{ + RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated()); + + while (CSSParserValue* value = m_valueList->current()) { + if (value->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) { + if (!parseFontFaceSrcURI(values.get())) + return false; + } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) { + if (!parseFontFaceSrcLocal(values.get())) + return false; + } else + return false; + } + if (!values->length()) + return false; + + addProperty(CSSPropertySrc, values.release(), m_important); + m_valueList->next(); + return true; +} + +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; +} + +// Returns the number of characters which form a valid double +// and are terminated by the given terminator character +static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator) +{ + int length = end - string; + if (length < 1) + return 0; + + bool decimalMarkSeen = false; + int processedLength = 0; + + for (int i = 0; i < length; ++i) { + if (string[i] == terminator) { + processedLength = i; + break; + } + if (!isASCIIDigit(string[i])) { + if (!decimalMarkSeen && string[i] == '.') + decimalMarkSeen = true; + else + return 0; + } + } + + if (decimalMarkSeen && processedLength == 1) + return 0; + + return processedLength; +} + +// Returns the number of characters consumed for parsing a valid double +// terminated by the given terminator character +static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value) +{ + int length = checkForValidDouble(string, end, terminator); + if (!length) + return 0; + + int position = 0; + double localValue = 0; + + // The consumed characters here are guaranteed to be + // ASCII digits with or without a decimal mark + for (; position < length; ++position) { + if (string[position] == '.') + break; + localValue = localValue * 10 + string[position] - '0'; + } + + if (++position == length) { + value = localValue; + return length; + } + + double fraction = 0; + double scale = 1; + + while (position < length && scale < MAX_SCALE) { + fraction = fraction * 10 + string[position++] - '0'; + scale *= 10; + } + + value = localValue + fraction / scale; + return length; +} + +static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value) +{ + const UChar* current = string; + double 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)) { + double newValue = localValue * 10 + *current++ - '0'; + if (newValue >= 255) { + // Clamp values at 255. + localValue = 255; + while (current != end && isASCIIDigit(*current)) + ++current; + break; + } + localValue = newValue; + } + + if (current == end) + return false; + + if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%')) + return false; + + if (*current == '.') { + // We already parsed the integral part, try to parse + // the fraction part of the percentage value. + double percentage = 0; + int numCharactersParsed = parseDouble(current, end, '%', percentage); + if (!numCharactersParsed) + return false; + current += numCharactersParsed; + if (*current != '%') + return false; + localValue += percentage; + } + + if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%') + return false; + + if (*current == '%') { + expect = CSSPrimitiveValue::CSS_PERCENTAGE; + localValue = localValue / 100.0 * 256.0; + // Clamp values at 255 for percentages over 100% + if (localValue > 255) + localValue = 255; + current++; + } else + expect = CSSPrimitiveValue::CSS_NUMBER; + + while (current != end && isHTMLSpace(*current)) + current++; + if (current == end || *current++ != terminator) + return false; + // Clamp negative values at zero. + value = negative ? 0 : static_cast<int>(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, const char terminator, int& value) +{ + while (string != end && isHTMLSpace(*string)) + string++; + + bool negative = false; + + if (string != end && *string == '-') { + negative = true; + string++; + } + + value = 0; + + int length = end - string; + if (length < 2) + return false; + + if (string[length - 1] != terminator) + return false; + + if (string[0] != '0' && string[0] != '1' && string[0] != '.') { + if (checkForValidDouble(string, end, terminator)) { + value = negative ? 0 : 255; + string = end; + return true; + } + return false; + } + + if (length == 2 && string[0] != '.') { + value = !negative && 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 = negative ? 0 : tenthAlphaValues[string[length - 2] - '0']; + string = end; + return true; + } + + double alpha = 0; + if (!parseDouble(string, end, terminator, alpha)) + return false; + value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0)); + string = end; + return true; +} + +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::fastParseColor(RGBA32& rgb, const String& name, bool strict) +{ + const UChar* characters = name.characters(); + unsigned length = name.length(); + CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN; + + 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 (!parseColorIntOrPercentage(current, end, ',', expect, red)) + return false; + if (!parseColorIntOrPercentage(current, end, ',', expect, green)) + return false; + if (!parseColorIntOrPercentage(current, end, ',', expect, 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 (!parseColorIntOrPercentage(current, end, ',', expect, red)) + return false; + if (!parseColorIntOrPercentage(current, end, ',', expect, green)) + return false; + if (!parseColorIntOrPercentage(current, end, ')', expect, 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 cssValuePool()->createColorValue(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", static_cast<int>((value->fValue+.5))); + if (!fastParseColor(c, str, 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 (!fastParseColor(c, value->string, 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, CSSValuePool* cssValuePool) + : property(prop) + , m_cssValuePool(cssValuePool) + , 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 = m_cssValuePool->createValue(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 = m_cssValuePool->createIdentifierValue(v->id); + allowStyle = false; + if (allowX) + allowBreak = false; + else { + allowBlur = false; + allowSpread = false; + allowColor = false; + } + } + + CSSPropertyID property; + CSSValuePool* m_cssValuePool; + + 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; +}; + +PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, int propId) +{ + ShadowParseContext context(static_cast<CSSPropertyID>(propId), cssValuePool()); + CSSParserValue* val; + while ((val = 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 0; +#if ENABLE(SVG) + // -webkit-svg-shadow does not support multiple values. + if (static_cast<CSSPropertyID>(propId) == CSSPropertyWebkitSvgShadow) + return 0; +#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 0; + + // A length is allowed here. Construct the value and add it. + context.commitLength(val); + } else if (val->id == CSSValueInset) { + if (!context.allowStyle) + return 0; + + 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) + || val->id == CSSValueCurrentcolor); + if (isColor) { + if (!context.allowColor) + return 0; + parsedColor = cssValuePool()->createIdentifierValue(val->id); + } + + if (!parsedColor) + // It's not built-in. Try to parse it as a color. + parsedColor = parseColor(val); + + if (!parsedColor || !context.allowColor) + return 0; // 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()); + } + + valueList->next(); + } + + if (context.allowBreak) { + context.commitValue(); + if (context.values && context.values->length()) + return context.values.release(); + } + + return 0; +} + +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 = cssValuePool()->createValue(0, CSSPrimitiveValue::CSS_PX); + else { + if (!validUnit(val, FLength | FPercent, m_strict)) + return false; + offset = createPrimitiveNumericValue(val); + } + + // Now for the mask. + RefPtr<CSSValue> mask; + val = m_valueList->next(); + if (val) { + if (!parseBorderImage(propId, mask)) + return false; + } + + RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction, offset.release(), mask.release()); + addProperty(propId, reflectValue.release(), important); + m_valueList->next(); + return true; +} + +bool CSSParser::parseFlex(int propId, bool important) +{ + CSSParserValue* value = m_valueList->current(); + CSSParserValueList* args = value->function->args.get(); + if (!equalIgnoringCase(value->function->name, "-webkit-flex(") || !args || !args->size() || args->size() > 3 || m_valueList->next()) + return false; + + static const double unsetValue = -1; + double positiveFlex = unsetValue; + double negativeFlex = unsetValue; + RefPtr<CSSPrimitiveValue> preferredSize; + + while (CSSParserValue* arg = args->current()) { + if (validUnit(arg, FNumber | FNonNeg, m_strict)) { + if (positiveFlex == unsetValue) + positiveFlex = arg->fValue; + else if (negativeFlex == unsetValue) + negativeFlex = arg->fValue; + else if (!arg->fValue) { + // flex() only allows a preferred size of 0 (sans units) if the positive and negative flex values have already been set. + preferredSize = cssValuePool()->createValue(0, CSSPrimitiveValue::CSS_PX); + } else { + // We only allow 3 numbers without units if the last value is 0. E.g., flex(1 1 1) is invalid. + return false; + } + } else if (!preferredSize && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg, m_strict))) + preferredSize = parseValidPrimitive(arg->id, arg); + else { + // Not a valid arg for flex(). + return false; + } + args->next(); + } + + if (positiveFlex == unsetValue) + positiveFlex = 1; + if (negativeFlex == unsetValue) + negativeFlex = 0; + if (!preferredSize) + preferredSize = cssValuePool()->createValue(0, CSSPrimitiveValue::CSS_PX); + + RefPtr<CSSFlexValue> flex = CSSFlexValue::create(clampToFloat(positiveFlex), clampToFloat(negativeFlex), preferredSize); + addProperty(propId, flex.release(), important); + return true; +} + +struct BorderImageParseContext { + BorderImageParseContext(CSSValuePool* cssValuePool) + : m_cssValuePool(cssValuePool) + , m_canAdvance(false) + , m_allowCommit(true) + , m_allowImage(true) + , m_allowImageSlice(true) + , m_allowRepeat(true) + , m_allowSlash(false) + , m_requireWidth(false) + , m_requireOutset(false) + {} + + bool canAdvance() const { return m_canAdvance; } + void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; } + + bool allowCommit() const { return m_allowCommit; } + bool allowImage() const { return m_allowImage; } + bool allowImageSlice() const { return m_allowImageSlice; } + bool allowRepeat() const { return m_allowRepeat; } + bool allowSlash() const { return m_allowSlash; } + + bool requireWidth() const { return m_requireWidth; } + bool requireOutset() const { return m_requireOutset; } + + void commitImage(PassRefPtr<CSSValue> image) + { + m_image = image; + m_canAdvance = true; + m_allowCommit = true; + m_allowImage = m_allowSlash = m_requireWidth = m_requireOutset = false; + m_allowImageSlice = !m_imageSlice; + m_allowRepeat = !m_repeat; + } + void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice) + { + m_imageSlice = slice; + m_canAdvance = true; + m_allowCommit = m_allowSlash = true; + m_allowImageSlice = m_requireWidth = m_requireOutset = false; + m_allowImage = !m_image; + m_allowRepeat = !m_repeat; + } + void commitSlash() + { + m_canAdvance = true; + m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowSlash = false; + if (!m_borderSlice) { + m_requireWidth = true; + m_requireOutset = false; + } else { + m_requireOutset = true; + m_requireWidth = false; + } + } + void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice) + { + m_borderSlice = slice; + m_canAdvance = true; + m_allowCommit = m_allowSlash = true; + m_allowImageSlice = m_requireWidth = m_requireOutset = false; + m_allowImage = !m_image; + m_allowRepeat = !m_repeat; + } + void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset) + { + m_outset = outset; + m_canAdvance = true; + m_allowCommit = true; + m_allowImageSlice = m_allowSlash = m_requireWidth = m_requireOutset = false; + m_allowImage = !m_image; + m_allowRepeat = !m_repeat; + } + void commitRepeat(PassRefPtr<CSSValue> repeat) + { + m_repeat = repeat; + m_canAdvance = true; + m_allowCommit = true; + m_allowRepeat = m_allowSlash = m_requireWidth = m_requireOutset = false; + m_allowImageSlice = !m_imageSlice; + m_allowImage = !m_image; + } + + PassRefPtr<CSSValue> commitBorderImage() + { + // Make our new border image value now. + return CSSBorderImageValue::create(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat); + } + + CSSValuePool* m_cssValuePool; + + bool m_canAdvance; + + bool m_allowCommit; + bool m_allowImage; + bool m_allowImageSlice; + bool m_allowRepeat; + bool m_allowSlash; + + bool m_requireWidth; + bool m_requireOutset; + + RefPtr<CSSValue> m_image; + RefPtr<CSSBorderImageSliceValue> m_imageSlice; + RefPtr<CSSPrimitiveValue> m_borderSlice; + RefPtr<CSSPrimitiveValue> m_outset; + + RefPtr<CSSValue> m_repeat; +}; + +bool CSSParser::parseBorderImage(int propId, RefPtr<CSSValue>& result) +{ + ShorthandScope scope(this, propId); + BorderImageParseContext context(cssValuePool()); + while (CSSParserValue* val = m_valueList->current()) { + context.setCanAdvance(false); + + if (!context.canAdvance() && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') + context.commitSlash(); + + if (!context.canAdvance() && context.allowImage()) { + 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(m_valueList.get(), value)) + context.commitImage(value); + else + return false; + } else if (val->id == CSSValueNone) + context.commitImage(CSSImageValue::create()); + } + + if (!context.canAdvance() && context.allowImageSlice()) { + RefPtr<CSSBorderImageSliceValue> imageSlice; + if (parseBorderImageSlice(propId, imageSlice)) + context.commitImageSlice(imageSlice.release()); + } + + if (!context.canAdvance() && context.allowRepeat()) { + RefPtr<CSSValue> repeat; + if (parseBorderImageRepeat(repeat)) + context.commitRepeat(repeat); + } + + if (!context.canAdvance() && context.requireWidth()) { + RefPtr<CSSPrimitiveValue> borderSlice; + if (parseBorderImageWidth(borderSlice)) + context.commitBorderWidth(borderSlice.release()); + } + + if (!context.canAdvance() && context.requireOutset()) { + RefPtr<CSSPrimitiveValue> borderOutset; + if (parseBorderImageOutset(borderOutset)) + context.commitBorderOutset(borderOutset.release()); + } + + if (!context.canAdvance()) + return false; + + m_valueList->next(); + } + + if (context.allowCommit()) { + // Need to fully commit as a single value. + result = context.commitBorderImage(); + return true; + } + + return false; +} + +static bool isBorderImageRepeatKeyword(int id) +{ + return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound; +} + +bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result) +{ + RefPtr<CSSPrimitiveValue> firstValue; + RefPtr<CSSPrimitiveValue> secondValue; + CSSParserValue* val = m_valueList->current(); + if (isBorderImageRepeatKeyword(val->id)) + firstValue = cssValuePool()->createIdentifierValue(val->id); + else + return false; + + val = m_valueList->next(); + if (val) { + if (isBorderImageRepeatKeyword(val->id)) + secondValue = cssValuePool()->createIdentifierValue(val->id); + else if (!inShorthand()) { + // If we're not parsing a shorthand then we are invalid. + return false; + } else { + // We need to rewind the value list, so that when its advanced we'll + // end up back at this value. + m_valueList->previous(); + } + } else + secondValue = firstValue; + + result = cssValuePool()->createValue(Pair::create(firstValue, secondValue)); + return true; +} + +class BorderImageSliceParseContext { +public: + BorderImageSliceParseContext(CSSValuePool* cssValuePool) + : m_cssValuePool(cssValuePool) + , m_allowNumber(true) + , m_allowFill(false) + , m_allowFinalCommit(false) + , m_fill(false) + { } + + bool allowNumber() const { return m_allowNumber; } + bool allowFill() const { return m_allowFill; } + bool allowFinalCommit() const { return m_allowFinalCommit; } + CSSPrimitiveValue* top() const { return m_top.get(); } + + void commitNumber(CSSParserValue* v) + { + RefPtr<CSSPrimitiveValue> val = m_cssValuePool->createValue(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_allowNumber = !m_left; + m_allowFill = true; + m_allowFinalCommit = true; + } + + void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = false; } + + void setAllowFinalCommit() { m_allowFinalCommit = true; } + void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; } + + PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice() + { + // We need to clone and repeat values for any omissions. + ASSERT(m_top); + if (!m_right) { + m_right = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_bottom = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + } + if (!m_bottom) { + m_bottom = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = m_cssValuePool->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + } + if (!m_left) + m_left = m_cssValuePool->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + + // Now build a rect value to hold all four of our primitive values. + RefPtr<Quad> quad = Quad::create(); + quad->setTop(m_top); + quad->setRight(m_right); + quad->setBottom(m_bottom); + quad->setLeft(m_left); + + // Make our new border image value now. + return CSSBorderImageSliceValue::create(m_cssValuePool->createValue(quad.release()), m_fill); + } + +private: + CSSValuePool* m_cssValuePool; + + bool m_allowNumber; + bool m_allowFill; + bool m_allowFinalCommit; + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_right; + RefPtr<CSSPrimitiveValue> m_bottom; + RefPtr<CSSPrimitiveValue> m_left; + + bool m_fill; +}; + +bool CSSParser::parseBorderImageSlice(int propId, RefPtr<CSSBorderImageSliceValue>& result) +{ + BorderImageSliceParseContext context(cssValuePool()); + CSSParserValue* val; + while ((val = m_valueList->current())) { + if (context.allowNumber() && validUnit(val, FInteger | FNonNeg | FPercent, true)) { + context.commitNumber(val); + } else if (context.allowFill() && val->id == CSSValueFill) + context.commitFill(); + else if (!inShorthand()) { + // If we're not parsing a shorthand then we are invalid. + return false; + } else { + if (context.allowFinalCommit()) { + // We're going to successfully parse, but we don't want to consume this token. + m_valueList->previous(); + } + break; + } + m_valueList->next(); + } + + if (context.allowFinalCommit()) { + // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default. + // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling... + if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect) + context.commitFill(); + + // Need to fully commit as a single value. + result = context.commitBorderImageSlice(); + return true; + } + + return false; +} + +class BorderImageQuadParseContext { +public: + BorderImageQuadParseContext(CSSValuePool* cssValuePool) + : m_cssValuePool(cssValuePool) + , m_allowNumber(true) + , m_allowFinalCommit(false) + { } + + bool allowNumber() const { return m_allowNumber; } + bool allowFinalCommit() const { return m_allowFinalCommit; } + CSSPrimitiveValue* top() const { return m_top.get(); } + + void commitNumber(CSSParserValue* v) + { + RefPtr<CSSPrimitiveValue> val; + if (v->id == CSSValueAuto) + val = m_cssValuePool->createIdentifierValue(v->id); + else + val = m_cssValuePool->createValue(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_allowNumber = !m_left; + m_allowFinalCommit = true; + } + + void setAllowFinalCommit() { m_allowFinalCommit = true; } + void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; } + + PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad() + { + // We need to clone and repeat values for any omissions. + ASSERT(m_top); + if (!m_right) { + m_right = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_bottom = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + } + if (!m_bottom) { + m_bottom = m_cssValuePool->createValue(m_top->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType()); + m_left = m_cssValuePool->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + } + if (!m_left) + m_left = m_cssValuePool->createValue(m_right->getDoubleValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType()); + + // Now build a quad value to hold all four of our primitive values. + RefPtr<Quad> quad = Quad::create(); + quad->setTop(m_top); + quad->setRight(m_right); + quad->setBottom(m_bottom); + quad->setLeft(m_left); + + // Make our new value now. + return m_cssValuePool->createValue(quad.release()); + } + +private: + CSSValuePool* m_cssValuePool; + + bool m_allowNumber; + bool m_allowFinalCommit; + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_right; + RefPtr<CSSPrimitiveValue> m_bottom; + RefPtr<CSSPrimitiveValue> m_left; +}; + +bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result) +{ + BorderImageQuadParseContext context(cssValuePool()); + CSSParserValue* val; + while ((val = m_valueList->current())) { + if (context.allowNumber() && (validUnit(val, validUnits, true) || val->id == CSSValueAuto)) { + context.commitNumber(val); + } else if (!inShorthand()) { + // If we're not parsing a shorthand then we are invalid. + return false; + } else { + if (context.allowFinalCommit()) + m_valueList->previous(); // The shorthand loop will advance back to this point. + break; + } + m_valueList->next(); + } + + if (context.allowFinalCommit()) { + // Need to fully commit as a single value. + result = context.commitBorderImageQuad(); + return true; + } + return false; +} + +bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result) +{ + return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result); +} + +bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result) +{ + return parseBorderImageQuad(FLength | FInteger | FNonNeg, result); +} + +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 | FNonNeg, m_strict)) + return false; + + RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value); + + 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]); + + ImplicitScope implicitScope(this, PropertyImplicit); + addProperty(CSSPropertyBorderTopLeftRadius, cssValuePool()->createValue(Pair::create(radii[0][0].release(), radii[1][0].release())), important); + addProperty(CSSPropertyBorderTopRightRadius, cssValuePool()->createValue(Pair::create(radii[0][1].release(), radii[1][1].release())), important); + addProperty(CSSPropertyBorderBottomRightRadius, cssValuePool()->createValue(Pair::create(radii[0][2].release(), radii[1][2].release())), important); + addProperty(CSSPropertyBorderBottomLeftRadius, cssValuePool()->createValue(Pair::create(radii[0][3].release(), radii[1][3].release())), important); + return true; +} + +bool CSSParser::parseAspectRatio(bool important) +{ + unsigned num = m_valueList->size(); + if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) { + addProperty(CSSPropertyWebkitAspectRatio, cssValuePool()->createIdentifierValue(CSSValueNone), important); + return true; + } + + if (num != 3) + return false; + + CSSParserValue* lvalue = m_valueList->valueAt(0); + CSSParserValue* op = m_valueList->valueAt(1); + CSSParserValue* rvalue = m_valueList->valueAt(2); + + if (op->unit != CSSParserValue::Operator || op->iValue != '/') + return false; + + if (!validUnit(lvalue, FNumber | FNonNeg, m_strict) || !validUnit(rvalue, FNumber | FNonNeg, m_strict)) + return false; + + if (!lvalue->fValue || !rvalue->fValue) + return false; + + addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important); + + 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 = createPrimitiveStringValue(val); + state = VAL; + m_valueList->next(); + continue; + } + break; + case VAL: { + int i = defaultValue; + if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) { + i = clampToInteger(val->fValue); + m_valueList->next(); + } + + list->append(cssValuePool()->createValue(Pair::create(counterName.release(), + cssValuePool()->createValue(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, CSSValuePool* cssValuePool) +{ + RefPtr<CSSPrimitiveValue> result; + if (a->unit == CSSPrimitiveValue::CSS_IDENT) { + if ((equalIgnoringCase(a->string, "left") && horizontal) + || (equalIgnoringCase(a->string, "top") && !horizontal)) + result = cssValuePool->createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE); + else if ((equalIgnoringCase(a->string, "right") && horizontal) + || (equalIgnoringCase(a->string, "bottom") && !horizontal)) + result = cssValuePool->createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE); + else if (equalIgnoringCase(a->string, "center")) + result = cssValuePool->createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE); + } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) + result = cssValuePool->createValue(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 = p->cssValuePool()->createValue(0, CSSPrimitiveValue::CSS_NUMBER); + else + stop.m_position = p->cssValuePool()->createValue(1, CSSPrimitiveValue::CSS_NUMBER); + + int id = args->current()->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) + stop.m_color = p->cssValuePool()->createIdentifierValue(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 = p->cssValuePool()->createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER); + else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER) + stop.m_position = p->cssValuePool()->createValue(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 = p->cssValuePool()->createIdentifierValue(id); + else + stop.m_color = p->parseColor(stopArg); + if (!stop.m_color) + return false; + } + + return true; +} + +bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient) +{ + // Walk the arguments. + CSSParserValueList* args = 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, cssValuePool()); + 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, cssValuePool()); + 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(createPrimitiveNumericValue(a)); + + // 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, cssValuePool()); + 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, cssValuePool()); + 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(createPrimitiveNumericValue(a)); + } + + // 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, CSSValuePool* cssValuePool) +{ + 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 cssValuePool->createIdentifierValue(a->id); +} + +static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value) +{ + int id = value->id; + if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor) + return p->cssValuePool()->createIdentifierValue(id); + + return p->parseColor(value); +} + +bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +{ + RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating); + + // Walk the arguments. + CSSParserValueList* args = 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(createPrimitiveNumericValue(a)); + + 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, cssValuePool()))) { + if (isHorizontal) + startX = location; + else + startY = location; + + a = args->next(); + if (a) { + if ((location = valueFromSideKeyword(a, isHorizontal, cssValuePool()))) { + if (isHorizontal) { + if (startX) + return false; + startX = location; + } else { + if (startY) + return false; + startY = location; + } + + a = args->next(); + } + } + + expectComma = true; + } + + if (!startX && !startY) + startY = cssValuePool()->createIdentifierValue(CSSValueTop); + + result->setFirstX(startX.release()); + result->setFirstY(startY.release()); + } + + if (!parseGradientColorStops(args, result.get(), expectComma)) + return false; + + Vector<CSSGradientColorStop>& stops = result->stops(); + if (stops.isEmpty()) + return false; + + gradient = result.release(); + return true; +} + +bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating) +{ + RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating); + + // Walk the arguments. + CSSParserValueList* args = 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 (!a) + return false; + + 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 = cssValuePool()->createIdentifierValue(a->id); + foundValue = true; + break; + case CSSValueClosestSide: + case CSSValueClosestCorner: + case CSSValueFarthestSide: + case CSSValueFarthestCorner: + case CSSValueContain: + case CSSValueCover: + sizeValue = cssValuePool()->createIdentifierValue(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 = createPrimitiveNumericValue(a); + a = args->next(); + if (!a) + return false; + + expectComma = true; + } + + if (validUnit(a, FLength | FPercent, m_strict)) { + verticalSize = createPrimitiveNumericValue(a); + + 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); + + if (!parseGradientColorStops(args, result.get(), expectComma)) + return false; + + gradient = result.release(); + return true; +} + +bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma) +{ + CSSParserValue* a = valueList->current(); + + // Now look for color stops. + while (a) { + // Look for the comma before the next stop. + if (expectComma) { + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + + a = valueList->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 = valueList->next(); + if (a) { + if (validUnit(a, FLength | FPercent, m_strict)) { + stop.m_position = createPrimitiveNumericValue(a); + a = valueList->next(); + } + } + + gradient->addStop(stop); + expectComma = true; + } + + // Must have 2 or more stops to be valid. + return gradient->stops().size() > 1; +} + +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(") + || equalIgnoringCase(val->function->name, "-webkit-cross-fade("); +} + +bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value) +{ + CSSParserValue* val = valueList->current(); + + if (val->unit != CSSParserValue::Function) + return false; + + if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) + return parseDeprecatedGradient(valueList, value); + + if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) + return parseLinearGradient(valueList, value, NonRepeating); + + if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) + return parseLinearGradient(valueList, value, Repeating); + + if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) + return parseRadialGradient(valueList, value, NonRepeating); + + if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) + return parseRadialGradient(valueList, value, Repeating); + + if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) + return parseCanvas(valueList, value); + + if (equalIgnoringCase(val->function->name, "-webkit-cross-fade(")) + return parseCrossfade(valueList, value); + + return false; +} + +bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade) +{ + RefPtr<CSSCrossfadeValue> result; + + // Walk the arguments. + CSSParserValueList* args = valueList->current()->function->args.get(); + if (!args || args->size() != 5) + return false; + CSSParserValue* a = args->current(); + RefPtr<CSSValue> fromImageValue; + RefPtr<CSSValue> toImageValue; + + // The first argument is the "from" image. It is a fill image. + if (!a || !parseFillImage(args, fromImageValue)) + return false; + a = args->next(); + + // Skip a comma + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + a = args->next(); + + // The second argument is the "to" image. It is a fill image. + if (!a || !parseFillImage(args, toImageValue)) + return false; + a = args->next(); + + // Skip a comma + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return false; + a = args->next(); + + // The third argument is the crossfade value. It is a percentage or a fractional number. + RefPtr<CSSPrimitiveValue> percentage; + if (!a) + return false; + + if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) + percentage = cssValuePool()->createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER); + else if (a->unit == CSSPrimitiveValue::CSS_NUMBER) + percentage = cssValuePool()->createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER); + else + return false; + + result = CSSCrossfadeValue::create(fromImageValue, toImageValue); + result->setPercentage(percentage); + + crossfade = result; + + return true; +} + +bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas) +{ + RefPtr<CSSCanvasValue> result = CSSCanvasValue::create(); + + // Walk the arguments. + CSSParserValueList* args = 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 (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) { + // 1st param of perspective() must be a non-negative number (deprecated) or length. + if (!validUnit(a, FNumber | FLength | FNonNeg, true)) + return 0; + } else if (!validUnit(a, unit, true)) + return 0; + + // Add the value to the current transform operation. + transformValue->append(createPrimitiveNumericValue(a)); + + a = args->next(); + if (!a) + break; + if (a->unit != CSSParserValue::Operator || a->iValue != ',') + return 0; + a = args->next(); + + argNumber++; + } + } + + return list.release(); +} + +#if ENABLE(CSS_FILTERS) + +static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount) +{ + if (equalIgnoringCase(name, "grayscale(")) + filterType = WebKitCSSFilterValue::GrayscaleFilterOperation; + else if (equalIgnoringCase(name, "sepia(")) + filterType = WebKitCSSFilterValue::SepiaFilterOperation; + else if (equalIgnoringCase(name, "saturate(")) + filterType = WebKitCSSFilterValue::SaturateFilterOperation; + else if (equalIgnoringCase(name, "hue-rotate(")) + filterType = WebKitCSSFilterValue::HueRotateFilterOperation; + else if (equalIgnoringCase(name, "invert(")) + filterType = WebKitCSSFilterValue::InvertFilterOperation; + else if (equalIgnoringCase(name, "opacity(")) + filterType = WebKitCSSFilterValue::OpacityFilterOperation; + else if (equalIgnoringCase(name, "brightness(")) + filterType = WebKitCSSFilterValue::BrightnessFilterOperation; + else if (equalIgnoringCase(name, "contrast(")) + filterType = WebKitCSSFilterValue::ContrastFilterOperation; + else if (equalIgnoringCase(name, "blur(")) + filterType = WebKitCSSFilterValue::BlurFilterOperation; + else if (equalIgnoringCase(name, "drop-shadow(")) { + filterType = WebKitCSSFilterValue::DropShadowFilterOperation; + maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed. + } +#if ENABLE(CSS_SHADERS) + else if (equalIgnoringCase(name, "custom(")) + filterType = WebKitCSSFilterValue::CustomFilterOperation; +#endif +} + +#if ENABLE(CSS_SHADERS) +static bool acceptCommaOperator(CSSParserValueList* argsList) +{ + if (CSSParserValue* arg = argsList->current()) { + if (arg->unit != CSSParserValue::Operator || arg->iValue != ',') + return false; + argsList->next(); + } + return true; +} + +PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilter(CSSParserValue* value) +{ + CSSParserValueList* argsList = value->function->args.get(); + if (!argsList) + return 0; + + RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::CustomFilterOperation); + + // Custom filter syntax: + // + // vertexShader: <uri> | none + // fragmentShader: <uri> | none + // + // box: filter-box | border-box | padding-box | content-box + // vertexMesh: +<integer>{1,2}[wsp<box>][wsp'detached'] + // + // param-value: true|false[wsp+true|false]{0-3} | + // <number>[wsp+<number>]{0-3} | + // <array> | + // <transform> | + // <texture(<uri>)> + // array: 'array('<number>[wsp<number>]*')' + // css-3d-transform: <transform-function>;[<transform-function>]* + // transform: <css-3d-transform> | <mat> + // mat: 'mat2('<number>(,<number>){3}')' | + // 'mat3('<number>(,<number>){8}')' | + // 'mat4('<number>(,<number>){15}')' ) + // param-def: <param-name>wsp<param-value> + // param-name: <ident> + // params: [<param-def>[,<param-def>*]] + // + // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>]) + + // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>] + RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated(); + bool hadAtLeastOneCustomShader = false; + CSSParserValue* arg; + while ((arg = argsList->current())) { + RefPtr<CSSValue> value; + if (arg->id == CSSValueNone) + value = cssValuePool()->createIdentifierValue(CSSValueNone); + else if (arg->unit == CSSPrimitiveValue::CSS_URI) { + KURL shaderURL = m_styleSheet ? m_styleSheet->completeURL(arg->string) : KURL(); + value = WebKitCSSShaderValue::create(shaderURL.string()); + hadAtLeastOneCustomShader = true; + } + if (!value) + break; + shadersList->append(value.release()); + argsList->next(); + } + + if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList)) + return 0; + + filterValue->append(shadersList.release()); + + // 2. Parse the mesh size <vertex-mesh> + RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated(); + + while ((arg = argsList->current())) { + if (!validUnit(arg, FInteger | FNonNeg, true)) + break; + int integerValue = clampToInteger(arg->fValue); + // According to the specification we can only accept positive non-zero values. + if (integerValue < 1) + return 0; + meshSizeList->append(cssValuePool()->createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER)); + argsList->next(); + } + + if (meshSizeList->length() > 2) + return 0; + + if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox + || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox)) { + meshSizeList->append(cssValuePool()->createIdentifierValue(arg->id)); + argsList->next(); + } + + if ((arg = argsList->current()) && arg->id == CSSValueDetached) { + meshSizeList->append(cssValuePool()->createIdentifierValue(arg->id)); + argsList->next(); + } + + if (meshSizeList->length()) { + if (!acceptCommaOperator(argsList)) + return 0; + filterValue->append(meshSizeList.release()); + } + + // 3. Parser the parameters. + RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated(); + + while ((arg = argsList->current())) { + if (arg->id || arg->unit != CSSPrimitiveValue::CSS_IDENT) + return 0; + + RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated(); + parameter->append(createPrimitiveStringValue(arg)); + argsList->next(); + + if (!(arg = argsList->current())) + return 0; + + // TODO: Implement other parameters types parsing. + // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 + // 3d-transforms: https://bugs.webkit.org/show_bug.cgi?id=71443 + // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444 + RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated(); + while ((arg = argsList->current())) { + // If we hit a comma it means we finished this parameter's values. + if (arg->unit == CSSParserValue::Operator && arg->iValue == ',') + break; + if (!validUnit(arg, FNumber, true)) + return 0; + paramValueList->append(cssValuePool()->createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER)); + argsList->next(); + } + if (!paramValueList->length() || paramValueList->length() > 4) + return 0; + parameter->append(paramValueList.release()); + paramList->append(parameter.release()); + if (!acceptCommaOperator(argsList)) + return 0; + } + + if (paramList->length()) + filterValue->append(paramList.release()); + + return filterValue; +} +#endif + +PassRefPtr<WebKitCSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType) +{ + RefPtr<WebKitCSSFilterValue> filterValue = WebKitCSSFilterValue::create(filterType); + ASSERT(args); + + switch (filterType) { + case WebKitCSSFilterValue::GrayscaleFilterOperation: + case WebKitCSSFilterValue::SepiaFilterOperation: + case WebKitCSSFilterValue::SaturateFilterOperation: + case WebKitCSSFilterValue::InvertFilterOperation: + case WebKitCSSFilterValue::OpacityFilterOperation: + case WebKitCSSFilterValue::BrightnessFilterOperation: + case WebKitCSSFilterValue::ContrastFilterOperation: { + // One optional argument, 0-1 or 0%-100%, if missing use 100%. + if (args->size() > 1) + return 0; + + if (args->size()) { + CSSParserValue* value = args->current(); + if (!validUnit(value, FNumber | FPercent | FNonNeg, true)) + return 0; + + double amount = value->fValue; + + // Saturate, Brightness and Contrast allow values over 100%. + if (filterType != WebKitCSSFilterValue::SaturateFilterOperation + && filterType != WebKitCSSFilterValue::BrightnessFilterOperation + && filterType != WebKitCSSFilterValue::ContrastFilterOperation) { + double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0; + if (amount > maxAllowed) + return 0; + } + + filterValue->append(cssValuePool()->createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit))); + } + break; + } + case WebKitCSSFilterValue::HueRotateFilterOperation: { + // hue-rotate() takes one optional angle. + if (args->size() > 1) + return 0; + + if (args->size()) { + CSSParserValue* argument = args->current(); + if (!validUnit(argument, FAngle, true)) + return 0; + + filterValue->append(createPrimitiveNumericValue(argument)); + } + break; + } + case WebKitCSSFilterValue::BlurFilterOperation: { + // Blur takes a single length. Zero parameters are allowed. + if (args->size() > 1) + return 0; + + if (args->size()) { + CSSParserValue* argument = args->current(); + if (!validUnit(argument, FLength | FNonNeg, true)) + return 0; + + filterValue->append(createPrimitiveNumericValue(argument)); + } + break; + } + case WebKitCSSFilterValue::DropShadowFilterOperation: { + // drop-shadow() takes a single shadow. + RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter); + if (!shadowValueList || shadowValueList->length() != 1) + return 0; + + filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0)); + break; + } + default: + ASSERT_NOT_REACHED(); + } + return filterValue.release(); +} + +PassRefPtr<CSSValueList> CSSParser::parseFilter() +{ + if (!m_valueList) + return 0; + + // The filter is a list of functional primitives that specify individual operations. + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function)) + return 0; + + WebKitCSSFilterValue::FilterOperationType filterType = WebKitCSSFilterValue::UnknownFilterOperation; + + // See if the specified primitive is one we understand. + if (value->unit == CSSPrimitiveValue::CSS_URI) { + RefPtr<WebKitCSSFilterValue> referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation); + list->append(referenceFilterValue); + referenceFilterValue->append(cssValuePool()->createValue(value->string, CSSPrimitiveValue::CSS_STRING)); + } else { + const CSSParserString name = value->function->name; + unsigned maximumArgumentCount = 1; + + filterInfoForName(name, filterType, maximumArgumentCount); + + if (filterType == WebKitCSSFilterValue::UnknownFilterOperation) + return 0; + +#if ENABLE(CSS_SHADERS) + if (filterType == WebKitCSSFilterValue::CustomFilterOperation) { + RefPtr<WebKitCSSFilterValue> filterValue = parseCustomFilter(value); + if (!filterValue) + return 0; + list->append(filterValue.release()); + continue; + } +#endif + CSSParserValueList* args = value->function->args.get(); + if (!args) + return 0; + + RefPtr<WebKitCSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType); + if (!filterValue) + return 0; + + list->append(filterValue); + } + } + + return list.release(); +} +#endif + +static bool validFlowName(const String& flowName) +{ + if (equalIgnoringCase(flowName, "auto") + || equalIgnoringCase(flowName, "default") + || equalIgnoringCase(flowName, "inherit") + || equalIgnoringCase(flowName, "initial") + || equalIgnoringCase(flowName, "none")) + return false; + return true; +} + +// auto | <ident> +bool CSSParser::parseFlowThread(int propId, bool important) +{ + ASSERT(propId == CSSPropertyWebkitFlowInto); + + if (m_valueList->size() != 1) + return false; + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + if (value->id == CSSValueAuto) { + addProperty(propId, cssValuePool()->createIdentifierValue(value->id), important); + return true; + } + + String inputProperty = String(value->string); + if (!inputProperty.isEmpty()) { + if (!validFlowName(inputProperty)) + return false; + addProperty(propId, cssValuePool()->createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); + } else + addProperty(propId, cssValuePool()->createIdentifierValue(CSSValueAuto), important); + + return true; +} + +// -webkit-flow-from: none | <ident> +bool CSSParser::parseRegionThread(int propId, bool important) +{ + ASSERT(propId == CSSPropertyWebkitFlowFrom); + + if (m_valueList->size() != 1) + return false; + + CSSParserValue* value = m_valueList->current(); + if (!value) + return false; + + if (value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + + if (value->id == CSSValueNone) + addProperty(propId, cssValuePool()->createIdentifierValue(value->id), important); + else { + String inputProperty = String(value->string); + if (!inputProperty.isEmpty()) { + if (!validFlowName(inputProperty)) + return false; + addProperty(propId, cssValuePool()->createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); + } else + addProperty(propId, cssValuePool()->createIdentifierValue(CSSValueNone), important); + } + + return true; +} + +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: { + value = parseFillPositionX(m_valueList.get()); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitTransformOriginY: { + value = parseFillPositionY(m_valueList.get()); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitTransformOriginZ: { + if (validUnit(m_valueList->current(), FLength, m_strict)) + value = createPrimitiveNumericValue(m_valueList->current()); + 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.get(), value, value2); + break; + case CSSPropertyWebkitPerspectiveOriginX: { + value = parseFillPositionX(m_valueList.get()); + if (value) + m_valueList->next(); + break; + } + case CSSPropertyWebkitPerspectiveOriginY: { + value = parseFillPositionY(m_valueList.get()); + 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, createPrimitiveStringValue(value), important); + m_valueList->next(); + return true; + } + + if (value->id == CSSValueNone) { + if (fill || shape || (valueListSize != 1 && !inShorthand())) + return false; + addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool()->createIdentifierValue(CSSValueNone), important); + m_valueList->next(); + return true; + } + + if (value->id == CSSValueOpen || value->id == CSSValueFilled) { + if (fill) + return false; + fill = cssValuePool()->createIdentifierValue(value->id); + } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) { + if (shape) + return false; + shape = cssValuePool()->createIdentifierValue(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; +} + +bool CSSParser::parseLineBoxContain(bool important) +{ + LineBoxContain lineBoxContain = LineBoxContainNone; + + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (value->id == CSSValueBlock) { + if (lineBoxContain & LineBoxContainBlock) + return false; + lineBoxContain |= LineBoxContainBlock; + } else if (value->id == CSSValueInline) { + if (lineBoxContain & LineBoxContainInline) + return false; + lineBoxContain |= LineBoxContainInline; + } else if (value->id == CSSValueFont) { + if (lineBoxContain & LineBoxContainFont) + return false; + lineBoxContain |= LineBoxContainFont; + } else if (value->id == CSSValueGlyphs) { + if (lineBoxContain & LineBoxContainGlyphs) + return false; + lineBoxContain |= LineBoxContainGlyphs; + } else if (value->id == CSSValueReplaced) { + if (lineBoxContain & LineBoxContainReplaced) + return false; + lineBoxContain |= LineBoxContainReplaced; + } else if (value->id == CSSValueInlineBox) { + if (lineBoxContain & LineBoxContainInlineBox) + return false; + lineBoxContain |= LineBoxContainInlineBox; + } else + return false; + } + + if (!lineBoxContain) + return false; + + addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important); + return true; +} + +bool CSSParser::parseFontFeatureTag(CSSValueList* settings) +{ + // Feature tag name consists of 4-letter characters. + static const int tagNameLength = 4; + + CSSParserValue* value = m_valueList->current(); + // Feature tag name comes first + if (value->unit != CSSPrimitiveValue::CSS_STRING && value->unit != CSSPrimitiveValue::CSS_IDENT) + return false; + if (value->string.length != tagNameLength) + return false; + for (int i = 0; i < tagNameLength; ++i) { + // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification. + UChar character = value->string.characters[i]; + if (character < 0x20 || character > 0x7E) + return false; + } + + String tag = value->string; + int tagValue = 1; + // Feature tag values could follow: <integer> | on | off + value = m_valueList->next(); + if (value) { + if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) { + tagValue = clampToInteger(value->fValue); + if (tagValue < 0) + return false; + m_valueList->next(); + } else if (value->id == CSSValueOn || value->id == CSSValueOff) { + tagValue = value->id == CSSValueOn; + m_valueList->next(); + } + } + settings->append(FontFeatureValue::create(tag, tagValue)); + return true; +} + +bool CSSParser::parseFontFeatureSettings(bool important) +{ + if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) { + RefPtr<CSSPrimitiveValue> normalValue = cssValuePool()->createIdentifierValue(CSSValueNormal); + m_valueList->next(); + addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important); + return true; + } + + RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated(); + for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { + if (!parseFontFeatureTag(settings.get())) + return false; + + // If the list isn't parsed fully, the current value should be comma. + value = m_valueList->current(); + if (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')) + return false; + } + if (settings->length()) { + addProperty(CSSPropertyWebkitFontFeatureSettings, settings.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 ANYFUNCTION: + case NOTFUNCTION: + case CALCFUNCTION: + case MINFUNCTION: + case MAXFUNCTION: + 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; + } +} + +CSSParserSelector* CSSParser::createFloatingSelector() +{ + CSSParserSelector* selector = new CSSParserSelector; + m_floatingSelectors.add(selector); + return selector; +} + +PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector) +{ + if (selector) { + ASSERT(m_floatingSelectors.contains(selector)); + m_floatingSelectors.remove(selector); + } + return adoptPtr(selector); +} + +Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector() +{ + Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >; + m_floatingSelectorVectors.add(selectorVector); + return selectorVector; +} + +PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector) +{ + if (selectorVector) { + ASSERT(m_floatingSelectorVectors.contains(selectorVector)); + m_floatingSelectorVectors.remove(selectorVector); + } + return adoptPtr(selectorVector); +} + +CSSParserValueList* CSSParser::createFloatingValueList() +{ + CSSParserValueList* list = new CSSParserValueList; + m_floatingValueLists.add(list); + return list; +} + +PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list) +{ + if (list) { + ASSERT(m_floatingValueLists.contains(list)); + m_floatingValueLists.remove(list); + } + return adoptPtr(list); +} + +CSSParserFunction* CSSParser::createFloatingFunction() +{ + CSSParserFunction* function = new CSSParserFunction; + m_floatingFunctions.add(function); + return function; +} + +PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function) +{ + if (function) { + ASSERT(m_floatingFunctions.contains(function)); + m_floatingFunctions.remove(function); + } + return adoptPtr(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_parsedMediaLists.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_parsedRules.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_parsedRules.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_parsedRules.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_parsedRules.append(rule.release()); + return rulePtr; +} + +CSSRule* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* 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_parsedRules.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->value())->append(value.release()); + } else if (id == CSSPropertyFontFamily && (!property->value()->isValueList() || static_cast<CSSValueList*>(property->value())->length() != 1)) { + // Unlike font-family property, font-family descriptor in @font-face rule + // has to be a value list with exactly one family name. It cannot have a + // have 'initial' value and cannot 'inherit' from parent. + // 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_parsedRules.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); +} + +void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers) +{ + AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace; + QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace); + if (!specifiers->isUnknownPseudoElement()) { + specifiers->setTag(tag); + return; + } + + CSSParserSelector* lastShadowDescendant = specifiers; + CSSParserSelector* history = specifiers; + while (history->tagHistory()) { + history = history->tagHistory(); + if (history->hasShadowDescendant()) + lastShadowDescendant = history; + } + + if (lastShadowDescendant->tagHistory()) { + lastShadowDescendant->tagHistory()->setTag(tag); + return; + } + + // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used. + // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*'). + OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector); + elementNameSelector->setTag(tag); + lastShadowDescendant->setTagHistory(elementNameSelector.release()); + lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant); +} + +CSSParserSelector* CSSParser::updateSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier) +{ + if (newSpecifier->isUnknownPseudoElement()) { + // Unknown pseudo element always goes at the top of selector chain. + newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers)); + return newSpecifier; + } + if (specifiers->isUnknownPseudoElement()) { + // Specifiers for unknown pseudo element go right behind it in the chain. + specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant); + return specifiers; + } + specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier)); + return specifiers; +} + +CSSRule* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector) +{ + // FIXME: Margin at-rules are ignored. + m_allowImportRules = m_allowNamespaceDeclarations = false; + CSSPageRule* pageRule = 0; + if (pageSelector) { + RefPtr<CSSPageRule> rule = CSSPageRule::create(m_styleSheet, m_lastSelectorLineNumber); + Vector<OwnPtr<CSSParserSelector> > selectorVector; + selectorVector.append(pageSelector); + rule->adoptSelectorVector(selectorVector); + rule->setDeclaration(CSSMutableStyleDeclaration::create(rule.get(), m_parsedProperties, m_numParsedProperties)); + pageRule = rule.get(); + m_parsedRules.append(rule.release()); + } + clearProperties(); + return pageRule; +} + +void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors) +{ + if (selectors) + m_reusableRegionSelectorVector.swap(*selectors); +} + +CSSRule* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, CSSRuleList* rules) +{ + if (!regionSelector || !rules) + return 0; + + m_allowImportRules = m_allowNamespaceDeclarations = false; + + RefPtr<WebKitCSSRegionRule> regionRule = WebKitCSSRegionRule::create(m_styleSheet, regionSelector, rules); + + WebKitCSSRegionRule* result = regionRule.get(); + m_parsedRules.append(regionRule.release()); + + return result; +} + +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 = static_cast<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(keyframe.get(), m_parsedProperties, m_numParsedProperties)); + + clearProperties(); + + WebKitCSSKeyframeRule* keyframePtr = keyframe.get(); + m_parsedRules.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::updateLastMediaLine(MediaList* media) +{ + media->setLastLine(m_lineNumber); +} + +void CSSParser::markSelectorListStart() +{ + m_selectorListRange.start = yytext - m_data.get(); +} + +void CSSParser::markSelectorListEnd() +{ + if (!m_currentRuleData) + return; + UChar* listEnd = yytext; + while (listEnd > m_data.get() + 1) { + if (isHTMLSpace(*(listEnd - 1))) + --listEnd; + else + break; + } + m_selectorListRange.end = listEnd - m_data.get(); +} + +void CSSParser::markRuleBodyStart() +{ + unsigned offset = yytext - m_data.get(); + 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.get(); + if (offset > m_ruleBodyRange.end) + m_ruleBodyRange.end = offset; +} + +void CSSParser::markPropertyStart() +{ + if (!m_inStyleRuleOrDeclaration) + return; + m_propertyRange.start = yytext - m_data.get(); +} + +void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) +{ + if (!m_inStyleRuleOrDeclaration) + return; + unsigned offset = yytext - m_data.get(); + 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.get() + start, end - start).stripWhiteSpace(); + if (propertyString.endsWith(";", true)) + propertyString = propertyString.left(propertyString.length() - 1); + 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 PLATFORM(IOS) + if (!strcmp(buffer, "-webkit-hyphenate-locale")) { + // Worked in iOS 4.2. + const char* const webkitLocale = "-webkit-locale"; + name = webkitLocale; + length = strlen(webkitLocale); + } +#endif + } + + 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<UChar> 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. + buffer[index++] = '\\'; + placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase); + 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. + // However, since the {ident} rule precedes the {nth} rule, some of those + // tokens are identified as string literal. Furthermore we need to accept + // "odd" and "even" which does not match to an+b. + return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even") + || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n"); +} + +#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 000000000..adc19025a --- /dev/null +++ b/Source/WebCore/css/CSSParser.h @@ -0,0 +1,450 @@ +/* + * 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 "CSSSelector.h" +#include "Color.h" +#include "MediaQuery.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> + +#if ENABLE(CSS_FILTERS) +#include "WebKitCSSFilterValue.h" +#endif + +namespace WebCore { + +class CSSBorderImageSliceValue; +class CSSMappedAttributeDeclaration; +class CSSMutableStyleDeclaration; +class CSSPrimitiveValue; +class CSSValuePool; +class CSSProperty; +class CSSRule; +class CSSRuleList; +class CSSSelectorList; +class CSSStyleSheet; +class CSSValue; +class CSSValueList; +class CSSWrapShape; +class Document; +class MediaList; +class MediaQueryExp; +class StyledElement; +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<WebKitCSSKeyframeRule> parseKeyframeRule(CSSStyleSheet*, const String&); + static bool parseValue(CSSMutableStyleDeclaration*, int propId, const String&, bool important, bool strict); + static bool parseColor(RGBA32& color, const String&, bool strict = false); + static bool parseSystemColor(RGBA32& color, const String&, Document*); + PassRefPtr<CSSPrimitiveValue> parseValidPrimitive(int propId, CSSParserValue*); + bool parseDeclaration(CSSMutableStyleDeclaration*, const String&, RefPtr<CSSStyleSourceData>* = 0, CSSStyleSheet* contextStyleSheet = 0); + bool parseMediaQuery(MediaList*, const String&); + + static bool parseMappedAttributeValue(CSSMappedAttributeDeclaration*, StyledElement*, int propertyId, const String&); + + Document* findDocument() const; + + CSSValuePool* cssValuePool() const { return m_cssValuePool.get(); } + + void addProperty(int propId, PassRefPtr<CSSValue>, bool important, bool implicit = false); + 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); + bool parseQuotes(int propId, bool important); + + PassRefPtr<CSSValue> parseAttr(CSSParserValueList* args); + + PassRefPtr<CSSValue> parseBackgroundColor(); + + bool parseFillImage(CSSParserValueList*, RefPtr<CSSValue>&); + + enum FillPositionFlag { InvalidFillPosition = 0, AmbiguousFillPosition = 1, XFillPosition = 2, YFillPosition = 4 }; + PassRefPtr<CSSValue> parseFillPositionComponent(CSSParserValueList*, unsigned& cumulativeFlags, FillPositionFlag& individualFlag); + PassRefPtr<CSSValue> parseFillPositionX(CSSParserValueList*); + PassRefPtr<CSSValue> parseFillPositionY(CSSParserValueList*); + 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); + +#if ENABLE(CSS_GRID_LAYOUT) + bool parseGridTrackList(int propId, bool important); +#endif + + bool parseDashboardRegions(int propId, bool important); + + bool parseShape(int propId, bool important); + + bool parseWrapShape(bool shapeInside, bool important); + PassRefPtr<CSSWrapShape> parseWrapShapeRect(CSSParserValueList* args); + PassRefPtr<CSSWrapShape> parseWrapShapeCircle(CSSParserValueList* args); + PassRefPtr<CSSWrapShape> parseWrapShapeEllipse(CSSParserValueList* args); + PassRefPtr<CSSWrapShape> parseWrapShapePolygon(CSSParserValueList* args); + + 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 fastParseColor(RGBA32&, const String&, 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 + + // CSS3 Parsing Routines (for properties specific to CSS3) + PassRefPtr<CSSValueList> parseShadow(CSSParserValueList*, int propId); + bool parseBorderImage(int propId, RefPtr<CSSValue>&); + bool parseBorderImageRepeat(RefPtr<CSSValue>&); + bool parseBorderImageSlice(int propId, RefPtr<CSSBorderImageSliceValue>&); + bool parseBorderImageWidth(RefPtr<CSSPrimitiveValue>&); + bool parseBorderImageOutset(RefPtr<CSSPrimitiveValue>&); + bool parseBorderRadius(int propId, bool important); + + bool parseAspectRatio(bool important); + + bool parseReflect(int propId, bool important); + + bool parseFlex(int propId, bool important); + + // Image generators + bool parseCanvas(CSSParserValueList*, RefPtr<CSSValue>&); + + bool parseDeprecatedGradient(CSSParserValueList*, RefPtr<CSSValue>&); + bool parseLinearGradient(CSSParserValueList*, RefPtr<CSSValue>&, CSSGradientRepeat repeating); + bool parseRadialGradient(CSSParserValueList*, RefPtr<CSSValue>&, CSSGradientRepeat repeating); + bool parseGradientColorStops(CSSParserValueList*, CSSGradientValue*, bool expectComma); + + bool parseCrossfade(CSSParserValueList*, RefPtr<CSSValue>&); + +#if ENABLE(CSS_FILTERS) + PassRefPtr<CSSValueList> parseFilter(); + PassRefPtr<WebKitCSSFilterValue> parseBuiltinFilterArguments(CSSParserValueList*, WebKitCSSFilterValue::FilterOperationType); +#if ENABLE(CSS_SHADERS) + PassRefPtr<WebKitCSSFilterValue> parseCustomFilter(CSSParserValue*); +#endif +#endif + + 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); + + bool parseLineBoxContain(bool important); + + bool parseFontFeatureTag(CSSValueList*); + bool parseFontFeatureSettings(bool important); + + bool parseFlowThread(int propId, bool important); + bool parseRegionThread(int propId, bool important); + + int yyparse(); + + CSSParserSelector* createFloatingSelector(); + PassOwnPtr<CSSParserSelector> sinkFloatingSelector(CSSParserSelector*); + + Vector<OwnPtr<CSSParserSelector> >* createFloatingSelectorVector(); + PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >*); + + CSSParserValueList* createFloatingValueList(); + PassOwnPtr<CSSParserValueList> sinkFloatingValueList(CSSParserValueList*); + + CSSParserFunction* createFloatingFunction(); + PassOwnPtr<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<OwnPtr<CSSParserSelector> >* selectors); + CSSRule* createFontFaceRule(); + CSSRule* createPageRule(PassOwnPtr<CSSParserSelector> pageSelector); + CSSRule* createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, CSSRuleList* rules); + 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 updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*); + CSSParserSelector* updateSpecifiers(CSSParserSelector*, CSSParserSelector*); + + void invalidBlockHit(); + + Vector<OwnPtr<CSSParserSelector> >* reusableSelectorVector() { return &m_reusableSelectorVector; } + + void setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors); + Vector<OwnPtr<CSSParserSelector> >* reusableRegionSelectorVector() { return &m_reusableRegionSelectorVector; } + + void updateLastSelectorLineAndPosition(); + void updateLastMediaLine(MediaList*); + + void clearProperties(); + + bool m_strict; + bool m_important; + int m_id; + CSSStyleSheet* m_styleSheet; + RefPtr<CSSRule> m_rule; + RefPtr<WebKitCSSKeyframeRule> m_keyframe; + OwnPtr<MediaQuery> m_mediaQuery; + OwnPtr<CSSParserValueList> m_valueList; + CSSProperty** m_parsedProperties; + CSSSelectorList* m_selectorListForParseSelector; + + RefPtr<CSSValuePool> m_cssValuePool; + 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 setStyleSheet(CSSStyleSheet*); + void ensureCSSValuePool(); + + 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(CSSParserValueList*, RefPtr<CSSValue>&); + + bool parseValue(CSSMutableStyleDeclaration*, int propId, const String&, bool important, CSSStyleSheet* contextStyleSheet = 0); + + 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); + + bool parseFontFaceSrcURI(CSSValueList*); + bool parseFontFaceSrcLocal(CSSValueList*); + + bool parseColor(const String&); + + OwnArrayPtr<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<CSSRule> > m_parsedRules; + Vector<RefPtr<MediaList> > m_parsedMediaLists; + Vector<RefPtr<CSSRuleList> > m_parsedRuleLists; + HashSet<CSSParserSelector*> m_floatingSelectors; + HashSet<Vector<OwnPtr<CSSParserSelector> >*> m_floatingSelectorVectors; + HashSet<CSSParserValueList*> m_floatingValueLists; + HashSet<CSSParserFunction*> m_floatingFunctions; + + OwnPtr<MediaQuery> m_floatingMediaQuery; + OwnPtr<MediaQueryExp> m_floatingMediaQueryExp; + OwnPtr<Vector<OwnPtr<MediaQueryExp> > > m_floatingMediaQueryExpList; + + Vector<OwnPtr<CSSParserSelector> > m_reusableSelectorVector; + Vector<OwnPtr<CSSParserSelector> > m_reusableRegionSelectorVector; + + // 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); + + bool parseBorderImageQuad(Units, RefPtr<CSSPrimitiveValue>&); + + PassRefPtr<CSSPrimitiveValue> createPrimitiveNumericValue(CSSParserValue*); + PassRefPtr<CSSPrimitiveValue> createPrimitiveStringValue(CSSParserValue*); + + friend class TransformOperationInfo; +#if ENABLE(CSS_FILTERS) + friend class FilterOperationInfo; +#endif +}; + +int cssPropertyID(const CSSParserString&); +int cssPropertyID(const String&); +int cssValueKeywordID(const CSSParserString&); + +class ShorthandScope { + WTF_MAKE_FAST_ALLOCATED; +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 000000000..5af2a9a16 --- /dev/null +++ b/Source/WebCore/css/CSSParserValues.cpp @@ -0,0 +1,135 @@ +/* + * 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 "CSSSelector.h" +#include "CSSSelectorList.h" + +namespace WebCore { + +using namespace WTF; + +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::insertValueAt(unsigned i, const CSSParserValue& v) +{ + m_values.insert(i, v); +} + +void CSSParserValueList::deleteValueAt(unsigned i) +{ + m_values.remove(i); +} + +void CSSParserValueList::extend(CSSParserValueList& valueList) +{ + for (unsigned int i = 0; i < valueList.size(); ++i) + m_values.append(*(valueList.valueAt(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 = CSSPrimitiveValue::createAllowingMarginQuirk(fValue, CSSPrimitiveValue::CSS_EMS); + return parsedValue; +} + +CSSParserSelector::CSSParserSelector() + : m_selector(adoptPtr(fastNew<CSSSelector>())) +{ +} + +CSSParserSelector::~CSSParserSelector() +{ + if (!m_tagHistory) + return; + Vector<OwnPtr<CSSParserSelector>, 16> toDelete; + OwnPtr<CSSParserSelector> selector = m_tagHistory.release(); + while (true) { + OwnPtr<CSSParserSelector> next = selector->m_tagHistory.release(); + toDelete.append(selector.release()); + if (!next) + break; + selector = next.release(); + } +} + +void CSSParserSelector::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector) +{ + CSSSelectorList* selectorList = fastNew<CSSSelectorList>(); + selectorList->adoptSelectorVector(selectorVector); + m_selector->setSelectorList(adoptPtr(selectorList)); +} + +void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector> selector, CSSSelector::Relation after) +{ + if (m_tagHistory) + selector->setTagHistory(m_tagHistory.release()); + setRelation(before); + selector->setRelation(after); + m_tagHistory = selector; +} + +void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr<CSSParserSelector> selector) +{ + CSSParserSelector* end = this; + while (end->tagHistory()) + end = end->tagHistory(); + end->setRelation(relation); + end->setTagHistory(selector); +} + +} + diff --git a/Source/WebCore/css/CSSParserValues.h b/Source/WebCore/css/CSSParserValues.h new file mode 100644 index 000000000..90d26a46d --- /dev/null +++ b/Source/WebCore/css/CSSParserValues.h @@ -0,0 +1,146 @@ +/* + * 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 "CSSSelector.h" +#include "CSSValueList.h" +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class CSSValue; +class QualifiedName; + +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 { + WTF_MAKE_FAST_ALLOCATED; +public: + CSSParserValueList() + : m_current(0) + { + } + ~CSSParserValueList(); + + void addValue(const CSSParserValue&); + void insertValueAt(unsigned, const CSSParserValue&); + void deleteValueAt(unsigned); + void extend(CSSParserValueList&); + + 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* previous() + { + if (!m_current) + return 0; + --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 { + WTF_MAKE_FAST_ALLOCATED; +public: + CSSParserString name; + OwnPtr<CSSParserValueList> args; +}; + +class CSSParserSelector { + WTF_MAKE_FAST_ALLOCATED; +public: + CSSParserSelector(); + ~CSSParserSelector(); + + PassOwnPtr<CSSSelector> releaseSelector() { return m_selector.release(); } + + void setTag(const QualifiedName& value) { m_selector->setTag(value); } + void setValue(const AtomicString& value) { m_selector->setValue(value); } + void setAttribute(const QualifiedName& value) { m_selector->setAttribute(value); } + void setArgument(const AtomicString& value) { m_selector->setArgument(value); } + void setMatch(CSSSelector::Match value) { m_selector->m_match = value; } + void setRelation(CSSSelector::Relation value) { m_selector->m_relation = value; } + void setForPage() { m_selector->setForPage(); } + + void adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector); + + CSSSelector::PseudoType pseudoType() const { return m_selector->pseudoType(); } + bool isUnknownPseudoElement() const { return m_selector->isUnknownPseudoElement(); } + bool isSimple() const { return !m_tagHistory && m_selector->isSimple(); } + bool hasShadowDescendant() const; + + CSSParserSelector* tagHistory() const { return m_tagHistory.get(); } + void setTagHistory(PassOwnPtr<CSSParserSelector> selector) { m_tagHistory = selector; } + void insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector>, CSSSelector::Relation after); + void appendTagHistory(CSSSelector::Relation, PassOwnPtr<CSSParserSelector>); + +private: + OwnPtr<CSSSelector> m_selector; + OwnPtr<CSSParserSelector> m_tagHistory; +}; + +inline bool CSSParserSelector::hasShadowDescendant() const +{ + return m_selector->relation() == CSSSelector::ShadowDescendant; +} + +} + +#endif diff --git a/Source/WebCore/css/CSSPrimitiveValue.cpp b/Source/WebCore/css/CSSPrimitiveValue.cpp new file mode 100644 index 000000000..a439cbf52 --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValue.cpp @@ -0,0 +1,955 @@ +/* + * (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 "CSSWrapShapes.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/StdLibExtras.h> +#include <wtf/text/StringBuffer.h> +#include <wtf/text/StringBuilder.h> + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +using namespace WTF; + +namespace WebCore { + +static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitTypes unitType) +{ + switch (unitType) { + case CSSPrimitiveValue:: CSS_CM: + case CSSPrimitiveValue:: CSS_DEG: + case CSSPrimitiveValue:: CSS_DIMENSION: + case CSSPrimitiveValue:: CSS_EMS: + case CSSPrimitiveValue:: CSS_EXS: + case CSSPrimitiveValue:: CSS_GRAD: + case CSSPrimitiveValue:: CSS_HZ: + case CSSPrimitiveValue:: CSS_IN: + case CSSPrimitiveValue:: CSS_KHZ: + case CSSPrimitiveValue:: CSS_MM: + case CSSPrimitiveValue:: CSS_MS: + case CSSPrimitiveValue:: CSS_NUMBER: + case CSSPrimitiveValue:: CSS_PERCENTAGE: + case CSSPrimitiveValue:: CSS_PC: + case CSSPrimitiveValue:: CSS_PT: + case CSSPrimitiveValue:: CSS_PX: + case CSSPrimitiveValue:: CSS_RAD: + case CSSPrimitiveValue:: CSS_REMS: + case CSSPrimitiveValue:: CSS_S: + case CSSPrimitiveValue:: CSS_TURN: + return true; + case CSSPrimitiveValue:: CSS_ATTR: + case CSSPrimitiveValue:: CSS_COUNTER: + case CSSPrimitiveValue:: CSS_COUNTER_NAME: + case CSSPrimitiveValue:: CSS_DASHBOARD_REGION: + case CSSPrimitiveValue:: CSS_IDENT: + case CSSPrimitiveValue:: CSS_PAIR: + case CSSPrimitiveValue:: CSS_PARSER_HEXCOLOR: + case CSSPrimitiveValue:: CSS_PARSER_IDENTIFIER: + case CSSPrimitiveValue:: CSS_PARSER_INTEGER: + case CSSPrimitiveValue:: CSS_PARSER_OPERATOR: + case CSSPrimitiveValue:: CSS_RECT: + case CSSPrimitiveValue:: CSS_QUAD: + case CSSPrimitiveValue:: CSS_RGBCOLOR: + case CSSPrimitiveValue:: CSS_SHAPE: + case CSSPrimitiveValue:: CSS_STRING: + case CSSPrimitiveValue:: CSS_UNICODE_RANGE: + case CSSPrimitiveValue:: CSS_UNKNOWN: + case CSSPrimitiveValue:: CSS_URI: + return false; + } + + ASSERT_NOT_REACHED(); + return false; +} + +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; +} + +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* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally. + AtomicString& keywordString = keywordStrings[valueOrPropertyID]; + if (keywordString.isNull()) + keywordString = getValueName(valueOrPropertyID); + return keywordString; + } + + if (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties) { + static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Leaked intentionally. + AtomicString& propertyString = propertyStrings[valueOrPropertyID - firstCSSProperty]; + if (propertyString.isNull()) + propertyString = getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID)); + return propertyString; + } + + return nullAtom; +} + +CSSPrimitiveValue::CSSPrimitiveValue() + : CSSValue(PrimitiveClass) +{ +} + +CSSPrimitiveValue::CSSPrimitiveValue(int ident) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + m_value.ident = ident; +} + +CSSPrimitiveValue::CSSPrimitiveValue(ClassType classType, int ident) + : CSSValue(classType) +{ + m_primitiveUnitType = CSS_IDENT; + m_value.ident = ident; +} + +CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = type; + ASSERT(isfinite(num)); + m_value.num = num; +} + +CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = type; + if ((m_value.string = str.impl())) + m_value.string->ref(); +} + + +CSSPrimitiveValue::CSSPrimitiveValue(ClassType classType, const String& str, UnitTypes type) + : CSSValue(classType) +{ + m_primitiveUnitType = type; + if ((m_value.string = str.impl())) + m_value.string->ref(); +} + +CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_RGBCOLOR; + m_value.rgbcolor = color; +} + +CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) + : CSSValue(PrimitiveClass) +{ + switch (length.type()) { + case Auto: + m_primitiveUnitType = CSS_IDENT; + m_value.ident = CSSValueAuto; + break; + case WebCore::Fixed: + m_primitiveUnitType = CSS_PX; + m_value.num = length.value(); + break; + case Intrinsic: + m_primitiveUnitType = CSS_IDENT; + m_value.ident = CSSValueIntrinsic; + break; + case MinIntrinsic: + m_primitiveUnitType = CSS_IDENT; + m_value.ident = CSSValueMinIntrinsic; + break; + case Percent: + m_primitiveUnitType = CSS_PERCENTAGE; + ASSERT(isfinite(length.percent())); + m_value.num = length.percent(); + break; + case Relative: + case Undefined: + ASSERT_NOT_REACHED(); + break; + } +} + +void CSSPrimitiveValue::init(PassRefPtr<Counter> c) +{ + m_primitiveUnitType = CSS_COUNTER; + m_hasCachedCSSText = false; + m_value.counter = c.leakRef(); +} + +void CSSPrimitiveValue::init(PassRefPtr<Rect> r) +{ + m_primitiveUnitType = CSS_RECT; + m_hasCachedCSSText = false; + m_value.rect = r.leakRef(); +} + +void CSSPrimitiveValue::init(PassRefPtr<Quad> quad) +{ + m_primitiveUnitType = CSS_QUAD; + m_hasCachedCSSText = false; + m_value.quad = quad.leakRef(); +} + +#if ENABLE(DASHBOARD_SUPPORT) +void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r) +{ + m_primitiveUnitType = CSS_DASHBOARD_REGION; + m_hasCachedCSSText = false; + m_value.region = r.leakRef(); +} +#endif + +void CSSPrimitiveValue::init(PassRefPtr<Pair> p) +{ + m_primitiveUnitType = CSS_PAIR; + m_hasCachedCSSText = false; + m_value.pair = p.leakRef(); +} + +void CSSPrimitiveValue::init(PassRefPtr<CSSWrapShape> shape) +{ + m_primitiveUnitType = CSS_SHAPE; + m_hasCachedCSSText = false; + m_value.shape = shape.leakRef(); +} + +CSSPrimitiveValue::~CSSPrimitiveValue() +{ + cleanup(); +} + +void CSSPrimitiveValue::cleanup() +{ + switch (m_primitiveUnitType) { + 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_QUAD: + m_value.quad->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 + case CSS_SHAPE: + m_value.shape->deref(); + break; + default: + break; + } + + m_primitiveUnitType = 0; + if (m_hasCachedCSSText) { + cssTextCache().remove(this); + m_hasCachedCSSText = false; + } +} + +template<> int CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); +} + +template<> Length CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + // FIXME: Length.h no longer expects 28 bit integers, so these bounds should be INT_MAX and INT_MIN + return Length(roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)), Fixed); +} + +template<> short CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); +} + +template<> unsigned short CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return roundForImpreciseConversion<unsigned short, USHRT_MAX, 0>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); +} + +template<> float CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); +} + +template<> double CSSPrimitiveValue::computeLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) +{ + return 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->fontMetrics().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: + ASSERT_NOT_REACHED(); + 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 (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitTypes>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType)) + return false; + if (requestedUnitType == static_cast<UnitTypes>(m_primitiveUnitType) || requestedUnitType == CSS_DIMENSION) { + *result = m_value.num; + return true; + } + + UnitTypes sourceUnitType = static_cast<UnitTypes>(m_primitiveUnitType); + 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_primitiveUnitType 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_primitiveUnitType) { + 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_primitiveUnitType) { + 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_primitiveUnitType != CSS_COUNTER) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.counter; +} + +Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_primitiveUnitType != CSS_RECT) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.rect; +} + +Quad* CSSPrimitiveValue::getQuadValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_primitiveUnitType != CSS_QUAD) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.quad; +} + +PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const +{ + ec = 0; + if (m_primitiveUnitType != 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_primitiveUnitType != CSS_PAIR) { + ec = INVALID_ACCESS_ERR; + return 0; + } + + return m_value.pair; +} + +static String formatNumber(double number) +{ + DecimalNumber decimal(number); + + StringBuffer<UChar> buffer(decimal.bufferLengthForStringDecimal()); + unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length()); + ASSERT_UNUSED(length, length == buffer.length()); + + return String::adopt(buffer); +} + +String CSSPrimitiveValue::customCssText() 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_primitiveUnitType) { + 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(")); + + StringBuilder result; + result.reserveCapacity(6 + m_value.string->length()); + + result.append(attrParen); + result.append(m_value.string); + result.append(')'); + + text = result.toString(); + break; + } + case CSS_COUNTER_NAME: + text = "counter("; + text += m_value.string; + text += ")"; + break; + case CSS_COUNTER: { + DEFINE_STATIC_LOCAL(const String, counterParen, ("counter(")); + DEFINE_STATIC_LOCAL(const String, countersParen, ("counters(")); + DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); + + StringBuilder result; + String separator = m_value.counter->separator(); + result.append(separator.isEmpty() ? counterParen : countersParen); + + result.append(m_value.counter->identifier()); + if (!separator.isEmpty()) { + result.append(commaSpace); + result.append(quoteCSSStringIfNeeded(separator)); + } + String listStyle = m_value.counter->listStyle(); + if (!listStyle.isEmpty()) { + result.append(commaSpace); + result.append(listStyle); + } + result.append(')'); + + text = result.toString(); + break; + } + case CSS_RECT: { + DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); + + Rect* rectVal = getRectValue(); + StringBuilder result; + result.reserveCapacity(32); + result.append(rectParen); + + result.append(rectVal->top()->cssText()); + result.append(' '); + + result.append(rectVal->right()->cssText()); + result.append(' '); + + result.append(rectVal->bottom()->cssText()); + result.append(' '); + + result.append(rectVal->left()->cssText()); + result.append(')'); + + text = result.toString(); + break; + } + case CSS_QUAD: { + Quad* quadVal = getQuadValue(); + Vector<UChar> result; + result.reserveInitialCapacity(32); + append(result, quadVal->top()->cssText()); + if (quadVal->right() != quadVal->top() || quadVal->bottom() != quadVal->top() || quadVal->left() != quadVal->top()) { + result.append(' '); + append(result, quadVal->right()->cssText()); + if (quadVal->bottom() != quadVal->top() || quadVal->right() != quadVal->left()) { + result.append(' '); + append(result, quadVal->bottom()->cssText()); + if (quadVal->left() != quadVal->right()) { + result.append(' '); + append(result, quadVal->left()->cssText()); + } + } + } + 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_primitiveUnitType == 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(); + if (m_value.pair->second() != m_value.pair->first()) { + 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_primitiveUnitType == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) { + ASSERT(region->right()->m_primitiveUnitType == CSS_IDENT); + ASSERT(region->bottom()->m_primitiveUnitType == CSS_IDENT); + ASSERT(region->left()->m_primitiveUnitType == 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; + case CSS_SHAPE: + text = m_value.shape->cssText(); + break; + } + + ASSERT(!cssTextCache().contains(this)); + cssTextCache().set(this, text); + m_hasCachedCSSText = true; + return text; +} + +void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + if (m_primitiveUnitType == 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 000000000..8fd4ad209 --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValue.h @@ -0,0 +1,281 @@ +/* + * (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/MathExtras.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class Counter; +class DashboardRegion; +class Pair; +class Quad; +class RGBColor; +class Rect; +class RenderStyle; +class CSSWrapShape; + +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 is used internally for counter names (as opposed to counter values) + CSS_COUNTER_NAME = 109, + + // This is used by the CSS Exclusions draft + CSS_SHAPE = 110, + + // Used by border images. + CSS_QUAD = 111 + }; + + // 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; } + + bool isLength() const { return isUnitTypeLength(m_primitiveUnitType); } + bool isPercentage() const { return m_primitiveUnitType == CSSPrimitiveValue::CSS_PERCENTAGE; } + bool isNumber() const { return m_primitiveUnitType == CSSPrimitiveValue::CSS_NUMBER; } + + static PassRefPtr<CSSPrimitiveValue> createIdentifier(int identifier) { return adoptRef(new CSSPrimitiveValue(identifier)); } + static PassRefPtr<CSSPrimitiveValue> createColor(unsigned rgbValue) { return adoptRef(new CSSPrimitiveValue(rgbValue)); } + static PassRefPtr<CSSPrimitiveValue> create(double value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); } + static PassRefPtr<CSSPrimitiveValue> create(const String& value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); } + + template<typename T> static PassRefPtr<CSSPrimitiveValue> create(T value) + { + return adoptRef(new CSSPrimitiveValue(value)); + } + + // 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. + static PassRefPtr<CSSPrimitiveValue> createAllowingMarginQuirk(double value, UnitTypes type) + { + CSSPrimitiveValue* quirkValue = new CSSPrimitiveValue(value, type); + quirkValue->m_isQuirkValue = true; + return adoptRef(quirkValue); + } + + ~CSSPrimitiveValue(); + + void cleanup(); + + unsigned short primitiveType() const { return m_primitiveUnitType; } + + /* + * 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. + */ + template<typename T> T computeLength(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false); + + // use with care!!! + void setPrimitiveType(unsigned short type) { m_primitiveUnitType = 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 getValue<float>(unitType, ec); } + float getFloatValue(unsigned short unitType) const { return getValue<float>(unitType); } + float getFloatValue() const { return getValue<float>(); } + + int getIntValue(unsigned short unitType, ExceptionCode& ec) const { return getValue<int>(unitType, ec); } + int getIntValue(unsigned short unitType) const { return getValue<int>(unitType); } + int getIntValue() const { return getValue<int>(); } + + template<typename T> inline T getValue(unsigned short unitType, ExceptionCode& ec) const { return clampTo<T>(getDoubleValue(unitType, ec)); } + template<typename T> inline T getValue(unsigned short unitType) const { return clampTo<T>(getDoubleValue(unitType)); } + template<typename T> inline T getValue() const { return clampTo<T>(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_primitiveUnitType != CSS_COUNTER ? 0 : m_value.counter; } + + Rect* getRectValue(ExceptionCode&) const; + Rect* getRectValue() const { return m_primitiveUnitType != CSS_RECT ? 0 : m_value.rect; } + + Quad* getQuadValue(ExceptionCode&) const; + Quad* getQuadValue() const { return m_primitiveUnitType != CSS_QUAD ? 0 : m_value.quad; } + + PassRefPtr<RGBColor> getRGBColorValue(ExceptionCode&) const; + RGBA32 getRGBA32Value() const { return m_primitiveUnitType != CSS_RGBCOLOR ? 0 : m_value.rgbcolor; } + + Pair* getPairValue(ExceptionCode&) const; + Pair* getPairValue() const { return m_primitiveUnitType != CSS_PAIR ? 0 : m_value.pair; } + + DashboardRegion* getDashboardRegionValue() const { return m_primitiveUnitType != CSS_DASHBOARD_REGION ? 0 : m_value.region; } + + CSSWrapShape* getShapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? 0 : m_value.shape; } + + int getIdent() const { return m_primitiveUnitType == CSS_IDENT ? m_value.ident : 0; } + + template<typename T> inline operator T() const; // Defined in CSSPrimitiveValueMappings.h + + String customCssText() const; + + bool isQuirkValue() { return m_isQuirkValue; } + + void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +protected: + CSSPrimitiveValue(ClassType, int ident); + CSSPrimitiveValue(ClassType, const String&, UnitTypes); + +private: + CSSPrimitiveValue(); + // FIXME: int vs. unsigned overloading is too subtle to distinguish the color and identifier cases. + CSSPrimitiveValue(int ident); + CSSPrimitiveValue(unsigned color); // RGB value + CSSPrimitiveValue(const Length&); + CSSPrimitiveValue(const String&, UnitTypes); + CSSPrimitiveValue(double, UnitTypes); + + template<typename T> CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h + template<typename T> CSSPrimitiveValue(T* val) + : CSSValue(PrimitiveClass) + { + init(PassRefPtr<T>(val)); + } + + template<typename T> CSSPrimitiveValue(PassRefPtr<T> val) + : CSSValue(PrimitiveClass) + { + 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<Quad>); + void init(PassRefPtr<DashboardRegion>); // FIXME: Dashboard region should not be a primitive value. + void init(PassRefPtr<CSSWrapShape>); + + bool getDoubleValueInternal(UnitTypes targetUnitType, double* result) const; + + double computeLengthDouble(RenderStyle* currentStyle, RenderStyle* rootStyle, double multiplier, bool computingFontSize); + + union { + int ident; + double num; + StringImpl* string; + Counter* counter; + Rect* rect; + Quad* quad; + unsigned rgbcolor; + Pair* pair; + DashboardRegion* region; + CSSWrapShape* shape; + } 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 000000000..04f17048c --- /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 [Optional=CallWithDefaultValue] unsigned short unitType, + in [Optional=CallWithDefaultValue] float floatValue) + raises(DOMException); + float getFloatValue(in [Optional=CallWithDefaultValue] unsigned short unitType) + raises(DOMException); + [OldStyleObjC] void setStringValue(in [Optional=CallWithDefaultValue] unsigned short stringType, + in [Optional=CallWithDefaultValue] 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 000000000..f8444ca6a --- /dev/null +++ b/Source/WebCore/css/CSSPrimitiveValueMappings.h @@ -0,0 +1,3926 @@ +/* + * Copyright (C) 2007 Alexey Proskuryakov <ap@nypop.com>. + * Copyright (C) 2008, 2009, 2010, 2011 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 "FontDescription.h" +#include "FontSmoothingMode.h" +#include "GraphicsTypes.h" +#include "Path.h" +#include "RenderStyleConstants.h" +#include "SVGRenderStyleDefs.h" +#include "TextDirection.h" +#include "TextOrientation.h" +#include "TextRenderingMode.h" +#include "ThemeTypes.h" +#include "UnicodeBidi.h" + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterOperation.h" +#endif + +#include <wtf/MathExtras.h> + +namespace WebCore { + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(short i) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_NUMBER; + m_value.num = static_cast<double>(i); +} + +template<> inline CSSPrimitiveValue::operator short() const +{ + if (m_primitiveUnitType == CSS_NUMBER) + return clampTo<short>(m_value.num); + + ASSERT_NOT_REACHED(); + return 0; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(unsigned short i) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_NUMBER; + m_value.num = static_cast<double>(i); +} + +template<> inline CSSPrimitiveValue::operator unsigned short() const +{ + if (m_primitiveUnitType == CSS_NUMBER) + return clampTo<unsigned short>(m_value.num); + + ASSERT_NOT_REACHED(); + return 0; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(int i) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_NUMBER; + m_value.num = static_cast<double>(i); +} + +template<> inline CSSPrimitiveValue::operator int() const +{ + if (m_primitiveUnitType == CSS_NUMBER) + return clampTo<int>(m_value.num); + + ASSERT_NOT_REACHED(); + return 0; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(unsigned i) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_NUMBER; + m_value.num = static_cast<double>(i); +} + +template<> inline CSSPrimitiveValue::operator unsigned() const +{ + if (m_primitiveUnitType == CSS_NUMBER) + return clampTo<unsigned>(m_value.num); + + ASSERT_NOT_REACHED(); + return 0; +} + + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(float i) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_NUMBER; + m_value.num = static_cast<double>(i); +} + +template<> inline CSSPrimitiveValue::operator float() const +{ + if (m_primitiveUnitType == CSS_NUMBER) + return clampTo<float>(m_value.num); + + ASSERT_NOT_REACHED(); + return 0.0f; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ColumnSpan columnSpan) + : CSSValue(PrimitiveClass) +{ + switch (columnSpan) { + case ColumnSpanAll: + m_primitiveUnitType = CSS_IDENT; + m_value.ident = CSSValueAll; + break; + case ColumnSpanOne: + m_primitiveUnitType = CSS_NUMBER; + m_value.num = 1; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ColumnSpan() const +{ + if (m_primitiveUnitType == CSS_IDENT && m_value.ident == CSSValueAll) + return ColumnSpanAll; + if (m_primitiveUnitType == CSS_NUMBER && m_value.num == 1) + return ColumnSpanOne; + ASSERT_NOT_REACHED(); + return ColumnSpanOne; +} + + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(PrintColorAdjust value) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (value) { + case PrintColorAdjustExact: + m_value.ident = CSSValueExact; + break; + case PrintColorAdjustEconomy: + m_value.ident = CSSValueEconomy; + break; + } +} + +template<> inline CSSPrimitiveValue::operator PrintColorAdjust() const +{ + switch (m_value.ident) { + case CSSValueEconomy: + return PrintColorAdjustEconomy; + case CSSValueExact: + return PrintColorAdjustExact; + default: + ASSERT_NOT_REACHED(); + return PrintColorAdjustEconomy; + } +} + + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBorderStyle e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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 +{ + if (m_value.ident == CSSValueAuto) // Valid for CSS outline-style + return DOTTED; + return (EBorderStyle)(m_value.ident - CSSValueNone); +} + +template<> inline CSSPrimitiveValue::operator OutlineIsAuto() const +{ + if (m_value.ident == CSSValueAuto) + return AUTO_ON; + return AUTO_OFF; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CompositeOperator e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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 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 CSSValuePlusLighter: + return CompositePlusLighter; + default: + ASSERT_NOT_REACHED(); + return CompositeClear; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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 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(EBackfaceVisibility e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case BackfaceVisibilityVisible: + m_value.ident = CSSValueVisible; + break; + case BackfaceVisibilityHidden: + m_value.ident = CSSValueHidden; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBackfaceVisibility() const +{ + switch (m_value.ident) { + case CSSValueVisible: + return BackfaceVisibilityVisible; + case CSSValueHidden: + return BackfaceVisibilityHidden; + default: + ASSERT_NOT_REACHED(); + return BackfaceVisibilityHidden; + } +} + + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillAttachment e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(EBoxPack e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case Start: + m_value.ident = CSSValueStart; + break; + case Center: + m_value.ident = CSSValueCenter; + break; + case End: + m_value.ident = CSSValueEnd; + break; + case Justify: + m_value.ident = CSSValueJustify; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxPack() const +{ + switch (m_value.ident) { + case CSSValueStart: + return Start; + case CSSValueEnd: + return End; + case CSSValueCenter: + return Center; + case CSSValueJustify: + return Justify; + default: + ASSERT_NOT_REACHED(); + return Justify; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxAlignment e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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; + } +} + +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; + default: + ASSERT_NOT_REACHED(); + return BSTRETCH; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxSizing e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case BORDER_BOX: + m_value.ident = CSSValueBorderBox; + break; + case CONTENT_BOX: + m_value.ident = CSSValueContentBox; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBoxSizing() const +{ + switch (m_value.ident) { + case CSSValueBorderBox: + return BORDER_BOX; + case CSSValueContentBox: + return CONTENT_BOX; + default: + ASSERT_NOT_REACHED(); + return BORDER_BOX; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxDirection e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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; + case BOX: + m_value.ident = CSSValueWebkitBox; + break; + case INLINE_BOX: + m_value.ident = CSSValueWebkitInlineBox; + break; + case FLEXBOX: + m_value.ident = CSSValueWebkitFlexbox; + break; + case INLINE_FLEXBOX: + m_value.ident = CSSValueWebkitInlineFlexbox; + break; +#if ENABLE(CSS_GRID_LAYOUT) + case GRID: + m_value.ident = CSSValueWebkitGrid; + break; + case INLINE_GRID: + m_value.ident = CSSValueWebkitInlineGrid; + break; +#endif + case NONE: + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EDisplay() const +{ + if (m_value.ident == CSSValueNone) + return NONE; + + EDisplay display = static_cast<EDisplay>(m_value.ident - CSSValueInline); + ASSERT(display >= INLINE && display <= NONE); + return display; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EEmptyCell e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(EFlexAlign e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case AlignStart: + m_value.ident = CSSValueStart; + break; + case AlignEnd: + m_value.ident = CSSValueEnd; + break; + case AlignCenter: + m_value.ident = CSSValueCenter; + break; + case AlignStretch: + m_value.ident = CSSValueStretch; + break; + case AlignBaseline: + m_value.ident = CSSValueBaseline; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFlexAlign() const +{ + switch (m_value.ident) { + case CSSValueStart: + return AlignStart; + case CSSValueEnd: + return AlignEnd; + case CSSValueCenter: + return AlignCenter; + case CSSValueStretch: + return AlignStretch; + case CSSValueBaseline: + return AlignBaseline; + default: + ASSERT_NOT_REACHED(); + return AlignStart; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexPack e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case PackStart: + m_value.ident = CSSValueStart; + break; + case PackEnd: + m_value.ident = CSSValueEnd; + break; + case PackCenter: + m_value.ident = CSSValueCenter; + break; + case PackJustify: + m_value.ident = CSSValueJustify; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFlexPack() const +{ + switch (m_value.ident) { + case CSSValueStart: + return PackStart; + case CSSValueEnd: + return PackEnd; + case CSSValueCenter: + return PackCenter; + case CSSValueJustify: + return PackJustify; + default: + ASSERT_NOT_REACHED(); + return PackStart; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexDirection e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case FlowRow: + m_value.ident = CSSValueRow; + break; + case FlowRowReverse: + m_value.ident = CSSValueRowReverse; + break; + case FlowColumn: + m_value.ident = CSSValueColumn; + break; + case FlowColumnReverse: + m_value.ident = CSSValueColumnReverse; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFlexDirection() const +{ + switch (m_value.ident) { + case CSSValueRow: + return FlowRow; + case CSSValueRowReverse: + return FlowRowReverse; + case CSSValueColumn: + return FlowColumn; + case CSSValueColumnReverse: + return FlowColumnReverse; + default: + ASSERT_NOT_REACHED(); + return FlowRow; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexWrap e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case FlexNoWrap: + m_value.ident = CSSValueNowrap; + break; + case FlexWrap: + m_value.ident = CSSValueWrap; + break; + case FlexWrapReverse: + m_value.ident = CSSValueWrapReverse; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFlexWrap() const +{ + switch (m_value.ident) { + case CSSValueNowrap: + return FlexNoWrap; + case CSSValueWrap: + return FlexWrap; + case CSSValueWrapReverse: + return FlexWrapReverse; + default: + ASSERT_NOT_REACHED(); + return FlexNoWrap; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFloat e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case NoFloat: + m_value.ident = CSSValueNone; + break; + case LeftFloat: + m_value.ident = CSSValueLeft; + break; + case RightFloat: + m_value.ident = CSSValueRight; + break; + case PositionedFloat: + m_value.ident = CSSValueWebkitPositioned; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EFloat() const +{ + switch (m_value.ident) { + case CSSValueLeft: + return LeftFloat; + case CSSValueRight: + return RightFloat; + case CSSValueNone: + case CSSValueCenter: // Non-standard CSS value + return NoFloat; + case CSSValueWebkitPositioned: + return PositionedFloat; + default: + ASSERT_NOT_REACHED(); + return NoFloat; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EKHTMLLineBreak e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(RegionOverflow e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case AutoRegionOverflow: + m_value.ident = CSSValueAuto; + break; + case BreakRegionOverflow: + m_value.ident = CSSValueBreak; + break; + } +} + +template<> inline CSSPrimitiveValue::operator RegionOverflow() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return AutoRegionOverflow; + case CSSValueBreak: + return BreakRegionOverflow; + default: + ASSERT_NOT_REACHED(); + return AutoRegionOverflow; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMarqueeDirection e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case TAAUTO: + m_value.ident = CSSValueWebkitAuto; + break; + case TASTART: + m_value.ident = CSSValueStart; + break; + case TAEND: + m_value.ident = CSSValueEnd; + 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: + return TASTART; + case CSSValueEnd: + return TAEND; + default: + return static_cast<ETextAlign>(m_value.ident - CSSValueWebkitAuto); + } +} + +template<> inline CSSPrimitiveValue::operator ETextDecoration() const +{ + switch (m_value.ident) { + case CSSValueNone: + return TDNONE; + case CSSValueUnderline: + return UNDERLINE; + case CSSValueOverline: + return OVERLINE; + case CSSValueLineThrough: + return LINE_THROUGH; + case CSSValueBlink: + return BLINK; + default: + ASSERT_NOT_REACHED(); + return TDNONE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextSecurity e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case UBNormal: + m_value.ident = CSSValueNormal; + break; + case Embed: + m_value.ident = CSSValueEmbed; + break; + case Override: + m_value.ident = CSSValueBidiOverride; + break; + case Isolate: + m_value.ident = CSSValueWebkitIsolate; + break; + case Plaintext: + m_value.ident = CSSValueWebkitPlaintext; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EUnicodeBidi() const +{ + switch (m_value.ident) { + case CSSValueNormal: + return UBNormal; + case CSSValueEmbed: + return Embed; + case CSSValueBidiOverride: + return Override; + case CSSValueWebkitIsolate: + return Isolate; + case CSSValueWebkitPlaintext: + return Plaintext; + default: + ASSERT_NOT_REACHED(); + return UBNormal; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserDrag e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(EVerticalAlign a) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (a) { + case TOP: + m_value.ident = CSSValueTop; + break; + case BOTTOM: + m_value.ident = CSSValueBottom; + break; + case MIDDLE: + m_value.ident = CSSValueMiddle; + break; + case BASELINE: + m_value.ident = CSSValueBaseline; + break; + case TEXT_BOTTOM: + m_value.ident = CSSValueTextBottom; + break; + case TEXT_TOP: + m_value.ident = CSSValueTextTop; + break; + case SUB: + m_value.ident = CSSValueSub; + break; + case SUPER: + m_value.ident = CSSValueSuper; + break; + case BASELINE_MIDDLE: + m_value.ident = CSSValueWebkitBaselineMiddle; + break; + case LENGTH: + m_value.ident = CSSValueInvalid; + } +} + +template<> inline CSSPrimitiveValue::operator EVerticalAlign() const +{ + switch (m_value.ident) { + case CSSValueTop: + return TOP; + case CSSValueBottom: + return BOTTOM; + case CSSValueMiddle: + return MIDDLE; + case CSSValueBaseline: + return BASELINE; + case CSSValueTextBottom: + return TEXT_BOTTOM; + case CSSValueTextTop: + return TEXT_TOP; + case CSSValueSub: + return SUB; + case CSSValueSuper: + return SUPER; + case CSSValueWebkitBaselineMiddle: + return BASELINE_MIDDLE; + default: + ASSERT_NOT_REACHED(); + return TOP; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EVisibility e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(TextOverflow overflow) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (overflow) { + case TextOverflowClip: + m_value.ident = CSSValueClip; + break; + case TextOverflowEllipsis: + m_value.ident = CSSValueEllipsis; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextOverflow() const +{ + switch (m_value.ident) { + case CSSValueClip: + return TextOverflowClip; + case CSSValueEllipsis: + return TextOverflowEllipsis; + default: + ASSERT_NOT_REACHED(); + return TextOverflowClip; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisFill fill) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(TextOrientation e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case TextOrientationVerticalRight: + m_value.ident = CSSValueVerticalRight; + break; + case TextOrientationUpright: + m_value.ident = CSSValueUpright; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TextOrientation() const +{ + switch (m_value.ident) { + case CSSValueVerticalRight: + return TextOrientationVerticalRight; + case CSSValueUpright: + return TextOrientationUpright; + default: + ASSERT_NOT_REACHED(); + return TextOrientationVerticalRight; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPointerEvents e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(FontWeight weight) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (weight) { + case FontWeight900: + m_value.ident = CSSValue900; + return; + case FontWeight800: + m_value.ident = CSSValue800; + return; + case FontWeight700: + m_value.ident = CSSValue700; + return; + case FontWeight600: + m_value.ident = CSSValue600; + return; + case FontWeight500: + m_value.ident = CSSValue500; + return; + case FontWeight400: + m_value.ident = CSSValue400; + return; + case FontWeight300: + m_value.ident = CSSValue300; + return; + case FontWeight200: + m_value.ident = CSSValue200; + return; + case FontWeight100: + m_value.ident = CSSValue100; + return; + } + + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueNormal; +} + +template<> inline CSSPrimitiveValue::operator FontWeight() const +{ + switch (m_value.ident) { + case CSSValueBold: + return FontWeightBold; + case CSSValueNormal: + return FontWeightNormal; + case CSSValue900: + return FontWeight900; + case CSSValue800: + return FontWeight800; + case CSSValue700: + return FontWeight700; + case CSSValue600: + return FontWeight600; + case CSSValue500: + return FontWeight500; + case CSSValue400: + return FontWeight400; + case CSSValue300: + return FontWeight300; + case CSSValue200: + return FontWeight200; + case CSSValue100: + return FontWeight100; + } + + ASSERT_NOT_REACHED(); + return FontWeightNormal; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontItalic italic) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (italic) { + case FontItalicOff: + m_value.ident = CSSValueNormal; + return; + case FontItalicOn: + m_value.ident = CSSValueItalic; + return; + } + + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueNormal; +} + +template<> inline CSSPrimitiveValue::operator FontItalic() const +{ + switch (m_value.ident) { + case CSSValueOblique: + // FIXME: oblique is the same as italic for the moment... + case CSSValueItalic: + return FontItalicOn; + case CSSValueNormal: + return FontItalicOff; + } + ASSERT_NOT_REACHED(); + return FontItalicOff; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontSmallCaps smallCaps) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (smallCaps) { + case FontSmallCapsOff: + m_value.ident = CSSValueNormal; + return; + case FontSmallCapsOn: + m_value.ident = CSSValueSmallCaps; + return; + } + + ASSERT_NOT_REACHED(); + m_value.ident = CSSValueNormal; +} + +template<> inline CSSPrimitiveValue::operator FontSmallCaps() const +{ + switch (m_value.ident) { + case CSSValueSmallCaps: + return FontSmallCapsOn; + case CSSValueNormal: + return FontSmallCapsOff; + } + ASSERT_NOT_REACHED(); + return FontSmallCapsOff; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextRenderingMode e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(LineGridSnap gridSnap) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (gridSnap) { + case LineGridSnapNone: + m_value.ident = CSSValueNone; + break; + case LineGridSnapBaseline: + m_value.ident = CSSValueBaseline; + break; + case LineGridSnapBounds: + m_value.ident = CSSValueBounds; + break; + } +} + +template<> inline CSSPrimitiveValue::operator LineGridSnap() const +{ + switch (m_value.ident) { + case CSSValueNone: + return LineGridSnapNone; + case CSSValueBaseline: + return LineGridSnapBaseline; + case CSSValueBounds: + return LineGridSnapBounds; + default: + ASSERT_NOT_REACHED(); + return LineGridSnapNone; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ESpeak e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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 Order() const +{ + switch (m_value.ident) { + case CSSValueLogical: + return LogicalOrder; + case CSSValueVisual: + return VisualOrder; + default: + ASSERT_NOT_REACHED(); + return LogicalOrder; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Order e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case LogicalOrder: + m_value.ident = CSSValueLogical; + break; + case VisualOrder: + m_value.ident = CSSValueVisual; + 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(CSS_SHADERS) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CustomFilterOperation::MeshBoxType meshBoxType) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (meshBoxType) { + case CustomFilterOperation::FILTER_BOX: + m_value.ident = CSSValueFilterBox; + break; + case CustomFilterOperation::BORDER_BOX: + m_value.ident = CSSValueBorderBox; + break; + case CustomFilterOperation::PADDING_BOX: + m_value.ident = CSSValuePaddingBox; + break; + case CustomFilterOperation::CONTENT_BOX: + m_value.ident = CSSValueContentBox; + break; + } +} + +template<> inline CSSPrimitiveValue::operator CustomFilterOperation::MeshBoxType() const +{ + switch (m_value.ident) { + case CSSValueFilterBox: + return CustomFilterOperation::FILTER_BOX; + case CSSValueBorderBox: + return CustomFilterOperation::BORDER_BOX; + case CSSValuePaddingBox: + return CustomFilterOperation::PADDING_BOX; + case CSSValueContentBox: + return CustomFilterOperation::CONTENT_BOX; + default: + ASSERT_NOT_REACHED(); + return CustomFilterOperation::FILTER_BOX; + } +} +#endif // ENABLE(CSS_SHADERS) + +#if ENABLE(SVG) + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineCap e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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; + } +} + +#endif + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBorderCollapse e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case BSEPARATE: + m_value.ident = CSSValueSeparate; + break; + case BCOLLAPSE: + m_value.ident = CSSValueCollapse; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBorderCollapse() const +{ + switch (m_value.ident) { + case CSSValueSeparate: + return BSEPARATE; + case CSSValueCollapse: + return BCOLLAPSE; + default: + ASSERT_NOT_REACHED(); + return BSEPARATE; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBorderFit e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case BorderFitBorder: + m_value.ident = CSSValueBorder; + break; + case BorderFitLines: + m_value.ident = CSSValueLines; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EBorderFit() const +{ + switch (m_value.ident) { + case CSSValueBorder: + return BorderFitBorder; + case CSSValueLines: + return BorderFitLines; + default: + ASSERT_NOT_REACHED(); + return BorderFitLines; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EImageRendering e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case ImageRenderingAuto: + m_value.ident = CSSValueAuto; + break; + case ImageRenderingOptimizeSpeed: + m_value.ident = CSSValueOptimizespeed; + break; + case ImageRenderingOptimizeQuality: + m_value.ident = CSSValueOptimizequality; + break; + case ImageRenderingOptimizeContrast: + m_value.ident = CSSValueWebkitOptimizeContrast; + break; + } +} + +template<> inline CSSPrimitiveValue::operator EImageRendering() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return ImageRenderingAuto; + case CSSValueOptimizespeed: + return ImageRenderingOptimizeSpeed; + case CSSValueOptimizequality: + return ImageRenderingOptimizeQuality; + case CSSValueWebkitOptimizeContrast: + return ImageRenderingOptimizeContrast; + default: + ASSERT_NOT_REACHED(); + return ImageRenderingAuto; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETransformStyle3D e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case TransformStyle3DFlat: + m_value.ident = CSSValueFlat; + break; + case TransformStyle3DPreserve3D: + m_value.ident = CSSValuePreserve3d; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ETransformStyle3D() const +{ + switch (m_value.ident) { + case CSSValueFlat: + return TransformStyle3DFlat; + case CSSValuePreserve3d: + return TransformStyle3DPreserve3D; + default: + ASSERT_NOT_REACHED(); + return TransformStyle3DFlat; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ColumnAxis e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case HorizontalColumnAxis: + m_value.ident = CSSValueHorizontal; + break; + case VerticalColumnAxis: + m_value.ident = CSSValueVertical; + break; + case AutoColumnAxis: + m_value.ident = CSSValueAuto; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ColumnAxis() const +{ + switch (m_value.ident) { + case CSSValueHorizontal: + return HorizontalColumnAxis; + case CSSValueVertical: + return VerticalColumnAxis; + case CSSValueAuto: + return AutoColumnAxis; + default: + ASSERT_NOT_REACHED(); + return AutoColumnAxis; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WrapFlow wrapFlow) +: CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (wrapFlow) { + case WrapFlowAuto: + m_value.ident = CSSValueAuto; + break; + case WrapFlowBoth: + m_value.ident = CSSValueBoth; + break; + case WrapFlowLeft: + m_value.ident = CSSValueLeft; + break; + case WrapFlowRight: + m_value.ident = CSSValueRight; + break; + case WrapFlowMaximum: + m_value.ident = CSSValueMaximum; + break; + case WrapFlowClear: + m_value.ident = CSSValueClear; + break; + } +} + +template<> inline CSSPrimitiveValue::operator WrapFlow() const +{ + switch (m_value.ident) { + case CSSValueAuto: + return WrapFlowAuto; + case CSSValueBoth: + return WrapFlowBoth; + case CSSValueLeft: + return WrapFlowLeft; + case CSSValueRight: + return WrapFlowRight; + case CSSValueMaximum: + return WrapFlowMaximum; + case CSSValueClear: + return WrapFlowClear; + default: + ASSERT_NOT_REACHED(); + return WrapFlowAuto; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WrapThrough wrapThrough) +: CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (wrapThrough) { + case WrapThroughWrap: + m_value.ident = CSSValueWrap; + break; + case WrapThroughNone: + m_value.ident = CSSValueNone; + break; + } +} + +template<> inline CSSPrimitiveValue::operator WrapThrough() const +{ + switch (m_value.ident) { + case CSSValueWrap: + return WrapThroughWrap; + case CSSValueNone: + return WrapThroughNone; + default: + ASSERT_NOT_REACHED(); + return WrapThroughWrap; + } +} + +#if ENABLE(SVG) + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorInterpolation e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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(EShapeRendering e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + switch (e) { + case SR_AUTO: + m_value.ident = CSSValueAuto; + break; + case SR_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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_IDENT; + 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 // ENABLE(SVG) + +} + +#endif diff --git a/Source/WebCore/css/CSSProperty.cpp b/Source/WebCore/css/CSSProperty.cpp new file mode 100644 index 000000000..3bbf03227 --- /dev/null +++ b/Source/WebCore/css/CSSProperty.cpp @@ -0,0 +1,674 @@ +/** + * (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" : "") + "; "; +} + +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; + } +} + +bool CSSProperty::isInheritedProperty(unsigned propertyID) +{ + switch (static_cast<CSSPropertyID>(propertyID)) { + case CSSPropertyBorderCollapse: + case CSSPropertyBorderSpacing: + case CSSPropertyCaptionSide: + case CSSPropertyColor: + case CSSPropertyCursor: + case CSSPropertyDirection: + case CSSPropertyEmptyCells: + case CSSPropertyFont: + case CSSPropertyFontFamily: + case CSSPropertyFontSize: + case CSSPropertyFontStyle: + case CSSPropertyFontVariant: + case CSSPropertyFontWeight: + case CSSPropertyImageRendering: + case CSSPropertyLetterSpacing: + case CSSPropertyLineHeight: + case CSSPropertyListStyle: + case CSSPropertyListStyleImage: + case CSSPropertyListStyleType: + case CSSPropertyListStylePosition: + case CSSPropertyOrphans: + case CSSPropertyPointerEvents: + case CSSPropertyQuotes: + case CSSPropertyResize: + case CSSPropertySpeak: + case CSSPropertyTextAlign: + case CSSPropertyTextDecoration: + case CSSPropertyTextIndent: + case CSSPropertyTextRendering: + case CSSPropertyTextShadow: + case CSSPropertyTextTransform: + case CSSPropertyVisibility: + case CSSPropertyWebkitAspectRatio: + case CSSPropertyWebkitBorderHorizontalSpacing: + case CSSPropertyWebkitBorderVerticalSpacing: + case CSSPropertyWebkitBoxDirection: + case CSSPropertyWebkitColorCorrection: + case CSSPropertyWebkitFontFeatureSettings: + case CSSPropertyWebkitFontSmoothing: + case CSSPropertyWebkitLocale: + case CSSPropertyWebkitHighlight: + case CSSPropertyWebkitHyphenateCharacter: + case CSSPropertyWebkitHyphenateLimitAfter: + case CSSPropertyWebkitHyphenateLimitBefore: + case CSSPropertyWebkitHyphenateLimitLines: + case CSSPropertyWebkitHyphens: + case CSSPropertyWebkitLineBoxContain: + case CSSPropertyWebkitLineBreak: + case CSSPropertyWebkitLineGrid: + case CSSPropertyWebkitLineGridSnap: + case CSSPropertyWebkitNbspMode: + case CSSPropertyWebkitPrintColorAdjust: + case CSSPropertyWebkitRtlOrdering: + case CSSPropertyWebkitTextCombine: + case CSSPropertyWebkitTextDecorationsInEffect: + case CSSPropertyWebkitTextEmphasis: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextEmphasisPosition: + case CSSPropertyWebkitTextEmphasisStyle: + case CSSPropertyWebkitTextFillColor: + case CSSPropertyWebkitTextOrientation: + case CSSPropertyWebkitTextSecurity: + case CSSPropertyWebkitTextSizeAdjust: + case CSSPropertyWebkitTextStroke: + case CSSPropertyWebkitTextStrokeColor: + case CSSPropertyWebkitTextStrokeWidth: + case CSSPropertyWebkitUserModify: + case CSSPropertyWebkitUserSelect: + case CSSPropertyWebkitWritingMode: + case CSSPropertyWhiteSpace: + case CSSPropertyWidows: + case CSSPropertyWordBreak: + case CSSPropertyWordSpacing: + case CSSPropertyWordWrap: +#if ENABLE(SVG) + case CSSPropertyClipRule: + case CSSPropertyColorInterpolation: + case CSSPropertyColorInterpolationFilters: + case CSSPropertyColorRendering: + case CSSPropertyFill: + case CSSPropertyFillOpacity: + case CSSPropertyFillRule: + case CSSPropertyGlyphOrientationHorizontal: + case CSSPropertyGlyphOrientationVertical: + case CSSPropertyKerning: + case CSSPropertyMarker: + case CSSPropertyMarkerEnd: + case CSSPropertyMarkerMid: + case CSSPropertyMarkerStart: + case CSSPropertyStroke: + case CSSPropertyStrokeDasharray: + case CSSPropertyStrokeDashoffset: + case CSSPropertyStrokeLinecap: + case CSSPropertyStrokeLinejoin: + case CSSPropertyStrokeMiterlimit: + case CSSPropertyStrokeOpacity: + case CSSPropertyStrokeWidth: + case CSSPropertyShapeRendering: + case CSSPropertyTextAnchor: + case CSSPropertyWritingMode: +#endif +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyWebkitTapHighlightColor: +#endif + return true; + case CSSPropertyDisplay: + case CSSPropertyZoom: + case CSSPropertyBackground: + case CSSPropertyBackgroundAttachment: + case CSSPropertyBackgroundClip: + case CSSPropertyBackgroundColor: + case CSSPropertyBackgroundImage: + case CSSPropertyBackgroundOrigin: + case CSSPropertyBackgroundPosition: + case CSSPropertyBackgroundPositionX: + case CSSPropertyBackgroundPositionY: + case CSSPropertyBackgroundRepeat: + case CSSPropertyBackgroundRepeatX: + case CSSPropertyBackgroundRepeatY: + case CSSPropertyBackgroundSize: + case CSSPropertyBorder: + case CSSPropertyBorderBottom: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderBottomLeftRadius: + case CSSPropertyBorderBottomRightRadius: + case CSSPropertyBorderBottomStyle: + case CSSPropertyBorderBottomWidth: + case CSSPropertyBorderColor: + case CSSPropertyBorderImage: + case CSSPropertyBorderImageOutset: + case CSSPropertyBorderImageRepeat: + case CSSPropertyBorderImageSlice: + case CSSPropertyBorderImageSource: + case CSSPropertyBorderImageWidth: + case CSSPropertyBorderLeft: + case CSSPropertyBorderLeftColor: + case CSSPropertyBorderLeftStyle: + case CSSPropertyBorderLeftWidth: + case CSSPropertyBorderRadius: + case CSSPropertyBorderRight: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderRightStyle: + case CSSPropertyBorderRightWidth: + case CSSPropertyBorderStyle: + case CSSPropertyBorderTop: + case CSSPropertyBorderTopColor: + case CSSPropertyBorderTopLeftRadius: + case CSSPropertyBorderTopRightRadius: + case CSSPropertyBorderTopStyle: + case CSSPropertyBorderTopWidth: + case CSSPropertyBorderWidth: + case CSSPropertyBottom: + case CSSPropertyBoxShadow: + case CSSPropertyBoxSizing: + case CSSPropertyClear: + case CSSPropertyClip: + case CSSPropertyContent: + case CSSPropertyCounterIncrement: + case CSSPropertyCounterReset: + case CSSPropertyFloat: + case CSSPropertyFontStretch: + case CSSPropertyHeight: + case CSSPropertyLeft: + case CSSPropertyMargin: + case CSSPropertyMarginBottom: + case CSSPropertyMarginLeft: + case CSSPropertyMarginRight: + case CSSPropertyMarginTop: + case CSSPropertyMaxHeight: + case CSSPropertyMaxWidth: + case CSSPropertyMinHeight: + case CSSPropertyMinWidth: + case CSSPropertyOpacity: + case CSSPropertyOutline: + case CSSPropertyOutlineColor: + case CSSPropertyOutlineOffset: + case CSSPropertyOutlineStyle: + case CSSPropertyOutlineWidth: + case CSSPropertyOverflow: + case CSSPropertyOverflowX: + case CSSPropertyOverflowY: + case CSSPropertyPadding: + case CSSPropertyPaddingBottom: + case CSSPropertyPaddingLeft: + case CSSPropertyPaddingRight: + case CSSPropertyPaddingTop: + case CSSPropertyPage: + case CSSPropertyPageBreakAfter: + case CSSPropertyPageBreakBefore: + case CSSPropertyPageBreakInside: + case CSSPropertyPosition: + case CSSPropertyRight: + case CSSPropertySize: + case CSSPropertySrc: + case CSSPropertyTableLayout: + case CSSPropertyTextLineThrough: + case CSSPropertyTextLineThroughColor: + case CSSPropertyTextLineThroughMode: + case CSSPropertyTextLineThroughStyle: + case CSSPropertyTextLineThroughWidth: + case CSSPropertyTextOverflow: + case CSSPropertyTextOverline: + case CSSPropertyTextOverlineColor: + case CSSPropertyTextOverlineMode: + case CSSPropertyTextOverlineStyle: + case CSSPropertyTextOverlineWidth: + case CSSPropertyTextUnderline: + case CSSPropertyTextUnderlineColor: + case CSSPropertyTextUnderlineMode: + case CSSPropertyTextUnderlineStyle: + case CSSPropertyTextUnderlineWidth: + case CSSPropertyTop: + case CSSPropertyUnicodeBidi: + case CSSPropertyUnicodeRange: + case CSSPropertyVerticalAlign: + case CSSPropertyWidth: + case CSSPropertyZIndex: + case CSSPropertyWebkitAnimation: + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitAnimationDirection: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitAnimationFillMode: + case CSSPropertyWebkitAnimationIterationCount: + case CSSPropertyWebkitAnimationName: + case CSSPropertyWebkitAnimationPlayState: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitAppearance: + case CSSPropertyWebkitBackfaceVisibility: + case CSSPropertyWebkitBackgroundClip: + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyWebkitBackgroundOrigin: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitBorderAfter: + case CSSPropertyWebkitBorderAfterColor: + case CSSPropertyWebkitBorderAfterStyle: + case CSSPropertyWebkitBorderAfterWidth: + case CSSPropertyWebkitBorderBefore: + case CSSPropertyWebkitBorderBeforeColor: + case CSSPropertyWebkitBorderBeforeStyle: + case CSSPropertyWebkitBorderBeforeWidth: + case CSSPropertyWebkitBorderEnd: + case CSSPropertyWebkitBorderEndColor: + case CSSPropertyWebkitBorderEndStyle: + case CSSPropertyWebkitBorderEndWidth: + case CSSPropertyWebkitBorderFit: + case CSSPropertyWebkitBorderImage: + case CSSPropertyWebkitBorderRadius: + case CSSPropertyWebkitBorderStart: + case CSSPropertyWebkitBorderStartColor: + case CSSPropertyWebkitBorderStartStyle: + case CSSPropertyWebkitBorderStartWidth: + case CSSPropertyWebkitBoxAlign: + case CSSPropertyWebkitBoxFlex: + case CSSPropertyWebkitBoxFlexGroup: + case CSSPropertyWebkitBoxLines: + case CSSPropertyWebkitBoxOrdinalGroup: + case CSSPropertyWebkitBoxOrient: + case CSSPropertyWebkitBoxPack: + case CSSPropertyWebkitBoxReflect: + case CSSPropertyWebkitBoxShadow: + case CSSPropertyWebkitColumnAxis: + case CSSPropertyWebkitColumnBreakAfter: + case CSSPropertyWebkitColumnBreakBefore: + case CSSPropertyWebkitColumnBreakInside: + case CSSPropertyWebkitColumnCount: + case CSSPropertyWebkitColumnGap: + case CSSPropertyWebkitColumnRule: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitColumnRuleStyle: + case CSSPropertyWebkitColumnRuleWidth: + case CSSPropertyWebkitColumnSpan: + case CSSPropertyWebkitColumnWidth: + case CSSPropertyWebkitColumns: +#if ENABLE(CSS_FILTERS) + case CSSPropertyWebkitFilter: +#endif + case CSSPropertyWebkitFlexOrder: + case CSSPropertyWebkitFlexPack: + case CSSPropertyWebkitFlexAlign: + case CSSPropertyWebkitFlexDirection: + case CSSPropertyWebkitFlexFlow: + case CSSPropertyWebkitFlexWrap: + case CSSPropertyWebkitFontSizeDelta: +#if ENABLE(CSS_GRID_LAYOUT) + case CSSPropertyWebkitGridColumns: + case CSSPropertyWebkitGridRows: +#endif + case CSSPropertyWebkitLineClamp: + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + case CSSPropertyWebkitMarginAfterCollapse: + case CSSPropertyWebkitMarginBeforeCollapse: + case CSSPropertyWebkitMarginBottomCollapse: + case CSSPropertyWebkitMarginTopCollapse: + case CSSPropertyWebkitMarginCollapse: + case CSSPropertyWebkitMarginAfter: + case CSSPropertyWebkitMarginBefore: + case CSSPropertyWebkitMarginEnd: + case CSSPropertyWebkitMarginStart: + case CSSPropertyWebkitMarquee: + case CSSPropertyWebkitMarqueeDirection: + case CSSPropertyWebkitMarqueeIncrement: + case CSSPropertyWebkitMarqueeRepetition: + case CSSPropertyWebkitMarqueeSpeed: + case CSSPropertyWebkitMarqueeStyle: + case CSSPropertyWebkitMask: + case CSSPropertyWebkitMaskAttachment: + case CSSPropertyWebkitMaskBoxImage: + case CSSPropertyWebkitMaskBoxImageOutset: + case CSSPropertyWebkitMaskBoxImageRepeat: + case CSSPropertyWebkitMaskBoxImageSlice: + case CSSPropertyWebkitMaskBoxImageSource: + case CSSPropertyWebkitMaskBoxImageWidth: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskComposite: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskOrigin: + case CSSPropertyWebkitMaskPosition: + case CSSPropertyWebkitMaskPositionX: + case CSSPropertyWebkitMaskPositionY: + case CSSPropertyWebkitMaskRepeat: + case CSSPropertyWebkitMaskRepeatX: + case CSSPropertyWebkitMaskRepeatY: + case CSSPropertyWebkitMaskSize: + case CSSPropertyWebkitMatchNearestMailBlockquoteColor: + case CSSPropertyWebkitMaxLogicalWidth: + case CSSPropertyWebkitMaxLogicalHeight: + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + case CSSPropertyWebkitPaddingAfter: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitPerspective: + case CSSPropertyWebkitPerspectiveOrigin: + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: + case CSSPropertyWebkitTransform: + case CSSPropertyWebkitTransformOrigin: + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + case CSSPropertyWebkitTransformStyle: + case CSSPropertyWebkitTransition: + case CSSPropertyWebkitTransitionDelay: + case CSSPropertyWebkitTransitionDuration: + case CSSPropertyWebkitTransitionProperty: + case CSSPropertyWebkitTransitionTimingFunction: + case CSSPropertyWebkitUserDrag: + case CSSPropertyWebkitFlowInto: + case CSSPropertyWebkitFlowFrom: + case CSSPropertyWebkitRegionOverflow: + case CSSPropertyWebkitRegionBreakAfter: + case CSSPropertyWebkitRegionBreakBefore: + case CSSPropertyWebkitRegionBreakInside: + case CSSPropertyWebkitWrap: + case CSSPropertyWebkitWrapFlow: + case CSSPropertyWebkitWrapMargin: + case CSSPropertyWebkitWrapPadding: + case CSSPropertyWebkitWrapShapeInside: + case CSSPropertyWebkitWrapShapeOutside: + case CSSPropertyWebkitWrapThrough: +#if ENABLE(SVG) + case CSSPropertyClipPath: + case CSSPropertyMask: + case CSSPropertyEnableBackground: + case CSSPropertyFilter: + case CSSPropertyFloodColor: + case CSSPropertyFloodOpacity: + case CSSPropertyLightingColor: + case CSSPropertyStopColor: + case CSSPropertyStopOpacity: + case CSSPropertyColorProfile: + case CSSPropertyAlignmentBaseline: + case CSSPropertyBaselineShift: + case CSSPropertyDominantBaseline: + case CSSPropertyVectorEffect: + case CSSPropertyWebkitSvgShadow: +#endif +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPropertyWebkitDashboardRegion: +#endif + return false; + case CSSPropertyInvalid: + ASSERT_NOT_REACHED(); + return false; + } + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSProperty.h b/Source/WebCore/css/CSSProperty.h new file mode 100644 index 000000000..2674544d1 --- /dev/null +++ b/Source/WebCore/css/CSSProperty.h @@ -0,0 +1,76 @@ +/* + * (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 { + WTF_MAKE_FAST_ALLOCATED; +public: + CSSProperty(unsigned 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_inherited(isInheritedProperty(propID)) + , m_value(value) + { + } + + int id() const { return m_id; } + int shorthandID() const { return m_shorthandID; } + + bool isImportant() const { return m_important; } + bool isImplicit() const { return m_implicit; } + bool isInherited() const { return m_inherited; } + + CSSValue* value() const { return m_value.get(); } + + String cssText() const; + + static int resolveDirectionAwareProperty(int propertyID, TextDirection, WritingMode); + static bool isInheritedProperty(unsigned propertyID); + + // Make sure the following fits in 4 bytes. Really. + unsigned m_id : 14; + unsigned m_shorthandID : 14; // 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. + bool m_inherited : 1; + + 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 000000000..bdd128c77 --- /dev/null +++ b/Source/WebCore/css/CSSPropertyLonghand.cpp @@ -0,0 +1,247 @@ +/* + * (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))) + + static const int fontProperties[] = { + CSSPropertyFontFamily, + CSSPropertyFontSize, + CSSPropertyFontStyle, + CSSPropertyFontVariant, + CSSPropertyFontWeight, + CSSPropertyLineHeight + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyFont, fontProperties); + + // 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 flexFlowProperties[] = { CSSPropertyWebkitFlexDirection, CSSPropertyWebkitFlexWrap }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitFlexFlow, flexFlowProperties); + + 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 webkitWrapProperties[] = { + CSSPropertyWebkitWrapFlow, + CSSPropertyWebkitWrapMargin, + CSSPropertyWebkitWrapPadding + }; + SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSSPropertyWebkitWrap, webkitWrapProperties); + + 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 000000000..9633c025a --- /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 000000000..c0299da60 --- /dev/null +++ b/Source/WebCore/css/CSSPropertyNames.in @@ -0,0 +1,375 @@ +// +// 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-feature-settings +-webkit-font-smoothing +-webkit-locale +-webkit-text-orientation +-epub-text-orientation = -webkit-text-orientation +-webkit-text-size-adjust +-webkit-writing-mode +-epub-writing-mode = -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 +-webkit-border-bottom-left-radius = border-bottom-left-radius +border-bottom-right-radius +-webkit-border-bottom-right-radius = border-bottom-right-radius +border-bottom-style +border-bottom-width +border-collapse +border-color +border-image +border-image-outset +border-image-repeat +border-image-slice +border-image-source +border-image-width +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 +-webkit-border-top-left-radius = border-top-left-radius +border-top-right-radius +-webkit-border-top-right-radius = border-top-right-radius +border-top-style +border-top-width +border-width +bottom +box-shadow +box-sizing +// -webkit-box-sizing worked in Safari 4 and earlier. +-webkit-box-sizing = box-sizing +caption-side +-epub-caption-side = caption-side +clear +clip +content +counter-increment +counter-reset +cursor +empty-cells +float +font-stretch +height +image-rendering +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 +// 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. +-webkit-opacity = 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 +-epub-text-transform = 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 +-epub-word-break = 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-aspect-ratio +-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-axis +-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 +#if defined(ENABLE_CSS_FILTERS) && ENABLE_CSS_FILTERS +-webkit-filter +#endif +-webkit-flex-align +-webkit-flex-direction +-webkit-flex-flow +-webkit-flex-order +-webkit-flex-pack +-webkit-flex-wrap +-webkit-font-size-delta +-webkit-highlight +-webkit-hyphenate-character +-webkit-hyphenate-limit-after +-webkit-hyphenate-limit-before +-webkit-hyphenate-limit-lines +-webkit-hyphens +-epub-hyphens = -webkit-hyphens +-webkit-line-box-contain +-webkit-line-break +-webkit-line-clamp +-webkit-line-grid +-webkit-line-grid-snap +-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-box-image-outset +-webkit-mask-box-image-repeat +-webkit-mask-box-image-slice +-webkit-mask-box-image-source +-webkit-mask-box-image-width +-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-print-color-adjust +-webkit-rtl-ordering +-webkit-text-combine +-epub-text-combine = -webkit-text-combine +-webkit-text-decorations-in-effect +-webkit-text-emphasis +-epub-text-emphasis = -webkit-text-emphasis +-webkit-text-emphasis-color +-epub-text-emphasis-color = -webkit-text-emphasis-color +-webkit-text-emphasis-position +-webkit-text-emphasis-style +-epub-text-emphasis-style = -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 +-webkit-flow-into +-webkit-flow-from +-webkit-region-overflow +-webkit-wrap-shape-inside +-webkit-wrap-shape-outside +-webkit-wrap-margin +-webkit-wrap-padding +-webkit-region-break-after +-webkit-region-break-before +-webkit-region-break-inside +-webkit-wrap-flow +-webkit-wrap-through +-webkit-wrap +#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS +-webkit-tap-highlight-color +#endif +#if defined(ENABLE_CSS_GRID_LAYOUT) && ENABLE_CSS_GRID_LAYOUT +-webkit-grid-columns +-webkit-grid-rows +#endif diff --git a/Source/WebCore/css/CSSPropertySourceData.cpp b/Source/WebCore/css/CSSPropertySourceData.cpp new file mode 100644 index 000000000..d17ac8db6 --- /dev/null +++ b/Source/WebCore/css/CSSPropertySourceData.cpp @@ -0,0 +1,123 @@ +/* + * 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) +{ +} + +unsigned SourceRange::length() const +{ + return end - start; +} + +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 000000000..f20af1af8 --- /dev/null +++ b/Source/WebCore/css/CSSPropertySourceData.h @@ -0,0 +1,100 @@ +/* + * 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/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSStyleRule; + +struct SourceRange { + SourceRange(); + SourceRange(unsigned start, unsigned end); + unsigned length() const; + + 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/CSSReflectValue.cpp b/Source/WebCore/css/CSSReflectValue.cpp new file mode 100644 index 000000000..911d110b9 --- /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::customCssText() 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 000000000..5b03efe89 --- /dev/null +++ b/Source/WebCore/css/CSSReflectValue.h @@ -0,0 +1,70 @@ +/* + * 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(); } + + String customCssText() const; + + void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +private: + CSSReflectValue(CSSReflectionDirection direction, PassRefPtr<CSSPrimitiveValue> offset, PassRefPtr<CSSValue> mask) + : CSSValue(ReflectClass) + , m_direction(direction) + , m_offset(offset) + , m_mask(mask) + { + } + + 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 000000000..e30bc1c13 --- /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 000000000..5399848da --- /dev/null +++ b/Source/WebCore/css/CSSRule.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, 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 "CSSCharsetRule.h" +#include "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSMediaRule.h" +#include "CSSPageRule.h" +#include "CSSStyleRule.h" +#include "CSSUnknownRule.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSRegionRule.h" +#include "NotImplemented.h" + +namespace WebCore { + +struct SameSizeAsCSSRule : public RefCounted<SameSizeAsCSSRule> { + unsigned bitfields; + void* pointerUnion; +}; + +COMPILE_ASSERT(sizeof(CSSRule) == sizeof(SameSizeAsCSSRule), CSSRule_should_stay_small); + +void CSSRule::setCssText(const String& /*cssText*/, ExceptionCode& /*ec*/) +{ + notImplemented(); +} + +String CSSRule::cssText() const +{ + switch (type()) { + case UNKNOWN_RULE: + return String(); + case STYLE_RULE: + case PAGE_RULE: + return static_cast<const CSSStyleRule*>(this)->cssText(); + case CHARSET_RULE: + return static_cast<const CSSCharsetRule*>(this)->cssText(); + case IMPORT_RULE: + return static_cast<const CSSImportRule*>(this)->cssText(); + case MEDIA_RULE: + return static_cast<const CSSMediaRule*>(this)->cssText(); + case FONT_FACE_RULE: + return static_cast<const CSSFontFaceRule*>(this)->cssText(); + case WEBKIT_KEYFRAMES_RULE: + return static_cast<const WebKitCSSKeyframesRule*>(this)->cssText(); + case WEBKIT_KEYFRAME_RULE: + return static_cast<const WebKitCSSKeyframeRule*>(this)->cssText(); + case WEBKIT_REGION_RULE: + return static_cast<const WebKitCSSRegionRule*>(this)->cssText(); + } + ASSERT_NOT_REACHED(); + return String(); +} + +void CSSRule::destroy() +{ + switch (type()) { + case UNKNOWN_RULE: + delete static_cast<CSSUnknownRule*>(this); + return; + case STYLE_RULE: + delete static_cast<CSSStyleRule*>(this); + return; + case PAGE_RULE: + delete static_cast<CSSPageRule*>(this); + return; + case CHARSET_RULE: + delete static_cast<CSSCharsetRule*>(this); + return; + case IMPORT_RULE: + delete static_cast<CSSImportRule*>(this); + return; + case MEDIA_RULE: + delete static_cast<CSSMediaRule*>(this); + return; + case FONT_FACE_RULE: + delete static_cast<CSSFontFaceRule*>(this); + return; + case WEBKIT_KEYFRAMES_RULE: + delete static_cast<WebKitCSSKeyframesRule*>(this); + return; + case WEBKIT_KEYFRAME_RULE: + delete static_cast<WebKitCSSKeyframeRule*>(this); + return; + case WEBKIT_REGION_RULE: + delete static_cast<WebKitCSSRegionRule*>(this); + return; + } + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSRule.h b/Source/WebCore/css/CSSRule.h new file mode 100644 index 000000000..4f3ca3b74 --- /dev/null +++ b/Source/WebCore/css/CSSRule.h @@ -0,0 +1,146 @@ +/* + * (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. + * Copyright (C) 2011 Andreas Kling (kling@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 CSSRule_h +#define CSSRule_h + +#include "CSSStyleSheet.h" +#include "KURLHash.h" +#include <wtf/ListHashSet.h> + +namespace WebCore { + +typedef int ExceptionCode; + +class CSSRule : public RefCounted<CSSRule> { +public: + // Override RefCounted's deref() to ensure operator delete is called on + // the appropriate subclass type. + void deref() + { + if (derefBase()) + destroy(); + } + + enum Type { + 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, + WEBKIT_REGION_RULE + }; + + Type type() const { return static_cast<Type>(m_type); } + + bool isCharsetRule() const { return type() == CHARSET_RULE; } + bool isFontFaceRule() const { return type() == FONT_FACE_RULE; } + bool isKeyframeRule() const { return type() == WEBKIT_KEYFRAME_RULE; } + bool isKeyframesRule() const { return type() == WEBKIT_KEYFRAMES_RULE; } + bool isMediaRule() const { return type() == MEDIA_RULE; } + bool isPageRule() const { return type() == PAGE_RULE; } + bool isStyleRule() const { return type() == STYLE_RULE; } + bool isRegionRule() const { return type() == WEBKIT_REGION_RULE; } + bool isImportRule() const { return type() == IMPORT_RULE; } + + bool useStrictParsing() const + { + if (parentRule()) + return parentRule()->useStrictParsing(); + if (parentStyleSheet()) + return parentStyleSheet()->useStrictParsing(); + return true; + } + + void setParentStyleSheet(CSSStyleSheet* styleSheet) + { + m_parentIsRule = false; + m_parentStyleSheet = styleSheet; + } + + void setParentRule(CSSRule* rule) + { + m_parentIsRule = true; + m_parentRule = rule; + } + + CSSStyleSheet* parentStyleSheet() const + { + if (m_parentIsRule) + return m_parentRule ? m_parentRule->parentStyleSheet() : 0; + return m_parentStyleSheet; + } + + CSSRule* parentRule() const { return m_parentIsRule ? m_parentRule : 0; } + + String cssText() const; + void setCssText(const String&, ExceptionCode&); + + KURL baseURL() const + { + if (CSSStyleSheet* parentSheet = parentStyleSheet()) + return parentSheet->baseURL(); + return KURL(); + } + +protected: + CSSRule(CSSStyleSheet* parent, Type type) + : m_sourceLine(0) + , m_hasCachedSelectorText(false) + , m_parentIsRule(false) + , m_type(type) + , m_parentStyleSheet(parent) + { + } + + // NOTE: This class is non-virtual for memory and performance reasons. + // Don't go making it virtual again unless you know exactly what you're doing! + + ~CSSRule() { } + + int sourceLine() const { return m_sourceLine; } + void setSourceLine(int sourceLine) { m_sourceLine = sourceLine; } + bool hasCachedSelectorText() const { return m_hasCachedSelectorText; } + void setHasCachedSelectorText(bool hasCachedSelectorText) const { m_hasCachedSelectorText = hasCachedSelectorText; } + +private: + // Only used by CSSStyleRule but kept here to maximize struct packing. + signed m_sourceLine : 26; + mutable unsigned m_hasCachedSelectorText : 1; + unsigned m_parentIsRule : 1; + unsigned m_type : 4; + union { + CSSRule* m_parentRule; + CSSStyleSheet* m_parentStyleSheet; + }; + + void destroy(); +}; + +} // namespace WebCore + +#endif // CSSRule_h diff --git a/Source/WebCore/css/CSSRule.idl b/Source/WebCore/css/CSSRule.idl new file mode 100644 index 000000000..0fda9efd4 --- /dev/null +++ b/Source/WebCore/css/CSSRule.idl @@ -0,0 +1,54 @@ +/* + * 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, + GenerateIsReachable, + CustomToJS, + Polymorphic, + V8DependentLifetime + ] 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; + const unsigned short WEBKIT_REGION_RULE = 10; + + 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 000000000..6b080ef0b --- /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 "CSSStyleSheet.h" +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +CSSRuleList::CSSRuleList() +{ +} + +CSSRuleList::CSSRuleList(CSSStyleSheet* styleSheet, bool omitCharsetRules) + : m_styleSheet(styleSheet) +{ + if (styleSheet && omitCharsetRules) { + m_styleSheet = 0; + for (unsigned i = 0; i < styleSheet->length(); ++i) { + CSSRule* rule = styleSheet->item(i); + if (!rule->isCharsetRule()) + append(static_cast<CSSRule*>(rule)); + } + } +} + +CSSRuleList::~CSSRuleList() +{ +} + +unsigned CSSRuleList::length() const +{ + return m_styleSheet ? m_styleSheet->length() : m_lstCSSRules.size(); +} + +CSSRule* CSSRuleList::item(unsigned index) const +{ + if (m_styleSheet) + return m_styleSheet->item(index); + + if (index < m_lstCSSRules.size()) + return m_lstCSSRules[index].get(); + return 0; +} + +void CSSRuleList::deleteRule(unsigned index) +{ + ASSERT(!m_styleSheet); + + if (index >= m_lstCSSRules.size()) + return; + + m_lstCSSRules.remove(index); +} + +void CSSRuleList::append(CSSRule* rule) +{ + ASSERT(!m_styleSheet); + + if (!rule) + return; + + m_lstCSSRules.append(rule); +} + +unsigned CSSRuleList::insertRule(CSSRule* rule, unsigned index) +{ + ASSERT(!m_styleSheet); + + if (!rule || index > m_lstCSSRules.size()) + return 0; + + m_lstCSSRules.insert(index, rule); + return index; +} + +String CSSRuleList::rulesText() const +{ + StringBuilder result; + + for (unsigned index = 0; index < length(); ++index) { + result.append(" "); + result.append(item(index)->cssText()); + result.append("\n"); + } + + return result.toString(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSRuleList.h b/Source/WebCore/css/CSSRuleList.h new file mode 100644 index 000000000..ea52c8607 --- /dev/null +++ b/Source/WebCore/css/CSSRuleList.h @@ -0,0 +1,71 @@ +/* + * (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> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CSSRule; +class CSSStyleSheet; + +class CSSRuleList : public RefCounted<CSSRuleList> { +public: + static PassRefPtr<CSSRuleList> create(CSSStyleSheet* styleSheet, bool omitCharsetRules = false) + { + return adoptRef(new CSSRuleList(styleSheet, omitCharsetRules)); + } + static PassRefPtr<CSSRuleList> create() + { + return adoptRef(new CSSRuleList); + } + ~CSSRuleList(); + + unsigned length() const; + CSSRule* item(unsigned index) const; + + // FIXME: Not part of the CSSOM. Only used by @media and @-webkit-keyframes rules. + unsigned insertRule(CSSRule*, unsigned index); + void deleteRule(unsigned index); + + void append(CSSRule*); + + CSSStyleSheet* styleSheet() { return m_styleSheet.get(); } + + String rulesText() const; + +private: + CSSRuleList(); + CSSRuleList(CSSStyleSheet*, bool omitCharsetRules); + + RefPtr<CSSStyleSheet> m_styleSheet; + 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 000000000..ed86eaa26 --- /dev/null +++ b/Source/WebCore/css/CSSRuleList.idl @@ -0,0 +1,38 @@ +/* + * 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 [ + CustomIsReachable, + HasIndexGetter, + V8DependentLifetime + ] CSSRuleList { + readonly attribute unsigned long length; + CSSRule item(in [Optional=CallWithDefaultValue] unsigned long index); + }; + +} diff --git a/Source/WebCore/css/CSSSegmentedFontFace.cpp b/Source/WebCore/css/CSSSegmentedFontFace.cpp new file mode 100644 index 000000000..f462c24c4 --- /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 "CSSFontFaceSource.h" +#include "CSSFontSelector.h" +#include "Document.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; + + 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() + 1) << (FontTraitsMaskWidth + 1)) | ((fontDescription.orientation() == Vertical ? 1 : 0) << FontTraitsMaskWidth) | desiredTraitsMask; + + SegmentedFontData*& fontData = m_fontDataTable.add(hashKey, 0).first->second; + if (fontData) + return fontData; + + OwnPtr<SegmentedFontData> newFontData = adoptPtr(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) + newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData)); + else { + for (unsigned j = 0; j < numRanges; ++j) + newFontData->appendRange(FontDataRange(ranges[j].from(), ranges[j].to(), faceFontData)); + } + } + } + if (newFontData->numRanges()) { + ASSERT(m_fontSelector->document()); + if (Document* document = m_fontSelector->document()) { + fontData = newFontData.get(); + document->registerCustomFont(newFontData.release()); + } + } + + return fontData; +} + +} diff --git a/Source/WebCore/css/CSSSegmentedFontFace.h b/Source/WebCore/css/CSSSegmentedFontFace.h new file mode 100644 index 000000000..3efc47a63 --- /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 000000000..be28c601b --- /dev/null +++ b/Source/WebCore/css/CSSSelector.cpp @@ -0,0 +1,778 @@ +/* + * 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 "CSSSelectorList.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; + +void CSSSelector::createRareData() +{ + if (m_hasRareData) + return; + // Move the value to the rare data stucture. + m_data.m_rareData = new RareData(adoptRef(m_data.m_value)); + m_hasRareData = true; +} + +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: + // FIXME: PsuedoAny should base the specificity on the sub-selectors. + // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html + if (pseudoType() == PseudoNot) { + ASSERT(selectorList()); + s += selectorList()->first()->specificityForOneSelector(); + } else + 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 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; +#if ENABLE(FULLSCREEN_API) + case PseudoFullScreen: + return FULL_SCREEN; + case PseudoFullScreenDocument: + return FULL_SCREEN_DOCUMENT; + case PseudoFullScreenAncestor: + return FULL_SCREEN_ANCESTOR; + case PseudoAnimatingFullScreenTransition: + return ANIMATING_FULL_SCREEN_TRANSITION; +#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 PseudoAny: + 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, any, ("-webkit-any(")); + 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, 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")); +#if ENABLE(DATALIST) + DEFINE_STATIC_LOCAL(AtomicString, inputListButton, ("-webkit-input-list-button")); +#endif + 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, 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, 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, selection, ("selection")); + 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")); + DEFINE_STATIC_LOCAL(AtomicString, fullScreenAncestor, ("-webkit-full-screen-ancestor")); + DEFINE_STATIC_LOCAL(AtomicString, animatingFullScreenTransition, ("-webkit-animating-full-screen-transition")); +#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(any.impl(), CSSSelector::PseudoAny); + nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill); + nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore); + nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked); + 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(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(link.impl(), CSSSelector::PseudoLink); + nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang); + 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(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(selection.impl(), CSSSelector::PseudoSelection); + 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); + nameToPseudoType->set(fullScreenAncestor.impl(), CSSSelector::PseudoFullScreenAncestor); + nameToPseudoType->set(animatingFullScreenTransition.impl(), CSSSelector::PseudoAnimatingFullScreenTransition); +#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; +} + +bool CSSSelector::isUnknownPseudoType(const AtomicString& name) +{ + return parsePseudoType(name) == PseudoUnknown; +} + +void CSSSelector::extractPseudoType() const +{ + if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass) + return; + + m_pseudoType = parsePseudoType(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 PseudoInputListButton: + case PseudoResizer: + case PseudoScrollbar: + case PseudoScrollbarCorner: + case PseudoScrollbarButton: + case PseudoScrollbarThumb: + case PseudoScrollbarTrack: + case PseudoScrollbarTrackPiece: + case PseudoSelection: + 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 PseudoAny: + 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: + case PseudoFullScreenAncestor: + case PseudoAnimatingFullScreenTransition: +#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->value() != sel2->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->value(), str); + } else if (cs->m_match == CSSSelector::Class) { + str += "."; + serializeIdentifier(cs->value(), str); + } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) { + str += ":"; + str += cs->value(); + + switch (cs->pseudoType()) { + case PseudoNot: + ASSERT(cs->selectorList()); + str += cs->selectorList()->first()->selectorText(); + str += ")"; + break; + case PseudoLang: + case PseudoNthChild: + case PseudoNthLastChild: + case PseudoNthOfType: + case PseudoNthLastOfType: + str += cs->argument(); + str += ")"; + break; + case PseudoAny: { + CSSSelector* firstSubSelector = cs->selectorList()->first(); + for (CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (subSelector != firstSubSelector) + str += ","; + str += subSelector->selectorText(); + } + str += ")"; + break; + } + default: + break; + } + } else if (cs->m_match == CSSSelector::PseudoElement) { + str += "::"; + str += cs->value(); + } else if (cs->isAttributeSelector()) { + 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->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 if (cs->relation() == CSSSelector::ShadowDescendant) + str = tagHistoryText + str; + else + // Descendant + str = tagHistoryText + " " + str; + } + + return str; +} + +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::setSelectorList(PassOwnPtr<CSSSelectorList> selectorList) +{ + createRareData(); + m_data.m_rareData->m_selectorList = selectorList; +} + +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 (selectorList() || 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; +} + +CSSSelector::RareData::RareData(PassRefPtr<AtomicStringImpl> value) + : m_value(value.leakRef()) + , m_a(0) + , m_b(0) + , m_attribute(anyQName()) + , m_argument(nullAtom) +{ +} + +CSSSelector::RareData::~RareData() +{ + if (m_value) + m_value->deref(); +} + +// 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; + } +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSSelector.h b/Source/WebCore/css/CSSSelector.h new file mode 100644 index 000000000..afd52def9 --- /dev/null +++ b/Source/WebCore/css/CSSSelector.h @@ -0,0 +1,374 @@ +/* + * 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 CSSSelectorList; + + // this class represents a selector for a StyleRule + class CSSSelector { + WTF_MAKE_NONCOPYABLE(CSSSelector); WTF_MAKE_FAST_ALLOCATED; + public: + CSSSelector() + : m_relation(Descendant) + , m_match(None) + , m_pseudoType(PseudoNotParsed) + , m_parsedNth(false) + , m_isLastInSelectorList(false) + , m_isLastInTagHistory(true) + , 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_isLastInTagHistory(true) + , m_hasRareData(false) + , m_isForPage(false) + , m_tag(qName) + { + } + + ~CSSSelector() + { + if (m_hasRareData) + delete m_data.m_rareData; + else if (m_data.m_value) + m_data.m_value->deref(); + } + + /** + * 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, + ShadowDescendant + }; + + enum PseudoType { + PseudoNotParsed = 0, + PseudoUnknown, + PseudoEmpty, + PseudoFirstChild, + PseudoFirstOfType, + PseudoLastChild, + PseudoLastOfType, + PseudoOnlyChild, + PseudoOnlyOfType, + PseudoFirstLine, + PseudoFirstLetter, + PseudoNthChild, + PseudoNthOfType, + PseudoNthLastChild, + PseudoNthLastOfType, + PseudoLink, + PseudoVisited, + PseudoAny, + PseudoAnyLink, + PseudoAutofill, + PseudoHover, + PseudoDrag, + PseudoFocus, + PseudoActive, + PseudoChecked, + PseudoEnabled, + PseudoFullPageMedia, + PseudoDefault, + PseudoDisabled, + 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, + PseudoInputListButton, + PseudoLeftPage, + PseudoRightPage, + PseudoFirstPage, +#if ENABLE(FULLSCREEN_API) + PseudoFullScreen, + PseudoFullScreenDocument, + PseudoFullScreenAncestor, + PseudoAnimatingFullScreenTransition, +#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 bool isUnknownPseudoType(const AtomicString&); + static PseudoId pseudoId(PseudoType); + + // Selectors are kept in an array by CSSSelectorList. The next component of the selector is + // the next item in the array. + CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); } + + bool hasTag() const { return m_tag != anyQName(); } + + const QualifiedName& tag() const { return m_tag; } + // AtomicString is really just an AtomicStringImpl* so the cast below is safe. + // FIXME: Perhaps call sites could be changed to accept AtomicStringImpl? + const AtomicString& value() const { return *reinterpret_cast<const AtomicString*>(m_hasRareData ? &m_data.m_rareData->m_value : &m_data.m_value); } + const QualifiedName& attribute() const; + const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; } + CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; } + + void setTag(const QualifiedName& value) { m_tag = value; } + void setValue(const AtomicString&); + void setAttribute(const QualifiedName&); + void setArgument(const AtomicString&); + void setSelectorList(PassOwnPtr<CSSSelectorList>); + + bool parseNth(); + bool matchNth(int count); + + bool matchesPseudoElement() const; + bool isUnknownPseudoElement() const; + bool isSiblingSelector() const; + bool isAttributeSelector() const; + + Relation relation() const { return static_cast<Relation>(m_relation); } + + bool isLastInSelectorList() const { return m_isLastInSelectorList; } + void setLastInSelectorList() { m_isLastInSelectorList = true; } + bool isLastInTagHistory() const { return m_isLastInTagHistory; } + void setNotLastInTagHistory() { m_isLastInTagHistory = false; } + + 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_isLastInTagHistory : 1; + bool m_hasRareData : 1; + bool m_isForPage : 1; + + unsigned specificityForOneSelector() const; + unsigned specificityForPage() const; + void extractPseudoType() const; + + struct RareData { + WTF_MAKE_NONCOPYABLE(RareData); WTF_MAKE_FAST_ALLOCATED; + public: + RareData(PassRefPtr<AtomicStringImpl> value); + ~RareData(); + + bool parseNth(); + bool matchNth(int count); + + AtomicStringImpl* m_value; // Plain pointer to keep things uniform with the union. + int m_a; // Used for :nth-* + int m_b; // Used for :nth-* + QualifiedName m_attribute; // used for attribute selector + AtomicString m_argument; // Used for :contains, :lang and :nth-* + OwnPtr<CSSSelectorList> m_selectorList; // Used for :-webkit-any and :not + }; + void createRareData(); + + union DataUnion { + DataUnion() : m_value(0) { } + AtomicStringImpl* m_value; + RareData* m_rareData; + } m_data; + + QualifiedName m_tag; + }; + +inline const QualifiedName& CSSSelector::attribute() const +{ + ASSERT(isAttributeSelector()); + ASSERT(m_hasRareData); + return m_data.m_rareData->m_attribute; +} + +inline bool CSSSelector::matchesPseudoElement() const +{ + if (m_pseudoType == PseudoUnknown) + extractPseudoType(); + return m_match == PseudoElement; +} + +inline bool CSSSelector::isUnknownPseudoElement() const +{ + return m_match == PseudoElement && m_pseudoType == PseudoUnknown; +} + +inline bool CSSSelector::isSiblingSelector() const +{ + PseudoType type = pseudoType(); + return m_relation == DirectAdjacent + || m_relation == IndirectAdjacent + || type == PseudoEmpty + || type == PseudoFirstChild + || type == PseudoFirstOfType + || type == PseudoLastChild + || type == PseudoLastOfType + || type == PseudoOnlyChild + || type == PseudoOnlyOfType + || type == PseudoNthChild + || type == PseudoNthOfType + || type == PseudoNthLastChild + || type == PseudoNthLastOfType; +} + +inline bool CSSSelector::isAttributeSelector() const +{ + return m_match == CSSSelector::Exact + || m_match == CSSSelector::Set + || m_match == CSSSelector::List + || m_match == CSSSelector::Hyphen + || m_match == CSSSelector::Contain + || m_match == CSSSelector::Begin + || m_match == CSSSelector::End; +} + +inline void CSSSelector::setValue(const AtomicString& value) +{ + // Need to do ref counting manually for the union. + if (m_hasRareData) { + if (m_data.m_rareData->m_value) + m_data.m_rareData->m_value->deref(); + m_data.m_rareData->m_value = value.impl(); + m_data.m_rareData->m_value->ref(); + return; + } + if (m_data.m_value) + m_data.m_value->deref(); + m_data.m_value = value.impl(); + m_data.m_value->ref(); +} + +inline void move(PassOwnPtr<CSSSelector> from, CSSSelector* to) +{ + memcpy(to, from.get(), 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(from.leakPtr()); +} + +} // namespace WebCore + +#endif // CSSSelector_h diff --git a/Source/WebCore/css/CSSSelectorList.cpp b/Source/WebCore/css/CSSSelectorList.cpp new file mode 100644 index 000000000..80430537a --- /dev/null +++ b/Source/WebCore/css/CSSSelectorList.cpp @@ -0,0 +1,186 @@ +/* + * 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" + +#include "CSSParserValues.h" +#include <wtf/text/StringBuilder.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<OwnPtr<CSSParserSelector> >& selectorVector) +{ + deleteSelectors(); + const size_t vectorSize = selectorVector.size(); + size_t flattenedSize = 0; + for (size_t i = 0; i < vectorSize; ++i) { + for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) + ++flattenedSize; + } + ASSERT(flattenedSize); + if (flattenedSize == 1) { + m_selectorArray = selectorVector[0]->releaseSelector().leakPtr(); + m_selectorArray->setLastInSelectorList(); + ASSERT(m_selectorArray->isLastInTagHistory()); + selectorVector.shrink(0); + return; + } + m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); + size_t arrayIndex = 0; + for (size_t i = 0; i < vectorSize; ++i) { + CSSParserSelector* current = selectorVector[i].get(); + while (current) { + OwnPtr<CSSSelector> selector = current->releaseSelector(); + current = current->tagHistory(); + move(selector.release(), &m_selectorArray[arrayIndex]); + ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); + if (current) + m_selectorArray[arrayIndex].setNotLastInTagHistory(); + ++arrayIndex; + } + ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); + } + ASSERT(flattenedSize == arrayIndex); + m_selectorArray[arrayIndex - 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); + } +} + +String CSSSelectorList::selectorsText() const +{ + StringBuilder result; + + for (CSSSelector* s = first(); s; s = next(s)) { + if (s != first()) + result.append(", "); + result.append(s->selectorText()); + } + + return result.toString(); +} + +template <typename Functor> +static bool forEachTagSelector(Functor& functor, CSSSelector* selector) +{ + ASSERT(selector); + + do { + if (functor(selector)) + return true; + if (CSSSelectorList* selectorList = selector->selectorList()) { + for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (forEachTagSelector(functor, subSelector)) + 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->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom) + return true; + if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) + return true; + return false; + } +}; + +bool CSSSelectorList::selectorsNeedNamespaceResolution() +{ + SelectorNeedsNamespaceResolutionFunctor functor; + return forEachSelector(functor, this); +} + +class SelectorHasUnknownPseudoElementFunctor { +public: + bool operator()(CSSSelector* selector) + { + return selector->isUnknownPseudoElement(); + } +}; + +bool CSSSelectorList::hasUnknownPseudoElements() const +{ + SelectorHasUnknownPseudoElementFunctor 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 000000000..7d45a6a54 --- /dev/null +++ b/Source/WebCore/css/CSSSelectorList.h @@ -0,0 +1,71 @@ +/* + * 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" + +namespace WebCore { + +class CSSParserSelector; + +class CSSSelectorList { + WTF_MAKE_NONCOPYABLE(CSSSelectorList); WTF_MAKE_FAST_ALLOCATED; +public: + CSSSelectorList() : m_selectorArray(0) { } + ~CSSSelectorList(); + + void adopt(CSSSelectorList& list); + void adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector); + + CSSSelector* first() const { return m_selectorArray ? m_selectorArray : 0; } + static CSSSelector* next(CSSSelector*); + bool hasOneSelector() const { return m_selectorArray && !next(m_selectorArray); } + + bool selectorsNeedNamespaceResolution(); + bool hasUnknownPseudoElements() const; + + String selectorsText() const; + +private: + void deleteSelectors(); + + // End of a multipart selector is indicated by m_isLastInTagHistory bit in the last item. + // End of the array is indicated by m_isLastInSelectorList bit in the last item. + CSSSelector* m_selectorArray; +}; + +inline CSSSelector* CSSSelectorList::next(CSSSelector* current) +{ + // Skip subparts of compound selectors. + while (!current->isLastInTagHistory()) + current++; + return current->isLastInSelectorList() ? 0 : current + 1; +} + +} // namespace WebCore + +#endif // CSSSelectorList_h diff --git a/Source/WebCore/css/CSSStyleApplyProperty.cpp b/Source/WebCore/css/CSSStyleApplyProperty.cpp new file mode 100644 index 000000000..389f25c4a --- /dev/null +++ b/Source/WebCore/css/CSSStyleApplyProperty.cpp @@ -0,0 +1,1807 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#include "config.h" +#include "CSSStyleApplyProperty.h" + +#include "CSSAspectRatioValue.h" +#include "CSSCursorImageValue.h" +#include "CSSFlexValue.h" +#include "CSSPrimitiveValueMappings.h" +#include "CSSStyleSelector.h" +#include "CSSValueList.h" +#include "CursorList.h" +#include "Document.h" +#include "Element.h" +#include "Pair.h" +#include "RenderObject.h" +#include "RenderStyle.h" +#include "Settings.h" +#include <wtf/StdLibExtras.h> +#include <wtf/UnusedParam.h> + +using namespace std; + +namespace WebCore { + +enum ExpandValueBehavior {SuppressValue = 0, ExpandValue}; +template <ExpandValueBehavior expandValue, CSSPropertyID one = CSSPropertyInvalid, CSSPropertyID two = CSSPropertyInvalid, CSSPropertyID three = CSSPropertyInvalid, CSSPropertyID four = CSSPropertyInvalid> +class ApplyPropertyExpanding { +public: + + template <CSSPropertyID id> + static inline void applyInheritValue(CSSStyleSelector* selector) + { + if (id == CSSPropertyInvalid) + return; + + const CSSStyleApplyProperty& table = CSSStyleApplyProperty::sharedCSSStyleApplyProperty(); + const PropertyHandler& handler = table.propertyHandler(id); + if (handler.isValid()) + handler.applyInheritValue(selector); + } + + static void applyInheritValue(CSSStyleSelector* selector) + { + applyInheritValue<one>(selector); + applyInheritValue<two>(selector); + applyInheritValue<three>(selector); + applyInheritValue<four>(selector); + } + + template <CSSPropertyID id> + static inline void applyInitialValue(CSSStyleSelector* selector) + { + if (id == CSSPropertyInvalid) + return; + + const CSSStyleApplyProperty& table = CSSStyleApplyProperty::sharedCSSStyleApplyProperty(); + const PropertyHandler& handler = table.propertyHandler(id); + if (handler.isValid()) + handler.applyInitialValue(selector); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + applyInitialValue<one>(selector); + applyInitialValue<two>(selector); + applyInitialValue<three>(selector); + applyInitialValue<four>(selector); + } + + template <CSSPropertyID id> + static inline void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (id == CSSPropertyInvalid) + return; + + const CSSStyleApplyProperty& table = CSSStyleApplyProperty::sharedCSSStyleApplyProperty(); + const PropertyHandler& handler = table.propertyHandler(id); + if (handler.isValid()) + handler.applyValue(selector, value); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!expandValue) + return; + + applyValue<one>(selector, value); + applyValue<two>(selector, value); + applyValue<three>(selector, value); + applyValue<four>(selector, value); + } + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +template <typename GetterType, GetterType (RenderStyle::*getterFunction)() const, typename SetterType, void (RenderStyle::*setterFunction)(SetterType), typename InitialType, InitialType (*initialFunction)()> +class ApplyPropertyDefaultBase { +public: + static void setValue(RenderStyle* style, SetterType value) { (style->*setterFunction)(value); } + static GetterType value(RenderStyle* style) { return (style->*getterFunction)(); } + static InitialType initial() { return (*initialFunction)(); } + static void applyInheritValue(CSSStyleSelector* selector) { setValue(selector->style(), value(selector->parentStyle())); } + static void applyInitialValue(CSSStyleSelector* selector) { setValue(selector->style(), initial()); } + static void applyValue(CSSStyleSelector*, CSSValue*) { } + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +template <typename GetterType, GetterType (RenderStyle::*getterFunction)() const, typename SetterType, void (RenderStyle::*setterFunction)(SetterType), typename InitialType, InitialType (*initialFunction)()> +class ApplyPropertyDefault { +public: + static void setValue(RenderStyle* style, SetterType value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (value->isPrimitiveValue()) + setValue(selector->style(), *static_cast<CSSPrimitiveValue*>(value)); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<GetterType, getterFunction, SetterType, setterFunction, InitialType, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +template <typename NumberType, NumberType (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(NumberType), NumberType (*initialFunction)(), int idMapsToMinusOne = CSSValueAuto> +class ApplyPropertyNumber { +public: + static void setValue(RenderStyle* style, NumberType value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == idMapsToMinusOne) + setValue(selector->style(), -1); + else + setValue(selector->style(), primitiveValue->getValue<NumberType>(CSSPrimitiveValue::CSS_NUMBER)); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<NumberType, getterFunction, NumberType, setterFunction, NumberType, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +template <StyleImage* (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(PassRefPtr<StyleImage>), StyleImage* (*initialFunction)(), CSSPropertyID property> +class ApplyPropertyStyleImage { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) { (selector->style()->*setterFunction)(selector->styleImage(property, value)); } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<StyleImage*, getterFunction, PassRefPtr<StyleImage>, setterFunction, StyleImage*, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum AutoValueType {Number = 0, ComputeLength}; +template <typename T, T (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(T), bool (RenderStyle::*hasAutoFunction)() const, void (RenderStyle::*setAutoFunction)(), AutoValueType valueType = Number, int autoIdentity = CSSValueAuto> +class ApplyPropertyAuto { +public: + static void setValue(RenderStyle* style, T value) { (style->*setterFunction)(value); } + static T value(RenderStyle* style) { return (style->*getterFunction)(); } + static bool hasAuto(RenderStyle* style) { return (style->*hasAutoFunction)(); } + static void setAuto(RenderStyle* style) { (style->*setAutoFunction)(); } + + static void applyInheritValue(CSSStyleSelector* selector) + { + if (hasAuto(selector->parentStyle())) + setAuto(selector->style()); + else + setValue(selector->style(), value(selector->parentStyle())); + } + + static void applyInitialValue(CSSStyleSelector* selector) { setAuto(selector->style()); } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == autoIdentity) + setAuto(selector->style()); + else if (valueType == Number) + setValue(selector->style(), *primitiveValue); + else if (valueType == ComputeLength) + setValue(selector->style(), primitiveValue->computeLength<T>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom())); + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +enum ColorInherit {NoInheritFromParent = 0, InheritFromParent}; +Color defaultInitialColor(); +Color defaultInitialColor() { return Color(); } +template <ColorInherit inheritColorFromParent, + const Color& (RenderStyle::*getterFunction)() const, + void (RenderStyle::*setterFunction)(const Color&), + void (RenderStyle::*visitedLinkSetterFunction)(const Color&), + const Color& (RenderStyle::*defaultFunction)() const, + Color (*initialFunction)() = &defaultInitialColor> +class ApplyPropertyColor { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + // Visited link style can never explicitly inherit from parent visited link style so no separate getters are needed. + const Color& color = (selector->parentStyle()->*getterFunction)(); + applyColorValue(selector, color.isValid() ? color : (selector->parentStyle()->*defaultFunction)()); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + applyColorValue(selector, initialFunction()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (inheritColorFromParent && primitiveValue->getIdent() == CSSValueCurrentcolor) + applyInheritValue(selector); + else { + if (selector->applyPropertyToRegularStyle()) + (selector->style()->*setterFunction)(selector->colorFromPrimitiveValue(primitiveValue)); + if (selector->applyPropertyToVisitedLinkStyle()) + (selector->style()->*visitedLinkSetterFunction)(selector->colorFromPrimitiveValue(primitiveValue, /* forVisitedLink */ true)); + } + } + + static void applyColorValue(CSSStyleSelector* selector, const Color& color) + { + if (selector->applyPropertyToRegularStyle()) + (selector->style()->*setterFunction)(color); + if (selector->applyPropertyToVisitedLinkStyle()) + (selector->style()->*visitedLinkSetterFunction)(color); + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +template <TextDirection (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(TextDirection), TextDirection (*initialFunction)()> +class ApplyPropertyDirection { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + ApplyPropertyDefault<TextDirection, getterFunction, TextDirection, setterFunction, TextDirection, initialFunction>::applyValue(selector, value); + Element* element = selector->element(); + if (element && selector->element() == element->document()->documentElement()) + element->document()->setDirectionSetOnDocumentElement(true); + } + + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefault<TextDirection, getterFunction, TextDirection, setterFunction, TextDirection, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum LengthAuto { AutoDisabled = 0, AutoEnabled }; +enum LengthIntrinsic { IntrinsicDisabled = 0, IntrinsicEnabled }; +enum LengthMinIntrinsic { MinIntrinsicDisabled = 0, MinIntrinsicEnabled }; +enum LengthNone { NoneDisabled = 0, NoneEnabled }; +enum LengthUndefined { UndefinedDisabled = 0, UndefinedEnabled }; +enum LengthFlexDirection { FlexDirectionDisabled = 0, FlexWidth, FlexHeight }; +template <Length (RenderStyle::*getterFunction)() const, + void (RenderStyle::*setterFunction)(Length), + Length (*initialFunction)(), + LengthAuto autoEnabled = AutoDisabled, + LengthIntrinsic intrinsicEnabled = IntrinsicDisabled, + LengthMinIntrinsic minIntrinsicEnabled = MinIntrinsicDisabled, + LengthNone noneEnabled = NoneDisabled, + LengthUndefined noneUndefined = UndefinedDisabled, + LengthFlexDirection flexDirection = FlexDirectionDisabled> +class ApplyPropertyLength { +public: + static void setValue(RenderStyle* style, Length value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) { + if (!flexDirection || !value->isFlexValue()) + return; + + CSSFlexValue* flexValue = static_cast<CSSFlexValue*>(value); + value = flexValue->preferredSize(); + + if (flexDirection == FlexWidth) { + selector->style()->setFlexboxWidthPositiveFlex(flexValue->positiveFlex()); + selector->style()->setFlexboxWidthNegativeFlex(flexValue->negativeFlex()); + } else if (flexDirection == FlexHeight) { + selector->style()->setFlexboxHeightPositiveFlex(flexValue->positiveFlex()); + selector->style()->setFlexboxHeightNegativeFlex(flexValue->negativeFlex()); + } + } + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (noneEnabled && primitiveValue->getIdent() == CSSValueNone) + if (noneUndefined) + setValue(selector->style(), Length(Undefined)); + else + setValue(selector->style(), Length()); + else if (intrinsicEnabled && primitiveValue->getIdent() == CSSValueIntrinsic) + setValue(selector->style(), Length(Intrinsic)); + else if (minIntrinsicEnabled && primitiveValue->getIdent() == CSSValueMinIntrinsic) + setValue(selector->style(), Length(MinIntrinsic)); + else if (autoEnabled && primitiveValue->getIdent() == CSSValueAuto) + setValue(selector->style(), Length()); + else { + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) { + Length length = primitiveValue->computeLength<Length>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom()); + length.setQuirk(primitiveValue->isQuirkValue()); + setValue(selector->style(), length); + } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) + setValue(selector->style(), Length(primitiveValue->getDoubleValue(), Percent)); + } + } + + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<Length, getterFunction, Length, setterFunction, Length, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum StringIdentBehavior { NothingMapsToNull = 0, MapNoneToNull, MapAutoToNull }; +template <StringIdentBehavior identBehavior, const AtomicString& (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(const AtomicString&), const AtomicString& (*initialFunction)()> +class ApplyPropertyString { +public: + static void setValue(RenderStyle* style, const AtomicString& value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if ((identBehavior == MapNoneToNull && primitiveValue->getIdent() == CSSValueNone) + || (identBehavior == MapAutoToNull && primitiveValue->getIdent() == CSSValueAuto)) + setValue(selector->style(), nullAtom); + else + setValue(selector->style(), primitiveValue->getStringValue()); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<const AtomicString&, getterFunction, const AtomicString&, setterFunction, const AtomicString&, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +template <LengthSize (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(LengthSize), LengthSize (*initialFunction)()> +class ApplyPropertyBorderRadius { +public: + static void setValue(RenderStyle* style, LengthSize value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + 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()->computeLength<int>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom()))), Fixed); + if (pair->second()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + radiusHeight = Length(pair->second()->getDoubleValue(), Percent); + else + radiusHeight = Length(max(intMinForLength, min(intMaxForLength, pair->second()->computeLength<int>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom()))), Fixed); + int width = radiusWidth.value(); + int height = radiusHeight.value(); + if (width < 0 || height < 0) + return; + if (!width) + radiusHeight = radiusWidth; // Null out the other value. + else if (!height) + radiusWidth = radiusHeight; // Null out the other value. + + LengthSize size(radiusWidth, radiusHeight); + setValue(selector->style(), size); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<LengthSize, getterFunction, LengthSize, setterFunction, LengthSize, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +template <typename T> +struct FillLayerAccessorTypes { + typedef T Setter; + typedef T Getter; +}; + +template <> +struct FillLayerAccessorTypes<StyleImage*> { + typedef PassRefPtr<StyleImage> Setter; + typedef StyleImage* Getter; +}; + +template <typename T, + CSSPropertyID propertyId, + EFillLayerType fillLayerType, + FillLayer* (RenderStyle::*accessLayersFunction)(), + const FillLayer* (RenderStyle::*layersFunction)() const, + bool (FillLayer::*testFunction)() const, + typename FillLayerAccessorTypes<T>::Getter (FillLayer::*getFunction)() const, + void (FillLayer::*setFunction)(typename FillLayerAccessorTypes<T>::Setter), + void (FillLayer::*clearFunction)(), + typename FillLayerAccessorTypes<T>::Getter (*initialFunction)(EFillLayerType), + void (CSSStyleSelector::*mapFillFunction)(CSSPropertyID, FillLayer*, CSSValue*)> +class ApplyPropertyFillLayer { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + FillLayer* currChild = (selector->style()->*accessLayersFunction)(); + FillLayer* prevChild = 0; + const FillLayer* currParent = (selector->parentStyle()->*layersFunction)(); + while (currParent && (currParent->*testFunction)()) { + if (!currChild) { + /* Need to make a new layer.*/ + currChild = new FillLayer(fillLayerType); + prevChild->setNext(currChild); + } + (currChild->*setFunction)((currParent->*getFunction)()); + prevChild = currChild; + currChild = prevChild->next(); + currParent = currParent->next(); + } + + while (currChild) { + /* Reset any remaining layers to not have the property set. */ + (currChild->*clearFunction)(); + currChild = currChild->next(); + } + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + FillLayer* currChild = (selector->style()->*accessLayersFunction)(); + (currChild->*setFunction)((*initialFunction)(fillLayerType)); + for (currChild = currChild->next(); currChild; currChild = currChild->next()) + (currChild->*clearFunction)(); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + FillLayer* currChild = (selector->style()->*accessLayersFunction)(); + 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(fillLayerType); + prevChild->setNext(currChild); + } + (selector->*mapFillFunction)(propertyId, currChild, valueList->itemWithoutBoundsCheck(i)); + prevChild = currChild; + currChild = currChild->next(); + } + } else { + (selector->*mapFillFunction)(propertyId, currChild, value); + currChild = currChild->next(); + } + while (currChild) { + /* Reset all remaining layers to not have the property set. */ + (currChild->*clearFunction)(); + currChild = currChild->next(); + } + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +enum ComputeLengthNormal {NormalDisabled = 0, NormalEnabled}; +enum ComputeLengthThickness {ThicknessDisabled = 0, ThicknessEnabled}; +enum ComputeLengthSVGZoom {SVGZoomDisabled = 0, SVGZoomEnabled}; +template <typename T, + T (RenderStyle::*getterFunction)() const, + void (RenderStyle::*setterFunction)(T), + T (*initialFunction)(), + ComputeLengthNormal normalEnabled = NormalDisabled, + ComputeLengthThickness thicknessEnabled = ThicknessDisabled, + ComputeLengthSVGZoom svgZoomEnabled = SVGZoomDisabled> +class ApplyPropertyComputeLength { +public: + static void setValue(RenderStyle* style, T value) { (style->*setterFunction)(value); } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + // note: CSSPropertyLetter/WordSpacing right now sets to zero if it's not a primitive value for some reason... + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + int ident = primitiveValue->getIdent(); + T length; + if (normalEnabled && ident == CSSValueNormal) { + length = 0; + } else if (thicknessEnabled && ident == CSSValueThin) { + length = 1; + } else if (thicknessEnabled && ident == CSSValueMedium) { + length = 3; + } else if (thicknessEnabled && ident == CSSValueThick) { + length = 5; + } else if (ident == CSSValueInvalid) { + float zoom = (svgZoomEnabled && selector->useSVGZoomRules()) ? 1.0f : selector->style()->effectiveZoom(); + length = primitiveValue->computeLength<T>(selector->style(), selector->rootElementStyle(), zoom); + } else { + ASSERT_NOT_REACHED(); + length = 0; + } + + setValue(selector->style(), length); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<T, getterFunction, T, setterFunction, T, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +template <typename T, T (FontDescription::*getterFunction)() const, void (FontDescription::*setterFunction)(T), T initialValue> +class ApplyPropertyFont { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + FontDescription fontDescription = selector->fontDescription(); + (fontDescription.*setterFunction)((selector->parentFontDescription().*getterFunction)()); + selector->setFontDescription(fontDescription); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + FontDescription fontDescription = selector->fontDescription(); + (fontDescription.*setterFunction)(initialValue); + selector->setFontDescription(fontDescription); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + FontDescription fontDescription = selector->fontDescription(); + (fontDescription.*setterFunction)(*primitiveValue); + selector->setFontDescription(fontDescription); + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyFontSize { +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. + static float largerFontSize(float size) + { + // 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; + } + + // Like the previous function, but for the keyword "smaller". + static float smallerFontSize(float size) + { + // 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; + } +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + float size = selector->parentStyle()->fontDescription().specifiedSize(); + + if (size < 0) + return; + + FontDescription fontDescription = selector->style()->fontDescription(); + fontDescription.setKeywordSize(selector->parentStyle()->fontDescription().keywordSize()); + selector->setFontSize(fontDescription, size); + selector->setFontDescription(fontDescription); + return; + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + FontDescription fontDescription = selector->style()->fontDescription(); + float size = selector->fontSizeForKeyword(selector->document(), CSSValueMedium, fontDescription.useFixedDefaultSize()); + + if (size < 0) + return; + + fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); + selector->setFontSize(fontDescription, size); + selector->setFontDescription(fontDescription); + return; + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + FontDescription fontDescription = selector->style()->fontDescription(); + fontDescription.setKeywordSize(0); + float parentSize = 0; + bool parentIsAbsoluteSize = false; + float size = 0; + + if (selector->hasParentNode()) { + parentSize = selector->parentStyle()->fontDescription().specifiedSize(); + parentIsAbsoluteSize = selector->parentStyle()->fontDescription().isAbsoluteSize(); + } + + if (int ident = primitiveValue->getIdent()) { + // Keywords are being used. + switch (ident) { + case CSSValueXxSmall: + case CSSValueXSmall: + case CSSValueSmall: + case CSSValueMedium: + case CSSValueLarge: + case CSSValueXLarge: + case CSSValueXxLarge: + case CSSValueWebkitXxxLarge: + size = selector->fontSizeForKeyword(selector->document(), ident, fontDescription.useFixedDefaultSize()); + fontDescription.setKeywordSize(ident - CSSValueXxSmall + 1); + break; + case CSSValueLarger: + size = largerFontSize(parentSize); + break; + case CSSValueSmaller: + size = smallerFontSize(parentSize); + break; + default: + return; + } + + fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && (ident == CSSValueLarger || ident == 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 (primitiveValue->isLength()) + size = primitiveValue->computeLength<float>(selector->parentStyle(), selector->rootElementStyle(), 1.0, true); + else if (primitiveValue->isPercentage()) + size = (primitiveValue->getFloatValue() * parentSize) / 100.0f; + else + return; + } + + if (size < 0) + return; + + selector->setFontSize(fontDescription, size); + selector->setFontDescription(fontDescription); + return; + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyFontWeight { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + FontDescription fontDescription = selector->fontDescription(); + switch (primitiveValue->getIdent()) { + case CSSValueInvalid: + ASSERT_NOT_REACHED(); + break; + case CSSValueBolder: + fontDescription.setWeight(fontDescription.bolderWeight()); + break; + case CSSValueLighter: + fontDescription.setWeight(fontDescription.lighterWeight()); + break; + default: + fontDescription.setWeight(*primitiveValue); + } + selector->setFontDescription(fontDescription); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyFont<FontWeight, &FontDescription::weight, &FontDescription::setWeight, FontWeightNormal>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum BorderImageType { Image = 0, Mask }; +template <BorderImageType borderImageType, + CSSPropertyID property, + const NinePieceImage& (RenderStyle::*getterFunction)() const, + void (RenderStyle::*setterFunction)(const NinePieceImage&)> +class ApplyPropertyBorderImage { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + NinePieceImage image; + if (borderImageType == Mask) + image.setMaskDefaults(); + selector->mapNinePieceImage(property, value, image); + (selector->style()->*setterFunction)(image); + } + + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<const NinePieceImage&, getterFunction, const NinePieceImage&, setterFunction, NinePieceImage, &RenderStyle::initialNinePieceImage>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum BorderImageModifierType { Outset, Repeat, Slice, Width }; +template <BorderImageType type, BorderImageModifierType modifier> +class ApplyPropertyBorderImageModifier { +private: + static inline const NinePieceImage& getValue(RenderStyle* style) { return type == Image ? style->borderImage() : style->maskBoxImage(); } + static inline void setValue(RenderStyle* style, const NinePieceImage& value) { return type == Image ? style->setBorderImage(value) : style->setMaskBoxImage(value); } +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + NinePieceImage image(getValue(selector->style())); + switch (modifier) { + case Outset: + image.copyOutsetFrom(getValue(selector->parentStyle())); + break; + case Repeat: + image.copyRepeatFrom(getValue(selector->parentStyle())); + break; + case Slice: + image.copyImageSlicesFrom(getValue(selector->parentStyle())); + break; + case Width: + image.copyBorderSlicesFrom(getValue(selector->parentStyle())); + break; + } + setValue(selector->style(), image); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + NinePieceImage image(getValue(selector->style())); + switch (modifier) { + case Outset: + image.setOutset(LengthBox()); + break; + case Repeat: + image.setHorizontalRule(StretchImageRule); + image.setVerticalRule(StretchImageRule); + break; + case Slice: + // Masks have a different initial value for slices. Preserve the value of 0 for backwards compatibility. + image.setImageSlices(type == Image ? LengthBox(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent)) : LengthBox()); + image.setFill(false); + break; + case Width: + // Masks have a different initial value for widths. They use an 'auto' value rather than trying to fit to the border. + image.setBorderSlices(type == Image ? LengthBox(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative)) : LengthBox()); + break; + } + setValue(selector->style(), image); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + NinePieceImage image(getValue(selector->style())); + switch (modifier) { + case Outset: + image.setOutset(selector->mapNinePieceImageQuad(value)); + break; + case Repeat: + selector->mapNinePieceImageRepeat(value, image); + break; + case Slice: + selector->mapNinePieceImageSlice(value, image); + break; + case Width: + image.setBorderSlices(selector->mapNinePieceImageQuad(value)); + break; + } + setValue(selector->style(), image); + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +template <CSSPropertyID id, StyleImage* (RenderStyle::*getterFunction)() const, void (RenderStyle::*setterFunction)(PassRefPtr<StyleImage>), StyleImage* (*initialFunction)()> +class ApplyPropertyBorderImageSource { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) { (selector->style()->*setterFunction)(selector->styleImage(id, value)); } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<StyleImage*, getterFunction, PassRefPtr<StyleImage>, setterFunction, StyleImage*, initialFunction>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +enum CounterBehavior {Increment = 0, Reset}; +template <CounterBehavior counterBehavior> +class ApplyPropertyCounter { +public: + static void emptyFunction(CSSStyleSelector*) { } + static void applyInheritValue(CSSStyleSelector* selector) + { + CounterDirectiveMap& map = selector->style()->accessCounterDirectives(); + CounterDirectiveMap& parentMap = selector->parentStyle()->accessCounterDirectives(); + + typedef CounterDirectiveMap::iterator Iterator; + Iterator end = parentMap.end(); + for (Iterator it = parentMap.begin(); it != end; ++it) { + CounterDirectives& directives = map.add(it->first, CounterDirectives()).first->second; + if (counterBehavior == Reset) { + directives.m_reset = it->second.m_reset; + directives.m_resetValue = it->second.m_resetValue; + } else { + // Inheriting a counter-increment means taking the parent's current value for the counter + // and adding it to itself. + directives.m_increment = it->second.m_increment; + directives.m_incrementValue = 0; + if (directives.m_increment) { + float incrementValue = directives.m_incrementValue; + directives.m_incrementValue = clampToInteger(incrementValue + it->second.m_incrementValue); + } else { + directives.m_increment = true; + directives.m_incrementValue = it->second.m_incrementValue; + } + } + } + } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isValueList()) + return; + + CSSValueList* list = static_cast<CSSValueList*>(value); + + CounterDirectiveMap& map = selector->style()->accessCounterDirectives(); + typedef CounterDirectiveMap::iterator Iterator; + + Iterator end = map.end(); + for (Iterator it = map.begin(); it != end; ++it) + if (counterBehavior == Reset) + 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(); + int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue(); + CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second; + if (counterBehavior == Reset) { + directives.m_reset = true; + directives.m_resetValue = value; + } else { + if (directives.m_increment) { + float incrementValue = directives.m_incrementValue; + directives.m_incrementValue = clampToInteger(incrementValue + value); + } else { + directives.m_increment = true; + directives.m_incrementValue = value; + } + } + + } + } + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &emptyFunction, &applyValue); } +}; + + +class ApplyPropertyCursor { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + selector->style()->setCursor(selector->parentStyle()->cursor()); + selector->style()->setCursorList(selector->parentStyle()->cursors()); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + selector->style()->clearCursorList(); + selector->style()->setCursor(RenderStyle::initialCursor()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + selector->style()->clearCursorList(); + if (value->isValueList()) { + CSSValueList* list = static_cast<CSSValueList*>(value); + int len = list->length(); + selector->style()->setCursor(CURSOR_AUTO); + for (int i = 0; i < len; i++) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (!item->isPrimitiveValue()) + continue; + CSSPrimitiveValue* 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(selector->element())) // Elements with SVG cursors are not allowed to share style. + selector->style()->setUnique(); + selector->style()->addCursor(selector->cachedOrPendingFromValue(CSSPropertyCursor, image), image->hotSpot()); + } + } else if (type == CSSPrimitiveValue::CSS_IDENT) + selector->style()->setCursor(*primitiveValue); + } + } else if (value->isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + int type = primitiveValue->primitiveType(); + if (type == CSSPrimitiveValue::CSS_IDENT && selector->style()->cursor() != ECursor(*primitiveValue)) + selector->style()->setCursor(*primitiveValue); + } + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyTextAlign { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + if (primitiveValue->getIdent() != CSSValueWebkitMatchParent) + selector->style()->setTextAlign(*primitiveValue); + else if (selector->parentStyle()->textAlign() == TASTART) + selector->style()->setTextAlign(selector->parentStyle()->isLeftToRightDirection() ? LEFT : RIGHT); + else if (selector->parentStyle()->textAlign() == TAEND) + selector->style()->setTextAlign(selector->parentStyle()->isLeftToRightDirection() ? RIGHT : LEFT); + else + selector->style()->setTextAlign(selector->parentStyle()->textAlign()); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<ETextAlign, &RenderStyle::textAlign, ETextAlign, &RenderStyle::setTextAlign, ETextAlign, &RenderStyle::initialTextAlign>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +class ApplyPropertyTextDecoration { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + ETextDecoration t = RenderStyle::initialTextDecoration(); + for (CSSValueListIterator i(value); i.hasMore(); i.advance()) { + CSSValue* item = i.value(); + ASSERT(item->isPrimitiveValue()); + t |= *static_cast<CSSPrimitiveValue*>(item); + } + selector->style()->setTextDecoration(t); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<ETextDecoration, &RenderStyle::textDecoration, ETextDecoration, &RenderStyle::setTextDecoration, ETextDecoration, &RenderStyle::initialTextDecoration>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +class ApplyPropertyLineHeight { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + Length lineHeight; + + if (primitiveValue->getIdent() == CSSValueNormal) + lineHeight = Length(-100.0, Percent); + else if (primitiveValue->isLength()) { + double multiplier = selector->style()->effectiveZoom(); + if (selector->style()->textSizeAdjust()) { + if (Frame* frame = selector->document()->frame()) + multiplier *= frame->textZoomFactor(); + } + lineHeight = primitiveValue->computeLength<Length>(selector->style(), selector->rootElementStyle(), multiplier); + } else if (primitiveValue->isPercentage()) { + // FIXME: percentage should not be restricted to an integer here. + lineHeight = Length((selector->style()->fontSize() * primitiveValue->getIntValue()) / 100, Fixed); + } else if (primitiveValue->isNumber()) { + // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent). + lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent); + } else + return; + selector->style()->setLineHeight(lineHeight); + } + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<Length, &RenderStyle::lineHeight, Length, &RenderStyle::setLineHeight, Length, &RenderStyle::initialLineHeight>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +class ApplyPropertyPageSize { +private: + static Length mmLength(double mm) { return CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM)->computeLength<Length>(0, 0); } + static Length inchLength(double inch) { return CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN)->computeLength<Length>(0, 0); } + static bool getPageSizeFromName(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) + 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) { + switch (pageOrientation->getIdent()) { + case CSSValueLandscape: + std::swap(width, height); + break; + case CSSValuePortrait: + // Nothing to do. + break; + default: + return false; + } + } + return true; + } +public: + static void applyInheritValue(CSSStyleSelector*) { } + static void applyInitialValue(CSSStyleSelector*) { } + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + selector->style()->resetPageSizeType(); + Length width; + Length height; + PageSizeType pageSizeType = PAGE_SIZE_AUTO; + CSSValueListInspector inspector(value); + switch (inspector.length()) { + case 2: { + // <length>{2} | <page-size> <orientation> + if (!inspector.first()->isPrimitiveValue() || !inspector.second()->isPrimitiveValue()) + return; + CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(inspector.first()); + CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(inspector.second()); + if (first->isLength()) { + // <length>{2} + if (!second->isLength()) + return; + width = first->computeLength<Length>(selector->style(), selector->rootElementStyle()); + height = second->computeLength<Length>(selector->style(), selector->rootElementStyle()); + } else { + // <page-size> <orientation> + // The value order is guaranteed. See CSSParser::parseSizeParameter. + if (!getPageSizeFromName(first, second, width, height)) + return; + } + pageSizeType = PAGE_SIZE_RESOLVED; + break; + } + case 1: { + // <length> | auto | <page-size> | [ portrait | landscape] + if (!inspector.first()->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(inspector.first()); + if (primitiveValue->isLength()) { + // <length> + pageSizeType = PAGE_SIZE_RESOLVED; + width = height = primitiveValue->computeLength<Length>(selector->style(), selector->rootElementStyle()); + } else { + if (primitiveValue->primitiveType() != 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 (!getPageSizeFromName(primitiveValue, 0, width, height)) + return; + } + } + break; + } + default: + return; + } + selector->style()->setPageSizeType(pageSizeType); + selector->style()->setPageSize(LengthSize(width, height)); + } + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyTextEmphasisStyle { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + selector->style()->setTextEmphasisFill(selector->parentStyle()->textEmphasisFill()); + selector->style()->setTextEmphasisMark(selector->parentStyle()->textEmphasisMark()); + selector->style()->setTextEmphasisCustomMark(selector->parentStyle()->textEmphasisCustomMark()); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + selector->style()->setTextEmphasisFill(RenderStyle::initialTextEmphasisFill()); + selector->style()->setTextEmphasisMark(RenderStyle::initialTextEmphasisMark()); + selector->style()->setTextEmphasisCustomMark(RenderStyle::initialTextEmphasisCustomMark()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + 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) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (!item->isPrimitiveValue()) + continue; + + CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(item); + if (value->getIdent() == CSSValueFilled || value->getIdent() == CSSValueOpen) + selector->style()->setTextEmphasisFill(*value); + else + selector->style()->setTextEmphasisMark(*value); + } + selector->style()->setTextEmphasisCustomMark(nullAtom); + return; + } + + if (!value->isPrimitiveValue()) + return; + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING) { + selector->style()->setTextEmphasisFill(TextEmphasisFillFilled); + selector->style()->setTextEmphasisMark(TextEmphasisMarkCustom); + selector->style()->setTextEmphasisCustomMark(primitiveValue->getStringValue()); + return; + } + + selector->style()->setTextEmphasisCustomMark(nullAtom); + + if (primitiveValue->getIdent() == CSSValueFilled || primitiveValue->getIdent() == CSSValueOpen) { + selector->style()->setTextEmphasisFill(*primitiveValue); + selector->style()->setTextEmphasisMark(TextEmphasisMarkAuto); + } else { + selector->style()->setTextEmphasisFill(TextEmphasisFillFilled); + selector->style()->setTextEmphasisMark(*primitiveValue); + } + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +template <typename T, + T (Animation::*getterFunction)() const, + void (Animation::*setterFunction)(T), + bool (Animation::*testFunction)() const, + void (Animation::*clearFunction)(), + T (*initialFunction)(), + void (CSSStyleSelector::*mapFunction)(Animation*, CSSValue*), + AnimationList* (RenderStyle::*animationGetterFunction)(), + const AnimationList* (RenderStyle::*immutableAnimationGetterFunction)() const> +class ApplyPropertyAnimation { +public: + static void setValue(Animation* animation, T value) { (animation->*setterFunction)(value); } + static T value(const Animation* animation) { return (animation->*getterFunction)(); } + static bool test(const Animation* animation) { return (animation->*testFunction)(); } + static void clear(Animation* animation) { (animation->*clearFunction)(); } + static T initial() { return (*initialFunction)(); } + static void map(CSSStyleSelector* selector, Animation* animation, CSSValue* value) { (selector->*mapFunction)(animation, value); } + static AnimationList* accessAnimations(RenderStyle* style) { return (style->*animationGetterFunction)(); } + static const AnimationList* animations(RenderStyle* style) { return (style->*immutableAnimationGetterFunction)(); } + + static void applyInheritValue(CSSStyleSelector* selector) + { + AnimationList* list = accessAnimations(selector->style()); + const AnimationList* parentList = animations(selector->parentStyle()); + size_t i = 0, parentSize = parentList ? parentList->size() : 0; + for ( ; i < parentSize && test(parentList->animation(i)); ++i) { + if (list->size() <= i) + list->append(Animation::create()); + setValue(list->animation(i), value(parentList->animation(i))); + } + + /* Reset any remaining animations to not have the property set. */ + for ( ; i < list->size(); ++i) + clear(list->animation(i)); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + AnimationList* list = accessAnimations(selector->style()); + if (list->isEmpty()) + list->append(Animation::create()); + setValue(list->animation(0), initial()); + for (size_t i = 1; i < list->size(); ++i) + clear(list->animation(i)); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + AnimationList* list = accessAnimations(selector->style()); + size_t childIndex = 0; + if (value->isValueList()) { + /* Walk each value and put it into an animation, creating new animations as needed. */ + for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { + if (childIndex <= list->size()) + list->append(Animation::create()); + map(selector, list->animation(childIndex), i.value()); + ++childIndex; + } + } else { + if (list->isEmpty()) + list->append(Animation::create()); + map(selector, list->animation(childIndex), value); + childIndex = 1; + } + for ( ; childIndex < list->size(); ++childIndex) { + /* Reset all remaining animations to not have the property set. */ + clear(list->animation(childIndex)); + } + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyOutlineStyle { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + ApplyPropertyDefaultBase<OutlineIsAuto, &RenderStyle::outlineStyleIsAuto, OutlineIsAuto, &RenderStyle::setOutlineStyleIsAuto, OutlineIsAuto, &RenderStyle::initialOutlineStyleIsAuto>::applyInheritValue(selector); + ApplyPropertyDefaultBase<EBorderStyle, &RenderStyle::outlineStyle, EBorderStyle, &RenderStyle::setOutlineStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::applyInheritValue(selector); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + ApplyPropertyDefaultBase<OutlineIsAuto, &RenderStyle::outlineStyleIsAuto, OutlineIsAuto, &RenderStyle::setOutlineStyleIsAuto, OutlineIsAuto, &RenderStyle::initialOutlineStyleIsAuto>::applyInitialValue(selector); + ApplyPropertyDefaultBase<EBorderStyle, &RenderStyle::outlineStyle, EBorderStyle, &RenderStyle::setOutlineStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::applyInitialValue(selector); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + ApplyPropertyDefault<OutlineIsAuto, &RenderStyle::outlineStyleIsAuto, OutlineIsAuto, &RenderStyle::setOutlineStyleIsAuto, OutlineIsAuto, &RenderStyle::initialOutlineStyleIsAuto>::applyValue(selector, value); + ApplyPropertyDefault<EBorderStyle, &RenderStyle::outlineStyle, EBorderStyle, &RenderStyle::setOutlineStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::applyValue(selector, value); + } + + static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } +}; + +class ApplyPropertyResize { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + EResize r = RESIZE_NONE; + switch (primitiveValue->getIdent()) { + case 0: + return; + case CSSValueAuto: + if (Settings* settings = selector->document()->settings()) + r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE; + break; + default: + r = *primitiveValue; + } + selector->style()->setResize(r); + } + + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<EResize, &RenderStyle::resize, EResize, &RenderStyle::setResize, EResize, &RenderStyle::initialResize>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +class ApplyPropertyVerticalAlign { +public: + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + if (primitiveValue->getIdent()) + return selector->style()->setVerticalAlign(*primitiveValue); + + Length length; + if (primitiveValue->isLength()) + length = primitiveValue->computeLength<Length>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom()); + else if (primitiveValue->isPercentage()) + length = Length(primitiveValue->getDoubleValue(), Percent); + + selector->style()->setVerticalAlignLength(length); + } + + static PropertyHandler createHandler() + { + PropertyHandler handler = ApplyPropertyDefaultBase<EVerticalAlign, &RenderStyle::verticalAlign, EVerticalAlign, &RenderStyle::setVerticalAlign, EVerticalAlign, &RenderStyle::initialVerticalAlign>::createHandler(); + return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); + } +}; + +class ApplyPropertyAspectRatio { +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + if (!selector->parentStyle()->hasAspectRatio()) + return; + selector->style()->setHasAspectRatio(true); + selector->style()->setAspectRatioDenominator(selector->parentStyle()->aspectRatioDenominator()); + selector->style()->setAspectRatioNumerator(selector->parentStyle()->aspectRatioNumerator()); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + selector->style()->setHasAspectRatio(RenderStyle::initialHasAspectRatio()); + selector->style()->setAspectRatioDenominator(RenderStyle::initialAspectRatioDenominator()); + selector->style()->setAspectRatioNumerator(RenderStyle::initialAspectRatioNumerator()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isAspectRatioValue()) { + selector->style()->setHasAspectRatio(false); + return; + } + CSSAspectRatioValue* aspectRatioValue = static_cast<CSSAspectRatioValue*>(value); + selector->style()->setHasAspectRatio(true); + selector->style()->setAspectRatioDenominator(aspectRatioValue->denominatorValue()); + selector->style()->setAspectRatioNumerator(aspectRatioValue->numeratorValue()); + } + + static PropertyHandler createHandler() + { + return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); + } +}; + +class ApplyPropertyZoom { +private: + static void resetEffectiveZoom(CSSStyleSelector* selector) + { + // Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect. + selector->setEffectiveZoom(selector->parentStyle() ? selector->parentStyle()->effectiveZoom() : RenderStyle::initialZoom()); + } + +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + resetEffectiveZoom(selector); + selector->setZoom(selector->parentStyle()->zoom()); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + resetEffectiveZoom(selector); + selector->setZoom(RenderStyle::initialZoom()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + ASSERT(value->isPrimitiveValue()); + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + if (primitiveValue->getIdent() == CSSValueNormal) { + resetEffectiveZoom(selector); + selector->setZoom(RenderStyle::initialZoom()); + } else if (primitiveValue->getIdent() == CSSValueReset) { + selector->setEffectiveZoom(RenderStyle::initialZoom()); + selector->setZoom(RenderStyle::initialZoom()); + } else if (primitiveValue->getIdent() == CSSValueDocument) { + float docZoom = selector->document()->renderer()->style()->zoom(); + selector->setEffectiveZoom(docZoom); + selector->setZoom(docZoom); + } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) { + resetEffectiveZoom(selector); + if (float percent = primitiveValue->getFloatValue()) + selector->setZoom(percent / 100.0f); + } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + resetEffectiveZoom(selector); + if (float number = primitiveValue->getFloatValue()) + selector->setZoom(number); + } + } + + static PropertyHandler createHandler() + { + return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); + } +}; + +class ApplyPropertyDisplay { +private: + static inline bool isValidDisplayValue(CSSStyleSelector* selector, EDisplay displayPropertyValue) + { +#if ENABLE(SVG) + if (selector->element() && selector->element()->isSVGElement() && selector->style()->styleType() == NOPSEUDO) + return (displayPropertyValue == INLINE || displayPropertyValue == BLOCK || displayPropertyValue == NONE); +#endif + return true; + } +public: + static void applyInheritValue(CSSStyleSelector* selector) + { + EDisplay display = selector->parentStyle()->display(); + if (!isValidDisplayValue(selector, display)) + return; + selector->style()->setDisplay(display); + } + + static void applyInitialValue(CSSStyleSelector* selector) + { + selector->style()->setDisplay(RenderStyle::initialDisplay()); + } + + static void applyValue(CSSStyleSelector* selector, CSSValue* value) + { + if (!value->isPrimitiveValue()) + return; + + EDisplay display = *static_cast<CSSPrimitiveValue*>(value); + + if (!isValidDisplayValue(selector, display)) + return; + + selector->style()->setDisplay(display); + } + + static PropertyHandler createHandler() + { + return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); + } +}; + +const CSSStyleApplyProperty& CSSStyleApplyProperty::sharedCSSStyleApplyProperty() +{ + DEFINE_STATIC_LOCAL(CSSStyleApplyProperty, cssStyleApplyPropertyInstance, ()); + return cssStyleApplyPropertyInstance; +} + +CSSStyleApplyProperty::CSSStyleApplyProperty() +{ + for (int i = 0; i < numCSSProperties; ++i) + m_propertyMap[i] = PropertyHandler(); + + setPropertyHandler(CSSPropertyWebkitAspectRatio, ApplyPropertyAspectRatio::createHandler()); + + setPropertyHandler(CSSPropertyColor, ApplyPropertyColor<InheritFromParent, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::setVisitedLinkColor, &RenderStyle::invalidColor, RenderStyle::initialColor>::createHandler()); + setPropertyHandler(CSSPropertyDirection, ApplyPropertyDirection<&RenderStyle::direction, &RenderStyle::setDirection, RenderStyle::initialDirection>::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundAttachment, ApplyPropertyFillLayer<EFillAttachment, CSSPropertyBackgroundAttachment, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isAttachmentSet, &FillLayer::attachment, &FillLayer::setAttachment, &FillLayer::clearAttachment, &FillLayer::initialFillAttachment, &CSSStyleSelector::mapFillAttachment>::createHandler()); + setPropertyHandler(CSSPropertyBackgroundClip, ApplyPropertyFillLayer<EFillBox, CSSPropertyBackgroundClip, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isClipSet, &FillLayer::clip, &FillLayer::setClip, &FillLayer::clearClip, &FillLayer::initialFillClip, &CSSStyleSelector::mapFillClip>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBackgroundClip, CSSPropertyBackgroundClip); + setPropertyHandler(CSSPropertyWebkitBackgroundComposite, ApplyPropertyFillLayer<CompositeOperator, CSSPropertyWebkitBackgroundComposite, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isCompositeSet, &FillLayer::composite, &FillLayer::setComposite, &FillLayer::clearComposite, &FillLayer::initialFillComposite, &CSSStyleSelector::mapFillComposite>::createHandler()); + + setPropertyHandler(CSSPropertyDisplay, ApplyPropertyDisplay::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundImage, ApplyPropertyFillLayer<StyleImage*, CSSPropertyBackgroundImage, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isImageSet, &FillLayer::image, &FillLayer::setImage, &FillLayer::clearImage, &FillLayer::initialFillImage, &CSSStyleSelector::mapFillImage>::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundOrigin, ApplyPropertyFillLayer<EFillBox, CSSPropertyBackgroundOrigin, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isOriginSet, &FillLayer::origin, &FillLayer::setOrigin, &FillLayer::clearOrigin, &FillLayer::initialFillOrigin, &CSSStyleSelector::mapFillOrigin>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBackgroundOrigin, CSSPropertyBackgroundOrigin); + + setPropertyHandler(CSSPropertyBackgroundPositionX, ApplyPropertyFillLayer<Length, CSSPropertyBackgroundPositionX, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isXPositionSet, &FillLayer::xPosition, &FillLayer::setXPosition, &FillLayer::clearXPosition, &FillLayer::initialFillXPosition, &CSSStyleSelector::mapFillXPosition>::createHandler()); + setPropertyHandler(CSSPropertyBackgroundPositionY, ApplyPropertyFillLayer<Length, CSSPropertyBackgroundPositionY, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isYPositionSet, &FillLayer::yPosition, &FillLayer::setYPosition, &FillLayer::clearYPosition, &FillLayer::initialFillYPosition, &CSSStyleSelector::mapFillYPosition>::createHandler()); + setPropertyHandler(CSSPropertyBackgroundPosition, ApplyPropertyExpanding<SuppressValue, CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY>::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundRepeatX, ApplyPropertyFillLayer<EFillRepeat, CSSPropertyBackgroundRepeatX, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isRepeatXSet, &FillLayer::repeatX, &FillLayer::setRepeatX, &FillLayer::clearRepeatX, &FillLayer::initialFillRepeatX, &CSSStyleSelector::mapFillRepeatX>::createHandler()); + setPropertyHandler(CSSPropertyBackgroundRepeatY, ApplyPropertyFillLayer<EFillRepeat, CSSPropertyBackgroundRepeatY, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isRepeatYSet, &FillLayer::repeatY, &FillLayer::setRepeatY, &FillLayer::clearRepeatY, &FillLayer::initialFillRepeatY, &CSSStyleSelector::mapFillRepeatY>::createHandler()); + setPropertyHandler(CSSPropertyBackgroundRepeat, ApplyPropertyExpanding<SuppressValue, CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY>::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundSize, ApplyPropertyFillLayer<FillSize, CSSPropertyBackgroundSize, BackgroundFillLayer, &RenderStyle::accessBackgroundLayers, &RenderStyle::backgroundLayers, + &FillLayer::isSizeSet, &FillLayer::size, &FillLayer::setSize, &FillLayer::clearSize, &FillLayer::initialFillSize, &CSSStyleSelector::mapFillSize>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBackgroundSize, CSSPropertyBackgroundSize); + + setPropertyHandler(CSSPropertyWebkitMaskAttachment, ApplyPropertyFillLayer<EFillAttachment, CSSPropertyWebkitMaskAttachment, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isAttachmentSet, &FillLayer::attachment, &FillLayer::setAttachment, &FillLayer::clearAttachment, &FillLayer::initialFillAttachment, &CSSStyleSelector::mapFillAttachment>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskClip, ApplyPropertyFillLayer<EFillBox, CSSPropertyWebkitMaskClip, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isClipSet, &FillLayer::clip, &FillLayer::setClip, &FillLayer::clearClip, &FillLayer::initialFillClip, &CSSStyleSelector::mapFillClip>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskComposite, ApplyPropertyFillLayer<CompositeOperator, CSSPropertyWebkitMaskComposite, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isCompositeSet, &FillLayer::composite, &FillLayer::setComposite, &FillLayer::clearComposite, &FillLayer::initialFillComposite, &CSSStyleSelector::mapFillComposite>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitMaskImage, ApplyPropertyFillLayer<StyleImage*, CSSPropertyWebkitMaskImage, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isImageSet, &FillLayer::image, &FillLayer::setImage, &FillLayer::clearImage, &FillLayer::initialFillImage, &CSSStyleSelector::mapFillImage>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitMaskOrigin, ApplyPropertyFillLayer<EFillBox, CSSPropertyWebkitMaskOrigin, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isOriginSet, &FillLayer::origin, &FillLayer::setOrigin, &FillLayer::clearOrigin, &FillLayer::initialFillOrigin, &CSSStyleSelector::mapFillOrigin>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskSize, ApplyPropertyFillLayer<FillSize, CSSPropertyWebkitMaskSize, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isSizeSet, &FillLayer::size, &FillLayer::setSize, &FillLayer::clearSize, &FillLayer::initialFillSize, &CSSStyleSelector::mapFillSize>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitMaskPositionX, ApplyPropertyFillLayer<Length, CSSPropertyWebkitMaskPositionX, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isXPositionSet, &FillLayer::xPosition, &FillLayer::setXPosition, &FillLayer::clearXPosition, &FillLayer::initialFillXPosition, &CSSStyleSelector::mapFillXPosition>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskPositionY, ApplyPropertyFillLayer<Length, CSSPropertyWebkitMaskPositionY, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isYPositionSet, &FillLayer::yPosition, &FillLayer::setYPosition, &FillLayer::clearYPosition, &FillLayer::initialFillYPosition, &CSSStyleSelector::mapFillYPosition>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskPosition, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitMaskPositionX, CSSPropertyWebkitMaskPositionY>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitMaskRepeatX, ApplyPropertyFillLayer<EFillRepeat, CSSPropertyWebkitMaskRepeatX, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isRepeatXSet, &FillLayer::repeatX, &FillLayer::setRepeatX, &FillLayer::clearRepeatX, &FillLayer::initialFillRepeatX, &CSSStyleSelector::mapFillRepeatX>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskRepeatY, ApplyPropertyFillLayer<EFillRepeat, CSSPropertyWebkitMaskRepeatY, MaskFillLayer, &RenderStyle::accessMaskLayers, &RenderStyle::maskLayers, + &FillLayer::isRepeatYSet, &FillLayer::repeatY, &FillLayer::setRepeatY, &FillLayer::clearRepeatY, &FillLayer::initialFillRepeatY, &CSSStyleSelector::mapFillRepeatY>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskRepeat, ApplyPropertyExpanding<SuppressValue, CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY>::createHandler()); + + setPropertyHandler(CSSPropertyBackgroundColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor, &RenderStyle::invalidColor>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottomColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyBorderLeftColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyBorderRightColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyBorderTopColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor, &RenderStyle::color>::createHandler()); + + setPropertyHandler(CSSPropertyBorderTopStyle, ApplyPropertyDefault<EBorderStyle, &RenderStyle::borderTopStyle, EBorderStyle, &RenderStyle::setBorderTopStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::createHandler()); + setPropertyHandler(CSSPropertyBorderRightStyle, ApplyPropertyDefault<EBorderStyle, &RenderStyle::borderRightStyle, EBorderStyle, &RenderStyle::setBorderRightStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottomStyle, ApplyPropertyDefault<EBorderStyle, &RenderStyle::borderBottomStyle, EBorderStyle, &RenderStyle::setBorderBottomStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::createHandler()); + setPropertyHandler(CSSPropertyBorderLeftStyle, ApplyPropertyDefault<EBorderStyle, &RenderStyle::borderLeftStyle, EBorderStyle, &RenderStyle::setBorderLeftStyle, EBorderStyle, &RenderStyle::initialBorderStyle>::createHandler()); + + setPropertyHandler(CSSPropertyBorderTopWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + setPropertyHandler(CSSPropertyBorderRightWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottomWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + setPropertyHandler(CSSPropertyBorderLeftWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + setPropertyHandler(CSSPropertyOutlineWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + setPropertyHandler(CSSPropertyWebkitColumnRuleWidth, ApplyPropertyComputeLength<unsigned short, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth, &RenderStyle::initialBorderWidth, NormalDisabled, ThicknessEnabled>::createHandler()); + + setPropertyHandler(CSSPropertyBorderTop, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderTopColor, CSSPropertyBorderTopStyle, CSSPropertyBorderTopWidth>::createHandler()); + setPropertyHandler(CSSPropertyBorderRight, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderRightColor, CSSPropertyBorderRightStyle, CSSPropertyBorderRightWidth>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottom, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderBottomColor, CSSPropertyBorderBottomStyle, CSSPropertyBorderBottomWidth>::createHandler()); + setPropertyHandler(CSSPropertyBorderLeft, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderLeftColor, CSSPropertyBorderLeftStyle, CSSPropertyBorderLeftWidth>::createHandler()); + + setPropertyHandler(CSSPropertyBorderStyle, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle>::createHandler()); + setPropertyHandler(CSSPropertyBorderWidth, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth>::createHandler()); + setPropertyHandler(CSSPropertyBorderColor, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor>::createHandler()); + setPropertyHandler(CSSPropertyBorder, ApplyPropertyExpanding<SuppressValue, CSSPropertyBorderStyle, CSSPropertyBorderWidth, CSSPropertyBorderColor>::createHandler()); + + setPropertyHandler(CSSPropertyBorderImage, ApplyPropertyBorderImage<Image, CSSPropertyBorderImage, &RenderStyle::borderImage, &RenderStyle::setBorderImage>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBorderImage, ApplyPropertyBorderImage<Image, CSSPropertyWebkitBorderImage, &RenderStyle::borderImage, &RenderStyle::setBorderImage>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImage, ApplyPropertyBorderImage<Mask, CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage>::createHandler()); + + setPropertyHandler(CSSPropertyBorderImageOutset, ApplyPropertyBorderImageModifier<Image, Outset>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImageOutset, ApplyPropertyBorderImageModifier<Mask, Outset>::createHandler()); + setPropertyHandler(CSSPropertyBorderImageRepeat, ApplyPropertyBorderImageModifier<Image, Repeat>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImageRepeat, ApplyPropertyBorderImageModifier<Mask, Repeat>::createHandler()); + setPropertyHandler(CSSPropertyBorderImageSlice, ApplyPropertyBorderImageModifier<Image, Slice>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImageSlice, ApplyPropertyBorderImageModifier<Mask, Slice>::createHandler()); + setPropertyHandler(CSSPropertyBorderImageWidth, ApplyPropertyBorderImageModifier<Image, Width>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImageWidth, ApplyPropertyBorderImageModifier<Mask, Width>::createHandler()); + + setPropertyHandler(CSSPropertyBorderImageSource, ApplyPropertyBorderImageSource<CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource, &RenderStyle::initialBorderImageSource>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMaskBoxImageSource, ApplyPropertyBorderImageSource<CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource, &RenderStyle::initialMaskBoxImageSource>::createHandler()); + + setPropertyHandler(CSSPropertyBorderTopLeftRadius, ApplyPropertyBorderRadius<&RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius, &RenderStyle::initialBorderRadius>::createHandler()); + setPropertyHandler(CSSPropertyBorderTopRightRadius, ApplyPropertyBorderRadius<&RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius, &RenderStyle::initialBorderRadius>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottomLeftRadius, ApplyPropertyBorderRadius<&RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius, &RenderStyle::initialBorderRadius>::createHandler()); + setPropertyHandler(CSSPropertyBorderBottomRightRadius, ApplyPropertyBorderRadius<&RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius, &RenderStyle::initialBorderRadius>::createHandler()); + setPropertyHandler(CSSPropertyBorderRadius, ApplyPropertyExpanding<ExpandValue, CSSPropertyBorderTopLeftRadius, CSSPropertyBorderTopRightRadius, CSSPropertyBorderBottomLeftRadius, CSSPropertyBorderBottomRightRadius>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBorderRadius, CSSPropertyBorderRadius); + + setPropertyHandler(CSSPropertyWebkitBorderHorizontalSpacing, ApplyPropertyComputeLength<short, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing, &RenderStyle::initialHorizontalBorderSpacing>::createHandler()); + setPropertyHandler(CSSPropertyWebkitBorderVerticalSpacing, ApplyPropertyComputeLength<short, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing, &RenderStyle::initialVerticalBorderSpacing>::createHandler()); + setPropertyHandler(CSSPropertyBorderSpacing, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyWebkitBorderVerticalSpacing>::createHandler()); + + setPropertyHandler(CSSPropertyLetterSpacing, ApplyPropertyComputeLength<int, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing, &RenderStyle::initialLetterWordSpacing, NormalEnabled, ThicknessDisabled, SVGZoomEnabled>::createHandler()); + setPropertyHandler(CSSPropertyWordSpacing, ApplyPropertyComputeLength<int, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing, &RenderStyle::initialLetterWordSpacing, NormalEnabled, ThicknessDisabled, SVGZoomEnabled>::createHandler()); + + setPropertyHandler(CSSPropertyCursor, ApplyPropertyCursor::createHandler()); + + setPropertyHandler(CSSPropertyCounterIncrement, ApplyPropertyCounter<Increment>::createHandler()); + setPropertyHandler(CSSPropertyCounterReset, ApplyPropertyCounter<Reset>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitFlexOrder, ApplyPropertyDefault<int, &RenderStyle::flexOrder, int, &RenderStyle::setFlexOrder, int, &RenderStyle::initialFlexOrder>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlexPack, ApplyPropertyDefault<EFlexPack, &RenderStyle::flexPack, EFlexPack, &RenderStyle::setFlexPack, EFlexPack, &RenderStyle::initialFlexPack>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlexAlign, ApplyPropertyDefault<EFlexAlign, &RenderStyle::flexAlign, EFlexAlign, &RenderStyle::setFlexAlign, EFlexAlign, &RenderStyle::initialFlexAlign>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlexDirection, ApplyPropertyDefault<EFlexDirection, &RenderStyle::flexDirection, EFlexDirection, &RenderStyle::setFlexDirection, EFlexDirection, &RenderStyle::initialFlexDirection>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlexWrap, ApplyPropertyDefault<EFlexWrap, &RenderStyle::flexWrap, EFlexWrap, &RenderStyle::setFlexWrap, EFlexWrap, &RenderStyle::initialFlexWrap>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlexFlow, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitFlexDirection, CSSPropertyWebkitFlexWrap>::createHandler()); + + setPropertyHandler(CSSPropertyFontSize, ApplyPropertyFontSize::createHandler()); + setPropertyHandler(CSSPropertyFontStyle, ApplyPropertyFont<FontItalic, &FontDescription::italic, &FontDescription::setItalic, FontItalicOff>::createHandler()); + setPropertyHandler(CSSPropertyFontVariant, ApplyPropertyFont<FontSmallCaps, &FontDescription::smallCaps, &FontDescription::setSmallCaps, FontSmallCapsOff>::createHandler()); + setPropertyHandler(CSSPropertyTextRendering, ApplyPropertyFont<TextRenderingMode, &FontDescription::textRenderingMode, &FontDescription::setTextRenderingMode, AutoTextRendering>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFontSmoothing, ApplyPropertyFont<FontSmoothingMode, &FontDescription::fontSmoothing, &FontDescription::setFontSmoothing, AutoSmoothing>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextOrientation, ApplyPropertyFont<TextOrientation, &FontDescription::textOrientation, &FontDescription::setTextOrientation, TextOrientationVerticalRight>::createHandler()); + setPropertyHandler(CSSPropertyFontWeight, ApplyPropertyFontWeight::createHandler()); + + setPropertyHandler(CSSPropertyTextAlign, ApplyPropertyTextAlign::createHandler()); + setPropertyHandler(CSSPropertyTextDecoration, ApplyPropertyTextDecoration::createHandler()); + + setPropertyHandler(CSSPropertyOutlineStyle, ApplyPropertyOutlineStyle::createHandler()); + setPropertyHandler(CSSPropertyOutlineColor, ApplyPropertyColor<InheritFromParent, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::setVisitedLinkOutlineColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyOutlineOffset, ApplyPropertyComputeLength<int, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset, &RenderStyle::initialOutlineOffset>::createHandler()); + + setPropertyHandler(CSSPropertyOutline, ApplyPropertyExpanding<SuppressValue, CSSPropertyOutlineWidth, CSSPropertyOutlineColor, CSSPropertyOutlineStyle>::createHandler()); + + setPropertyHandler(CSSPropertyOverflowX, ApplyPropertyDefault<EOverflow, &RenderStyle::overflowX, EOverflow, &RenderStyle::setOverflowX, EOverflow, &RenderStyle::initialOverflowX>::createHandler()); + setPropertyHandler(CSSPropertyOverflowY, ApplyPropertyDefault<EOverflow, &RenderStyle::overflowY, EOverflow, &RenderStyle::setOverflowY, EOverflow, &RenderStyle::initialOverflowY>::createHandler()); + setPropertyHandler(CSSPropertyOverflow, ApplyPropertyExpanding<ExpandValue, CSSPropertyOverflowX, CSSPropertyOverflowY>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitColumnRuleColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextEmphasisColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::textEmphasisColor, &RenderStyle::setTextEmphasisColor, &RenderStyle::setVisitedLinkTextEmphasisColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextFillColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::setVisitedLinkTextFillColor, &RenderStyle::color>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextStrokeColor, ApplyPropertyColor<NoInheritFromParent, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor, &RenderStyle::color>::createHandler()); + + setPropertyHandler(CSSPropertyTop, ApplyPropertyLength<&RenderStyle::top, &RenderStyle::setTop, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyRight, ApplyPropertyLength<&RenderStyle::right, &RenderStyle::setRight, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyBottom, ApplyPropertyLength<&RenderStyle::bottom, &RenderStyle::setBottom, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyLeft, ApplyPropertyLength<&RenderStyle::left, &RenderStyle::setLeft, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); + + setPropertyHandler(CSSPropertyWidth, ApplyPropertyLength<&RenderStyle::width, &RenderStyle::setWidth, &RenderStyle::initialSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled, NoneDisabled, UndefinedDisabled, FlexWidth>::createHandler()); + setPropertyHandler(CSSPropertyHeight, ApplyPropertyLength<&RenderStyle::height, &RenderStyle::setHeight, &RenderStyle::initialSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled, NoneDisabled, UndefinedDisabled, FlexHeight>::createHandler()); + + setPropertyHandler(CSSPropertyTextIndent, ApplyPropertyLength<&RenderStyle::textIndent, &RenderStyle::setTextIndent, &RenderStyle::initialTextIndent>::createHandler()); + + setPropertyHandler(CSSPropertyLineHeight, ApplyPropertyLineHeight::createHandler()); + + setPropertyHandler(CSSPropertyListStyleImage, ApplyPropertyStyleImage<&RenderStyle::listStyleImage, &RenderStyle::setListStyleImage, &RenderStyle::initialListStyleImage, CSSPropertyListStyleImage>::createHandler()); + setPropertyHandler(CSSPropertyListStylePosition, ApplyPropertyDefault<EListStylePosition, &RenderStyle::listStylePosition, EListStylePosition, &RenderStyle::setListStylePosition, EListStylePosition, &RenderStyle::initialListStylePosition>::createHandler()); + setPropertyHandler(CSSPropertyListStyleType, ApplyPropertyDefault<EListStyleType, &RenderStyle::listStyleType, EListStyleType, &RenderStyle::setListStyleType, EListStyleType, &RenderStyle::initialListStyleType>::createHandler()); + setPropertyHandler(CSSPropertyListStyle, ApplyPropertyExpanding<SuppressValue, CSSPropertyListStyleType, CSSPropertyListStyleImage, CSSPropertyListStylePosition>::createHandler()); + + setPropertyHandler(CSSPropertyMaxHeight, ApplyPropertyLength<&RenderStyle::maxHeight, &RenderStyle::setMaxHeight, &RenderStyle::initialMaxSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled, NoneEnabled, UndefinedEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMaxWidth, ApplyPropertyLength<&RenderStyle::maxWidth, &RenderStyle::setMaxWidth, &RenderStyle::initialMaxSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled, NoneEnabled, UndefinedEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMinHeight, ApplyPropertyLength<&RenderStyle::minHeight, &RenderStyle::setMinHeight, &RenderStyle::initialMinSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMinWidth, ApplyPropertyLength<&RenderStyle::minWidth, &RenderStyle::setMinWidth, &RenderStyle::initialMinSize, AutoEnabled, IntrinsicEnabled, MinIntrinsicEnabled>::createHandler()); + + setPropertyHandler(CSSPropertyMarginTop, ApplyPropertyLength<&RenderStyle::marginTop, &RenderStyle::setMarginTop, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMarginRight, ApplyPropertyLength<&RenderStyle::marginRight, &RenderStyle::setMarginRight, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMarginBottom, ApplyPropertyLength<&RenderStyle::marginBottom, &RenderStyle::setMarginBottom, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMarginLeft, ApplyPropertyLength<&RenderStyle::marginLeft, &RenderStyle::setMarginLeft, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); + setPropertyHandler(CSSPropertyMargin, ApplyPropertyExpanding<SuppressValue, CSSPropertyMarginTop, CSSPropertyMarginRight, CSSPropertyMarginBottom, CSSPropertyMarginLeft>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitMarginBeforeCollapse, ApplyPropertyDefault<EMarginCollapse, &RenderStyle::marginBeforeCollapse, EMarginCollapse, &RenderStyle::setMarginBeforeCollapse, EMarginCollapse, &RenderStyle::initialMarginBeforeCollapse>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMarginAfterCollapse, ApplyPropertyDefault<EMarginCollapse, &RenderStyle::marginAfterCollapse, EMarginCollapse, &RenderStyle::setMarginAfterCollapse, EMarginCollapse, &RenderStyle::initialMarginAfterCollapse>::createHandler()); + setPropertyHandler(CSSPropertyWebkitMarginTopCollapse, CSSPropertyWebkitMarginBeforeCollapse); + setPropertyHandler(CSSPropertyWebkitMarginBottomCollapse, CSSPropertyWebkitMarginAfterCollapse); + setPropertyHandler(CSSPropertyWebkitMarginCollapse, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitMarginBeforeCollapse, CSSPropertyWebkitMarginAfterCollapse>::createHandler()); + + setPropertyHandler(CSSPropertyPaddingTop, ApplyPropertyLength<&RenderStyle::paddingTop, &RenderStyle::setPaddingTop, &RenderStyle::initialPadding>::createHandler()); + setPropertyHandler(CSSPropertyPaddingRight, ApplyPropertyLength<&RenderStyle::paddingRight, &RenderStyle::setPaddingRight, &RenderStyle::initialPadding>::createHandler()); + setPropertyHandler(CSSPropertyPaddingBottom, ApplyPropertyLength<&RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom, &RenderStyle::initialPadding>::createHandler()); + setPropertyHandler(CSSPropertyPaddingLeft, ApplyPropertyLength<&RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft, &RenderStyle::initialPadding>::createHandler()); + setPropertyHandler(CSSPropertyPadding, ApplyPropertyExpanding<SuppressValue, CSSPropertyPaddingTop, CSSPropertyPaddingRight, CSSPropertyPaddingBottom, CSSPropertyPaddingLeft>::createHandler()); + + setPropertyHandler(CSSPropertyResize, ApplyPropertyResize::createHandler()); + + setPropertyHandler(CSSPropertyVerticalAlign, ApplyPropertyVerticalAlign::createHandler()); + + setPropertyHandler(CSSPropertySize, ApplyPropertyPageSize::createHandler()); + + setPropertyHandler(CSSPropertyWebkitPerspectiveOriginX, ApplyPropertyLength<&RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX, &RenderStyle::initialPerspectiveOriginX>::createHandler()); + setPropertyHandler(CSSPropertyWebkitPerspectiveOriginY, ApplyPropertyLength<&RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY, &RenderStyle::initialPerspectiveOriginY>::createHandler()); + setPropertyHandler(CSSPropertyWebkitPerspectiveOrigin, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitPerspectiveOriginX, CSSPropertyWebkitPerspectiveOriginY>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransformOriginX, ApplyPropertyLength<&RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX, &RenderStyle::initialTransformOriginX>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransformOriginY, ApplyPropertyLength<&RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY, &RenderStyle::initialTransformOriginY>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransformOriginZ, ApplyPropertyComputeLength<float, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ, &RenderStyle::initialTransformOriginZ>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransformOrigin, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitTransformOriginX, CSSPropertyWebkitTransformOriginY, CSSPropertyWebkitTransformOriginZ>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitAnimationDelay, ApplyPropertyAnimation<double, &Animation::delay, &Animation::setDelay, &Animation::isDelaySet, &Animation::clearDelay, &Animation::initialAnimationDelay, &CSSStyleSelector::mapAnimationDelay, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationDirection, ApplyPropertyAnimation<Animation::AnimationDirection, &Animation::direction, &Animation::setDirection, &Animation::isDirectionSet, &Animation::clearDirection, &Animation::initialAnimationDirection, &CSSStyleSelector::mapAnimationDirection, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationDuration, ApplyPropertyAnimation<double, &Animation::duration, &Animation::setDuration, &Animation::isDurationSet, &Animation::clearDuration, &Animation::initialAnimationDuration, &CSSStyleSelector::mapAnimationDuration, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationFillMode, ApplyPropertyAnimation<unsigned, &Animation::fillMode, &Animation::setFillMode, &Animation::isFillModeSet, &Animation::clearFillMode, &Animation::initialAnimationFillMode, &CSSStyleSelector::mapAnimationFillMode, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationIterationCount, ApplyPropertyAnimation<int, &Animation::iterationCount, &Animation::setIterationCount, &Animation::isIterationCountSet, &Animation::clearIterationCount, &Animation::initialAnimationIterationCount, &CSSStyleSelector::mapAnimationIterationCount, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationName, ApplyPropertyAnimation<const String&, &Animation::name, &Animation::setName, &Animation::isNameSet, &Animation::clearName, &Animation::initialAnimationName, &CSSStyleSelector::mapAnimationName, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationPlayState, ApplyPropertyAnimation<EAnimPlayState, &Animation::playState, &Animation::setPlayState, &Animation::isPlayStateSet, &Animation::clearPlayState, &Animation::initialAnimationPlayState, &CSSStyleSelector::mapAnimationPlayState, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + setPropertyHandler(CSSPropertyWebkitAnimationTimingFunction, ApplyPropertyAnimation<const PassRefPtr<TimingFunction>, &Animation::timingFunction, &Animation::setTimingFunction, &Animation::isTimingFunctionSet, &Animation::clearTimingFunction, &Animation::initialAnimationTimingFunction, &CSSStyleSelector::mapAnimationTimingFunction, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitTransitionDelay, ApplyPropertyAnimation<double, &Animation::delay, &Animation::setDelay, &Animation::isDelaySet, &Animation::clearDelay, &Animation::initialAnimationDelay, &CSSStyleSelector::mapAnimationDelay, &RenderStyle::accessTransitions, &RenderStyle::transitions>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransitionDuration, ApplyPropertyAnimation<double, &Animation::duration, &Animation::setDuration, &Animation::isDurationSet, &Animation::clearDuration, &Animation::initialAnimationDuration, &CSSStyleSelector::mapAnimationDuration, &RenderStyle::accessTransitions, &RenderStyle::transitions>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransitionProperty, ApplyPropertyAnimation<int, &Animation::property, &Animation::setProperty, &Animation::isPropertySet, &Animation::clearProperty, &Animation::initialAnimationProperty, &CSSStyleSelector::mapAnimationProperty, &RenderStyle::accessTransitions, &RenderStyle::transitions>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTransitionTimingFunction, ApplyPropertyAnimation<const PassRefPtr<TimingFunction>, &Animation::timingFunction, &Animation::setTimingFunction, &Animation::isTimingFunctionSet, &Animation::clearTimingFunction, &Animation::initialAnimationTimingFunction, &CSSStyleSelector::mapAnimationTimingFunction, &RenderStyle::accessTransitions, &RenderStyle::transitions>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitColumnCount, ApplyPropertyAuto<unsigned short, &RenderStyle::columnCount, &RenderStyle::setColumnCount, &RenderStyle::hasAutoColumnCount, &RenderStyle::setHasAutoColumnCount>::createHandler()); + setPropertyHandler(CSSPropertyWebkitColumnGap, ApplyPropertyAuto<float, &RenderStyle::columnGap, &RenderStyle::setColumnGap, &RenderStyle::hasNormalColumnGap, &RenderStyle::setHasNormalColumnGap, ComputeLength, CSSValueNormal>::createHandler()); + setPropertyHandler(CSSPropertyWebkitColumnWidth, ApplyPropertyAuto<float, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth, &RenderStyle::hasAutoColumnWidth, &RenderStyle::setHasAutoColumnWidth, ComputeLength>::createHandler()); + setPropertyHandler(CSSPropertyWebkitColumns, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitFlowInto, ApplyPropertyString<MapAutoToNull, &RenderStyle::flowThread, &RenderStyle::setFlowThread, &RenderStyle::initialFlowThread>::createHandler()); + setPropertyHandler(CSSPropertyWebkitFlowFrom, ApplyPropertyString<MapNoneToNull, &RenderStyle::regionThread, &RenderStyle::setRegionThread, &RenderStyle::initialRegionThread>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitHighlight, ApplyPropertyString<MapNoneToNull, &RenderStyle::highlight, &RenderStyle::setHighlight, &RenderStyle::initialHighlight>::createHandler()); + setPropertyHandler(CSSPropertyWebkitHyphenateCharacter, ApplyPropertyString<MapAutoToNull, &RenderStyle::hyphenationString, &RenderStyle::setHyphenationString, &RenderStyle::initialHyphenationString>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitHyphenateLimitAfter, ApplyPropertyNumber<short, &RenderStyle::hyphenationLimitAfter, &RenderStyle::setHyphenationLimitAfter, &RenderStyle::initialHyphenationLimitAfter>::createHandler()); + setPropertyHandler(CSSPropertyWebkitHyphenateLimitBefore, ApplyPropertyNumber<short, &RenderStyle::hyphenationLimitBefore, &RenderStyle::setHyphenationLimitBefore, &RenderStyle::initialHyphenationLimitBefore>::createHandler()); + setPropertyHandler(CSSPropertyWebkitHyphenateLimitLines, ApplyPropertyNumber<short, &RenderStyle::hyphenationLimitLines, &RenderStyle::setHyphenationLimitLines, &RenderStyle::initialHyphenationLimitLines, CSSValueNoLimit>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitLineGrid, ApplyPropertyString<MapNoneToNull, &RenderStyle::lineGrid, &RenderStyle::setLineGrid, &RenderStyle::initialLineGrid>::createHandler()); + setPropertyHandler(CSSPropertyWebkitLineGridSnap, ApplyPropertyDefault<LineGridSnap, &RenderStyle::lineGridSnap, LineGridSnap, &RenderStyle::setLineGridSnap, LineGridSnap, &RenderStyle::initialLineGridSnap>::createHandler()); + + setPropertyHandler(CSSPropertyWebkitTextCombine, ApplyPropertyDefault<TextCombine, &RenderStyle::textCombine, TextCombine, &RenderStyle::setTextCombine, TextCombine, &RenderStyle::initialTextCombine>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextEmphasisPosition, ApplyPropertyDefault<TextEmphasisPosition, &RenderStyle::textEmphasisPosition, TextEmphasisPosition, &RenderStyle::setTextEmphasisPosition, TextEmphasisPosition, &RenderStyle::initialTextEmphasisPosition>::createHandler()); + setPropertyHandler(CSSPropertyWebkitTextEmphasisStyle, ApplyPropertyTextEmphasisStyle::createHandler()); + + setPropertyHandler(CSSPropertyWebkitWrapMargin, ApplyPropertyLength<&RenderStyle::wrapMargin, &RenderStyle::setWrapMargin, &RenderStyle::initialWrapMargin>::createHandler()); + setPropertyHandler(CSSPropertyWebkitWrapPadding, ApplyPropertyLength<&RenderStyle::wrapPadding, &RenderStyle::setWrapPadding, &RenderStyle::initialWrapPadding>::createHandler()); + setPropertyHandler(CSSPropertyWebkitWrapFlow, ApplyPropertyDefault<WrapFlow, &RenderStyle::wrapFlow, WrapFlow, &RenderStyle::setWrapFlow, WrapFlow, &RenderStyle::initialWrapFlow>::createHandler()); + setPropertyHandler(CSSPropertyWebkitWrapThrough, ApplyPropertyDefault<WrapThrough, &RenderStyle::wrapThrough, WrapThrough, &RenderStyle::setWrapThrough, WrapThrough, &RenderStyle::initialWrapThrough>::createHandler()); + setPropertyHandler(CSSPropertyWebkitWrap, ApplyPropertyExpanding<SuppressValue, CSSPropertyWebkitWrapFlow, CSSPropertyWebkitWrapMargin, CSSPropertyWebkitWrapPadding>::createHandler()); + + setPropertyHandler(CSSPropertyZIndex, ApplyPropertyAuto<int, &RenderStyle::zIndex, &RenderStyle::setZIndex, &RenderStyle::hasAutoZIndex, &RenderStyle::setHasAutoZIndex>::createHandler()); + setPropertyHandler(CSSPropertyZoom, ApplyPropertyZoom::createHandler()); +} + + +} diff --git a/Source/WebCore/css/CSSStyleApplyProperty.h b/Source/WebCore/css/CSSStyleApplyProperty.h new file mode 100644 index 000000000..2e83d0fc1 --- /dev/null +++ b/Source/WebCore/css/CSSStyleApplyProperty.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#ifndef CSSStyleApplyProperty_h +#define CSSStyleApplyProperty_h + +#include "CSSPropertyNames.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class CSSStyleSelector; +class CSSValue; +class CSSStyleApplyProperty; + +class PropertyHandler { +public: + typedef void (*InheritFunction)(CSSStyleSelector*); + typedef void (*InitialFunction)(CSSStyleSelector*); + typedef void (*ApplyFunction)(CSSStyleSelector*, CSSValue*); + PropertyHandler() : m_inherit(0), m_initial(0), m_apply(0) { } + PropertyHandler(InheritFunction inherit, InitialFunction initial, ApplyFunction apply) : m_inherit(inherit), m_initial(initial), m_apply(apply) { } + void applyInheritValue(CSSStyleSelector* selector) const { ASSERT(m_inherit); (*m_inherit)(selector); } + void applyInitialValue(CSSStyleSelector* selector) const { ASSERT(m_initial); (*m_initial)(selector); } + void applyValue(CSSStyleSelector* selector, CSSValue* value) const { ASSERT(m_apply); (*m_apply)(selector, value); } + bool isValid() const { return m_inherit && m_initial && m_apply; } + InheritFunction inheritFunction() const { return m_inherit; } + InitialFunction initialFunction() { return m_initial; } + ApplyFunction applyFunction() { return m_apply; } +private: + InheritFunction m_inherit; + InitialFunction m_initial; + ApplyFunction m_apply; +}; + +class CSSStyleApplyProperty { + WTF_MAKE_NONCOPYABLE(CSSStyleApplyProperty); +public: + static const CSSStyleApplyProperty& sharedCSSStyleApplyProperty(); + + const PropertyHandler& propertyHandler(CSSPropertyID property) const + { + ASSERT(valid(property)); + return m_propertyMap[index(property)]; + } +private: + CSSStyleApplyProperty(); + static int index(CSSPropertyID property) + { + return property - firstCSSProperty; + } + + static bool valid(CSSPropertyID property) + { + int i = index(property); + return i >= 0 && i < numCSSProperties; + } + + void setPropertyHandler(CSSPropertyID property, PropertyHandler handler) + { + ASSERT(valid(property)); + ASSERT(!propertyHandler(property).isValid()); + m_propertyMap[index(property)] = handler; + } + + void setPropertyHandler(CSSPropertyID newProperty, CSSPropertyID equivalentProperty) + { + ASSERT(valid(newProperty)); + ASSERT(valid(equivalentProperty)); + ASSERT(!propertyHandler(newProperty).isValid()); + m_propertyMap[index(newProperty)] = m_propertyMap[index(equivalentProperty)]; + } + + PropertyHandler m_propertyMap[numCSSProperties]; +}; + +} + +#endif // CSSStyleApplyProperty_h diff --git a/Source/WebCore/css/CSSStyleDeclaration.cpp b/Source/WebCore/css/CSSStyleDeclaration.cpp new file mode 100644 index 000000000..a1d61b88f --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.cpp @@ -0,0 +1,172 @@ +/* + * (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 "CSSElementStyleDeclaration.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSParser.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "CSSRule.h" +#include "Node.h" +#include "SVGElement.h" +#include <wtf/ASCIICType.h> +#include <wtf/text/CString.h> +#ifndef NDEBUG +#include <stdio.h> +#endif + +using namespace WTF; + +namespace WebCore { + +CSSStyleDeclaration::CSSStyleDeclaration(CSSRule* parent) + : m_strictParsing(!parent || parent->useStrictParsing()) +#ifndef NDEBUG + , m_iteratorCount(0) +#endif + , m_isElementStyleDeclaration(false) + , m_isInlineStyleDeclaration(false) + , m_parentRule(parent) +{ +} + +CSSStyleSheet* CSSStyleDeclaration::parentStyleSheet() const +{ + if (parentRule()) + return parentRule()->parentStyleSheet(); + if (isElementStyleDeclaration()) + return static_cast<const CSSElementStyleDeclaration*>(this)->styleSheet(); + return 0; +} + +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, const String& priority, ExceptionCode& ec) +{ + int propID = cssPropertyID(propertyName); + if (!propID) + 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); +} + +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); +} + +#ifndef NDEBUG +void CSSStyleDeclaration::showStyle() +{ + fprintf(stderr, "%s\n", cssText().ascii().data()); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSStyleDeclaration.h b/Source/WebCore/css/CSSStyleDeclaration.h new file mode 100644 index 000000000..a54b0c60a --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.h @@ -0,0 +1,111 @@ +/* + * (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 "CSSRule.h" +#include <wtf/Forward.h> + +namespace WebCore { + +class CSSMutableStyleDeclaration; +class CSSProperty; +class CSSStyleSheet; +class CSSValue; + +typedef int ExceptionCode; + +class CSSStyleDeclaration : public RefCounted<CSSStyleDeclaration> { + WTF_MAKE_NONCOPYABLE(CSSStyleDeclaration); +public: + virtual ~CSSStyleDeclaration() { } + + static bool isPropertyName(const String&); + + CSSRule* parentRule() const { return m_parentRule; } + void clearParentRule() { m_parentRule = 0; } + + CSSStyleSheet* parentStyleSheet() 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, 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; + +#ifndef NDEBUG + void showStyle(); +#endif + + bool isElementStyleDeclaration() const { return m_isElementStyleDeclaration; } + bool isInlineStyleDeclaration() const { return m_isInlineStyleDeclaration; } + +protected: + CSSStyleDeclaration(CSSRule* parentRule = 0); + + virtual bool cssPropertyMatches(const CSSProperty*) const; + + // The bits in this section are only used by specific subclasses but kept here + // to maximize struct packing. + + // CSSMutableStyleDeclaration bits: + bool m_strictParsing : 1; +#ifndef NDEBUG + unsigned m_iteratorCount : 4; +#endif + + // CSSElementStyleDeclaration bits: + bool m_isElementStyleDeclaration : 1; + bool m_isInlineStyleDeclaration : 1; + +private: + CSSRule* m_parentRule; +}; + +} // namespace WebCore + +#endif // CSSStyleDeclaration_h diff --git a/Source/WebCore/css/CSSStyleDeclaration.idl b/Source/WebCore/css/CSSStyleDeclaration.idl new file mode 100644 index 000000000..d1b470f87 --- /dev/null +++ b/Source/WebCore/css/CSSStyleDeclaration.idl @@ -0,0 +1,55 @@ +/* + * 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, + GenerateIsReachable=ImplRoot, + DelegatingPutFunction, + HasNameGetter, + HasIndexGetter, + CustomGetPropertyNames, + V8DependentLifetime + ] CSSStyleDeclaration { + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString cssText + setter raises(DOMException); + + [ConvertNullStringTo=Null] DOMString getPropertyValue(in [Optional=CallWithDefaultValue] DOMString propertyName); + [JSCCustom] CSSValue getPropertyCSSValue(in [Optional=CallWithDefaultValue] DOMString propertyName); + [ConvertNullStringTo=Null] DOMString removeProperty(in [Optional=CallWithDefaultValue] DOMString propertyName) + raises(DOMException); + [ConvertNullStringTo=Null] DOMString getPropertyPriority(in [Optional=CallWithDefaultValue] DOMString propertyName); + [OldStyleObjC] void setProperty(in [Optional=CallWithDefaultValue] DOMString propertyName, + in [ConvertNullToNullString,Optional=CallWithDefaultValue] DOMString value, + in [Optional=CallWithDefaultValue] DOMString priority) + raises(DOMException); + + readonly attribute unsigned long length; + DOMString item(in [Optional=CallWithDefaultValue] unsigned long index); + readonly attribute CSSRule parentRule; + + // Extensions + [ConvertNullStringTo=Null] DOMString getPropertyShorthand(in [Optional=CallWithDefaultValue] DOMString propertyName); + boolean isPropertyImplicit(in [Optional=CallWithDefaultValue] DOMString propertyName); + }; + +} diff --git a/Source/WebCore/css/CSSStyleRule.cpp b/Source/WebCore/css/CSSStyleRule.cpp new file mode 100644 index 000000000..6296e64b7 --- /dev/null +++ b/Source/WebCore/css/CSSStyleRule.cpp @@ -0,0 +1,150 @@ +/* + * (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 "CSSPageRule.h" +#include "CSSParser.h" +#include "CSSSelector.h" +#include "CSSStyleSheet.h" +#include "Document.h" +#include "StyledElement.h" +#include "StyleSheet.h" + +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +CSSStyleRule::CSSStyleRule(CSSStyleSheet* parent, int line, CSSRule::Type type) + : CSSRule(parent, type) +{ + setSourceLine(line); + + // m_sourceLine is a bitfield, so let's catch any overflow early in debug mode. + ASSERT(sourceLine() == line); +} + +CSSStyleRule::~CSSStyleRule() +{ + if (m_style) + m_style->clearParentRule(); + cleanup(); +} + +typedef HashMap<const CSSStyleRule*, String> SelectorTextCache; +static SelectorTextCache& selectorTextCache() +{ + DEFINE_STATIC_LOCAL(SelectorTextCache, cache, ()); + return cache; +} + +inline void CSSStyleRule::cleanup() +{ + if (hasCachedSelectorText()) { + selectorTextCache().remove(this); + setHasCachedSelectorText(false); + } +} + +String CSSStyleRule::generateSelectorText() const +{ + if (isPageRule()) + return static_cast<const CSSPageRule*>(this)->pageSelectorText(); + else { + StringBuilder builder; + for (CSSSelector* s = selectorList().first(); s; s = CSSSelectorList::next(s)) { + if (s != selectorList().first()) + builder.append(", "); + builder.append(s->selectorText()); + } + return builder.toString(); + } +} + +String CSSStyleRule::selectorText() const +{ + if (hasCachedSelectorText()) { + ASSERT(selectorTextCache().contains(this)); + return selectorTextCache().get(this); + } + + ASSERT(!selectorTextCache().contains(this)); + String text = generateSelectorText(); + selectorTextCache().set(this, text); + setHasCachedSelectorText(true); + return text; +} + +void CSSStyleRule::setSelectorText(const String& selectorText) +{ + Document* doc = 0; + + if (CSSStyleSheet* styleSheet = m_style->parentStyleSheet()) + doc = styleSheet->findDocument(); + + if (!doc && m_style->isElementStyleDeclaration()) { + if (StyledElement* element = static_cast<CSSElementStyleDeclaration*>(m_style.get())->element()) + doc = element->document(); + } + + 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 (hasCachedSelectorText()) { + ASSERT(selectorTextCache().contains(this)); + selectorTextCache().set(this, generateSelectorText()); + } + + if (this->selectorText() == oldSelectorText) + return; + + doc->styleSelectorChanged(DeferRecalcStyle); +} + +String CSSStyleRule::cssText() const +{ + String result = selectorText(); + + result += " { "; + result += m_style->cssText(); + result += "}"; + + return result; +} + +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 000000000..111c5f1aa --- /dev/null +++ b/Source/WebCore/css/CSSStyleRule.h @@ -0,0 +1,73 @@ +/* + * (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 "CSSMutableStyleDeclaration.h" +#include "CSSRule.h" +#include "CSSSelectorList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSSelector; + +class CSSStyleRule : public CSSRule { +public: + static PassRefPtr<CSSStyleRule> create(CSSStyleSheet* parent, int sourceLine) + { + return adoptRef(new CSSStyleRule(parent, sourceLine)); + } + ~CSSStyleRule(); + + String selectorText() const; + void setSelectorText(const String&); + + CSSMutableStyleDeclaration* style() const { return m_style.get(); } + + String cssText() const; + + void adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectors) { m_selectorList.adoptSelectorVector(selectors); } + void setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) { m_style = style; } + + const CSSSelectorList& selectorList() const { return m_selectorList; } + CSSMutableStyleDeclaration* declaration() { return m_style.get(); } + + void addSubresourceStyleURLs(ListHashSet<KURL>& urls); + + using CSSRule::sourceLine; + +protected: + CSSStyleRule(CSSStyleSheet* parent, int sourceLine, CSSRule::Type = CSSRule::STYLE_RULE); + +private: + void cleanup(); + String generateSelectorText() const; + + RefPtr<CSSMutableStyleDeclaration> m_style; + CSSSelectorList m_selectorList; +}; + +} // namespace WebCore + +#endif // CSSStyleRule_h diff --git a/Source/WebCore/css/CSSStyleRule.idl b/Source/WebCore/css/CSSStyleRule.idl new file mode 100644 index 000000000..4abfbfc45 --- /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 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 000000000..b0282c120 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSelector.cpp @@ -0,0 +1,5400 @@ +/* + * 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, 2011, 2012 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/) + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (C) Research In Motion Limited 2011. 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 "CSSStyleSelector.h" + +#include "Attribute.h" +#include "CachedImage.h" +#include "ContentData.h" +#include "Counter.h" +#include "CounterContent.h" +#include "CSSBorderImageValue.h" +#include "CSSCursorImageValue.h" +#include "CSSFontFaceRule.h" +#include "CSSFontSelector.h" +#include "CSSImportRule.h" +#include "CSSLineBoxContainValue.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 "CSSStyleApplyProperty.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSTimingFunctionValue.h" +#include "CSSValueList.h" +#include "CursorList.h" +#include "FontFamilyValue.h" +#include "FontFeatureValue.h" +#include "FontValue.h" +#include "Frame.h" +#include "FrameSelection.h" +#include "FrameView.h" +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLProgressElement.h" +#include "HTMLTextAreaElement.h" +#include "InspectorInstrumentation.h" +#include "KeyframeList.h" +#include "LinkHash.h" +#include "LocaleToScriptMapping.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 "QuotesData.h" +#include "Rect.h" +#include "RenderScrollbar.h" +#include "RenderScrollbarTheme.h" +#include "RenderStyleConstants.h" +#include "RenderTheme.h" +#include "RotateTransformOperation.h" +#include "ScaleTransformOperation.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "ShadowData.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 "WebKitCSSRegionRule.h" +#include "WebKitCSSTransformValue.h" +#include "WebKitFontFamilyNames.h" +#include "XMLNames.h" +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +#if ENABLE(CSS_FILTERS) +#include "FilterOperation.h" +#include "WebKitCSSFilterValue.h" +#endif + +#if ENABLE(DASHBOARD_SUPPORT) +#include "DashboardRegion.h" +#endif + +#if ENABLE(SVG) +#include "SVGNames.h" +#endif + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterOperation.h" +#include "StyleCachedShader.h" +#include "StylePendingShader.h" +#include "StyleShader.h" +#include "WebKitCSSShaderValue.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); + +class RuleData { +public: + RuleData(CSSStyleRule*, CSSSelector*, unsigned position); + + unsigned position() const { return m_position; } + CSSStyleRule* rule() const { return m_rule; } + CSSSelector* selector() const { return m_selector; } + + bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; } + bool hasMultipartSelector() const { return m_hasMultipartSelector; } + bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; } + bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; } + unsigned specificity() const { return m_specificity; } + unsigned linkMatchType() const { return m_linkMatchType; } + + // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance. + static const unsigned maximumIdentifierCount = 4; + const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; } + +private: + CSSStyleRule* m_rule; + CSSSelector* m_selector; + unsigned m_specificity; + // This number was picked fairly arbitrarily. We can probably lower it if we need to. + // Some simple testing showed <100,000 RuleData's on large sites. + unsigned m_position : 26; + unsigned m_hasFastCheckableSelector : 1; + unsigned m_hasMultipartSelector : 1; + unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1; + unsigned m_containsUncommonAttributeSelector : 1; + unsigned m_linkMatchType : 2; // SelectorChecker::LinkMatchMask + // Use plain array instead of a Vector to minimize memory overhead. + unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount]; +}; + +struct SameSizeAsRuleData { + void* a; + void* b; + unsigned c; + unsigned d; + unsigned e[4]; +}; + +COMPILE_ASSERT(sizeof(RuleData) == sizeof(SameSizeAsRuleData), RuleData_should_stay_small); + +class RuleSet { + WTF_MAKE_NONCOPYABLE(RuleSet); +public: + RuleSet(); + + typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<RuleData> > > AtomRuleMap; + + void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0); + + void addStyleRule(CSSStyleRule* item); + void addRule(CSSStyleRule* rule, CSSSelector* sel); + void addPageRule(CSSPageRule*); + void addToRuleSet(AtomicStringImpl* key, AtomRuleMap&, CSSStyleRule*, CSSSelector*); + void shrinkToFit(); + void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; } + + void collectFeatures(CSSStyleSelector::Features&) const; + + const Vector<RuleData>* idRules(AtomicStringImpl* key) const { return m_idRules.get(key); } + const Vector<RuleData>* classRules(AtomicStringImpl* key) const { return m_classRules.get(key); } + const Vector<RuleData>* tagRules(AtomicStringImpl* key) const { return m_tagRules.get(key); } + const Vector<RuleData>* shadowPseudoElementRules(AtomicStringImpl* key) const { return m_shadowPseudoElementRules.get(key); } + const Vector<RuleData>* linkPseudoClassRules() const { return &m_linkPseudoClassRules; } + const Vector<RuleData>* focusPseudoClassRules() const { return &m_focusPseudoClassRules; } + const Vector<RuleData>* universalRules() const { return &m_universalRules; } + const Vector<RuleData>* pageRules() const { return &m_pageRules; } + +public: + AtomRuleMap m_idRules; + AtomRuleMap m_classRules; + AtomRuleMap m_tagRules; + AtomRuleMap m_shadowPseudoElementRules; + Vector<RuleData> m_linkPseudoClassRules; + Vector<RuleData> m_focusPseudoClassRules; + Vector<RuleData> m_universalRules; + Vector<RuleData> m_pageRules; + unsigned m_ruleCount; + bool m_autoShrinkToFitEnabled; +}; + +static RuleSet* defaultStyle; +static RuleSet* defaultQuirksStyle; +static RuleSet* defaultPrintStyle; +static RuleSet* defaultViewSourceStyle; +static CSSStyleSheet* simpleDefaultStyleSheet; + +static RuleSet* siblingRulesInDefaultStyle; +static RuleSet* uncommonAttributeRulesInDefaultStyle; + +RenderStyle* CSSStyleSelector::s_styleNotYetAvailable; + +static void loadFullDefaultStyle(); +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}head{display:none}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 inline bool elementCanUseSimpleDefaultStyle(Element* e) +{ + return e->hasTagName(htmlTag) || e->hasTagName(headTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || e->hasTagName(aTag); +} + +static inline void collectSpecialRulesInDefaultStyle() +{ + CSSStyleSelector::Features features; + defaultStyle->collectFeatures(features); + ASSERT(features.idsInRules.isEmpty()); + delete siblingRulesInDefaultStyle; + delete uncommonAttributeRulesInDefaultStyle; + siblingRulesInDefaultStyle = features.siblingRules.leakPtr(); + uncommonAttributeRulesInDefaultStyle = features.uncommonAttributeRules.leakPtr(); +} + +static inline void assertNoSiblingRulesInDefaultStyle() +{ +#ifndef NDEBUG + if (siblingRulesInDefaultStyle) + return; + collectSpecialRulesInDefaultStyle(); + ASSERT(!siblingRulesInDefaultStyle); +#endif +} + +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; +} + +static CSSMutableStyleDeclaration* leftToRightDeclaration() +{ + DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, leftToRightDecl, (CSSMutableStyleDeclaration::create())); + if (!leftToRightDecl->length()) { + leftToRightDecl->setProperty(CSSPropertyDirection, "ltr", false); + leftToRightDecl->setStrictParsing(false); + } + return leftToRightDecl.get(); +} + +static CSSMutableStyleDeclaration* rightToLeftDeclaration() +{ + DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, rightToLeftDecl, (CSSMutableStyleDeclaration::create())); + if (!rightToLeftDecl->length()) { + rightToLeftDecl->setProperty(CSSPropertyDirection, "rtl", false); + rightToLeftDecl->setStrictParsing(false); + } + return rightToLeftDecl.get(); +} + +CSSStyleSelector::CSSStyleSelector(Document* document, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, + CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets, const Vector<RefPtr<CSSStyleSheet> >* documentUserSheets, + bool strictParsing, bool matchAuthorAndUserStyles) + : m_hasUAAppearance(false) + , m_backgroundData(BackgroundFillLayer) + , m_checker(document, strictParsing) + , m_parentStyle(0) + , m_rootElementStyle(0) + , m_element(0) + , m_styledElement(0) + , m_elementLinkState(NotInsideLink) + , m_parentNode(0) + , m_lineHeightValue(0) + , m_fontDirty(false) + , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles) + , m_sameOriginOnly(false) + , m_fontSelector(CSSFontSelector::create(document)) + , m_applyPropertyToRegularStyle(true) + , m_applyPropertyToVisitedLinkStyle(false) + , m_applyProperty(CSSStyleApplyProperty::sharedCSSStyleApplyProperty()) +#if ENABLE(CSS_SHADERS) + , m_hasPendingShaders(false) +#endif +{ + Element* root = document->documentElement(); + + if (!defaultStyle) { + if (!root || elementCanUseSimpleDefaultStyle(root)) + loadSimpleDefaultStyle(); + else { + loadFullDefaultStyle(); + } + } + + // 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 RuleSet); + // Adding rules from multiple sheets, shrink at the end. + m_authorStyle->disableAutoShrinkToFit(); + + // FIXME: This sucks! The user sheet is reparsed every time! + OwnPtr<RuleSet> tempUserStyle = adoptPtr(new RuleSet); + 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 (documentUserSheets) { + unsigned length = documentUserSheets->size(); + for (unsigned i = 0; i < length; i++) { + if (documentUserSheets->at(i)->isUserStyleSheet()) + tempUserStyle->addRulesFromSheet(documentUserSheets->at(i).get(), *m_medium, this); + else + m_authorStyle->addRulesFromSheet(documentUserSheets->at(i).get(), *m_medium, this); + } + } + + if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRules.size() > 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); + } + m_authorStyle->shrinkToFit(); + + collectFeatures(); + + if (document->renderer() && document->renderer()->style()) + document->renderer()->style()->font().update(fontSelector()); +} + +void CSSStyleSelector::collectFeatures() +{ + // Collect all ids and rules using sibling selectors (:first-child and similar) + // in the current set of stylesheets. Style sharing code uses this information to reject + // sharing candidates. + // Usually there are no sibling rules in the default style but the MathML sheet has some. + if (siblingRulesInDefaultStyle) + siblingRulesInDefaultStyle->collectFeatures(m_features); + if (uncommonAttributeRulesInDefaultStyle) + uncommonAttributeRulesInDefaultStyle->collectFeatures(m_features); + m_authorStyle->collectFeatures(m_features); + if (m_userStyle) + m_userStyle->collectFeatures(m_features); + if (m_features.siblingRules) + m_features.siblingRules->shrinkToFit(); + if (m_features.uncommonAttributeRules) + m_features.uncommonAttributeRules->shrinkToFit(); +} + +void CSSStyleSelector::appendAuthorStylesheets(unsigned firstNew, const Vector<RefPtr<StyleSheet> >& stylesheets) +{ + // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver + // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated. + unsigned size = stylesheets.size(); + for (unsigned i = firstNew; i < size; ++i) { + if (!stylesheets[i]->isCSSStyleSheet() || stylesheets[i]->disabled()) + continue; + m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(stylesheets[i].get()), *m_medium, this); + } + m_authorStyle->shrinkToFit(); + // FIXME: This really only needs to collect the features from the newly added sheets. + m_features.clear(); + collectFeatures(); + + if (document()->renderer() && document()->renderer()->style()) + document()->renderer()->style()->font().update(fontSelector()); +} + +void CSSStyleSelector::addRegionRule(PassRefPtr<WebKitCSSRegionRule> regionStyleRule) +{ + m_regionStyleRules.append(regionStyleRule); +} + +// This is a simplified style setting function for keyframe styles +void CSSStyleSelector::addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule) +{ + AtomicString s(rule->name()); + m_keyframesRuleMap.set(s.impl(), rule); +} + +CSSStyleSelector::~CSSStyleSelector() +{ + m_fontSelector->clearDocument(); + deleteAllValues(m_viewportDependentMediaQueryResults); +} + +CSSStyleSelector::Features::Features() + : usesFirstLineRules(false) + , usesBeforeAfterRules(false) + , usesLinkRules(false) +{ +} + +CSSStyleSelector::Features::~Features() +{ +} + +void CSSStyleSelector::Features::clear() +{ + idsInRules.clear(); + attrsInRules.clear(); + siblingRules.clear(); + uncommonAttributeRules.clear(); + usesFirstLineRules = false; + usesBeforeAfterRules = false; + usesLinkRules = false; +} + +static CSSStyleSheet* parseUASheet(const String& str) +{ + CSSStyleSheet* sheet = CSSStyleSheet::create().leakRef(); // 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); + ASSERT(defaultPrintStyle == defaultStyle); + delete defaultStyle; + simpleDefaultStyleSheet->deref(); + defaultStyle = new RuleSet; + defaultPrintStyle = new RuleSet; + simpleDefaultStyleSheet = 0; + } else { + ASSERT(!defaultStyle); + defaultStyle = new RuleSet; + defaultPrintStyle = new RuleSet; + defaultQuirksStyle = new RuleSet; + } + + // 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()); +} + +static void loadSimpleDefaultStyle() +{ + ASSERT(!defaultStyle); + ASSERT(!simpleDefaultStyleSheet); + + defaultStyle = new RuleSet; + // There are no media-specific rules in the simple default style. + defaultPrintStyle = defaultStyle; + defaultQuirksStyle = new RuleSet; + + 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 RuleSet; + defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval()); +} + +static void ensureDefaultStyleSheetsForElement(Element* element) +{ + if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(element)) { + loadFullDefaultStyle(); + assertNoSiblingRulesInDefaultStyle(); + collectSpecialRulesInDefaultStyle(); + } + +#if ENABLE(SVG) + static bool loadedSVGUserAgentSheet; + if (element->isSVGElement() && !loadedSVGUserAgentSheet) { + // SVG rules. + loadedSVGUserAgentSheet = true; + CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(svgSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(svgSheet, printEval()); + assertNoSiblingRulesInDefaultStyle(); + collectSpecialRulesInDefaultStyle(); + } +#endif + +#if ENABLE(MATHML) + static bool loadedMathMLUserAgentSheet; + if (element->isMathMLElement() && !loadedMathMLUserAgentSheet) { + // MathML rules. + loadedMathMLUserAgentSheet = true; + CSSStyleSheet* mathMLSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(mathMLSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval()); + // There are some sibling and uncommon attribute rules here. + collectSpecialRulesInDefaultStyle(); + } +#endif + +#if ENABLE(VIDEO) + static bool loadedMediaStyleSheet; + if (!loadedMediaStyleSheet && (element->hasTagName(videoTag) || element->hasTagName(audioTag))) { + loadedMediaStyleSheet = true; + String mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(element->document()->page())->extraMediaControlsStyleSheet(); + CSSStyleSheet* mediaControlsSheet = parseUASheet(mediaRules); + defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval()); + collectSpecialRulesInDefaultStyle(); + } +#endif + +#if ENABLE(FULLSCREEN_API) + static bool loadedFullScreenStyleSheet; + if (!loadedFullScreenStyleSheet && element->document()->webkitIsFullScreen()) { + loadedFullScreenStyleSheet = true; + String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraFullScreenStyleSheet(); + CSSStyleSheet* fullscreenSheet = parseUASheet(fullscreenRules); + defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval()); + defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval()); + collectSpecialRulesInDefaultStyle(); + } +#endif +} + +CSSStyleSelector::MatchedStyleDeclaration::MatchedStyleDeclaration() +{ + // Make sure all memory is zero initializes as we calculate hash over the bytes of this object. + memset(this, 0, sizeof(*this)); +} + +void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* styleDeclaration, unsigned linkMatchType) +{ + m_matchedDecls.grow(m_matchedDecls.size() + 1); + MatchedStyleDeclaration& newDeclaration = m_matchedDecls.last(); + newDeclaration.styleDeclaration = styleDeclaration; + newDeclaration.linkMatchType = linkMatchType; +} + +void CSSStyleSelector::matchRules(RuleSet* 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->idRules(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->classRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + } + const AtomicString& pseudoId = m_element->shadowPseudoId(); + if (!pseudoId.isEmpty()) { + ASSERT(m_styledElement); + matchRulesForList(rules->shadowPseudoElementRules(pseudoId.impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + } + if (m_element->isLink()) + matchRulesForList(rules->linkPseudoClassRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules); + if (m_checker.matchesFocusPseudoClass(m_element)) + matchRulesForList(rules->focusPseudoClassRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules); + matchRulesForList(rules->tagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules); + matchRulesForList(rules->universalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules); + + if (m_matchedRules.isEmpty()) + return; + + sortMatchedRules(); + + if (m_checker.isCollectingRulesOnly()) { + if (!m_ruleList) + m_ruleList = CSSRuleList::create(); + for (unsigned i = 0; i < m_matchedRules.size(); ++i) + m_ruleList->append(m_matchedRules[i]->rule()); + return; + } + + // Now transfer the set of matched rules over to our list of declarations. + // FIXME: This sucks, the inspector should get the style from the visited style itself. + bool swapVisitedUnvisited = InspectorInstrumentation::forcePseudoState(m_element, CSSSelector::PseudoVisited); + for (unsigned i = 0; i < m_matchedRules.size(); i++) { + if (m_style && m_matchedRules[i]->containsUncommonAttributeSelector()) + m_style->setAffectedByUncommonAttributeSelectors(); + unsigned linkMatchType = m_matchedRules[i]->linkMatchType(); + if (swapVisitedUnvisited && linkMatchType && linkMatchType != SelectorChecker::MatchAll) + linkMatchType = (linkMatchType == SelectorChecker::MatchVisited) ? SelectorChecker::MatchLink : SelectorChecker::MatchVisited; + addMatchedDeclaration(m_matchedRules[i]->rule()->declaration(), linkMatchType); + } +} + +class MatchingUARulesScope { +public: + MatchingUARulesScope(); + ~MatchingUARulesScope(); + + static bool isMatchingUARules(); + +private: + static bool m_matchingUARules; +}; + +MatchingUARulesScope::MatchingUARulesScope() +{ + ASSERT(!m_matchingUARules); + m_matchingUARules = true; +} + +MatchingUARulesScope::~MatchingUARulesScope() +{ + m_matchingUARules = false; +} + +inline bool MatchingUARulesScope::isMatchingUARules() +{ + return m_matchingUARules; +} + +bool MatchingUARulesScope::m_matchingUARules = false; + +inline static bool matchesInTreeScope(TreeScope* treeScope, bool ruleReachesIntoShadowDOM) +{ + return MatchingUARulesScope::isMatchingUARules() || treeScope->applyAuthorSheets() || ruleReachesIntoShadowDOM; +} + +void CSSStyleSelector::matchRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) +{ + if (!rules) + return; + // In some cases we may end up looking up style for random elements in the middle of a recursive tree resolve. + // Ancestor identifier filter won't be up-to-date in that case and we can't use the fast path. + bool canUseFastReject = m_checker.parentStackIsConsistent(m_parentNode); + + unsigned size = rules->size(); + for (unsigned i = 0; i < size; ++i) { + const RuleData& ruleData = rules->at(i); + if (canUseFastReject && m_checker.fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes())) + continue; + + CSSStyleRule* rule = ruleData.rule(); + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willMatchRule(document(), rule); + if (checkSelector(ruleData)) { + if (!matchesInTreeScope(m_element->treeScope(), m_checker.hasUnknownPseudoElements())) { + InspectorInstrumentation::didMatchRule(cookie, false); + continue; + } + // 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)) { + InspectorInstrumentation::didMatchRule(cookie, false); + continue; + } + if (m_sameOriginOnly && !m_checker.document()->securityOrigin()->canRequest(rule->baseURL())) { + InspectorInstrumentation::didMatchRule(cookie, false); + 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.pseudoStyle() == NOPSEUDO) { + if (m_checker.isCollectingRulesOnly()) { + InspectorInstrumentation::didMatchRule(cookie, false); + 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(&ruleData); + InspectorInstrumentation::didMatchRule(cookie, true); + continue; + } + } + InspectorInstrumentation::didMatchRule(cookie, false); + } +} + +static inline bool compareRules(const RuleData* r1, const RuleData* r2) +{ + unsigned specificity1 = r1->specificity(); + unsigned specificity2 = r2->specificity(); + return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2; +} + +void CSSStyleSelector::sortMatchedRules() +{ + std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules); +} + +void CSSStyleSelector::matchAllRules(MatchResult& result) +{ + matchUARules(result); + + // Now we check user sheet rules. + if (m_matchAuthorAndUserStyles) + matchRules(m_userStyle.get(), result.firstUserRule, result.lastUserRule, false); + + // 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()) { + result.lastAuthorRule = m_matchedDecls.size(); + if (result.firstAuthorRule == -1) + result.firstAuthorRule = result.lastAuthorRule; + addMatchedDeclaration(attr->decl()); + result.isCacheable = false; + } + } + } + + // 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()) { + Vector<CSSMutableStyleDeclaration*> additionalAttributeStyleDecls; + m_styledElement->additionalAttributeStyleDecls(additionalAttributeStyleDecls); + if (!additionalAttributeStyleDecls.isEmpty()) { + unsigned additionalDeclsSize = additionalAttributeStyleDecls.size(); + if (result.firstAuthorRule == -1) + result.firstAuthorRule = m_matchedDecls.size(); + result.lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1; + for (unsigned i = 0; i < additionalDeclsSize; ++i) + addMatchedDeclaration(additionalAttributeStyleDecls[i]); + result.isCacheable = false; + } + } + if (m_styledElement->isHTMLElement()) { + bool isAuto; + TextDirection textDirection = toHTMLElement(m_styledElement)->directionalityIfhasDirAutoAttribute(isAuto); + if (isAuto) + addMatchedDeclaration(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration()); + } + } + + // Check the rules in author sheets next. + if (m_matchAuthorAndUserStyles) + matchRules(m_authorStyle.get(), result.firstAuthorRule, result.lastAuthorRule, false); + + // Now check our inline style attribute. + if (m_matchAuthorAndUserStyles && m_styledElement) { + CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl(); + if (inlineDecl) { + result.lastAuthorRule = m_matchedDecls.size(); + if (result.firstAuthorRule == -1) + result.firstAuthorRule = result.lastAuthorRule; + addMatchedDeclaration(inlineDecl); + result.isCacheable = false; + } + } +} + +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.setPseudoStyle(pseudoID); + + m_parentNode = e ? e->parentNodeForRenderingAndStyle() : 0; + + 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.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 const unsigned cStyleSearchThreshold = 10; +static const unsigned cStyleSearchLevelThreshold = 10; + +Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned& visitedNodeCount) const +{ + if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold) + return 0; + if (!parent || !parent->isStyledElement()) + return 0; + StyledElement* p = static_cast<StyledElement*>(parent); + if (p->inlineStyleDecl()) + return 0; + if (p->hasID() && m_features.idsInRules.contains(p->idForStyleResolution().impl())) + return 0; + + RenderStyle* parentStyle = p->renderStyle(); + unsigned subcount = 0; + Node* thisCousin = p; + Node* currentNode = p->previousSibling(); + + // Reserve the tries for this level. This effectively makes sure that the algorithm + // will never go deeper than cStyleSearchLevelThreshold levels into recursion. + visitedNodeCount += cStyleSearchThreshold; + while (thisCousin) { + while (currentNode) { + ++subcount; + if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()) { + // Adjust for unused reserved tries. + visitedNodeCount -= cStyleSearchThreshold - subcount; + return currentNode->lastChild(); + } + if (subcount >= cStyleSearchThreshold) + return 0; + currentNode = currentNode->previousSibling(); + } + currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount); + thisCousin = currentNode; + } + + return 0; +} + +bool CSSStyleSelector::matchesRuleSet(RuleSet* ruleSet) +{ + int firstSiblingRule = -1, lastSiblingRule = -1; + matchRules(ruleSet, firstSiblingRule, lastSiblingRule, false); + if (m_matchedDecls.isEmpty()) + return false; + m_matchedDecls.clear(); + return true; +} + +bool CSSStyleSelector::canShareStyleWithControl(StyledElement* element) const +{ +#if ENABLE(PROGRESS_TAG) + if (element->hasTagName(progressTag)) { + if (!m_element->hasTagName(progressTag)) + return false; + + HTMLProgressElement* thisProgressElement = static_cast<HTMLProgressElement*>(element); + HTMLProgressElement* otherProgressElement = static_cast<HTMLProgressElement*>(m_element); + if (thisProgressElement->isDeterminate() != otherProgressElement->isDeterminate()) + return false; + + return true; + } +#endif + + HTMLInputElement* thisInputElement = element->toInputElement(); + HTMLInputElement* otherInputElement = m_element->toInputElement(); + + if (!thisInputElement || !otherInputElement) + return false; + + if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled()) + return false; + if (thisInputElement->shouldAppearChecked() != otherInputElement->shouldAppearChecked()) + return false; + if (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate()) + return false; + if (thisInputElement->required() != otherInputElement->required()) + return false; + + if (element->isEnabledFormControl() != m_element->isEnabledFormControl()) + return false; + + if (element->isDefaultButtonForForm() != m_element->isDefaultButtonForForm()) + return false; + + if (!m_element->document()->containsValidityStyleRules()) + return false; + + bool willValidate = element->willValidate(); + + if (willValidate != m_element->willValidate()) + return false; + + if (willValidate && (element->isValidFormControlElement() != m_element->isValidFormControlElement())) + return false; + + if (element->isInRange() != m_element->isInRange()) + return false; + + if (element->isOutOfRange() != m_element->isOutOfRange()) + return false; + + return true; +} + +bool CSSStyleSelector::canShareStyleWithElement(StyledElement* element) const +{ + RenderStyle* style = element->renderStyle(); + + if (!style) + return false; + if (style->unique()) + return false; + if (element->tagQName() != m_element->tagQName()) + return false; + if (element->hasClass() != m_element->hasClass()) + return false; + if (element->inlineStyleDecl()) + return false; + if (element->hasMappedAttributes() != m_styledElement->hasMappedAttributes()) + return false; + if (element->isLink() != m_element->isLink()) + return false; + if (style->affectedByUncommonAttributeSelectors()) + return false; + if (element->hovered() != m_element->hovered()) + return false; + if (element->active() != m_element->active()) + return false; + if (element->focused() != m_element->focused()) + return false; + if (element->shadowPseudoId() != m_element->shadowPseudoId()) + return false; + if (element == element->document()->cssTarget()) + return false; + if (m_element == m_element->document()->cssTarget()) + return false; + if (element->getAttribute(typeAttr) != m_element->getAttribute(typeAttr)) + return false; + if (element->fastGetAttribute(XMLNames::langAttr) != m_element->fastGetAttribute(XMLNames::langAttr)) + return false; + if (element->fastGetAttribute(langAttr) != m_element->fastGetAttribute(langAttr)) + return false; + if (element->fastGetAttribute(readonlyAttr) != m_element->fastGetAttribute(readonlyAttr)) + return false; + if (element->fastGetAttribute(cellpaddingAttr) != m_element->fastGetAttribute(cellpaddingAttr)) + return false; + + if (element->hasID() && m_features.idsInRules.contains(element->idForStyleResolution().impl())) + return false; + + bool isControl = element->isFormControlElement(); + + if (isControl != m_element->isFormControlElement()) + return false; + + if (isControl && !canShareStyleWithControl(element)) + 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 (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag) +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + // With proxying, the media elements are backed by a RenderEmbeddedObject. + || element->hasTagName(videoTag) || element->hasTagName(audioTag) +#endif + ) + return false; +#endif + + if (equalIgnoringCase(element->fastGetAttribute(dirAttr), "auto") || equalIgnoringCase(m_element->fastGetAttribute(dirAttr), "auto")) + return false; + + if (element->hasClass() && m_element->getAttribute(classAttr) != element->getAttribute(classAttr)) + return false; + + if (element->hasMappedAttributes() && !element->attributeMap()->mappedMapsEquivalent(m_styledElement->attributeMap())) + return false; + + if (element->isLink() && m_elementLinkState != style->insideLink()) + return false; + + return true; +} + +inline StyledElement* CSSStyleSelector::findSiblingForStyleSharing(Node* node, unsigned& count) const +{ + for (; node; node = node->previousSibling()) { + if (!node->isStyledElement()) + continue; + if (canShareStyleWithElement(static_cast<StyledElement*>(node))) + break; + if (count++ == cStyleSearchThreshold) + return 0; + } + return static_cast<StyledElement*>(node); +} + +static inline bool parentStylePreventsSharing(const RenderStyle* parentStyle) +{ + return parentStyle->childrenAffectedByPositionalRules() + || parentStyle->childrenAffectedByFirstChildRules() + || parentStyle->childrenAffectedByLastChildRules() + || parentStyle->childrenAffectedByDirectAdjacentRules(); +} + +RenderStyle* CSSStyleSelector::locateSharedStyle() +{ + if (!m_styledElement || !m_parentStyle) + return 0; + // If the element has inline style it is probably unique. + if (m_styledElement->inlineStyleDecl()) + return 0; + // Ids stop style sharing if they show up in the stylesheets. + if (m_styledElement->hasID() && m_features.idsInRules.contains(m_styledElement->idForStyleResolution().impl())) + return 0; + if (parentStylePreventsSharing(m_parentStyle)) + return 0; + + // Check previous siblings and their cousins. + unsigned count = 0; + unsigned visitedNodeCount = 0; + StyledElement* shareElement = 0; + Node* cousinList = m_styledElement->previousSibling(); + while (cousinList) { + shareElement = findSiblingForStyleSharing(cousinList, count); + if (shareElement) + break; + cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount); + } + + // If we have exhausted all our budget or our cousins. + if (!shareElement) + return 0; + + // Can't share if sibling rules apply. This is checked at the end as it should rarely fail. + if (matchesRuleSet(m_features.siblingRules.get())) + return 0; + // Can't share if attribute rules apply. + if (matchesRuleSet(m_features.uncommonAttributeRules.get())) + return 0; + // Tracking child index requires unique style for each node. This may get set by the sibling rule match above. + if (parentStylePreventsSharing(m_parentStyle)) + return 0; + return shareElement->renderStyle(); +} + +void CSSStyleSelector::matchUARules(MatchResult& result) +{ + MatchingUARulesScope scope; + + // First we match rules from the user agent sheet. + if (simpleDefaultStyleSheet) + result.isCacheable = false; + RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") + ? defaultPrintStyle : defaultStyle; + matchRules(userAgentStyleSheet, result.firstUARule, result.lastUARule, false); + + // In quirks mode, we match rules from the quirks user agent sheet. + if (!m_checker.strictParsing()) + matchRules(defaultQuirksStyle, result.firstUARule, result.lastUARule, false); + + // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet. + if (m_checker.document()->isViewSource()) { + if (!defaultViewSourceStyle) + loadViewSourceStyle(); + matchRules(defaultViewSourceStyle, result.firstUARule, result.lastUARule, false); + } +} + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForDocument(Document* document, CSSFontSelector* fontSelector) +{ + Frame* frame = document->frame(); + + RefPtr<RenderStyle> documentStyle = RenderStyle::create(); + documentStyle->setDisplay(BLOCK); + documentStyle->setRTLOrdering(document->visuallyOrdered() ? VisualOrder : LogicalOrder); + documentStyle->setZoom(frame ? frame->pageZoomFactor() : 1); + documentStyle->setPageScaleTransform(frame ? frame->frameScaleFactor() : 1); + documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY); + + 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()); + } + + if (frame) { + if (Page* page = frame->page()) { + const Page::Pagination& pagination = page->pagination(); + if (pagination.mode != Page::Pagination::Unpaginated) { + documentStyle->setColumnAxis(pagination.mode == Page::Pagination::HorizontallyPaginated ? HorizontalColumnAxis : VerticalColumnAxis); + documentStyle->setColumnGap(pagination.gap); + } + } + } + + FontDescription fontDescription; + fontDescription.setUsePrinterFont(document->printing()); + if (Settings* settings = document->settings()) { + fontDescription.setRenderingMode(settings->fontRenderingMode()); + const AtomicString& stdfont = settings->standardFontFamily(); + if (!stdfont.isEmpty()) { + fontDescription.setGenericFamily(FontDescription::StandardFamily); + 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(fontSelector); + + return documentStyle.release(); +} + +static inline bool isAtShadowBoundary(Element* element) +{ + if (!element) + return false; + ContainerNode* parentNode = element->parentNode(); + return parentNode && parentNode->isShadowRoot(); +} + +// 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* element, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault) +{ + // 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 && !element->document()->haveStylesheetsLoaded() && !element->renderer()) { + if (!s_styleNotYetAvailable) { + s_styleNotYetAvailable = RenderStyle::create().leakRef(); + s_styleNotYetAvailable->setDisplay(NONE); + s_styleNotYetAvailable->font().update(m_fontSelector); + } + element->document()->setHasNodesWithPlaceholderStyle(); + return s_styleNotYetAvailable; + } + + initElement(element); + initForStyleResolve(element, defaultParent); + if (allowSharing) { + RenderStyle* sharedStyle = locateSharedStyle(); + if (sharedStyle) + return sharedStyle; + } + + m_style = RenderStyle::create(); + + if (m_parentStyle) + m_style->inheritFrom(m_parentStyle); + else { + m_parentStyle = style(); + // Make sure our fonts are initialized if we don't inherit them from our parent style. + m_style->font().update(0); + } + + // Even if surrounding content is user-editable, shadow DOM should act as a single unit, and not necessarily be editable + if (isAtShadowBoundary(element)) + m_style->setUserModify(RenderStyle::initialUserModify()); + + if (element->isLink()) { + m_style->setIsLink(true); + m_style->setInsideLink(m_elementLinkState); + } + + ensureDefaultStyleSheetsForElement(element); + + MatchResult matchResult; + if (resolveForRootDefault) + matchUARules(matchResult); + else + matchAllRules(matchResult); + + applyMatchedDeclarations(matchResult); + + // Clean up our style object's display and text decorations (among other fixups). + adjustRenderStyle(style(), m_parentStyle, element); + + 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. + bool inheritedOnly = false; + if (keyframeRule->style()) + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1, inheritedOnly); + + // If our font got dirtied, go ahead and update it now. + 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, inheritedOnly); + + // If our font got dirtied by one of the non-essential font props, + // go ahead and update it a second time. + updateFont(); + + // Start loading images referenced by this style. + loadPendingImages(); + +#if ENABLE(CSS_SHADERS) + // Start loading the shaders referenced by this style. + loadPendingShaders(); +#endif + + // 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(); + + KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(list.animationName().impl()); + if (it == m_keyframesRuleMap.end()) + return; + + const WebKitCSSKeyframesRule* rule = it->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) +{ + if (!e) + return 0; + + initElement(e); + + initForStyleResolve(e, parentStyle, pseudo); + m_style = RenderStyle::create(); + + if (m_parentStyle) + m_style->inheritFrom(m_parentStyle); + + // 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. + MatchResult matchResult; + matchUARules(matchResult); + + if (m_matchAuthorAndUserStyles) { + matchRules(m_userStyle.get(), matchResult.firstUserRule, matchResult.lastUserRule, false); + matchRules(m_authorStyle.get(), matchResult.firstAuthorRule, matchResult.lastAuthorRule, false); + } + + if (m_matchedDecls.isEmpty()) + return 0; + + m_style->setStyleType(pseudo); + + applyMatchedDeclarations(matchResult); + + // 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(); + +#if ENABLE(CSS_SHADERS) + // Start loading the shaders referenced by this style. + loadPendingShaders(); +#endif + + // Now return the style. + return m_style.release(); +} + +PassRefPtr<RenderStyle> CSSStyleSelector::styleForPage(int pageIndex) +{ + initForStyleResolve(m_checker.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; + bool inheritedOnly = false; + applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1, inheritedOnly); + + // If our font got dirtied, go ahead and update it now. + 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, inheritedOnly); + + // Start loading images referenced by this style. + loadPendingImages(); + +#if ENABLE(CSS_SHADERS) + // Start loading the shaders referenced by this style. + loadPendingShaders(); +#endif + + // Now return the style. + return m_style.release(); +} + +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.strictParsing() && e) { + if (e->hasTagName(tdTag)) { + style->setDisplay(TABLE_CELL); + style->setFloating(NoFloat); + } + 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->isFloating() || + (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.strictParsing() && style->isFloating()) + 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->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->hasFilter())) + style->setZIndex(0); + + // 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, run-ins, or shadow DOM. + if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN + || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e)) + 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 we have first-letter pseudo style, do not share this style. + if (style->hasPseudoStyle(FIRST_LETTER)) + style->setUnique(); + +#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 +} + +bool CSSStyleSelector::checkRegionStyle(Element* e) +{ + m_checker.clearHasUnknownPseudoElements(); + m_checker.setPseudoStyle(NOPSEUDO); + + for (Vector<RefPtr<WebKitCSSRegionRule> >::iterator it = m_regionStyleRules.begin(); it != m_regionStyleRules.end(); ++it) { + const CSSSelectorList& regionSelectorList = (*it)->selectorList(); + for (CSSSelector* s = regionSelectorList.first(); s; s = regionSelectorList.next(s)) { + if (m_checker.checkSelector(s, e)) + return true; + } + } + + return false; +} + +void CSSStyleSelector::updateFont() +{ + if (!m_fontDirty) + return; + + 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, unsigned rulesToInclude) +{ + return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude); +} + +PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude) +{ + if (!e || !e->document()->haveStylesheetsLoaded()) + return 0; + + m_checker.setCollectingRulesOnly(true); + + initElement(e); + initForStyleResolve(e, 0, pseudoId); + + MatchResult dummy; + if (rulesToInclude & UAAndUserCSSRules) { + // First we match rules from the user agent sheet. + matchUARules(dummy); + + // Now we check user sheet rules. + if (m_matchAuthorAndUserStyles) + matchRules(m_userStyle.get(), dummy.firstUserRule, dummy.lastUserRule, rulesToInclude & EmptyCSSRules); + } + + if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) { + m_sameOriginOnly = !(rulesToInclude & CrossOriginCSSRules); + + // Check the rules in author sheets. + matchRules(m_authorStyle.get(), dummy.firstAuthorRule, dummy.lastAuthorRule, rulesToInclude & EmptyCSSRules); + + m_sameOriginOnly = false; + } + + m_checker.setCollectingRulesOnly(false); + + return m_ruleList.release(); +} + +inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData) +{ + m_dynamicPseudo = NOPSEUDO; + m_checker.clearHasUnknownPseudoElements(); + + // Let the slow path handle SVG as it has some additional rules regarding shadow trees. + if (ruleData.hasFastCheckableSelector() && !m_element->isSVGElement()) { + // We know this selector does not include any pseudo elements. + if (m_checker.pseudoStyle() != NOPSEUDO) + return false; + // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. + // This is limited to HTML only so we don't need to check the namespace. + if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_element->isHTMLElement()) { + if (!ruleData.hasMultipartSelector()) + return true; + } else if (!SelectorChecker::tagMatches(m_element, ruleData.selector())) + return false; + if (!SelectorChecker::fastCheckRightmostAttributeSelector(m_element, ruleData.selector())) + return false; + return m_checker.fastCheckSelector(ruleData.selector(), m_element); + } + + // Slow path. + SelectorChecker::SelectorMatch match = m_checker.checkSelector(ruleData.selector(), m_element, m_dynamicPseudo, false, SelectorChecker::VisitedMatchEnabled, style(), m_parentNode ? m_parentNode->renderStyle() : 0); + if (match != SelectorChecker::SelectorMatches) + return false; + if (m_checker.pseudoStyle() != NOPSEUDO && m_checker.pseudoStyle() != m_dynamicPseudo) + return false; + return true; +} + +bool CSSStyleSelector::determineStylesheetSelectorScopes(CSSStyleSheet* stylesheet, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes) +{ + ASSERT(!stylesheet->isLoading()); + + size_t size = stylesheet->length(); + for (size_t i = 0; i < size; i++) { + CSSRule* rule = stylesheet->item(i); + if (rule->isStyleRule()) { + CSSStyleRule* styleRule = static_cast<CSSStyleRule*>(rule); + if (!SelectorChecker::determineSelectorScopes(styleRule->selectorList(), idScopes, classScopes)) + return false; + continue; + } + if (rule->isImportRule()) { + CSSImportRule* importRule = static_cast<CSSImportRule*>(rule); + if (importRule->styleSheet()) { + if (!determineStylesheetSelectorScopes(importRule->styleSheet(), idScopes, classScopes)) + return false; + } + continue; + } + // FIXME: Media rules and maybe some others could be allowed. + return false; + } + return true; +} + +// ----------------------------------------------------------------- + +static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector* selector) +{ + const AtomicString& selectorNamespace = selector->tag().namespaceURI(); + if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI) + return false; + if (selector->m_match == CSSSelector::None) + return true; + if (selector->tag() != starAtom) + return false; + if (SelectorChecker::isCommonPseudoClassSelector(selector)) + return true; + return selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class; +} + +static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector) +{ + CSSSelectorList* selectorList = selector->selectorList(); + if (!selectorList) + return false; + for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (subSelector->isAttributeSelector()) + return true; + } + return false; +} + +static inline bool isCommonAttributeSelectorAttribute(const QualifiedName& attribute) +{ + // These are explicitly tested for equality in canShareStyleWithElement. + return attribute == typeAttr || attribute == readonlyAttr; +} + +static inline bool containsUncommonAttributeSelector(const CSSSelector* selector) +{ + while (selector) { + // Allow certain common attributes (used in the default style) in the selectors that match the current element. + if (selector->isAttributeSelector() && !isCommonAttributeSelectorAttribute(selector->attribute())) + return true; + if (selectorListContainsUncommonAttributeSelector(selector)) + return true; + if (selector->relation() != CSSSelector::SubSelector) + break; + selector = selector->tagHistory(); + }; + + for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) { + if (selector->isAttributeSelector()) + return true; + if (selectorListContainsUncommonAttributeSelector(selector)) + return true; + } + return false; +} + +RuleData::RuleData(CSSStyleRule* rule, CSSSelector* selector, unsigned position) + : m_rule(rule) + , m_selector(selector) + , m_specificity(selector->specificity()) + , m_position(position) + , m_hasFastCheckableSelector(SelectorChecker::isFastCheckableSelector(selector)) + , m_hasMultipartSelector(!!selector->tagHistory()) + , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector)) + , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector)) + , m_linkMatchType(SelectorChecker::determineLinkMatchType(selector)) +{ + SelectorChecker::collectIdentifierHashes(m_selector, m_descendantSelectorIdentifierHashes, maximumIdentifierCount); +} + +RuleSet::RuleSet() + : m_ruleCount(0) + , m_autoShrinkToFitEnabled(true) +{ +} + +void RuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, CSSStyleRule* rule, CSSSelector* selector) +{ + if (!key) + return; + OwnPtr<Vector<RuleData> >& rules = map.add(key, nullptr).first->second; + if (!rules) + rules = adoptPtr(new Vector<RuleData>); + rules->append(RuleData(rule, selector, m_ruleCount++)); +} + +void RuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel) +{ + if (sel->m_match == CSSSelector::Id) { + addToRuleSet(sel->value().impl(), m_idRules, rule, sel); + return; + } + if (sel->m_match == CSSSelector::Class) { + addToRuleSet(sel->value().impl(), m_classRules, rule, sel); + return; + } + if (sel->isUnknownPseudoElement()) { + addToRuleSet(sel->value().impl(), m_shadowPseudoElementRules, rule, sel); + return; + } + if (SelectorChecker::isCommonPseudoClassSelector(sel)) { + RuleData ruleData(rule, sel, m_ruleCount++); + switch (sel->pseudoType()) { + case CSSSelector::PseudoLink: + case CSSSelector::PseudoVisited: + case CSSSelector::PseudoAnyLink: + m_linkPseudoClassRules.append(ruleData); + return; + case CSSSelector::PseudoFocus: + m_focusPseudoClassRules.append(ruleData); + return; + default: + ASSERT_NOT_REACHED(); + } + return; + } + const AtomicString& localName = sel->tag().localName(); + if (localName != starAtom) { + addToRuleSet(localName.impl(), m_tagRules, rule, sel); + return; + } + + m_universalRules.append(RuleData(rule, sel, m_ruleCount++)); +} + +void RuleSet::addPageRule(CSSPageRule* rule) +{ + m_pageRules.append(RuleData(rule, rule->selectorList().first(), m_pageRules.size())); +} + +void RuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector) +{ + ASSERT(sheet); + + // 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++) { + CSSRule* rule = sheet->item(i); + if (rule->isStyleRule()) + addStyleRule(static_cast<CSSStyleRule*>(rule)); + else if (rule->isPageRule()) + addPageRule(static_cast<CSSPageRule*>(rule)); + else if (rule->isImportRule()) { + CSSImportRule* import = static_cast<CSSImportRule*>(rule); + if (import->styleSheet() && (!import->media() || medium.eval(import->media(), styleSelector))) + addRulesFromSheet(import->styleSheet(), medium, styleSelector); + } + else if (rule->isMediaRule()) { + CSSMediaRule* r = static_cast<CSSMediaRule*>(rule); + 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()) + addStyleRule(static_cast<CSSStyleRule*>(childItem)); + else if (childItem->isPageRule()) + addPageRule(static_cast<CSSPageRule*>(childItem)); + else if (childItem->isFontFaceRule() && styleSelector) { + // Add this font face to our set. + const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(childItem); + styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); + styleSelector->invalidateMatchedDeclarationCache(); + } else if (childItem->isKeyframesRule() && styleSelector) { + // Add this keyframe rule to our set. + styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(childItem)); + } + } // for rules + } // if rules + } else if (rule->isFontFaceRule() && styleSelector) { + // Add this font face to our set. + const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(rule); + styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); + styleSelector->invalidateMatchedDeclarationCache(); + } else if (rule->isKeyframesRule()) + styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(rule)); + else if (rule->isRegionRule() && styleSelector) + styleSelector->addRegionRule(static_cast<WebKitCSSRegionRule*>(rule)); + } + if (m_autoShrinkToFitEnabled) + shrinkToFit(); +} + +void RuleSet::addStyleRule(CSSStyleRule* rule) +{ + for (CSSSelector* s = rule->selectorList().first(); s; s = CSSSelectorList::next(s)) + addRule(rule, s); +} + +static inline void collectFeaturesFromSelector(CSSStyleSelector::Features& features, const CSSSelector* selector) +{ + if (selector->m_match == CSSSelector::Id && !selector->value().isEmpty()) + features.idsInRules.add(selector->value().impl()); + if (selector->isAttributeSelector()) + features.attrsInRules.add(selector->attribute().localName().impl()); + switch (selector->pseudoType()) { + case CSSSelector::PseudoFirstLine: + features.usesFirstLineRules = true; + break; + case CSSSelector::PseudoBefore: + case CSSSelector::PseudoAfter: + features.usesBeforeAfterRules = true; + break; + case CSSSelector::PseudoLink: + case CSSSelector::PseudoVisited: + features.usesLinkRules = true; + break; + default: + break; + } +} + +static void collectFeaturesFromList(CSSStyleSelector::Features& features, const Vector<RuleData>& rules) +{ + unsigned size = rules.size(); + for (unsigned i = 0; i < size; ++i) { + const RuleData& ruleData = rules[i]; + bool foundSiblingSelector = false; + for (CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) { + collectFeaturesFromSelector(features, selector); + + if (CSSSelectorList* selectorList = selector->selectorList()) { + for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (selector->isSiblingSelector()) + foundSiblingSelector = true; + collectFeaturesFromSelector(features, subSelector); + } + } else if (selector->isSiblingSelector()) + foundSiblingSelector = true; + } + if (foundSiblingSelector) { + if (!features.siblingRules) + features.siblingRules = adoptPtr(new RuleSet); + features.siblingRules->addRule(ruleData.rule(), ruleData.selector()); + } + if (ruleData.containsUncommonAttributeSelector()) { + if (!features.uncommonAttributeRules) + features.uncommonAttributeRules = adoptPtr(new RuleSet); + features.uncommonAttributeRules->addRule(ruleData.rule(), ruleData.selector()); + } + } +} + +void RuleSet::collectFeatures(CSSStyleSelector::Features& features) const +{ + AtomRuleMap::const_iterator end = m_idRules.end(); + for (AtomRuleMap::const_iterator it = m_idRules.begin(); it != end; ++it) + collectFeaturesFromList(features, *it->second); + end = m_classRules.end(); + for (AtomRuleMap::const_iterator it = m_classRules.begin(); it != end; ++it) + collectFeaturesFromList(features, *it->second); + end = m_tagRules.end(); + for (AtomRuleMap::const_iterator it = m_tagRules.begin(); it != end; ++it) + collectFeaturesFromList(features, *it->second); + end = m_shadowPseudoElementRules.end(); + for (AtomRuleMap::const_iterator it = m_shadowPseudoElementRules.begin(); it != end; ++it) + collectFeaturesFromList(features, *it->second); + collectFeaturesFromList(features, m_linkPseudoClassRules); + collectFeaturesFromList(features, m_focusPseudoClassRules); + collectFeaturesFromList(features, m_universalRules); +} + +static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map) +{ + RuleSet::AtomRuleMap::iterator end = map.end(); + for (RuleSet::AtomRuleMap::iterator it = map.begin(); it != end; ++it) + it->second->shrinkToFit(); +} + +void RuleSet::shrinkToFit() +{ + shrinkMapVectorsToFit(m_idRules); + shrinkMapVectorsToFit(m_classRules); + shrinkMapVectorsToFit(m_tagRules); + shrinkMapVectorsToFit(m_shadowPseudoElementRules); + m_linkPseudoClassRules.shrinkToFit(); + m_focusPseudoClassRules.shrinkToFit(); + m_universalRules.shrinkToFit(); + m_pageRules.shrinkToFit(); +} + +// ------------------------------------------------------------------------------------- +// this is mostly boring stuff on how to apply a certain rule to the renderstyle... + +static Length convertToLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, bool toFloat, 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)) { + if (toFloat) + l = Length(primitiveValue->computeLength<double>(style, rootStyle, multiplier), Fixed); + else + l = primitiveValue->computeLength<Length>(style, rootStyle, multiplier); + } + 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; +} + +static Length convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0) +{ + return convertToLength(primitiveValue, style, rootStyle, false, multiplier, ok); +} + +static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0) +{ + return convertToLength(primitiveValue, style, rootStyle, true, multiplier, ok); +} + +template <bool applyFirst> +void CSSStyleSelector::applyDeclaration(CSSMutableStyleDeclaration* styleDeclaration, bool isImportant, bool inheritedOnly) +{ + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willProcessRule(document(), styleDeclaration->parentRule()); + CSSMutableStyleDeclaration::const_iterator end = styleDeclaration->end(); + for (CSSMutableStyleDeclaration::const_iterator it = styleDeclaration->begin(); it != end; ++it) { + const CSSProperty& current = *it; + if (isImportant != current.isImportant()) + continue; + if (inheritedOnly && !current.isInherited()) { + // If the property value is explicitly inherited, we need to apply further non-inherited properties + // as they might override the value inherited here. For this reason we don't allow declarations with + // explicitly inherited properties to be cached. + ASSERT(!current.value()->isInheritedValue()); + continue; + } + int property = current.id(); + if (applyFirst) { + COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property); + COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 16, 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) + continue; + // we apply line-height later + if (property == CSSPropertyLineHeight) { + m_lineHeightValue = current.value(); + continue; + } + applyProperty(current.id(), current.value()); + continue; + } + if (property > CSSPropertyLineHeight) + applyProperty(current.id(), current.value()); + } + InspectorInstrumentation::didProcessRule(cookie); +} + +template <bool applyFirst> +void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex, bool inheritedOnly) +{ + if (startIndex == -1) + return; + + if (m_style->insideLink() != NotInsideLink) { + for (int i = startIndex; i <= endIndex; ++i) { + CSSMutableStyleDeclaration* styleDeclaration = m_matchedDecls[i].styleDeclaration; + unsigned linkMatchType = m_matchedDecls[i].linkMatchType; + // FIXME: It would be nicer to pass these as arguments but that requires changes in many places. + m_applyPropertyToRegularStyle = linkMatchType & SelectorChecker::MatchLink; + m_applyPropertyToVisitedLinkStyle = linkMatchType & SelectorChecker::MatchVisited; + + applyDeclaration<applyFirst>(styleDeclaration, isImportant, inheritedOnly); + } + m_applyPropertyToRegularStyle = true; + m_applyPropertyToVisitedLinkStyle = false; + return; + } + for (int i = startIndex; i <= endIndex; ++i) + applyDeclaration<applyFirst>(m_matchedDecls[i].styleDeclaration, isImportant, inheritedOnly); +} + +unsigned CSSStyleSelector::computeDeclarationHash(MatchedStyleDeclaration* declarations, unsigned size) +{ + return StringHasher::hashMemory(declarations, sizeof(MatchedStyleDeclaration) * size); +} + +bool operator==(const CSSStyleSelector::MatchResult& a, const CSSStyleSelector::MatchResult& b) +{ + return a.firstUARule == b.firstUARule + && a.lastUARule == b.lastUARule + && a.firstAuthorRule == b.firstAuthorRule + && a.lastAuthorRule == b.lastAuthorRule + && a.firstUserRule == b.firstUserRule + && a.lastUserRule == b.lastUserRule + && a.isCacheable == b.isCacheable; +} + +bool operator!=(const CSSStyleSelector::MatchResult& a, const CSSStyleSelector::MatchResult& b) +{ + return !(a == b); +} + +bool operator==(const CSSStyleSelector::MatchedStyleDeclaration& a, const CSSStyleSelector::MatchedStyleDeclaration& b) +{ + return a.styleDeclaration == b.styleDeclaration && a.linkMatchType == b.linkMatchType; +} + +bool operator!=(const CSSStyleSelector::MatchedStyleDeclaration& a, const CSSStyleSelector::MatchedStyleDeclaration& b) +{ + return !(a == b); +} + +const CSSStyleSelector::MatchedStyleDeclarationCacheItem* CSSStyleSelector::findFromMatchedDeclarationCache(unsigned hash, const MatchResult& matchResult) +{ + ASSERT(hash); + + MatchedStyleDeclarationCache::iterator it = m_matchedStyleDeclarationCache.find(hash); + if (it == m_matchedStyleDeclarationCache.end()) + return 0; + MatchedStyleDeclarationCacheItem& cacheItem = it->second; + ASSERT(cacheItem.matchResult.isCacheable); + + size_t size = m_matchedDecls.size(); + if (size != cacheItem.matchedStyleDeclarations.size()) + return 0; + for (size_t i = 0; i < size; ++i) { + if (m_matchedDecls[i] != cacheItem.matchedStyleDeclarations[i]) + return 0; + } + if (cacheItem.matchResult != matchResult) + return 0; + return &cacheItem; +} + +void CSSStyleSelector::addToMatchedDeclarationCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult) +{ + ASSERT(hash); + MatchedStyleDeclarationCacheItem cacheItem; + cacheItem.matchedStyleDeclarations.append(m_matchedDecls); + cacheItem.matchResult = matchResult; + // Note that we don't cache the original RenderStyle instance. It may be further modified. + // The RenderStyle in the cache is really just a holder for the substructures and never used as-is. + cacheItem.renderStyle = RenderStyle::clone(style); + cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle); + m_matchedStyleDeclarationCache.add(hash, cacheItem); +} + +void CSSStyleSelector::invalidateMatchedDeclarationCache() +{ + m_matchedStyleDeclarationCache.clear(); +} + +static bool isCacheableInMatchedDeclarationCache(const RenderStyle* style, const RenderStyle* parentStyle) +{ + if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique())) + return false; + if (style->hasAppearance()) + return false; + if (style->zoom() != RenderStyle::initialZoom()) + return false; + // The cache assumes static knowledge about which properties are inherited. + if (parentStyle->hasExplicitlyInheritedProperties()) + return false; + return true; +} + +void CSSStyleSelector::applyMatchedDeclarations(const MatchResult& matchResult) +{ + unsigned cacheHash = matchResult.isCacheable ? computeDeclarationHash(m_matchedDecls.data(), m_matchedDecls.size()) : 0; + bool applyInheritedOnly = false; + const MatchedStyleDeclarationCacheItem* cacheItem = 0; + if (cacheHash && (cacheItem = findFromMatchedDeclarationCache(cacheHash, matchResult))) { + // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact + // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the + // element context. This is fast and saves memory by reusing the style data structures. + m_style->copyNonInheritedFrom(cacheItem->renderStyle.get()); + if (m_parentStyle->inheritedDataShared(cacheItem->parentRenderStyle.get())) { + EInsideLink linkStatus = m_style->insideLink(); + // If the cache item parent style has identical inherited properties to the current parent style then the + // resulting style will be identical too. We copy the inherited properties over from the cache and are done. + m_style->inheritFrom(cacheItem->renderStyle.get()); + // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it. + m_style->setInsideLink(linkStatus); + return; + } + applyInheritedOnly = true; + } + // 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, applyInheritedOnly); + applyDeclarations<true>(true, matchResult.firstAuthorRule, matchResult.lastAuthorRule, applyInheritedOnly); + applyDeclarations<true>(true, matchResult.firstUserRule, matchResult.lastUserRule, applyInheritedOnly); + applyDeclarations<true>(true, matchResult.firstUARule, matchResult.lastUARule, applyInheritedOnly); + + if (cacheItem && cacheItem->renderStyle->effectiveZoom() != m_style->effectiveZoom()) { + m_fontDirty = true; + applyInheritedOnly = false; + } + + // If our font got dirtied, go ahead and update it now. + updateFont(); + + // Line-height is set when we are sure we decided on the font-size. + if (m_lineHeightValue) + applyProperty(CSSPropertyLineHeight, m_lineHeightValue); + + // Many properties depend on the font. If it changes we just apply all properties. + if (cacheItem && cacheItem->renderStyle->fontDescription() != m_style->fontDescription()) + applyInheritedOnly = false; + + // Now do the normal priority UA properties. + applyDeclarations<false>(false, matchResult.firstUARule, matchResult.lastUARule, applyInheritedOnly); + + // 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. + applyDeclarations<false>(false, matchResult.lastUARule + 1, m_matchedDecls.size() - 1, applyInheritedOnly); + applyDeclarations<false>(true, matchResult.firstAuthorRule, matchResult.lastAuthorRule, applyInheritedOnly); + applyDeclarations<false>(true, matchResult.firstUserRule, matchResult.lastUserRule, applyInheritedOnly); + applyDeclarations<false>(true, matchResult.firstUARule, matchResult.lastUARule, applyInheritedOnly); + + loadPendingImages(); + +#if ENABLE(CSS_SHADERS) + loadPendingShaders(); +#endif + + ASSERT(!m_fontDirty); + + if (cacheItem || !cacheHash) + return; + if (!isCacheableInMatchedDeclarationCache(m_style.get(), m_parentStyle)) + return; + addToMatchedDeclarationCache(m_style.get(), m_parentStyle, cacheHash, matchResult); +} + +void CSSStyleSelector::matchPageRules(RuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName) +{ + m_matchedRules.clear(); + + if (!rules) + return; + + matchPageRulesForList(rules->pageRules(), 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(); + + // 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(const Vector<RuleData>* rules, bool isLeftPage, bool isFirstPage, const String& pageName) +{ + if (!rules) + return; + + unsigned size = rules->size(); + for (unsigned i = 0; i < size; ++i) { + const RuleData& ruleData = rules->at(i); + CSSStyleRule* rule = ruleData.rule(); + const AtomicString& selectorLocalName = ruleData.selector()->tag().localName(); + if (selectorLocalName != starAtom && selectorLocalName != pageName) + continue; + CSSSelector::PseudoType pseudoType = ruleData.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(&ruleData); + } +} + +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 ""; +} + +void CSSStyleSelector::applyPropertyToStyle(int id, CSSValue* value, RenderStyle* style) +{ + initElement(0); + initForStyleResolve(0, style); + m_style = style; + applyPropertyToCurrentStyle(id, value); +} + +void CSSStyleSelector::applyPropertyToCurrentStyle(int id, CSSValue* value) +{ + 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; +} + +// 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 CSSStyleSelector::useSVGZoomRules() +{ + return m_element && m_element->isSVGElement(); +} + +#if ENABLE(CSS_GRID_LAYOUT) + +static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, CSSStyleSelector* selector, Length& length) +{ + if (primitiveValue->getIdent() == CSSValueAuto) { + length = Length(); + return true; + } + + int type = primitiveValue->primitiveType(); + if (CSSPrimitiveValue::isUnitTypeLength(type)) { + length = primitiveValue->computeLength<Length>(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom()); + length.setQuirk(primitiveValue->isQuirkValue()); + return true; + } + + if (type == CSSPrimitiveValue::CSS_PERCENTAGE) { + length = Length(primitiveValue->getDoubleValue(), Percent); + return true; + } + + return false; +} + +static bool createGridTrackList(CSSValue* value, Vector<Length>& lengths, CSSStyleSelector* selector) +{ + // Handle 'none'. + if (value->isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + if (primitiveValue->getIdent() == CSSValueNone) { + lengths.append(Length(Undefined)); + return true; + } + return false; + } + + if (value->isValueList()) { + for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { + CSSValue* currValue = i.value(); + if (!currValue->isPrimitiveValue()) + return false; + + Length length; + if (!createGridTrackBreadth(static_cast<CSSPrimitiveValue*>(currValue), selector, length)) + return false; + + lengths.append(length); + } + return true; + } + + return false; +} +#endif + +void CSSStyleSelector::applyProperty(int id, CSSValue *value) +{ + bool isInherit = m_parentNode && value->isInheritedValue(); + bool isInitial = value->isInitialValue() || (!m_parentNode && value->isInheritedValue()); + + ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit + + if (!applyPropertyToRegularStyle() && (!applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) { + // Limit the properties that can be applied to only the ones honored by :visited. + return; + } + + CSSPropertyID property = static_cast<CSSPropertyID>(id); + + if (isInherit && m_parentStyle && !m_parentStyle->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(property)) + m_parentStyle->setHasExplicitlyInheritedProperties(); + + // check lookup table for implementations and use when available + const PropertyHandler& handler = m_applyProperty.propertyHandler(property); + if (handler.isValid()) { + if (isInherit) + handler.applyInheritValue(this); + else if (isInitial) + handler.applyInitialValue(this); + else + handler.applyValue(this, value); + return; + } + + CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? static_cast<CSSPrimitiveValue*>(value) : 0; + + float zoomFactor = m_style->effectiveZoom(); + + // 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 (property) { +// ident only properties + case CSSPropertyBorderCollapse: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(borderCollapse, BorderCollapse) + return; + case CSSPropertyCaptionSide: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(captionSide, CaptionSide) + return; + case CSSPropertyClear: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(clear, Clear) + return; + case CSSPropertyEmptyCells: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(emptyCells, EmptyCells) + return; + case CSSPropertyFloat: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(floating, Floating) + 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_AND_PRIMITIVE_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak) + return; + case CSSPropertyPosition: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(position, Position) + return; + case CSSPropertyTableLayout: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(tableLayout, TableLayout) + 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; +// uri || inherit + 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 CSSPropertyWidows: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(widows, Widows) + return; + case CSSPropertyOrphans: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(orphans, Orphans) + 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 = convertToIntLength(rect->top(), style(), m_rootElementStyle, zoomFactor); + right = convertToIntLength(rect->right(), style(), m_rootElementStyle, zoomFactor); + bottom = convertToIntLength(rect->bottom(), style(), m_rootElementStyle, zoomFactor); + left = convertToIntLength(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; + + bool didSet = false; + for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { + CSSValue* item = i.value(); + if (item->isImageGeneratorValue()) { + m_style->setContent(StyleGeneratedImage::create(static_cast<CSSImageGeneratorValue*>(item)), 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); + const AtomicString& value = m_element->getAttribute(attr); + m_style->setContent(value.isNull() ? emptyAtom : value.impl(), didSet); + didSet = true; + // register the fact that the attribute value affects the style + m_features.attrsInRules.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(); + EListStyleType listStyleType = NoneListStyle; + int listStyleIdent = counterValue->listStyleIdent(); + if (listStyleIdent != CSSValueNone) + listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc); + OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(), listStyleType, counterValue->separator())); + m_style->setContent(counter.release(), didSet); + didSet = true; + break; + } + case CSSPrimitiveValue::CSS_IDENT: + switch (contentValue->getIdent()) { + case CSSValueOpenQuote: + m_style->setContent(OPEN_QUOTE, didSet); + didSet = true; + break; + case CSSValueCloseQuote: + m_style->setContent(CLOSE_QUOTE, didSet); + didSet = true; + break; + case CSSValueNoOpenQuote: + m_style->setContent(NO_OPEN_QUOTE, didSet); + didSet = true; + break; + case CSSValueNoCloseQuote: + m_style->setContent(NO_CLOSE_QUOTE, didSet); + didSet = true; + break; + default: + // normal and none do not have any effect. + {} + } + } + } + if (!didSet) + m_style->clearContent(); + return; + } + case CSSPropertyQuotes: + if (isInherit) { + if (m_parentStyle) + m_style->setQuotes(m_parentStyle->quotes()); + return; + } + if (isInitial) { + m_style->setQuotes(0); + return; + } + if (value->isValueList()) { + CSSValueList* list = static_cast<CSSValueList*>(value); + QuotesData* data = QuotesData::create(list->length()); + if (!data) + return; // Out of memory + String* quotes = data->data(); + for (CSSValueListIterator i = list; i.hasMore(); i.advance()) { + CSSValue* item = i.value(); + ASSERT(item->isPrimitiveValue()); + primitiveValue = static_cast<CSSPrimitiveValue*>(item); + ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING); + quotes[i.index()] = primitiveValue->getStringValue(); + } + m_style->setQuotes(adoptRef(data)); + } else if (primitiveValue) { + ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT); + if (primitiveValue->getIdent() == CSSValueNone) + m_style->setQuotes(adoptRef(QuotesData::create(0))); + } + 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()); + setFontDescription(fontDescription); + 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.document(), CSSValueXxSmall + fontDescription.keywordSize() - 1, false)); + fontDescription.setGenericFamily(initialDesc.genericFamily()); + if (!initialDesc.firstFamily().familyIsEmpty()) + fontDescription.setFamily(initialDesc.firstFamily()); + setFontDescription(fontDescription); + return; + } + + if (!value->isValueList()) + return; + FontDescription fontDescription = m_style->fontDescription(); + 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 (CSSValueListIterator i = value; i.hasMore(); i.advance()) { + CSSValue* item = i.value(); + if (!item->isPrimitiveValue()) + continue; + CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item); + AtomicString face; + Settings* settings = m_checker.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 = serifFamily; + fontDescription.setGenericFamily(FontDescription::SerifFamily); + break; + case CSSValueSansSerif: + face = sansSerifFamily; + fontDescription.setGenericFamily(FontDescription::SansSerifFamily); + break; + case CSSValueCursive: + face = cursiveFamily; + fontDescription.setGenericFamily(FontDescription::CursiveFamily); + break; + case CSSValueFantasy: + face = fantasyFamily; + fontDescription.setGenericFamily(FontDescription::FantasyFamily); + break; + case CSSValueMonospace: + face = monospaceFamily; + fontDescription.setGenericFamily(FontDescription::MonospaceFamily); + break; + case CSSValueWebkitPictograph: + face = pictographFamily; + fontDescription.setGenericFamily(FontDescription::PictographFamily); + 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.document(), CSSValueXxSmall + fontDescription.keywordSize() - 1, !oldFamilyUsedFixedDefaultSize)); + + setFontDescription(fontDescription); + } + 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 CSSPropertyFont: + if (isInherit) { + FontDescription fontDescription = m_parentStyle->fontDescription(); + m_style->setLineHeight(m_parentStyle->lineHeight()); + m_lineHeightValue = 0; + setFontDescription(fontDescription); + } else if (isInitial) { + Settings* settings = m_checker.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.document()->printing()); + const AtomicString& standardFontFamily = m_checker.document()->settings()->standardFontFamily(); + if (!standardFontFamily.isEmpty()) { + fontDescription.firstFamily().setFamily(standardFontFamily); + fontDescription.firstFamily().appendFamily(0); + } + fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); + setFontSize(fontDescription, fontSizeForKeyword(m_checker.document(), CSSValueMedium, false)); + m_style->setLineHeight(RenderStyle::initialLineHeight()); + m_lineHeightValue = 0; + setFontDescription(fontDescription); + } 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.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.document()->printing()); + + // Handle the zoom factor. + fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.document(), m_style.get(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules())); + setFontDescription(fontDescription); + } + } 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()); + // The previous properties can dirty our font but they don't try to read the font's + // properties back, which is safe. However if font-size is using the 'ex' unit, it will + // need query the dirtied font's x-height to get the computed size. To be safe in this + // case, let's just update the font now. + updateFont(); + applyProperty(CSSPropertyFontSize, font->size.get()); + + m_lineHeightValue = font->lineHeight.get(); + + applyProperty(CSSPropertyFontFamily, font->family.get()); + } + return; + + // CSS3 Properties + case CSSPropertyWebkitAppearance: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(appearance, Appearance) + return; + case CSSPropertyImageRendering: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(imageRendering, ImageRendering); + return; + case CSSPropertyTextShadow: + case CSSPropertyBoxShadow: + case CSSPropertyWebkitBoxShadow: { + if (isInherit) { + if (id == CSSPropertyTextShadow) + return m_style->setTextShadow(m_parentStyle->textShadow() ? adoptPtr(new ShadowData(*m_parentStyle->textShadow())) : nullptr); + return m_style->setBoxShadow(m_parentStyle->boxShadow() ? adoptPtr(new ShadowData(*m_parentStyle->boxShadow())) : nullptr); + } + if (isInitial || primitiveValue) // initial | none + return id == CSSPropertyTextShadow ? m_style->setTextShadow(nullptr) : m_style->setBoxShadow(nullptr); + + if (!value->isValueList()) + return; + + for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { + CSSValue* currValue = i.value(); + if (!currValue->isShadowValue()) + continue; + ShadowValue* item = static_cast<ShadowValue*>(currValue); + int x = item->x->computeLength<int>(style(), m_rootElementStyle, zoomFactor); + int y = item->y->computeLength<int>(style(), m_rootElementStyle, zoomFactor); + int blur = item->blur ? item->blur->computeLength<int>(style(), m_rootElementStyle, zoomFactor) : 0; + int spread = item->spread ? item->spread->computeLength<int>(style(), m_rootElementStyle, zoomFactor) : 0; + ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal; + Color color; + if (item->color) + color = colorFromPrimitiveValue(item->color.get()); + OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(x, y, blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent)); + if (id == CSSPropertyTextShadow) + m_style->setTextShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry + else + m_style->setBoxShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry + } + 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(reflectValue->offset()->computeLength<Length>(style(), m_rootElementStyle, zoomFactor)); + } + NinePieceImage mask; + mask.setMaskDefaults(); + 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(clampTo<float>(primitiveValue->getDoubleValue(), 0, 1)); + return; + case CSSPropertyWebkitBoxAlign: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxAlign, BoxAlign) + 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_AND_PRIMITIVE(backfaceVisibility, BackfaceVisibility) + 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_AND_PRIMITIVE(boxPack, BoxPack) + return; + case CSSPropertyWebkitBoxFlex: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxFlex, BoxFlex) + return; + case CSSPropertyWebkitBoxFlexGroup: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxFlexGroup, BoxFlexGroup) + return; + case CSSPropertyWebkitBoxOrdinalGroup: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxOrdinalGroup, BoxOrdinalGroup) + return; + case CSSPropertyBoxSizing: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxSizing, BoxSizing); + return; + case CSSPropertyWebkitColumnSpan: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(columnSpan, ColumnSpan) + 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_AND_PRIMITIVE_WITH_VALUE(columnBreakInside, ColumnBreakInside, PageBreak) + 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 CSSPropertyWebkitRegionBreakBefore: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(regionBreakBefore, RegionBreakBefore, PageBreak) + return; + case CSSPropertyWebkitRegionBreakAfter: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(regionBreakAfter, RegionBreakAfter, PageBreak) + return; + case CSSPropertyWebkitRegionBreakInside: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(regionBreakInside, RegionBreakInside, PageBreak) + return; + case CSSPropertyWebkitMarquee: + if (!m_parentNode || !value->isInheritedValue()) + 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; + 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; + } + 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 marqueeLength = convertToIntLength(primitiveValue, style(), m_rootElementStyle, 1, &ok); + if (ok) + m_style->setMarqueeIncrement(marqueeLength); + } + return; + } + case CSSPropertyWebkitMarqueeStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marqueeBehavior, MarqueeBehavior) + return; + case CSSPropertyWebkitRegionOverflow: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(regionOverflow, RegionOverflow); + return; + 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_AND_PRIMITIVE(textOverflow, TextOverflow) + 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 CSSPropertyWebkitHyphens: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(hyphens, Hyphens); + return; + case CSSPropertyWebkitLocale: { + HANDLE_INHERIT_AND_INITIAL(locale, Locale); + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setLocale(nullAtom); + else + m_style->setLocale(primitiveValue->getStringValue()); + FontDescription fontDescription = m_style->fontDescription(); + fontDescription.setScript(localeToScriptCodeForFontSelection(m_style->locale())); + setFontDescription(fontDescription); + return; + } + case CSSPropertyWebkitBorderFit: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(borderFit, BorderFit); + return; + case CSSPropertyWebkitTextSizeAdjust: { + HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust) + if (!primitiveValue || !primitiveValue->getIdent()) + return; + setTextSizeAdjust(primitiveValue->getIdent() == CSSValueAuto); + 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 = convertToIntLength(region->top(), style(), m_rootElementStyle); + Length right = convertToIntLength(region->right(), style(), m_rootElementStyle); + Length bottom = convertToIntLength(region->bottom(), style(), m_rootElementStyle); + Length left = convertToIntLength(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_AND_PRIMITIVE(rtlOrdering, RTLOrdering) + 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)->computeLength<float>(style(), m_rootElementStyle, zoomFactor); + break; + } + default: + width = primitiveValue->computeLength<float>(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 CSSPropertyWebkitTransformStyle: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(transformStyle3D, TransformStyle3D) + return; + case CSSPropertyWebkitPrintColorAdjust: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(printColorAdjust, PrintColorAdjust); + 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 = primitiveValue->computeLength<float>(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)->computeLength<float>(style(), m_rootElementStyle, zoomFactor); + } else + return; + + if (perspectiveValue >= 0.0f) + m_style->setPerspective(perspectiveValue); + return; + } + case CSSPropertyWebkitAnimation: + if (isInitial) + m_style->clearAnimations(); + else if (isInherit) + m_style->inheritAnimations(m_parentStyle->animations()); + return; + case CSSPropertyWebkitTransition: + if (isInitial) + m_style->clearTransitions(); + else if (isInherit) + m_style->inheritTransitions(m_parentStyle->transitions()); + 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.document()->settings(); + if (settings && settings->usesDashboardBackwardCompatibilityMode()) + return; +#endif + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(pointerEvents, PointerEvents) + return; + } +#if ENABLE(TOUCH_EVENTS) + case CSSPropertyWebkitTapHighlightColor: { + HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor); + if (!primitiveValue) + break; + + Color col = colorFromPrimitiveValue(primitiveValue); + m_style->setTapHighlightColor(col); + return; + } +#endif + case CSSPropertyWebkitColorCorrection: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(colorSpace, ColorSpace); + return; + case CSSPropertySpeak: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(speak, Speak); + 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 CSSPropertyWebkitMarginCollapse: + case CSSPropertyWebkitMarginBeforeCollapse: + case CSSPropertyWebkitMarginTopCollapse: + case CSSPropertyWebkitMarginAfterCollapse: + case CSSPropertyWebkitMarginBottomCollapse: + case CSSPropertyWebkitPaddingEnd: + case CSSPropertyWebkitPaddingStart: + case CSSPropertyWebkitPaddingBefore: + case CSSPropertyWebkitPaddingAfter: + case CSSPropertyWebkitLogicalWidth: + case CSSPropertyWebkitLogicalHeight: + case CSSPropertyWebkitMinLogicalWidth: + case CSSPropertyWebkitMinLogicalHeight: + case CSSPropertyWebkitMaxLogicalWidth: + case CSSPropertyWebkitMaxLogicalHeight: + { + int newId = CSSProperty::resolveDirectionAwareProperty(id, m_style->direction(), m_style->writingMode()); + ASSERT(newId != id); + return applyProperty(newId, value); + } + case CSSPropertyFontStretch: + case CSSPropertyPage: + 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; + + // 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); + setFontDescription(fontDescription); + return; + } + + case CSSPropertyWebkitLineBoxContain: { + HANDLE_INHERIT_AND_INITIAL(lineBoxContain, LineBoxContain) + if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { + m_style->setLineBoxContain(LineBoxContainNone); + return; + } + + if (!value->isCSSLineBoxContainValue()) + return; + + CSSLineBoxContainValue* lineBoxContainValue = static_cast<CSSLineBoxContainValue*>(value); + m_style->setLineBoxContain(lineBoxContainValue->value()); + return; + } + + case CSSPropertyWebkitColumnAxis: + HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(columnAxis, ColumnAxis); + return; + + case CSSPropertyWebkitWrapShapeInside: + HANDLE_INHERIT_AND_INITIAL(wrapShapeInside, WrapShapeInside); + if (!primitiveValue) + return; + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setWrapShapeInside(0); + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_SHAPE) + m_style->setWrapShapeInside(primitiveValue->getShapeValue()); + return; + + case CSSPropertyWebkitWrapShapeOutside: + HANDLE_INHERIT_AND_INITIAL(wrapShapeOutside, WrapShapeOutside); + if (!primitiveValue) + return; + if (primitiveValue->getIdent() == CSSValueAuto) + m_style->setWrapShapeOutside(0); + else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_SHAPE) + m_style->setWrapShapeOutside(primitiveValue->getShapeValue()); + return; + + // CSS Fonts Module Level 3 + case CSSPropertyWebkitFontFeatureSettings: { + if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal) { + setFontDescription(m_style->fontDescription().makeNormalFeatureSettings()); + return; + } + + if (!value->isValueList()) + return; + + FontDescription fontDescription = m_style->fontDescription(); + CSSValueList* list = static_cast<CSSValueList*>(value); + RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create(); + int len = list->length(); + for (int i = 0; i < len; ++i) { + CSSValue* item = list->itemWithoutBoundsCheck(i); + if (!item->isFontFeatureValue()) + continue; + FontFeatureValue* feature = static_cast<FontFeatureValue*>(item); + settings->append(FontFeature(feature->tag(), feature->value())); + } + fontDescription.setFeatureSettings(settings.release()); + setFontDescription(fontDescription); + return; + } + +#if ENABLE(CSS_FILTERS) + case CSSPropertyWebkitFilter: { + HANDLE_INHERIT_AND_INITIAL(filter, Filter); + FilterOperations operations; + createFilterOperations(value, style(), m_rootElementStyle, operations); + m_style->setFilter(operations); + return; + } +#endif +#if ENABLE(CSS_GRID_LAYOUT) + case CSSPropertyWebkitGridColumns: { + Vector<Length> lengths; + if (!createGridTrackList(value, lengths, this)) + return; + m_style->setGridColumns(lengths); + return; + } + case CSSPropertyWebkitGridRows: { + Vector<Length> lengths; + if (!createGridTrackList(value, lengths, this)) + return; + m_style->setGridRows(lengths); + return; + } +#endif + + // These properties are implemented in the CSSStyleApplyProperty lookup table. + case CSSPropertyColor: + case CSSPropertyDirection: + case CSSPropertyDisplay: + case CSSPropertyBackgroundAttachment: + case CSSPropertyBackgroundClip: + case CSSPropertyWebkitBackgroundClip: + case CSSPropertyWebkitBackgroundComposite: + case CSSPropertyBackgroundOrigin: + case CSSPropertyWebkitBackgroundOrigin: + case CSSPropertyBackgroundImage: + case CSSPropertyWebkitAspectRatio: + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitMaskAttachment: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskComposite: + case CSSPropertyWebkitMaskOrigin: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskSize: + case CSSPropertyBackgroundColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderTopColor: + case CSSPropertyBorderTopStyle: + case CSSPropertyBorderRightStyle: + case CSSPropertyBorderBottomStyle: + case CSSPropertyBorderLeftStyle: + case CSSPropertyBorderTopWidth: + case CSSPropertyBorderRightWidth: + case CSSPropertyBorderBottomWidth: + case CSSPropertyBorderLeftWidth: + case CSSPropertyBorder: + case CSSPropertyBorderStyle: + case CSSPropertyBorderWidth: + case CSSPropertyBorderColor: + case CSSPropertyBorderImage: + case CSSPropertyWebkitBorderImage: + case CSSPropertyWebkitMaskBoxImage: + case CSSPropertyBorderImageOutset: + case CSSPropertyWebkitMaskBoxImageOutset: + case CSSPropertyBorderImageRepeat: + case CSSPropertyWebkitMaskBoxImageRepeat: + case CSSPropertyBorderImageSlice: + case CSSPropertyWebkitMaskBoxImageSlice: + case CSSPropertyBorderImageWidth: + case CSSPropertyWebkitMaskBoxImageWidth: + case CSSPropertyBorderImageSource: + case CSSPropertyWebkitMaskBoxImageSource: + case CSSPropertyBorderTop: + case CSSPropertyBorderRight: + case CSSPropertyBorderBottom: + case CSSPropertyBorderLeft: + case CSSPropertyBorderRadius: + case CSSPropertyWebkitBorderRadius: + case CSSPropertyBorderTopLeftRadius: + case CSSPropertyBorderTopRightRadius: + case CSSPropertyBorderBottomLeftRadius: + case CSSPropertyBorderBottomRightRadius: + case CSSPropertyBorderSpacing: + case CSSPropertyWebkitBorderHorizontalSpacing: + case CSSPropertyWebkitBorderVerticalSpacing: + case CSSPropertyCounterIncrement: + case CSSPropertyCounterReset: + case CSSPropertyLetterSpacing: + case CSSPropertyWordSpacing: + case CSSPropertyWebkitFlexOrder: + case CSSPropertyWebkitFlexPack: + case CSSPropertyWebkitFlexAlign: + case CSSPropertyWebkitFlexDirection: + case CSSPropertyWebkitFlexFlow: + case CSSPropertyWebkitFlexWrap: + case CSSPropertyFontSize: + case CSSPropertyFontStyle: + case CSSPropertyFontVariant: + case CSSPropertyTextRendering: + case CSSPropertyWebkitTextOrientation: + case CSSPropertyWebkitFontSmoothing: + case CSSPropertyFontWeight: + case CSSPropertyOutline: + case CSSPropertyOutlineStyle: + case CSSPropertyOutlineWidth: + case CSSPropertyOutlineOffset: + case CSSPropertyWebkitColumnRuleWidth: + case CSSPropertyOutlineColor: + case CSSPropertyWebkitColumnRuleColor: + case CSSPropertyWebkitTextEmphasisColor: + case CSSPropertyWebkitTextFillColor: + case CSSPropertyWebkitTextStrokeColor: + case CSSPropertyBackgroundPosition: + case CSSPropertyBackgroundPositionX: + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPosition: + case CSSPropertyWebkitMaskPositionX: + case CSSPropertyWebkitMaskPositionY: + case CSSPropertyBackgroundRepeat: + case CSSPropertyBackgroundRepeatX: + case CSSPropertyBackgroundRepeatY: + case CSSPropertyWebkitMaskRepeat: + case CSSPropertyWebkitMaskRepeatX: + case CSSPropertyWebkitMaskRepeatY: + case CSSPropertyOverflow: + case CSSPropertyOverflowX: + case CSSPropertyOverflowY: + case CSSPropertyMaxWidth: + case CSSPropertyTop: + case CSSPropertyLeft: + case CSSPropertyRight: + case CSSPropertyBottom: + case CSSPropertyWidth: + case CSSPropertyMinWidth: + case CSSPropertyLineHeight: + case CSSPropertyListStyle: + case CSSPropertyListStyleImage: + case CSSPropertyListStylePosition: + case CSSPropertyListStyleType: + case CSSPropertyMarginTop: + case CSSPropertyMarginRight: + case CSSPropertyMarginBottom: + case CSSPropertyMarginLeft: + case CSSPropertyMargin: + case CSSPropertyPaddingTop: + case CSSPropertyPaddingRight: + case CSSPropertyPaddingBottom: + case CSSPropertyPaddingLeft: + case CSSPropertyPadding: + case CSSPropertyResize: + case CSSPropertySize: + case CSSPropertyTextAlign: + case CSSPropertyTextDecoration: + case CSSPropertyTextIndent: + case CSSPropertyMaxHeight: + case CSSPropertyHeight: + case CSSPropertyMinHeight: + case CSSPropertyVerticalAlign: + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + case CSSPropertyWebkitTransformOrigin: + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: + case CSSPropertyWebkitPerspectiveOrigin: + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitAnimationDirection: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitAnimationFillMode: + case CSSPropertyWebkitAnimationIterationCount: + case CSSPropertyWebkitAnimationName: + case CSSPropertyWebkitAnimationPlayState: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitTransitionDelay: + case CSSPropertyWebkitTransitionDuration: + case CSSPropertyWebkitTransitionProperty: + case CSSPropertyWebkitTransitionTimingFunction: + case CSSPropertyCursor: + case CSSPropertyWebkitColumns: + case CSSPropertyWebkitColumnCount: + case CSSPropertyWebkitColumnGap: + case CSSPropertyWebkitColumnWidth: + case CSSPropertyWebkitFlowInto: + case CSSPropertyWebkitFlowFrom: + case CSSPropertyWebkitHighlight: + case CSSPropertyWebkitHyphenateCharacter: + case CSSPropertyWebkitHyphenateLimitAfter: + case CSSPropertyWebkitHyphenateLimitBefore: + case CSSPropertyWebkitHyphenateLimitLines: + case CSSPropertyWebkitLineGrid: + case CSSPropertyWebkitLineGridSnap: + case CSSPropertyWebkitTextCombine: + case CSSPropertyWebkitTextEmphasisPosition: + case CSSPropertyWebkitTextEmphasisStyle: + case CSSPropertyWebkitWrapMargin: + case CSSPropertyWebkitWrapPadding: + case CSSPropertyWebkitWrapFlow: + case CSSPropertyWebkitWrapThrough: + case CSSPropertyWebkitWrap: + case CSSPropertyZIndex: + case CSSPropertyZoom: + ASSERT_NOT_REACHED(); + return; +#if ENABLE(SVG) + default: + // Try the SVG properties + applySVGProperty(id, value); + return; +#endif + } +} + +void CSSStyleSelector::mapFillAttachment(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + layer->setOrigin(FillLayer::initialFillOrigin(layer->type())); + return; + } + + if (!value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + layer->setOrigin(*primitiveValue); +} + +PassRefPtr<StyleImage> CSSStyleSelector::styleImage(CSSPropertyID property, CSSValue* value) +{ + if (value->isImageValue()) + return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value)); + + if (value->isImageGeneratorValue()) + return generatedOrPendingFromValue(property, static_cast<CSSImageGeneratorValue*>(value)); + + return 0; +} + +PassRefPtr<StyleImage> CSSStyleSelector::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value) +{ + RefPtr<StyleImage> image = value->cachedOrPendingImage(); + if (image && image->isPendingImage()) + m_pendingImageProperties.add(property); + return image.release(); +} + +PassRefPtr<StyleImage> CSSStyleSelector::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue* value) +{ + if (value->isPending()) { + m_pendingImageProperties.add(property); + return StylePendingImage::create(value); + } + return StyleGeneratedImage::create(value); +} + +void CSSStyleSelector::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value) +{ + if (value->isInitialValue()) { + layer->setImage(FillLayer::initialFillImage(layer->type())); + return; + } + + layer->setImage(styleImage(property, value)); +} + +void CSSStyleSelector::mapFillRepeatX(CSSPropertyID, FillLayer* layer, CSSValue* value) +{ + if (value->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue() || primitiveValue->getIdent() == CSSValueContain || primitiveValue->getIdent() == CSSValueCover) { + layer->setSizeLength(b); + return; + } + + Pair* pair = primitiveValue->getPairValue(); + + CSSPrimitiveValue* first = pair ? static_cast<CSSPrimitiveValue*>(pair->first()) : primitiveValue; + CSSPrimitiveValue* second = pair ? static_cast<CSSPrimitiveValue*>(pair->second()) : 0; + + Length firstLength, secondLength; + int firstType = first->primitiveType(); + int secondType = second ? second->primitiveType() : 0; + + float zoomFactor = m_style->effectiveZoom(); + + if (first->getIdent() == CSSValueAuto) + firstLength = Length(); + else if (CSSPrimitiveValue::isUnitTypeLength(firstType)) + firstLength = first->computeLength<Length>(style(), m_rootElementStyle, zoomFactor); + else if (firstType == CSSPrimitiveValue::CSS_PERCENTAGE) + firstLength = Length(first->getDoubleValue(), Percent); + else + return; + + if (!second || second->getIdent() == CSSValueAuto) + secondLength = Length(); + else if (CSSPrimitiveValue::isUnitTypeLength(secondType)) + secondLength = second->computeLength<Length>(style(), m_rootElementStyle, zoomFactor); + 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->isInitialValue()) { + 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 = primitiveValue->computeLength<Length>(style(), m_rootElementStyle, zoomFactor); + 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->isInitialValue()) { + 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 = primitiveValue->computeLength<Length>(style(), m_rootElementStyle, zoomFactor); + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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->isInitialValue()) { + 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). + CSSPropertyID imageProperty; + if (property == CSSPropertyWebkitBorderImage || property == CSSPropertyBorderImage) + imageProperty = CSSPropertyBorderImageSource; + else if (property == CSSPropertyWebkitMaskBoxImage) + imageProperty = CSSPropertyWebkitMaskBoxImageSource; + else + imageProperty = property; + + if (CSSValue* imageValue = borderImage->imageValue()) + image.setImage(styleImage(imageProperty, imageValue)); + + // Map in the image slices. + mapNinePieceImageSlice(borderImage->m_imageSlice.get(), image); + + // Map in the border slices. + if (borderImage->m_borderSlice) + image.setBorderSlices(mapNinePieceImageQuad(borderImage->m_borderSlice.get())); + + // Map in the outset. + if (borderImage->m_outset) + image.setOutset(mapNinePieceImageQuad(borderImage->m_outset.get())); + + if (property == CSSPropertyWebkitBorderImage) { + // We have to preserve the legacy behavior of -webkit-border-image and make the border slices + // also set the border widths. We don't need to worry about percentages, since we don't even support + // those on real borders yet. + if (image.borderSlices().top().isFixed()) + style()->setBorderTopWidth(image.borderSlices().top().value()); + if (image.borderSlices().right().isFixed()) + style()->setBorderRightWidth(image.borderSlices().right().value()); + if (image.borderSlices().bottom().isFixed()) + style()->setBorderBottomWidth(image.borderSlices().bottom().value()); + if (image.borderSlices().left().isFixed()) + style()->setBorderLeftWidth(image.borderSlices().left().value()); + } + + // Set the appropriate rules for stretch/round/repeat of the slices + mapNinePieceImageRepeat(borderImage->m_repeat.get(), image); +} + +void CSSStyleSelector::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) +{ + if (!value || !value->isBorderImageSliceValue()) + return; + + // Retrieve the border image value. + CSSBorderImageSliceValue* borderImageSlice = static_cast<CSSBorderImageSliceValue*>(value); + + // Set up a length box to represent our image slices. + LengthBox box; + Quad* slices = borderImageSlice->slices(); + if (slices->top()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_top = Length(slices->top()->getDoubleValue(), Percent); + else + box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (slices->bottom()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent); + else + box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (slices->left()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_left = Length(slices->left()->getDoubleValue(), Percent); + else + box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + if (slices->right()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_right = Length(slices->right()->getDoubleValue(), Percent); + else + box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + image.setImageSlices(box); + + // Set our fill mode. + image.setFill(borderImageSlice->m_fill); +} + +LengthBox CSSStyleSelector::mapNinePieceImageQuad(CSSValue* value) +{ + if (!value || !value->isPrimitiveValue()) + return LengthBox(); + + // Get our zoom value. + float zoom = useSVGZoomRules() ? 1.0f : style()->effectiveZoom(); + + // Retrieve the primitive value. + CSSPrimitiveValue* borderWidths = static_cast<CSSPrimitiveValue*>(value); + + // Set up a length box to represent our image slices. + LengthBox box; // Defaults to 'auto' so we don't have to handle that explicitly below. + Quad* slices = borderWidths->getQuadValue(); + if (slices->top()->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) + box.m_top = Length(slices->top()->getIntValue(), Relative); + else if (slices->top()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_top = Length(slices->top()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->top()->getIdent() != CSSValueAuto) + box.m_top = slices->top()->computeLength<Length>(style(), rootElementStyle(), zoom); + + if (slices->right()->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) + box.m_right = Length(slices->right()->getIntValue(), Relative); + else if (slices->right()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_right = Length(slices->right()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->right()->getIdent() != CSSValueAuto) + box.m_right = slices->right()->computeLength<Length>(style(), rootElementStyle(), zoom); + + if (slices->bottom()->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) + box.m_bottom = Length(slices->bottom()->getIntValue(), Relative); + else if (slices->bottom()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_bottom = Length(slices->bottom()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->bottom()->getIdent() != CSSValueAuto) + box.m_bottom = slices->bottom()->computeLength<Length>(style(), rootElementStyle(), zoom); + + if (slices->left()->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) + box.m_left = Length(slices->left()->getIntValue(), Relative); + else if (slices->left()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + box.m_left = Length(slices->left()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->left()->getIdent() != CSSValueAuto) + box.m_left = slices->left()->computeLength<Length>(style(), rootElementStyle(), zoom); + + return box; +} + +void CSSStyleSelector::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) +{ + if (!value || !value->isPrimitiveValue()) + return; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + Pair* pair = primitiveValue->getPairValue(); + if (!pair || !pair->first() || !pair->second()) + return; + + int firstIdentifier = pair->first()->getIdent(); + int secondIdentifier = pair->second()->getIdent(); + + ENinePieceImageRule horizontalRule; + switch (firstIdentifier) { + case CSSValueStretch: + horizontalRule = StretchImageRule; + break; + case CSSValueRound: + horizontalRule = RoundImageRule; + break; + case CSSValueSpace: + horizontalRule = SpaceImageRule; + break; + default: // CSSValueRepeat + horizontalRule = RepeatImageRule; + break; + } + image.setHorizontalRule(horizontalRule); + + ENinePieceImageRule verticalRule; + switch (secondIdentifier) { + case CSSValueStretch: + verticalRule = StretchImageRule; + break; + case CSSValueRound: + verticalRule = RoundImageRule; + break; + case CSSValueSpace: + verticalRule = SpaceImageRule; + 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.document(), CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize()); + else { + Settings* settings = m_checker.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); + fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.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(); + } + + return CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, zoomFactor, isAbsoluteSize, specifiedSize); +} + +float CSSStyleSelector::getComputedSizeFromSpecifiedSize(Document* document, float zoomFactor, bool isAbsoluteSize, float specifiedSize, ESmartMinimumForFontSize useSmartMinimumForFontSize) +{ + // Text with a 0px font size should not be visible and therefore needs to be + // exempt from minimum font size rules. Acid3 relies on this for pixel-perfect + // rendering. This is also compatible with other browsers that have minimum + // font size settings (e.g. Firefox). + if (fabsf(specifiedSize) < std::numeric_limits<float>::epsilon()) + return 0.0f; + + // 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 (useSmartMinimumForFontSize && 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); +} + +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::colorFromPrimitiveValue(CSSPrimitiveValue* value, bool forVisitedLink) const +{ + if (value->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) + return Color(value->getRGBA32Value()); + + if (value->primitiveType() != CSSPrimitiveValue::CSS_IDENT) + return Color(); + + int ident = value->getIdent(); + + switch (ident) { + case CSSValueWebkitText: + return m_element->document()->textColor(); + case CSSValueWebkitLink: + return (m_element->isLink() && forVisitedLink) ? m_element->document()->visitedLinkColor() : m_element->document()->linkColor(); + case CSSValueWebkitActivelink: + return m_element->document()->activeLinkColor(); + case CSSValueWebkitFocusRingColor: + return RenderTheme::focusRingColor(); + case CSSValueCurrentcolor: + return m_style->color(); + default: + return colorForCSSValue(ident); + } +} + +bool CSSStyleSelector::hasSelectorForAttribute(const AtomicString &attrname) const +{ + return m_features.attrsInRules.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; +} + +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; + for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { + CSSValue* currValue = i.value(); + if (!currValue->isWebKitCSSTransformValue()) + continue; + + WebKitCSSTransformValue* transformValue = static_cast<WebKitCSSTransformValue*>(i.value()); + 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 = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + else { + tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) { + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + ty = convertToFloatLength(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 = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + else if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation) + ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + else { + tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) { + if (transformValue->length() > 2) { + CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2)); + tz = convertToFloatLength(thirdValue, style, rootStyle, zoomFactor, &ok); + } + if (transformValue->length() > 1) { + CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1)); + ty = convertToFloatLength(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: { + bool ok = true; + Length p = Length(0, Fixed); + if (CSSPrimitiveValue::isUnitTypeLength(firstValue->primitiveType())) + p = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + else { + // This is a quirk that should go away when 3d transforms are finalized. + double val = firstValue->getDoubleValue(); + ok = val >= 0; + p = Length(clampToPositiveInteger(val), Fixed); + } + + if (!ok) + return false; + + operations.operations().append(PerspectiveTransformOperation::create(p)); + break; + } + case WebKitCSSTransformValue::UnknownTransformOperation: + ASSERT_NOT_REACHED(); + break; + } + } + + outOperations = operations; + return true; +} + +#if ENABLE(CSS_FILTERS) +static FilterOperation::OperationType filterOperationForType(WebKitCSSFilterValue::FilterOperationType type) +{ + switch (type) { + case WebKitCSSFilterValue::ReferenceFilterOperation: + return FilterOperation::REFERENCE; + case WebKitCSSFilterValue::GrayscaleFilterOperation: + return FilterOperation::GRAYSCALE; + case WebKitCSSFilterValue::SepiaFilterOperation: + return FilterOperation::SEPIA; + case WebKitCSSFilterValue::SaturateFilterOperation: + return FilterOperation::SATURATE; + case WebKitCSSFilterValue::HueRotateFilterOperation: + return FilterOperation::HUE_ROTATE; + case WebKitCSSFilterValue::InvertFilterOperation: + return FilterOperation::INVERT; + case WebKitCSSFilterValue::OpacityFilterOperation: + return FilterOperation::OPACITY; + case WebKitCSSFilterValue::BrightnessFilterOperation: + return FilterOperation::BRIGHTNESS; + case WebKitCSSFilterValue::ContrastFilterOperation: + return FilterOperation::CONTRAST; + case WebKitCSSFilterValue::BlurFilterOperation: + return FilterOperation::BLUR; + case WebKitCSSFilterValue::DropShadowFilterOperation: + return FilterOperation::DROP_SHADOW; +#if ENABLE(CSS_SHADERS) + case WebKitCSSFilterValue::CustomFilterOperation: + return FilterOperation::CUSTOM; +#endif + case WebKitCSSFilterValue::UnknownFilterOperation: + return FilterOperation::NONE; + } + return FilterOperation::NONE; +} + +#if ENABLE(CSS_SHADERS) +StyleShader* CSSStyleSelector::styleShader(CSSValue* value) +{ + if (value->isWebKitCSSShaderValue()) + return cachedOrPendingStyleShaderFromValue(static_cast<WebKitCSSShaderValue*>(value)); + return 0; +} + +StyleShader* CSSStyleSelector::cachedOrPendingStyleShaderFromValue(WebKitCSSShaderValue* value) +{ + StyleShader* shader = value->cachedOrPendingShader(); + if (shader && shader->isPendingShader()) + m_hasPendingShaders = true; + return shader; +} + +void CSSStyleSelector::loadPendingShaders() +{ + if (!m_style->hasFilter() || !m_hasPendingShaders) + return; + + CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader(); + + Vector<RefPtr<FilterOperation> >& filterOperations = m_style->filter().operations(); + for (unsigned i = 0; i < filterOperations.size(); ++i) { + RefPtr<FilterOperation> filterOperation = filterOperations.at(i); + if (filterOperation->getOperationType() == FilterOperation::CUSTOM) { + CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get()); + if (customFilter->vertexShader() && customFilter->vertexShader()->isPendingShader()) { + WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(customFilter->vertexShader())->cssShaderValue(); + customFilter->setVertexShader(shaderValue->cachedShader(cachedResourceLoader)); + } + if (customFilter->fragmentShader() && customFilter->fragmentShader()->isPendingShader()) { + WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(customFilter->fragmentShader())->cssShaderValue(); + customFilter->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader)); + } + } + } + m_hasPendingShaders = false; +} + +PassRefPtr<CustomFilterOperation> CSSStyleSelector::createCustomFilterOperation(WebKitCSSFilterValue* filterValue) +{ + ASSERT(filterValue->length()); + + CSSValue* shadersValue = filterValue->itemWithoutBoundsCheck(0); + ASSERT(shadersValue->isValueList()); + CSSValueList* shadersList = static_cast<CSSValueList*>(shadersValue); + + ASSERT(shadersList->length()); + RefPtr<StyleShader> vertexShader = styleShader(shadersList->itemWithoutBoundsCheck(0)); + RefPtr<StyleShader> fragmentShader = (shadersList->length() > 1) ? styleShader(shadersList->itemWithoutBoundsCheck(1)) : 0; + + unsigned meshRows = 1; + unsigned meshColumns = 1; + CustomFilterOperation::MeshBoxType meshBoxType = CustomFilterOperation::FILTER_BOX; + CustomFilterOperation::MeshType meshType = CustomFilterOperation::ATTACHED; + + if (filterValue->length() > 1) { + CSSValueListIterator iterator(filterValue->itemWithoutBoundsCheck(1)); + + // The second value might be the mesh box or the list of parameters: + // If it starts with a number or any of the mesh-box identifiers it is + // the mesh-box list, if not it means it is the parameters list. + + if (iterator.hasMore() && iterator.isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + // If only one integer value is specified, it will set both + // the rows and the columns. + meshRows = meshColumns = primitiveValue->getIntValue(); + iterator.advance(); + + // Try to match another number for the columns. + if (iterator.hasMore() && iterator.isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + meshColumns = primitiveValue->getIntValue(); + iterator.advance(); + } + } + } + } + + if (iterator.hasMore() && iterator.isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); + if (primitiveValue->getIdent() == CSSValueBorderBox + || primitiveValue->getIdent() == CSSValuePaddingBox + || primitiveValue->getIdent() == CSSValueContentBox + || primitiveValue->getIdent() == CSSValueFilterBox) { + meshBoxType = *primitiveValue; + iterator.advance(); + } + } + + if (iterator.hasMore() && iterator.isPrimitiveValue()) { + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); + if (primitiveValue->getIdent() == CSSValueDetached) { + meshType = CustomFilterOperation::DETACHED; + iterator.advance(); + } + } + } + + return CustomFilterOperation::create(vertexShader, fragmentShader, meshRows, meshColumns, meshBoxType, meshType); +} +#endif + +bool CSSStyleSelector::createFilterOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, FilterOperations& outOperations) +{ + if (!inValue || !inValue->isValueList()) { + outOperations.clear(); + return false; + } + + float zoomFactor = style ? style->effectiveZoom() : 1; + FilterOperations operations; + for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { + CSSValue* currValue = i.value(); + if (!currValue->isWebKitCSSFilterValue()) + continue; + + WebKitCSSFilterValue* filterValue = static_cast<WebKitCSSFilterValue*>(i.value()); + FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType()); + +#if ENABLE(CSS_SHADERS) + if (operationType == FilterOperation::CUSTOM) { + RefPtr<CustomFilterOperation> operation = createCustomFilterOperation(filterValue); + if (operation) + operations.operations().append(operation); + continue; + } +#endif + + // Check that all parameters are primitive values, with the + // exception of drop shadow which has a ShadowValue parameter. + if (operationType != FilterOperation::DROP_SHADOW) { + bool haveNonPrimitiveValue = false; + for (unsigned j = 0; j < filterValue->length(); ++j) { + if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { + haveNonPrimitiveValue = true; + break; + } + } + if (haveNonPrimitiveValue) + continue; + } + + CSSPrimitiveValue* firstValue = filterValue->length() ? static_cast<CSSPrimitiveValue*>(filterValue->itemWithoutBoundsCheck(0)) : 0; + switch (filterValue->operationType()) { + case WebKitCSSFilterValue::ReferenceFilterOperation: { + if (firstValue) + operations.operations().append(ReferenceFilterOperation::create(firstValue->getStringValue(), operationType)); + break; + } + case WebKitCSSFilterValue::GrayscaleFilterOperation: + case WebKitCSSFilterValue::SepiaFilterOperation: + case WebKitCSSFilterValue::SaturateFilterOperation: { + double amount = 1; + if (filterValue->length() == 1) { + amount = firstValue->getDoubleValue(); + if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) + amount /= 100; + } + + operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); + break; + } + case WebKitCSSFilterValue::HueRotateFilterOperation: { + double angle = 0; + if (filterValue->length() == 1) { + 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(BasicColorMatrixFilterOperation::create(angle, operationType)); + break; + } + case WebKitCSSFilterValue::InvertFilterOperation: + case WebKitCSSFilterValue::BrightnessFilterOperation: + case WebKitCSSFilterValue::ContrastFilterOperation: + case WebKitCSSFilterValue::OpacityFilterOperation: { + double amount = 1; + if (filterValue->length() == 1) { + amount = firstValue->getDoubleValue(); + if (firstValue->isPercentage()) + amount /= 100; + } + + operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); + break; + } + case WebKitCSSFilterValue::BlurFilterOperation: { + bool ok = true; + Length stdDeviation = Length(0, Fixed); + if (filterValue->length() >= 1) { + stdDeviation = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok); + } + if (!ok) + return false; + + operations.operations().append(BlurFilterOperation::create(stdDeviation, operationType)); + break; + } + case WebKitCSSFilterValue::DropShadowFilterOperation: { + if (filterValue->length() != 1) + return false; + + CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0); + if (!cssValue->isShadowValue()) + continue; + + ShadowValue* item = static_cast<ShadowValue*>(cssValue); + int x = item->x->computeLength<int>(style, rootStyle, zoomFactor); + int y = item->y->computeLength<int>(style, rootStyle, zoomFactor); + int blur = item->blur ? item->blur->computeLength<int>(style, rootStyle, zoomFactor) : 0; + Color color; + if (item->color) + color = colorFromPrimitiveValue(item->color.get()); + + operations.operations().append(DropShadowFilterOperation::create(x, y, blur, color.isValid() ? color : Color::transparent, operationType)); + break; + } + case WebKitCSSFilterValue::UnknownFilterOperation: + default: + ASSERT_NOT_REACHED(); + break; + } + } + + outOperations = operations; + return true; +} + +#endif + +PassRefPtr<StyleImage> CSSStyleSelector::loadPendingImage(StylePendingImage* pendingImage) +{ + CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader(); + + if (pendingImage->cssImageValue()) { + CSSImageValue* imageValue = pendingImage->cssImageValue(); + return imageValue->cachedImage(cachedResourceLoader); + } + + if (pendingImage->cssImageGeneratorValue()) { + CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue(); + imageGeneratorValue->loadSubimages(cachedResourceLoader); + return StyleGeneratedImage::create(imageGeneratorValue); + } + + return 0; +} + +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); + + switch (currentProperty) { + case CSSPropertyBackgroundImage: { + for (FillLayer* backgroundLayer = m_style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { + if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) + backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()))); + } + break; + } + case CSSPropertyContent: { + for (ContentData* contentData = const_cast<ContentData*>(m_style->contentData()); contentData; contentData = contentData->next()) { + if (contentData->isImage()) { + StyleImage* image = static_cast<ImageContentData*>(contentData)->image(); + if (image->isPendingImage()) { + RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image)); + if (loadedImage) + static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release()); + } + } + } + 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()) + currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image))); + } + } + } + break; + } + case CSSPropertyListStyleImage: { + if (m_style->listStyleImage() && m_style->listStyleImage()->isPendingImage()) + m_style->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(m_style->listStyleImage()))); + break; + } + case CSSPropertyBorderImageSource: { + if (m_style->borderImageSource() && m_style->borderImageSource()->isPendingImage()) + m_style->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_style->borderImageSource()))); + break; + } + case CSSPropertyWebkitBoxReflect: { + if (StyleReflection* reflection = m_style->boxReflect()) { + const NinePieceImage& maskImage = reflection->mask(); + if (maskImage.image() && maskImage.image()->isPendingImage()) { + RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image())); + reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); + } + } + break; + } + case CSSPropertyWebkitMaskBoxImageSource: { + if (m_style->maskBoxImageSource() && m_style->maskBoxImageSource()->isPendingImage()) + m_style->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_style->maskBoxImageSource()))); + break; + } + case CSSPropertyWebkitMaskImage: { + for (FillLayer* maskLayer = m_style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { + if (maskLayer->image() && maskLayer->image()->isPendingImage()) + maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()))); + } + 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 000000000..872b634f5 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSelector.h @@ -0,0 +1,419 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "CSSRule.h" +#include "LinkHash.h" +#include "MediaQueryExp.h" +#include "RenderStyle.h" +#include "SelectorChecker.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +enum ESmartMinimumForFontSize { DoNotUseSmartMinimumForFontSize, UseSmartMinimumForFontFize }; + +class CSSFontSelector; +class CSSMutableStyleDeclaration; +class CSSPageRule; +class CSSPrimitiveValue; +class CSSProperty; +class CSSFontFace; +class CSSFontFaceRule; +class CSSImageGeneratorValue; +class CSSImageValue; +class CSSRuleList; +class CSSSelector; +class CSSStyleApplyProperty; +class CSSStyleRule; +class CSSStyleSheet; +class CSSValue; +class ContainerNode; +class CustomFilterOperation; +class Document; +class Element; +class Frame; +class FrameView; +class KURL; +class KeyframeList; +class KeyframeValue; +class MediaQueryEvaluator; +class Node; +class RuleData; +class RuleSet; +class Settings; +class StyleImage; +class StylePendingImage; +class StyleShader; +class StyleSheet; +class StyleSheetList; +class StyledElement; +class WebKitCSSKeyframeRule; +class WebKitCSSKeyframesRule; +class WebKitCSSFilterValue; +class WebKitCSSRegionRule; +class WebKitCSSShaderValue; + +class MediaQueryResult { + WTF_MAKE_NONCOPYABLE(MediaQueryResult); WTF_MAKE_FAST_ALLOCATED; +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 { + WTF_MAKE_NONCOPYABLE(CSSStyleSelector); WTF_MAKE_FAST_ALLOCATED; +public: + CSSStyleSelector(Document*, StyleSheetList* authorSheets, CSSStyleSheet* mappedElementSheet, + CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets, const Vector<RefPtr<CSSStyleSheet> >* documentUserSheets, + bool strictParsing, bool matchAuthorAndUserStyles); + ~CSSStyleSelector(); + + // Using these during tree walk will allow style selector to optimize child and descendant selector lookups. + void pushParent(Element* parent) { m_checker.pushParent(parent); } + void popParent(Element* parent) { m_checker.popParent(parent); } + + PassRefPtr<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false); + + void keyframeStylesForAnimation(Element*, const RenderStyle*, KeyframeList&); + + PassRefPtr<RenderStyle> pseudoStyleForElement(PseudoId, Element*, RenderStyle* parentStyle = 0); + + PassRefPtr<RenderStyle> styleForPage(int pageIndex); + + static PassRefPtr<RenderStyle> styleForDocument(Document*, CSSFontSelector* = 0); + + RenderStyle* style() const { return m_style.get(); } + RenderStyle* parentStyle() const { return m_parentStyle; } + RenderStyle* rootElementStyle() const { return m_rootElementStyle; } + Element* element() const { return m_element; } + Document* document() const { return m_checker.document(); } + FontDescription fontDescription() { return style()->fontDescription(); } + FontDescription parentFontDescription() {return parentStyle()->fontDescription(); } + void setFontDescription(FontDescription fontDescription) { m_fontDirty |= style()->setFontDescription(fontDescription); } + void setZoom(float f) { m_fontDirty |= style()->setZoom(f); } + void setEffectiveZoom(float f) { m_fontDirty |= style()->setEffectiveZoom(f); } + void setTextSizeAdjust(bool b) { m_fontDirty |= style()->setTextSizeAdjust(b); } + bool hasParentNode() const { return m_parentNode; } + + void appendAuthorStylesheets(unsigned firstNew, const Vector<RefPtr<StyleSheet> >&); + + // Find the ids or classes the selectors on a stylesheet are scoped to. The selectors only apply to elements in subtrees where the root element matches the scope. + static bool determineStylesheetSelectorScopes(CSSStyleSheet*, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes); + +private: + void initForStyleResolve(Element*, RenderStyle* parentStyle = 0, PseudoId = NOPSEUDO); + void initElement(Element*); + void collectFeatures(); + RenderStyle* locateSharedStyle(); + bool matchesRuleSet(RuleSet*); + Node* locateCousinList(Element* parent, unsigned& visitedNodeCount) const; + StyledElement* findSiblingForStyleSharing(Node*, unsigned& count) const; + bool canShareStyleWithElement(StyledElement*) const; + + 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). + enum CSSRuleFilter { + UAAndUserCSSRules = 1 << 1, + AuthorCSSRules = 1 << 2, + EmptyCSSRules = 1 << 3, + CrossOriginCSSRules = 1 << 4, + AllButEmptyCSSRules = UAAndUserCSSRules | AuthorCSSRules | CrossOriginCSSRules, + AllCSSRules = AllButEmptyCSSRules | EmptyCSSRules, + }; + PassRefPtr<CSSRuleList> styleRulesForElement(Element*, unsigned rulesToInclude = AllButEmptyCSSRules); + PassRefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, PseudoId, unsigned rulesToInclude = AllButEmptyCSSRules); + + // 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); + +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*); + + void applyPropertyToCurrentStyle(int id, CSSValue*); + + void updateFont(); + + static float getComputedSizeFromSpecifiedSize(Document*, float zoomFactor, bool isAbsoluteSize, float specifiedSize, ESmartMinimumForFontSize = UseSmartMinimumForFontFize); + + void setFontSize(FontDescription&, float size); + +private: + static float getComputedSizeFromSpecifiedSize(Document*, RenderStyle*, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules); + +public: + bool useSVGZoomRules(); + + Color colorFromPrimitiveValue(CSSPrimitiveValue*, bool forVisitedLink = false) const; + + bool hasSelectorForAttribute(const AtomicString&) const; + + CSSFontSelector* fontSelector() const { return m_fontSelector.get(); } + + 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>); + void addPageStyle(PassRefPtr<CSSPageRule>); + void addRegionRule(PassRefPtr<WebKitCSSRegionRule>); + + bool checkRegionStyle(Element*); + + bool usesSiblingRules() const { return m_features.siblingRules; } + bool usesFirstLineRules() const { return m_features.usesFirstLineRules; } + bool usesBeforeAfterRules() const { return m_features.usesBeforeAfterRules; } + bool usesLinkRules() const { return m_features.usesLinkRules; } + + static bool createTransformOperations(CSSValue* inValue, RenderStyle* inStyle, RenderStyle* rootStyle, TransformOperations& outOperations); + + void invalidateMatchedDeclarationCache(); + +#if ENABLE(CSS_FILTERS) + bool createFilterOperations(CSSValue* inValue, RenderStyle* inStyle, RenderStyle* rootStyle, FilterOperations& outOperations); +#if ENABLE(CSS_SHADERS) + StyleShader* styleShader(CSSValue*); + StyleShader* cachedOrPendingStyleShaderFromValue(WebKitCSSShaderValue*); + PassRefPtr<CustomFilterOperation> createCustomFilterOperation(WebKitCSSFilterValue*); + void loadPendingShaders(); +#endif +#endif // ENABLE(CSS_FILTERS) + + struct Features { + Features(); + ~Features(); + void clear(); + HashSet<AtomicStringImpl*> idsInRules; + HashSet<AtomicStringImpl*> attrsInRules; + OwnPtr<RuleSet> siblingRules; + OwnPtr<RuleSet> uncommonAttributeRules; + bool usesFirstLineRules; + bool usesBeforeAfterRules; + bool usesLinkRules; + }; + +private: + // 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(const RuleData* rule) { m_matchedRules.append(rule); } + void addMatchedDeclaration(CSSMutableStyleDeclaration*, unsigned linkMatchType = SelectorChecker::MatchAll); + + struct MatchResult { + MatchResult() : firstUARule(-1), lastUARule(-1), firstAuthorRule(-1), lastAuthorRule(-1), firstUserRule(-1), lastUserRule(-1), isCacheable(true) { } + int firstUARule; + int lastUARule; + int firstAuthorRule; + int lastAuthorRule; + int firstUserRule; + int lastUserRule; + bool isCacheable; + }; + void matchAllRules(MatchResult&); + void matchUARules(MatchResult&); + void matchRules(RuleSet*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules); + void matchRulesForList(const Vector<RuleData>*, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules); + bool fastRejectSelector(const RuleData&) const; + void sortMatchedRules(); + + bool checkSelector(const RuleData&); + + void applyMatchedDeclarations(const MatchResult&); + template <bool firstPass> + void applyDeclarations(bool important, int startIndex, int endIndex, bool inheritedOnly); + template <bool firstPass> + void applyDeclaration(CSSMutableStyleDeclaration*, bool isImportant, bool inheritedOnly); + + void matchPageRules(RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName); + void matchPageRulesForList(const Vector<RuleData>*, 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<RuleSet> m_authorStyle; + OwnPtr<RuleSet> m_userStyle; + + Features m_features; + + bool m_hasUAAppearance; + BorderData m_borderData; + FillLayer m_backgroundData; + Color m_backgroundColor; + + typedef HashMap<AtomicStringImpl*, RefPtr<WebKitCSSKeyframesRule> > KeyframesRuleMap; + KeyframesRuleMap m_keyframesRuleMap; + + typedef Vector<RefPtr<WebKitCSSRegionRule> > RegionStyleRules; + RegionStyleRules m_regionStyleRules; + +public: + static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; } + + PassRefPtr<StyleImage> styleImage(CSSPropertyID, CSSValue*); + PassRefPtr<StyleImage> cachedOrPendingFromValue(CSSPropertyID, CSSImageValue*); + PassRefPtr<StyleImage> generatedOrPendingFromValue(CSSPropertyID, CSSImageGeneratorValue*); + + bool applyPropertyToRegularStyle() const { return m_applyPropertyToRegularStyle; } + bool applyPropertyToVisitedLinkStyle() const { return m_applyPropertyToVisitedLinkStyle; } + +private: + static RenderStyle* s_styleNotYetAvailable; + + 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*); + +public: + void mapNinePieceImage(CSSPropertyID, CSSValue*, NinePieceImage&); + void mapNinePieceImageSlice(CSSValue*, NinePieceImage&); + LengthBox mapNinePieceImageQuad(CSSValue*); + void mapNinePieceImageRepeat(CSSValue*, NinePieceImage&); +private: + bool canShareStyleWithControl(StyledElement*) const; + + void applyProperty(int id, CSSValue*); +#if ENABLE(SVG) + void applySVGProperty(int id, CSSValue*); +#endif + + PassRefPtr<StyleImage> loadPendingImage(StylePendingImage*); + void loadPendingImages(); + + struct MatchedStyleDeclaration { + MatchedStyleDeclaration(); + CSSMutableStyleDeclaration* styleDeclaration; + unsigned linkMatchType; + }; + static unsigned computeDeclarationHash(MatchedStyleDeclaration*, unsigned size); + struct MatchedStyleDeclarationCacheItem { + Vector<MatchedStyleDeclaration> matchedStyleDeclarations; + MatchResult matchResult; + RefPtr<RenderStyle> renderStyle; + RefPtr<RenderStyle> parentRenderStyle; + }; + const MatchedStyleDeclarationCacheItem* findFromMatchedDeclarationCache(unsigned hash, const MatchResult&); + void addToMatchedDeclarationCache(const RenderStyle*, const RenderStyle* parentStyle, unsigned hash, const MatchResult&); + + // 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<MatchedStyleDeclaration, 64> m_matchedDecls; + + typedef HashMap<unsigned, MatchedStyleDeclarationCacheItem> MatchedStyleDeclarationCache; + MatchedStyleDeclarationCache m_matchedStyleDeclarationCache; + + // A buffer used to hold the set of matched rules for an element, and a temporary buffer used for + // merge sorting. + Vector<const RuleData*, 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; + bool m_sameOriginOnly; + + RefPtr<CSSFontSelector> m_fontSelector; + Vector<MediaQueryResult*> m_viewportDependentMediaQueryResults; + + bool m_applyPropertyToRegularStyle; + bool m_applyPropertyToVisitedLinkStyle; + const CSSStyleApplyProperty& m_applyProperty; + +#if ENABLE(CSS_SHADERS) + bool m_hasPendingShaders; +#endif + + friend class CSSStyleApplyProperty; + friend bool operator==(const MatchedStyleDeclaration&, const MatchedStyleDeclaration&); + friend bool operator!=(const MatchedStyleDeclaration&, const MatchedStyleDeclaration&); + friend bool operator==(const MatchResult&, const MatchResult&); + friend bool operator!=(const MatchResult&, const MatchResult&); +}; + +} // namespace WebCore + +#endif // CSSStyleSelector_h diff --git a/Source/WebCore/css/CSSStyleSheet.cpp b/Source/WebCore/css/CSSStyleSheet.cpp new file mode 100644 index 000000000..707ca4c3c --- /dev/null +++ b/Source/WebCore/css/CSSStyleSheet.cpp @@ -0,0 +1,314 @@ +/* + * (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 "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSNamespace.h" +#include "CSSParser.h" +#include "CSSRuleList.h" +#include "CSSStyleRule.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(Node* parentNode, const String& href, const KURL& baseURL, const String& charset) + : StyleSheet(parentNode, href, baseURL) + , m_charset(charset) + , m_loadCompleted(false) + , m_strictParsing(false) + , m_isUserStyleSheet(false) + , m_hasSyntacticallyValidCSSHeader(true) +{ + ASSERT(isAcceptableCSSStyleSheetParent(parentNode)); +} + +CSSStyleSheet::CSSStyleSheet(CSSImportRule* 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_isUserStyleSheet = parentSheet ? parentSheet->isUserStyleSheet() : false; +} + +CSSStyleSheet::~CSSStyleSheet() +{ + // 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 < m_children.size(); ++i) { + ASSERT(m_children.at(i)->parentStyleSheet() == this); + m_children.at(i)->setParentStyleSheet(0); + } +} + +void CSSStyleSheet::append(PassRefPtr<CSSRule> child) +{ + CSSRule* c = child.get(); + m_children.append(child); + if (c->isImportRule()) + static_cast<CSSImportRule*>(c)->requestStyleSheet(); +} + +void CSSStyleSheet::remove(unsigned index) +{ + m_children.remove(index); +} + +unsigned CSSStyleSheet::insertRule(const String& rule, unsigned index, ExceptionCode& ec) +{ + ec = 0; + if (index > m_children.size()) { + 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 (!m_children.at(i)->isCharsetRule() && !m_children.at(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; + } + } + + CSSRule* c = r.get(); + m_children.insert(index, r.release()); + if (c->isImportRule()) + static_cast<CSSImportRule*>(c)->requestStyleSheet(); + + 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, m_children.size(), ec); +} + +PassRefPtr<CSSRuleList> CSSStyleSheet::cssRules(bool omitCharsetRules) +{ + KURL url = finalURL(); + Document* document = findDocument(); + if (!url.isEmpty() && document && !document->securityOrigin()->canRequest(url)) + return 0; + return CSSRuleList::create(this, omitCharsetRules); +} + +void CSSStyleSheet::deleteRule(unsigned index, ExceptionCode& ec) +{ + if (index >= m_children.size()) { + ec = INDEX_SIZE_ERR; + return; + } + + ec = 0; + m_children.at(index)->setParentStyleSheet(0); + m_children.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() +{ + for (unsigned i = 0; i < m_children.size(); ++i) { + CSSRule* rule = m_children.at(i).get(); + if (rule->isImportRule() && static_cast<CSSImportRule*>(rule)->isLoading()) + return true; + } + return false; +} + +void CSSStyleSheet::checkLoaded() +{ + if (isLoading()) + return; + + // Avoid |this| being deleted by scripts that run via + // ScriptableDocumentParser::executeScriptsWaitingForStylesheets(). + // See <rdar://problem/6622300>. + RefPtr<CSSStyleSheet> protector(this); + if (CSSStyleSheet* styleSheet = parentStyleSheet()) + styleSheet->checkLoaded(); + m_loadCompleted = ownerNode() ? ownerNode()->sheetLoaded() : true; +} + +void CSSStyleSheet::startLoadingDynamicSheet() +{ + if (Node* owner = ownerNode()) + owner->startLoadingDynamicSheet(); +} + +Node* CSSStyleSheet::findStyleSheetOwnerNode() const +{ + for (const CSSStyleSheet* sheet = this; sheet; sheet = sheet->parentStyleSheet()) { + if (Node* ownerNode = sheet->ownerNode()) + return ownerNode; + } + return 0; +} + +Document* CSSStyleSheet::findDocument() +{ + Node* ownerNode = findStyleSheetOwnerNode(); + + return ownerNode ? ownerNode->document() : 0; +} + +void CSSStyleSheet::styleSheetChanged() +{ + CSSStyleSheet* rootSheet = this; + while (CSSStyleSheet* parent = rootSheet->parentStyleSheet()) + rootSheet = parent; + + /* 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 (Document* documentToUpdate = rootSheet->findDocument()) + 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()) + return KURL(); + if (m_charset.isEmpty()) + return KURL(baseURL(), 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->m_children.size(); ++i) { + CSSRule* rule = styleSheet->m_children.at(i).get(); + if (rule->isImportRule()) { + if (CSSStyleSheet* ruleStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet()) + styleSheetQueue.append(ruleStyleSheet); + static_cast<CSSImportRule*>(rule)->addSubresourceStyleURLs(urls); + } else if (rule->isFontFaceRule()) + static_cast<CSSFontFaceRule*>(rule)->addSubresourceStyleURLs(urls); + else if (rule->isStyleRule() || rule->isPageRule()) + static_cast<CSSStyleRule*>(rule)->addSubresourceStyleURLs(urls); + } + } +} + +} diff --git a/Source/WebCore/css/CSSStyleSheet.h b/Source/WebCore/css/CSSStyleSheet.h new file mode 100644 index 000000000..b027365f2 --- /dev/null +++ b/Source/WebCore/css/CSSStyleSheet.h @@ -0,0 +1,135 @@ +/* + * (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<CSSImportRule*>(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, const String& charset) + { + return adoptRef(new CSSStyleSheet(ownerNode, originalURL, finalURL, charset)); + } + static PassRefPtr<CSSStyleSheet> create(CSSImportRule* 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(); + + CSSStyleSheet* parentStyleSheet() const + { + StyleSheet* parentSheet = StyleSheet::parentStyleSheet(); + ASSERT(!parentSheet || parentSheet->isCSSStyleSheet()); + return static_cast<CSSStyleSheet*>(parentSheet); + } + + 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); + + void styleSheetChanged(); + + virtual bool parseString(const String&, bool strict = true); + + bool parseStringAtLine(const String&, bool strict, int startLineNumber); + + virtual bool isLoading(); + + void checkLoaded(); + void startLoadingDynamicSheet(); + + Node* findStyleSheetOwnerNode() const; + Document* findDocument(); + + const String& charset() const { return m_charset; } + + bool loadCompleted() const { return m_loadCompleted; } + + KURL completeURL(const String& url) const; + 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; } + + void append(PassRefPtr<CSSRule>); + void remove(unsigned index); + + unsigned length() const { return m_children.size(); } + CSSRule* item(unsigned index) { return index < length() ? m_children.at(index).get() : 0; } + +private: + CSSStyleSheet(Node* ownerNode, const String& originalURL, const KURL& finalURL, const String& charset); + CSSStyleSheet(CSSImportRule* ownerRule, const String& originalURL, const KURL& finalURL, const String& charset); + + virtual bool isCSSStyleSheet() const { return true; } + virtual String type() const { return "text/css"; } + + Vector<RefPtr<CSSRule> > m_children; + 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 000000000..34978275e --- /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 [Optional=CallWithDefaultValue] DOMString rule, + in [Optional=CallWithDefaultValue] unsigned long index) + raises(DOMException); + void deleteRule(in [Optional=CallWithDefaultValue] unsigned long index) + raises(DOMException); + + // IE Extensions + readonly attribute CSSRuleList rules; + + long addRule(in [Optional=CallWithDefaultValue] DOMString selector, + in [Optional=CallWithDefaultValue] DOMString style, + in [Optional] unsigned long index) + raises(DOMException); + void removeRule(in [Optional=CallWithDefaultValue] unsigned long index) + raises(DOMException); + }; + +} diff --git a/Source/WebCore/css/CSSTimingFunctionValue.cpp b/Source/WebCore/css/CSSTimingFunctionValue.cpp new file mode 100644 index 000000000..dcf7bb29b --- /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::customCssText() const +{ + return "linear"; +} + +String CSSCubicBezierTimingFunctionValue::customCssText() 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::customCssText() 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 000000000..9958a8c21 --- /dev/null +++ b/Source/WebCore/css/CSSTimingFunctionValue.h @@ -0,0 +1,119 @@ +/* + * 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: + bool isLinearTimingFunctionValue() const { return classType() == LinearTimingFunctionClass; } + bool isCubicBezierTimingFunctionValue() const { return classType() == CubicBezierTimingFunctionClass; } + bool isStepsTimingFunctionValue() const { return classType() == StepsTimingFunctionClass; } + +protected: + CSSTimingFunctionValue(ClassType classType) + : CSSValue(classType) + { + } +}; + +class CSSLinearTimingFunctionValue : public CSSTimingFunctionValue { +public: + static PassRefPtr<CSSLinearTimingFunctionValue> create() + { + return adoptRef(new CSSLinearTimingFunctionValue); + } + + String customCssText() const; + +private: + CSSLinearTimingFunctionValue() + : CSSTimingFunctionValue(LinearTimingFunctionClass) + { + } +}; + +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)); + } + + String customCssText() const; + + 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) + : CSSTimingFunctionValue(CubicBezierTimingFunctionClass) + , m_x1(x1) + , m_y1(y1) + , m_x2(x2) + , m_y2(y2) + { + } + + 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; } + + String customCssText() const; + +private: + CSSStepsTimingFunctionValue(int steps, bool stepAtStart) + : CSSTimingFunctionValue(StepsTimingFunctionClass) + , m_steps(steps) + , m_stepAtStart(stepAtStart) + { + } + + 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 000000000..2c2c44d27 --- /dev/null +++ b/Source/WebCore/css/CSSUnicodeRangeValue.cpp @@ -0,0 +1,40 @@ +/* + * 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 { + +String CSSUnicodeRangeValue::customCssText() 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 000000000..4fe1db77c --- /dev/null +++ b/Source/WebCore/css/CSSUnicodeRangeValue.h @@ -0,0 +1,61 @@ +/* + * 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)); + } + + UChar32 from() const { return m_from; } + UChar32 to() const { return m_to; } + + String customCssText() const; + +private: + CSSUnicodeRangeValue(UChar32 from, UChar32 to) + : CSSValue(UnicodeRangeClass) + , 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 000000000..9f746ba0e --- /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 { +public: + CSSUnknownRule() : CSSRule(0, CSSRule::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 000000000..b62ceb873 --- /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.cpp b/Source/WebCore/css/CSSValue.cpp new file mode 100644 index 000000000..0e83c0818 --- /dev/null +++ b/Source/WebCore/css/CSSValue.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2011 Andreas Kling (kling@webkit.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 "CSSValue.h" + +#include "CSSAspectRatioValue.h" +#include "CSSBorderImageValue.h" +#include "CSSBorderImageSliceValue.h" +#include "CSSCanvasValue.h" +#include "CSSCrossfadeValue.h" +#include "CSSCursorImageValue.h" +#include "CSSFlexValue.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSFunctionValue.h" +#include "CSSGradientValue.h" +#include "CSSImageGeneratorValue.h" +#include "CSSImageValue.h" +#include "CSSInheritedValue.h" +#include "CSSInitialValue.h" +#include "CSSLineBoxContainValue.h" +#include "CSSPrimitiveValue.h" +#include "CSSReflectValue.h" +#include "CSSTimingFunctionValue.h" +#include "CSSUnicodeRangeValue.h" +#include "CSSValueList.h" +#include "FontValue.h" +#include "FontFamilyValue.h" +#include "FontFeatureValue.h" +#include "ShadowValue.h" +#include "SVGColor.h" +#include "SVGPaint.h" +#include "WebKitCSSFilterValue.h" +#include "WebKitCSSShaderValue.h" +#include "WebKitCSSTransformValue.h" + +namespace WebCore { + +class SameSizeAsCSSValue : public RefCounted<SameSizeAsCSSValue> { + unsigned char bitfields[2]; +}; + +COMPILE_ASSERT(sizeof(CSSValue) == sizeof(SameSizeAsCSSValue), CSS_value_should_stay_small); + +CSSValue::Type CSSValue::cssValueType() const +{ + if (isInheritedValue()) + return CSS_INHERIT; + if (isPrimitiveValue()) + return CSS_PRIMITIVE_VALUE; + if (isValueList()) + return CSS_VALUE_LIST; + if (isInitialValue()) + return CSS_INITIAL; + return CSS_CUSTOM; +} + +void CSSValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) +{ + if (isPrimitiveValue()) + static_cast<CSSPrimitiveValue*>(this)->addSubresourceStyleURLs(urls, styleSheet); + else if (isValueList()) + static_cast<CSSValueList*>(this)->addSubresourceStyleURLs(urls, styleSheet); + else if (classType() == BorderImageClass) + static_cast<CSSBorderImageValue*>(this)->addSubresourceStyleURLs(urls, styleSheet); + else if (classType() == FontFaceSrcClass) + static_cast<CSSFontFaceSrcValue*>(this)->addSubresourceStyleURLs(urls, styleSheet); + else if (classType() == ReflectClass) + static_cast<CSSReflectValue*>(this)->addSubresourceStyleURLs(urls, styleSheet); +} + +String CSSValue::cssText() const +{ + switch (classType()) { + case AspectRatioClass: + return static_cast<const CSSAspectRatioValue*>(this)->customCssText(); + case BorderImageClass: + return static_cast<const CSSBorderImageValue*>(this)->customCssText(); + case BorderImageSliceClass: + return static_cast<const CSSBorderImageSliceValue*>(this)->customCssText(); + case CanvasClass: + return static_cast<const CSSCanvasValue*>(this)->customCssText(); + case CursorImageClass: + return static_cast<const CSSCursorImageValue*>(this)->customCssText(); + case FontClass: + return static_cast<const FontValue*>(this)->customCssText(); + case FontFaceSrcClass: + return static_cast<const CSSFontFaceSrcValue*>(this)->customCssText(); + case FontFamilyClass: + return static_cast<const FontFamilyValue*>(this)->customCssText(); + case FontFeatureClass: + return static_cast<const FontFeatureValue*>(this)->customCssText(); + case FunctionClass: + return static_cast<const CSSFunctionValue*>(this)->customCssText(); + case LinearGradientClass: + return static_cast<const CSSLinearGradientValue*>(this)->customCssText(); + case RadialGradientClass: + return static_cast<const CSSRadialGradientValue*>(this)->customCssText(); + case CrossfadeClass: + return static_cast<const CSSCrossfadeValue*>(this)->customCssText(); + case ImageClass: + return static_cast<const CSSImageValue*>(this)->customCssText(); + case InheritedClass: + return static_cast<const CSSInheritedValue*>(this)->customCssText(); + case InitialClass: + return static_cast<const CSSInitialValue*>(this)->customCssText(); + case PrimitiveClass: + return static_cast<const CSSPrimitiveValue*>(this)->customCssText(); + case ReflectClass: + return static_cast<const CSSReflectValue*>(this)->customCssText(); + case ShadowClass: + return static_cast<const ShadowValue*>(this)->customCssText(); + case LinearTimingFunctionClass: + return static_cast<const CSSLinearTimingFunctionValue*>(this)->customCssText(); + case CubicBezierTimingFunctionClass: + return static_cast<const CSSCubicBezierTimingFunctionValue*>(this)->customCssText(); + case StepsTimingFunctionClass: + return static_cast<const CSSStepsTimingFunctionValue*>(this)->customCssText(); + case UnicodeRangeClass: + return static_cast<const CSSUnicodeRangeValue*>(this)->customCssText(); + case ValueListClass: + return static_cast<const CSSValueList*>(this)->customCssText(); + case WebKitCSSTransformClass: + return static_cast<const WebKitCSSTransformValue*>(this)->customCssText(); + case LineBoxContainClass: + return static_cast<const CSSLineBoxContainValue*>(this)->customCssText(); + case FlexClass: + return static_cast<const CSSFlexValue*>(this)->customCssText(); +#if ENABLE(CSS_FILTERS) + case WebKitCSSFilterClass: + return static_cast<const WebKitCSSFilterValue*>(this)->customCssText(); +#if ENABLE(CSS_SHADERS) + case WebKitCSSShaderClass: + return static_cast<const WebKitCSSShaderValue*>(this)->customCssText(); +#endif +#endif +#if ENABLE(SVG) + case SVGColorClass: + return static_cast<const SVGColor*>(this)->customCssText(); + case SVGPaintClass: + return static_cast<const SVGPaint*>(this)->customCssText(); +#endif + } + ASSERT_NOT_REACHED(); + return String(); +} + +void CSSValue::destroy() +{ + switch (classType()) { + case AspectRatioClass: + delete static_cast<CSSAspectRatioValue*>(this); + return; + case BorderImageClass: + delete static_cast<CSSBorderImageValue*>(this); + return; + case BorderImageSliceClass: + delete static_cast<CSSBorderImageSliceValue*>(this); + return; + case CanvasClass: + delete static_cast<CSSCanvasValue*>(this); + return; + case CursorImageClass: + delete static_cast<CSSCursorImageValue*>(this); + return; + case FontClass: + delete static_cast<FontValue*>(this); + return; + case FontFaceSrcClass: + delete static_cast<CSSFontFaceSrcValue*>(this); + return; + case FontFamilyClass: + delete static_cast<FontFamilyValue*>(this); + return; + case FontFeatureClass: + delete static_cast<FontFeatureValue*>(this); + return; + case FunctionClass: + delete static_cast<CSSFunctionValue*>(this); + return; + case LinearGradientClass: + delete static_cast<CSSLinearGradientValue*>(this); + return; + case RadialGradientClass: + delete static_cast<CSSRadialGradientValue*>(this); + return; + case CrossfadeClass: + delete static_cast<CSSCrossfadeValue*>(this); + return; + case ImageClass: + delete static_cast<CSSImageValue*>(this); + return; + case InheritedClass: + delete static_cast<CSSInheritedValue*>(this); + return; + case InitialClass: + delete static_cast<CSSInitialValue*>(this); + return; + case PrimitiveClass: + delete static_cast<CSSPrimitiveValue*>(this); + return; + case ReflectClass: + delete static_cast<CSSReflectValue*>(this); + return; + case ShadowClass: + delete static_cast<ShadowValue*>(this); + return; + case LinearTimingFunctionClass: + delete static_cast<CSSLinearTimingFunctionValue*>(this); + return; + case CubicBezierTimingFunctionClass: + delete static_cast<CSSCubicBezierTimingFunctionValue*>(this); + return; + case StepsTimingFunctionClass: + delete static_cast<CSSStepsTimingFunctionValue*>(this); + return; + case UnicodeRangeClass: + delete static_cast<CSSUnicodeRangeValue*>(this); + return; + case ValueListClass: + delete static_cast<CSSValueList*>(this); + return; + case WebKitCSSTransformClass: + delete static_cast<WebKitCSSTransformValue*>(this); + return; + case LineBoxContainClass: + delete static_cast<CSSLineBoxContainValue*>(this); + return; + case FlexClass: + delete static_cast<CSSFlexValue*>(this); + return; +#if ENABLE(CSS_FILTERS) + case WebKitCSSFilterClass: + delete static_cast<WebKitCSSFilterValue*>(this); + return; +#if ENABLE(CSS_SHADERS) + case WebKitCSSShaderClass: + delete static_cast<WebKitCSSShaderValue*>(this); + return; +#endif +#endif +#if ENABLE(SVG) + case SVGColorClass: + delete static_cast<SVGColor*>(this); + return; + case SVGPaintClass: + delete static_cast<SVGPaint*>(this); + return; +#endif + } + ASSERT_NOT_REACHED(); +} + +} diff --git a/Source/WebCore/css/CSSValue.h b/Source/WebCore/css/CSSValue.h new file mode 100644 index 000000000..ce95369ab --- /dev/null +++ b/Source/WebCore/css/CSSValue.h @@ -0,0 +1,189 @@ +/* + * (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 "KURLHash.h" +#include <wtf/ListHashSet.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSStyleSheet; + +typedef int ExceptionCode; + +class CSSValue : public RefCounted<CSSValue> { +public: + enum Type { + CSS_INHERIT = 0, + CSS_PRIMITIVE_VALUE = 1, + CSS_VALUE_LIST = 2, + CSS_CUSTOM = 3, + CSS_INITIAL = 4 + + }; + + // Override RefCounted's deref() to ensure operator delete is called on + // the appropriate subclass type. + void deref() + { + if (derefBase()) + destroy(); + } + + Type cssValueType() const; + + String cssText() const; + void setCssText(const String&, ExceptionCode&) { } // FIXME: Not implemented. + + bool isPrimitiveValue() const { return m_classType <= PrimitiveClass; } + bool isValueList() const { return m_classType >= ValueListClass; } + + bool isAspectRatioValue() const { return m_classType == AspectRatioClass; } + bool isBorderImageValue() const { return m_classType == BorderImageClass; } + bool isBorderImageSliceValue() const { return m_classType == BorderImageSliceClass; } + bool isCursorImageValue() const { return m_classType == CursorImageClass; } + bool isFontFamilyValue() const { return m_classType == FontFamilyClass; } + bool isFontFeatureValue() const { return m_classType == FontFeatureClass; } + bool isFontValue() const { return m_classType == FontClass; } + bool isImageGeneratorValue() const { return m_classType >= CanvasClass && m_classType <= RadialGradientClass; } + bool isImageValue() const { return m_classType == ImageClass || m_classType == CursorImageClass; } + bool isImplicitInitialValue() const { return m_classType == InitialClass && m_isImplicitInitialValue; } + bool isInheritedValue() const { return m_classType == InheritedClass; } + bool isInitialValue() const { return m_classType == InitialClass; } + bool isReflectValue() const { return m_classType == ReflectClass; } + bool isShadowValue() const { return m_classType == ShadowClass; } + bool isTimingFunctionValue() const { return m_classType >= CubicBezierTimingFunctionClass && m_classType <= StepsTimingFunctionClass; } + bool isWebKitCSSTransformValue() const { return m_classType == WebKitCSSTransformClass; } + bool isCSSLineBoxContainValue() const { return m_classType == LineBoxContainClass; } + bool isFlexValue() const { return m_classType == FlexClass; } +#if ENABLE(CSS_FILTERS) + bool isWebKitCSSFilterValue() const { return m_classType == WebKitCSSFilterClass; } +#if ENABLE(CSS_SHADERS) + bool isWebKitCSSShaderValue() const { return m_classType == WebKitCSSShaderClass; } +#endif +#endif // ENABLE(CSS_FILTERS) +#if ENABLE(SVG) + bool isSVGColor() const { return m_classType == SVGColorClass || m_classType == SVGPaintClass; } + bool isSVGPaint() const { return m_classType == SVGPaintClass; } +#endif + + void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +protected: + + static const size_t ClassTypeBits = 5; + enum ClassType { + // Primitive class types must appear before PrimitiveClass. + ImageClass, + CursorImageClass, + FontFamilyClass, + PrimitiveClass, + + // Image generator classes. + CanvasClass, + CrossfadeClass, + LinearGradientClass, + RadialGradientClass, + + // Timing function classes. + CubicBezierTimingFunctionClass, + LinearTimingFunctionClass, + StepsTimingFunctionClass, + + // Other class types. + AspectRatioClass, + BorderImageClass, + BorderImageSliceClass, + FontFeatureClass, + FontClass, + FontFaceSrcClass, + FunctionClass, + + InheritedClass, + InitialClass, + + ReflectClass, + ShadowClass, + UnicodeRangeClass, + LineBoxContainClass, + FlexClass, +#if ENABLE(CSS_FILTERS) && ENABLE(CSS_SHADERS) + WebKitCSSShaderClass, +#endif +#if ENABLE(SVG) + SVGColorClass, + SVGPaintClass, +#endif + + // List class types must appear after ValueListClass. + ValueListClass, +#if ENABLE(CSS_FILTERS) + WebKitCSSFilterClass, +#endif + WebKitCSSTransformClass, + // Do not append non-list class types here. + }; + + ClassType classType() const { return static_cast<ClassType>(m_classType); } + + explicit CSSValue(ClassType classType) + : m_primitiveUnitType(0) + , m_hasCachedCSSText(false) + , m_isQuirkValue(false) + , m_isImplicitInitialValue(false) + , m_isSpaceSeparatedValueList(false) + , m_classType(classType) + { + } + + // NOTE: This class is non-virtual for memory and performance reasons. + // Don't go making it virtual again unless you know exactly what you're doing! + + ~CSSValue() { } + +private: + void destroy(); + +protected: + // The bits in this section are only used by specific subclasses but kept here + // to maximize struct packing. + + // CSSPrimitiveValue bits: + unsigned char m_primitiveUnitType : 7; // CSSPrimitiveValue::UnitTypes + mutable bool m_hasCachedCSSText : 1; + bool m_isQuirkValue : 1; + + // CSSInitialValue bits: + bool m_isImplicitInitialValue : 1; + + // CSSValueList bits: + bool m_isSpaceSeparatedValueList : 1; + +private: + unsigned char m_classType : ClassTypeBits; // ClassType +}; + +} // namespace WebCore + +#endif // CSSValue_h diff --git a/Source/WebCore/css/CSSValue.idl b/Source/WebCore/css/CSSValue.idl new file mode 100644 index 000000000..25eb8033c --- /dev/null +++ b/Source/WebCore/css/CSSValue.idl @@ -0,0 +1,44 @@ +/* + * 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, + CustomIsReachable, + CustomFinalize, + Polymorphic, + V8DependentLifetime + ] 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 000000000..ba1c5f692 --- /dev/null +++ b/Source/WebCore/css/CSSValueKeywords.in @@ -0,0 +1,883 @@ +// 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 RenderStyleConstants.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 +outset +ridge +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 +-webkit-pictograph +// +// +// 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 +-webkit-match-parent +// +// 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 +-webkit-flexbox +-webkit-inline-flexbox +#if defined(ENABLE_CSS_GRID_LAYOUT) && ENABLE_CSS_GRID_LAYOUT +-webkit-grid +-webkit-inline-grid +#endif +//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 +-webkit-isolate +-webkit-plaintext +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_FLEX_ALIGN +// start +// end +// center +// baseline +// stretch + +// CSS_PROP_FLEX_FLOW +row +row-reverse +column +column-reverse +// nowrap +// wrap +wrap-reverse + +// 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 +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-adjust +economy +exact + +// -webkit-color-correction +//default +sRGB + +// (-webkit-view-mode:) media feature: +floating +fullscreen +maximized +minimized +windowed + +// -webkit-hyphenate-limit-lines +no-limit + +// -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 + +// -webkit-text-orientation +upright +vertical-right + +// -webkit-line-box-contain +font +glyphs +inline-box +replaced + +// -webkit-line-grid-snap +//none +//baseline +bounds + +// -webkit-font-feature-settings +on +off + +// image-rendering +//auto +//optimizeSpeed +optimizeQuality +-webkit-optimize-contrast + +// Positioned Floats +-webkit-positioned + +// -webkit-wrap-shape +nonzero +evenodd + +// -webkit-region-overflow +// auto +break + +// -webkit-wrap-flow +// auto +// both +// left +// right +maximum +// clear + +// -webkit-wrap-through +wrap +// none + +#if defined(ENABLE_CSS_FILTERS) && ENABLE_CSS_FILTERS +// -webkit-filter +#if defined(ENABLE_CSS_SHADERS) && ENABLE_CSS_SHADERS +// values for the custom() function +// border-box +// padding-box +// content-box +filter-box +detached +#endif // CSS_SHADERS +#endif // CSS_FILTERS diff --git a/Source/WebCore/css/CSSValueList.cpp b/Source/WebCore/css/CSSValueList.cpp new file mode 100644 index 000000000..661e183a7 --- /dev/null +++ b/Source/WebCore/css/CSSValueList.cpp @@ -0,0 +1,122 @@ +/* + * (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(ClassType classType, bool isSpaceSeparated) + : CSSValue(classType) +{ + m_isSpaceSeparatedValueList = isSpaceSeparated; +} + +CSSValueList::CSSValueList(bool isSpaceSeparated) + : CSSValue(ValueListClass) +{ + m_isSpaceSeparatedValueList = isSpaceSeparated; +} + +CSSValueList::CSSValueList(CSSParserValueList* list) + : CSSValue(ValueListClass) +{ + m_isSpaceSeparatedValueList = true; + if (list) { + size_t size = list->size(); + for (unsigned i = 0; i < size; ++i) + append(list->valueAt(i)->createCSSValue()); + } +} + +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) const +{ + // 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 = isSpaceSeparated() ? createSpaceSeparated() : createCommaSeparated(); + for (size_t index = 0; index < m_values.size(); index++) + newList->append(m_values[index]); + return newList; +} + +String CSSValueList::customCssText() const +{ + String result = ""; + + unsigned size = m_values.size(); + for (unsigned i = 0; i < size; i++) { + if (!result.isEmpty()) { + if (isSpaceSeparated()) + result += " "; + else + result += ", "; + } + result += m_values[i]->cssText(); + } + + return result; +} + +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 000000000..c62262a9e --- /dev/null +++ b/Source/WebCore/css/CSSValueList.h @@ -0,0 +1,103 @@ +/* + * (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)); + } + + size_t length() const { return m_values.size(); } + CSSValue* item(size_t index) { return index < m_values.size() ? m_values[index].get() : 0; } + CSSValue* itemWithoutBoundsCheck(size_t index) { return m_values[index].get(); } + + void append(PassRefPtr<CSSValue>); + void prepend(PassRefPtr<CSSValue>); + bool removeAll(CSSValue*); + bool hasValue(CSSValue*) const; + PassRefPtr<CSSValueList> copy(); + + String customCssText() const; + + void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*); + +protected: + CSSValueList(ClassType, bool isSpaceSeparated); + +private: + explicit CSSValueList(bool isSpaceSeparated); + explicit CSSValueList(CSSParserValueList*); + + bool isSpaceSeparated() const { return m_isSpaceSeparatedValueList; } + + Vector<RefPtr<CSSValue> > m_values; +}; + +// Objects of this class are intended to be stack-allocated and scoped to a single function. +// Please take care not to pass these around as they do hold onto a raw pointer. +class CSSValueListInspector { +public: + CSSValueListInspector(CSSValue* value) : m_list((value && value->isValueList()) ? static_cast<CSSValueList*>(value) : 0) { } + CSSValue* item(size_t index) const { ASSERT(index < length()); return m_list->itemWithoutBoundsCheck(index); } + CSSValue* first() const { return item(0); } + CSSValue* second() const { return item(1); } + size_t length() const { return m_list ? m_list->length() : 0; } +private: + CSSValueList* m_list; +}; + +// Wrapper that can be used to iterate over any CSSValue. Non-list values and 0 behave as zero-length lists. +// Objects of this class are intended to be stack-allocated and scoped to a single function. +// Please take care not to pass these around as they do hold onto a raw pointer. +class CSSValueListIterator { +public: + CSSValueListIterator(CSSValue* value) : m_inspector(value), m_position(0) { } + bool hasMore() const { return m_position < m_inspector.length(); } + CSSValue* value() const { return m_inspector.item(m_position); } + bool isPrimitiveValue() const { return value()->isPrimitiveValue(); } + void advance() { m_position++; ASSERT(m_position <= m_inspector.length());} + size_t index() const { return m_position; } +private: + CSSValueListInspector m_inspector; + size_t m_position; +}; +} // namespace WebCore + +#endif // CSSValueList_h diff --git a/Source/WebCore/css/CSSValueList.idl b/Source/WebCore/css/CSSValueList.idl new file mode 100644 index 000000000..63c8514de --- /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 [Optional=CallWithDefaultValue] unsigned long index); + }; + +} diff --git a/Source/WebCore/css/CSSValuePool.cpp b/Source/WebCore/css/CSSValuePool.cpp new file mode 100644 index 000000000..3d8893ea8 --- /dev/null +++ b/Source/WebCore/css/CSSValuePool.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#include "config.h" +#include "CSSValuePool.h" +#include "CSSValueKeywords.h" + +namespace WebCore { + +CSSValuePool::CSSValuePool() + : m_inheritedValue(CSSInheritedValue::create()) + , m_implicitInitialValue(CSSInitialValue::createImplicit()) + , m_explicitInitialValue(CSSInitialValue::createExplicit()) + , m_colorTransparent(CSSPrimitiveValue::createColor(Color::transparent)) + , m_colorWhite(CSSPrimitiveValue::createColor(Color::white)) + , m_colorBlack(CSSPrimitiveValue::createColor(Color::black)) + , m_pixelZero(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX)) + , m_percentZero(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PERCENTAGE)) + , m_numberZero(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_NUMBER)) +{ +} + +CSSValuePool::~CSSValuePool() +{ +} + +PassRefPtr<CSSPrimitiveValue> CSSValuePool::createIdentifierValue(int ident) +{ + if (ident <= 0 || ident >= numCSSValueKeywords) + return CSSPrimitiveValue::createIdentifier(ident); + + RefPtr<CSSPrimitiveValue> dummyValue; + pair<IdentifierValueCache::iterator, bool> entry = m_identifierValueCache.add(ident, dummyValue); + if (entry.second) + entry.first->second = CSSPrimitiveValue::createIdentifier(ident); + return entry.first->second; +} + +PassRefPtr<CSSPrimitiveValue> CSSValuePool::createColorValue(unsigned rgbValue) +{ + // These are the empty and deleted values of the hash table. + if (rgbValue == Color::transparent) + return m_colorTransparent; + if (rgbValue == Color::white) + return m_colorWhite; + // Just because it is common. + if (rgbValue == Color::black) + return m_colorBlack; + + // Just wipe out the cache and start rebuilding if it gets too big. + const int maximumColorCacheSize = 512; + if (m_colorValueCache.size() > maximumColorCacheSize) + m_colorValueCache.clear(); + + RefPtr<CSSPrimitiveValue> dummyValue; + pair<ColorValueCache::iterator, bool> entry = m_colorValueCache.add(rgbValue, dummyValue); + if (entry.second) + entry.first->second = CSSPrimitiveValue::createColor(rgbValue); + return entry.first->second; +} + +PassRefPtr<CSSPrimitiveValue> CSSValuePool::createValue(double value, CSSPrimitiveValue::UnitTypes type) +{ + // Small positive integers repeat often. + static const int maximumCacheableValue = 256; + if (value < 0 || value > maximumCacheableValue) + return CSSPrimitiveValue::create(value, type); + + int intValue = static_cast<int>(value); + if (value != intValue) + return CSSPrimitiveValue::create(value, type); + + IntegerValueCache* cache; + switch (type) { + case CSSPrimitiveValue::CSS_PX: + if (intValue == 0) + return m_pixelZero; + cache = &m_pixelValueCache; + break; + case CSSPrimitiveValue::CSS_PERCENTAGE: + if (intValue == 0) + return m_percentZero; + cache = &m_percentValueCache; + break; + case CSSPrimitiveValue::CSS_NUMBER: + if (intValue == 0) + return m_numberZero; + cache = &m_numberValueCache; + break; + default: + return CSSPrimitiveValue::create(value, type); + } + + RefPtr<CSSPrimitiveValue> dummyValue; + pair<IntegerValueCache::iterator, bool> entry = cache->add(intValue, dummyValue); + if (entry.second) + entry.first->second = CSSPrimitiveValue::create(value, type); + return entry.first->second; +} + +} diff --git a/Source/WebCore/css/CSSValuePool.h b/Source/WebCore/css/CSSValuePool.h new file mode 100644 index 000000000..bc751ebf7 --- /dev/null +++ b/Source/WebCore/css/CSSValuePool.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 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. 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 INC. 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. + */ + +#ifndef CSSValuePool_h +#define CSSValuePool_h + +#include "CSSInheritedValue.h" +#include "CSSInitialValue.h" +#include "CSSPrimitiveValue.h" +#include <wtf/HashMap.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CSSValuePool : public RefCounted<CSSValuePool> { +public: + static PassRefPtr<CSSValuePool> create() { return adoptRef(new CSSValuePool); } + ~CSSValuePool(); + + PassRefPtr<CSSInheritedValue> createInheritedValue() { return m_inheritedValue; } + PassRefPtr<CSSInitialValue> createImplicitInitialValue() { return m_implicitInitialValue; } + PassRefPtr<CSSInitialValue> createExplicitInitialValue() { return m_explicitInitialValue; } + PassRefPtr<CSSPrimitiveValue> createIdentifierValue(int identifier); + PassRefPtr<CSSPrimitiveValue> createColorValue(unsigned rgbValue); + PassRefPtr<CSSPrimitiveValue> createValue(double value, CSSPrimitiveValue::UnitTypes); + PassRefPtr<CSSPrimitiveValue> createValue(const String& value, CSSPrimitiveValue::UnitTypes type) { return CSSPrimitiveValue::create(value, type); } + template<typename T> static PassRefPtr<CSSPrimitiveValue> createValue(T value) { return CSSPrimitiveValue::create(value); } + +private: + CSSValuePool(); + + RefPtr<CSSInheritedValue> m_inheritedValue; + RefPtr<CSSInitialValue> m_implicitInitialValue; + RefPtr<CSSInitialValue> m_explicitInitialValue; + + typedef HashMap<int, RefPtr<CSSPrimitiveValue> > IdentifierValueCache; + IdentifierValueCache m_identifierValueCache; + + typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache; + ColorValueCache m_colorValueCache; + RefPtr<CSSPrimitiveValue> m_colorTransparent; + RefPtr<CSSPrimitiveValue> m_colorWhite; + RefPtr<CSSPrimitiveValue> m_colorBlack; + + typedef HashMap<int, RefPtr<CSSPrimitiveValue> > IntegerValueCache; + RefPtr<CSSPrimitiveValue> m_pixelZero; + RefPtr<CSSPrimitiveValue> m_percentZero; + RefPtr<CSSPrimitiveValue> m_numberZero; + IntegerValueCache m_pixelValueCache; + IntegerValueCache m_percentValueCache; + IntegerValueCache m_numberValueCache; +}; + +} + +#endif diff --git a/Source/WebCore/css/CSSWrapShapes.cpp b/Source/WebCore/css/CSSWrapShapes.cpp new file mode 100644 index 000000000..e5e9f98c3 --- /dev/null +++ b/Source/WebCore/css/CSSWrapShapes.cpp @@ -0,0 +1,149 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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 "CSSWrapShapes.h" + +#include <wtf/text/StringBuilder.h> + +using namespace WTF; + +namespace WebCore { + +String CSSWrapShapeRect::cssText() const +{ + DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); + DEFINE_STATIC_LOCAL(const String, comma, (", ")); + + StringBuilder result; + result.reserveCapacity(32); + result.append(rectParen); + + result.append(m_left->cssText()); + result.append(comma); + + result.append(m_top->cssText()); + result.append(comma); + + result.append(m_width->cssText()); + result.append(comma); + + result.append(m_height->cssText()); + + if (m_radiusX.get()) { + result.append(comma); + result.append(m_radiusX->cssText()); + + if (m_radiusY.get()) { + result.append(comma); + result.append(m_radiusY->cssText()); + } + } + + result.append(')'); + + return result.toString(); +} + +String CSSWrapShapeCircle::cssText() const +{ + DEFINE_STATIC_LOCAL(const String, circleParen, ("circle(")); + DEFINE_STATIC_LOCAL(const String, comma, (", ")); + + StringBuilder result; + result.reserveCapacity(32); + result.append(circleParen); + + result.append(m_left->cssText()); + result.append(comma); + + result.append(m_top->cssText()); + result.append(comma); + + result.append(m_radius->cssText()); + result.append(')'); + + return result.toString(); +} + +String CSSWrapShapeEllipse::cssText() const +{ + DEFINE_STATIC_LOCAL(const String, ellipseParen, ("ellipse(")); + DEFINE_STATIC_LOCAL(const String, comma, (", ")); + + StringBuilder result; + result.reserveCapacity(32); + result.append(ellipseParen); + + result.append(m_left->cssText()); + result.append(comma); + + result.append(m_top->cssText()); + result.append(comma); + + result.append(m_radiusX->cssText()); + result.append(comma); + + result.append(m_radiusY->cssText()); + result.append(')'); + + return result.toString(); +} + +String CSSWrapShapePolygon::cssText() const +{ + DEFINE_STATIC_LOCAL(const String, polygonParenEvenOdd, ("polygon(evenodd, ")); + DEFINE_STATIC_LOCAL(const String, polygonParenNonZero, ("polygon(nonzero, ")); + DEFINE_STATIC_LOCAL(const String, comma, (", ")); + + StringBuilder result; + result.reserveCapacity(32); + if (m_windRule == RULE_EVENODD) + result.append(polygonParenEvenOdd); + else + result.append(polygonParenNonZero); + + ASSERT(!(m_values.size() % 2)); + + for (unsigned i = 0; i < m_values.size(); i += 2) { + if (i) + result.append(' '); + result.append(m_values.at(i)->cssText()); + result.append(comma); + result.append(m_values.at(i + 1)->cssText()); + } + + result.append(')'); + + return result.toString(); +} + +} // namespace WebCore + diff --git a/Source/WebCore/css/CSSWrapShapes.h b/Source/WebCore/css/CSSWrapShapes.h new file mode 100644 index 000000000..3ff9fab83 --- /dev/null +++ b/Source/WebCore/css/CSSWrapShapes.h @@ -0,0 +1,173 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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 CSSWrapShapes_h +#define CSSWrapShapes_h + +#include "CSSPrimitiveValue.h" +#include "PlatformString.h" +#include "WindRule.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSWrapShape : public RefCounted<CSSWrapShape> { +public: + enum Type { + CSS_WRAP_SHAPE_RECT = 1, + CSS_WRAP_SHAPE_CIRCLE = 2, + CSS_WRAP_SHAPE_ELLIPSE = 3, + CSS_WRAP_SHAPE_POLYGON = 4, + CSS_WRAP_SHAPE_PATH = 5 + }; + + virtual Type type() = 0; + virtual String cssText() const = 0; + +public: + virtual ~CSSWrapShape() { } + +protected: + CSSWrapShape() { } +}; + +class CSSWrapShapeRect : public CSSWrapShape { +public: + static PassRefPtr<CSSWrapShapeRect> create() { return adoptRef(new CSSWrapShapeRect); } + + CSSPrimitiveValue* left() const { return m_left.get(); } + CSSPrimitiveValue* top() const { return m_top.get(); } + CSSPrimitiveValue* width() const { return m_width.get(); } + CSSPrimitiveValue* height() const { return m_height.get(); } + CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } + CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } + + void setLeft(PassRefPtr<CSSPrimitiveValue> left) { m_left = left; } + void setTop(PassRefPtr<CSSPrimitiveValue> top) { m_top = top; } + void setWidth(PassRefPtr<CSSPrimitiveValue> width) { m_width = width; } + void setHeight(PassRefPtr<CSSPrimitiveValue> height) { m_height = height; } + void setRadiusX(PassRefPtr<CSSPrimitiveValue> radiusX) { m_radiusX = radiusX; } + void setRadiusY(PassRefPtr<CSSPrimitiveValue> radiusY) { m_radiusY = radiusY; } + + virtual Type type() { return CSS_WRAP_SHAPE_RECT; } + virtual String cssText() const; + +private: + CSSWrapShapeRect() { } + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_left; + RefPtr<CSSPrimitiveValue> m_width; + RefPtr<CSSPrimitiveValue> m_height; + RefPtr<CSSPrimitiveValue> m_radiusX; + RefPtr<CSSPrimitiveValue> m_radiusY; +}; + +class CSSWrapShapeCircle : public CSSWrapShape { +public: + static PassRefPtr<CSSWrapShapeCircle> create() { return adoptRef(new CSSWrapShapeCircle); } + + CSSPrimitiveValue* left() const { return m_left.get(); } + CSSPrimitiveValue* top() const { return m_top.get(); } + CSSPrimitiveValue* radius() const { return m_radius.get(); } + + void setLeft(PassRefPtr<CSSPrimitiveValue> left) { m_left = left; } + void setTop(PassRefPtr<CSSPrimitiveValue> top) { m_top = top; } + void setRadius(PassRefPtr<CSSPrimitiveValue> radius) { m_radius = radius; } + + virtual Type type() { return CSS_WRAP_SHAPE_CIRCLE; } + virtual String cssText() const; + +private: + CSSWrapShapeCircle() { } + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_left; + RefPtr<CSSPrimitiveValue> m_radius; +}; + +class CSSWrapShapeEllipse : public CSSWrapShape { +public: + static PassRefPtr<CSSWrapShapeEllipse> create() { return adoptRef(new CSSWrapShapeEllipse); } + + CSSPrimitiveValue* left() const { return m_left.get(); } + CSSPrimitiveValue* top() const { return m_top.get(); } + CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } + CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } + + void setLeft(PassRefPtr<CSSPrimitiveValue> left) { m_left = left; } + void setTop(PassRefPtr<CSSPrimitiveValue> top) { m_top = top; } + void setRadiusX(PassRefPtr<CSSPrimitiveValue> radiusX) { m_radiusX = radiusX; } + void setRadiusY(PassRefPtr<CSSPrimitiveValue> radiusY) { m_radiusY = radiusY; } + + virtual Type type() { return CSS_WRAP_SHAPE_ELLIPSE; } + virtual String cssText() const; + +private: + CSSWrapShapeEllipse() { } + + RefPtr<CSSPrimitiveValue> m_top; + RefPtr<CSSPrimitiveValue> m_left; + RefPtr<CSSPrimitiveValue> m_radiusX; + RefPtr<CSSPrimitiveValue> m_radiusY; +}; + +class CSSWrapShapePolygon : public CSSWrapShape { +public: + static PassRefPtr<CSSWrapShapePolygon> create() { return adoptRef(new CSSWrapShapePolygon); } + + void appendPoint(PassRefPtr<CSSPrimitiveValue> x, PassRefPtr<CSSPrimitiveValue> y) + { + m_values.append(x); + m_values.append(y); + } + + PassRefPtr<CSSPrimitiveValue> getXAt(unsigned i) { return m_values.at(i * 2); } + PassRefPtr<CSSPrimitiveValue> getYAt(unsigned i) { return m_values.at(i * 2 + 1); } + + void setWindRule(WindRule w) { m_windRule = w; } + WindRule windRule() const { return m_windRule; } + + virtual Type type() { return CSS_WRAP_SHAPE_POLYGON; } + virtual String cssText() const; + +private: + CSSWrapShapePolygon() + : m_windRule(RULE_NONZERO) + { + } + + Vector<RefPtr<CSSPrimitiveValue> > m_values; + WindRule m_windRule; +}; + +} // namespace WebCore + +#endif // CSSWrapShapes_h diff --git a/Source/WebCore/css/Counter.h b/Source/WebCore/css/Counter.h new file mode 100644 index 000000000..c5c8176aa --- /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 listStyleIdent() const { return m_listStyle ? m_listStyle->getIdent() : 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; // ident + 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 000000000..6236c454e --- /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 000000000..91e5d7ae1 --- /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 000000000..615bd6cf5 --- /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 000000000..665895d3a --- /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(FontFamilyClass, 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::customCssText() const +{ + return quoteCSSStringIfNeeded(m_familyName); +} + +} diff --git a/Source/WebCore/css/FontFamilyValue.h b/Source/WebCore/css/FontFamilyValue.h new file mode 100644 index 000000000..b2fbaa29b --- /dev/null +++ b/Source/WebCore/css/FontFamilyValue.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 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; } + + String customCssText() const; + +private: + FontFamilyValue(const String& familyName); + + String m_familyName; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/FontFeatureValue.cpp b/Source/WebCore/css/FontFeatureValue.cpp new file mode 100644 index 000000000..62c396068 --- /dev/null +++ b/Source/WebCore/css/FontFeatureValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 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 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 "FontFeatureValue.h" + +#include "CSSParser.h" +#include "CSSValueKeywords.h" +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +FontFeatureValue::FontFeatureValue(const String& tag, int value) + : CSSValue(FontFeatureClass) + , m_tag(tag) + , m_value(value) +{ +} + +String FontFeatureValue::customCssText() const +{ + StringBuilder builder; + builder.append("'"); + builder.append(m_tag); + builder.append("' "); + builder.append(String::number(m_value)); + return builder.toString(); +} + +} diff --git a/Source/WebCore/css/FontFeatureValue.h b/Source/WebCore/css/FontFeatureValue.h new file mode 100644 index 000000000..7d5e036c0 --- /dev/null +++ b/Source/WebCore/css/FontFeatureValue.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 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 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 FontFeatureValue_h +#define FontFeatureValue_h + +#include "CSSValue.h" +#include "PlatformString.h" + +namespace WebCore { + +class FontFeatureValue : public CSSValue { +public: + static PassRefPtr<FontFeatureValue> create(const String& tag, int value) + { + return adoptRef(new FontFeatureValue(tag, value)); + } + + const String& tag() const { return m_tag; } + int value() const { return m_value; } + String customCssText() const; + +private: + FontFeatureValue(const String&, int); + + String m_tag; + const int m_value; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/FontValue.cpp b/Source/WebCore/css/FontValue.cpp new file mode 100644 index 000000000..8841a7993 --- /dev/null +++ b/Source/WebCore/css/FontValue.cpp @@ -0,0 +1,68 @@ +/** + * (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" +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +String FontValue::customCssText() const +{ + // font variant weight size / line-height family + + StringBuilder result; + + if (style) + result.append(style->cssText()); + if (variant) { + if (!result.isEmpty()) + result.append(' '); + result.append(variant->cssText()); + } + if (weight) { + if (!result.isEmpty()) + result.append(' '); + result.append(weight->cssText()); + } + if (size) { + if (!result.isEmpty()) + result.append(' '); + result.append(size->cssText()); + } + if (lineHeight) { + if (!size) + result.append(' '); + result.append('/'); + result.append(lineHeight->cssText()); + } + if (family) { + if (!result.isEmpty()) + result.append(' '); + result.append(family->cssText()); + } + + return result.toString(); +} + +} diff --git a/Source/WebCore/css/FontValue.h b/Source/WebCore/css/FontValue.h new file mode 100644 index 000000000..5f8336921 --- /dev/null +++ b/Source/WebCore/css/FontValue.h @@ -0,0 +1,58 @@ +/* + * (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); + } + + String customCssText() const; + + RefPtr<CSSPrimitiveValue> style; + RefPtr<CSSPrimitiveValue> variant; + RefPtr<CSSPrimitiveValue> weight; + RefPtr<CSSPrimitiveValue> size; + RefPtr<CSSPrimitiveValue> lineHeight; + RefPtr<CSSValueList> family; + +private: + FontValue() + : CSSValue(FontClass) + { + } +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaFeatureNames.cpp b/Source/WebCore/css/MediaFeatureNames.cpp new file mode 100644 index 000000000..85b8cbc1a --- /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 000000000..1daa4e9e1 --- /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 000000000..e4650c842 --- /dev/null +++ b/Source/WebCore/css/MediaList.cpp @@ -0,0 +1,249 @@ +/* + * (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* parentStyleSheet, bool fallbackToDescriptor) + : m_fallback(fallbackToDescriptor) + , m_parentStyleSheet(parentStyleSheet) + , m_lastLine(0) +{ +} + +MediaList::MediaList(CSSStyleSheet* parentStyleSheet, const String& media, bool fallbackToDescriptor) + : m_fallback(fallbackToDescriptor) + , m_parentStyleSheet(parentStyleSheet) + , m_lastLine(0) +{ + 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() +{ + 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, nullptr)); + 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, nullptr)); + } 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, nullptr)); + ec = 0; + } + } + + if (!ec) + notifyChanged(); +} + +void MediaList::appendMediaQuery(PassOwnPtr<MediaQuery> mediaQuery) +{ + m_queries.append(mediaQuery.leakPtr()); +} + +void MediaList::notifyChanged() +{ + if (!m_parentStyleSheet) + return; + + m_parentStyleSheet->styleSheetChanged(); +} + +} diff --git a/Source/WebCore/css/MediaList.h b/Source/WebCore/css/MediaList.h new file mode 100644 index 000000000..a0e0fca01 --- /dev/null +++ b/Source/WebCore/css/MediaList.h @@ -0,0 +1,102 @@ +/* + * (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 <wtf/Forward.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSImportRule; +class CSSRule; +class CSSStyleSheet; +class MediaQuery; + +typedef int ExceptionCode; + +class MediaList : public RefCounted<MediaList> { +public: + static PassRefPtr<MediaList> create() + { + return adoptRef(new MediaList(0, false)); + } + 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)); + } + + ~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; } + + CSSStyleSheet* parentStyleSheet() const { return m_parentStyleSheet; } + void setParentStyleSheet(CSSStyleSheet* styleSheet) + { + // MediaList should never be moved between style sheets. + ASSERT(styleSheet == m_parentStyleSheet || !m_parentStyleSheet || !styleSheet); + m_parentStyleSheet = styleSheet; + } + + int lastLine() const { return m_lastLine; } + void setLastLine(int lastLine) { m_lastLine = lastLine; } + +private: + MediaList(CSSStyleSheet* parentSheet, bool fallbackToDescription); + MediaList(CSSStyleSheet* parentSheet, const String& media, bool fallbackToDescription); + + void notifyChanged(); + + bool m_fallback; // true if failed media query parsing should fallback to media description parsing. + + CSSStyleSheet* m_parentStyleSheet; + Vector<MediaQuery*> m_queries; + int m_lastLine; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/MediaList.idl b/Source/WebCore/css/MediaList.idl new file mode 100644 index 000000000..2b441f00a --- /dev/null +++ b/Source/WebCore/css/MediaList.idl @@ -0,0 +1,46 @@ +/* + * 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 [ + GenerateIsReachable, + HasIndexGetter + ] MediaList { + + attribute [ConvertNullToNullString, ConvertNullStringTo=Null] DOMString mediaText + setter raises(DOMException); + readonly attribute unsigned long length; + + [ConvertNullStringTo=Null] DOMString item(in [Optional=CallWithDefaultValue] unsigned long index); + void deleteMedium(in [Optional=CallWithDefaultValue] DOMString oldMedium) + raises(DOMException); + void appendMedium(in [Optional=CallWithDefaultValue] DOMString newMedium) + raises(DOMException); + + }; + +} diff --git a/Source/WebCore/css/MediaQuery.cpp b/Source/WebCore/css/MediaQuery.cpp new file mode 100644 index 000000000..8fa5820df --- /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 000000000..cb14154df --- /dev/null +++ b/Source/WebCore/css/MediaQuery.h @@ -0,0 +1,71 @@ +/* + * 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 { + WTF_MAKE_NONCOPYABLE(MediaQuery); WTF_MAKE_FAST_ALLOCATED; +public: + enum Restrictor { + Only, Not, None + }; + + typedef Vector<OwnPtr<MediaQueryExp> > ExpressionVector; + + MediaQuery(Restrictor, const String& mediaType, PassOwnPtr<ExpressionVector> 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<ExpressionVector> 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 000000000..64d493392 --- /dev/null +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -0,0 +1,566 @@ +/* + * 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()->deviceScaleFactor(), static_cast<CSSPrimitiveValue*>(value)->getFloatValue(), op); + + return frame->page()->deviceScaleFactor() != 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 computeLength(CSSValue* value, bool strict, RenderStyle* style, RenderStyle* rootStyle, int& result) +{ + if (!value->isPrimitiveValue()) + return false; + + CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); + + if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { + result = primitiveValue->getIntValue(); + return !strict || !result; + } + + if (primitiveValue->isLength()) { + result = primitiveValue->computeLength<int>(style, rootStyle); + return true; + } + + 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(); + int length; + return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(sg.height()), length, 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(); + int length; + return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(sg.width()), length, 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(); + + if (value) { + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + int length; + return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(view->layoutHeight(), length, op); + } + + return view->layoutHeight() != 0; +} + +static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +{ + FrameView* view = frame->view(); + + if (value) { + RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); + int length; + return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(view->layoutWidth(), length, 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.get(), 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 000000000..ba838f207 --- /dev/null +++ b/Source/WebCore/css/MediaQueryEvaluator.h @@ -0,0 +1,91 @@ +/* + * 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 { + WTF_MAKE_NONCOPYABLE(MediaQueryEvaluator); WTF_MAKE_FAST_ALLOCATED; +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 + RefPtr<RenderStyle> m_style; + bool m_expResult; +}; + +} // namespace +#endif diff --git a/Source/WebCore/css/MediaQueryExp.cpp b/Source/WebCore/css/MediaQueryExp.cpp new file mode 100644 index 000000000..1f5322183 --- /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 000000000..feb61c084 --- /dev/null +++ b/Source/WebCore/css/MediaQueryExp.h @@ -0,0 +1,84 @@ +/* + * 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 { + WTF_MAKE_FAST_ALLOCATED; +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 000000000..aa3ef60d8 --- /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 000000000..8ff498859 --- /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 000000000..0d8b1f22d --- /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 [Optional=CallWithDefaultValue] MediaQueryListListener listener); + void removeListener(in [Optional=CallWithDefaultValue] MediaQueryListListener listener); + }; +} diff --git a/Source/WebCore/css/MediaQueryListListener.cpp b/Source/WebCore/css/MediaQueryListListener.cpp new file mode 100644 index 000000000..6f86bc2a4 --- /dev/null +++ b/Source/WebCore/css/MediaQueryListListener.cpp @@ -0,0 +1,50 @@ +/* + * 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, deprecatedGlobalObjectForPrototype(state), query)); +#else + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = state->context(); + if (context.IsEmpty()) + return; // JS may not be enabled. + v8::Context::Scope scope(context); + 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 000000000..de62683c0 --- /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 000000000..dfe659b0d --- /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 [Optional=CallWithDefaultValue] MediaQueryList list); + }; +} diff --git a/Source/WebCore/css/MediaQueryMatcher.cpp b/Source/WebCore/css/MediaQueryMatcher.cpp new file mode 100644 index 000000000..a5f35dd77 --- /dev/null +++ b/Source/WebCore/css/MediaQueryMatcher.cpp @@ -0,0 +1,157 @@ +/* + * 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 "Frame.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 nullptr; + + Element* documentElement = m_document->documentElement(); + if (!documentElement) + return nullptr; + + CSSStyleSelector* styleSelector = m_document->styleSelector(); + if (!styleSelector) + return nullptr; + + 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(adoptPtr(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 000000000..96bbf8337 --- /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 000000000..a95370dc3 --- /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 000000000..11ebfe4fa --- /dev/null +++ b/Source/WebCore/css/RGBColor.cpp @@ -0,0 +1,63 @@ +/* + * 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" +#include "CSSPrimitiveValue.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 000000000..875eb3715 --- /dev/null +++ b/Source/WebCore/css/RGBColor.h @@ -0,0 +1,59 @@ +/* + * 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 "Color.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + + class CSSPrimitiveValue; + + 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 000000000..1dc87bcfd --- /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 000000000..b70c6c45f --- /dev/null +++ b/Source/WebCore/css/Rect.h @@ -0,0 +1,70 @@ +/* + * 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() { } +}; + +class Quad : public RectBase, public RefCounted<Quad> { +public: + static PassRefPtr<Quad> create() { return adoptRef(new Quad); } + +private: + Quad() { } +}; + +} // namespace WebCore + +#endif // Rect_h diff --git a/Source/WebCore/css/Rect.idl b/Source/WebCore/css/Rect.idl new file mode 100644 index 000000000..60eb70e31 --- /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 000000000..7ef3b07d3 --- /dev/null +++ b/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp @@ -0,0 +1,211 @@ +/* + 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" +#include "SVGPaint.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<SVGPaint> CSSComputedStyleDeclaration::adjustSVGPaintForCurrentColor(PassRefPtr<SVGPaint> newPaint, RenderStyle* style) const +{ + RefPtr<SVGPaint> paint = newPaint; + if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paint->paintType() == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR) + paint->setColor(style->color()); + return paint.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 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 currentColorOrValidColor(style, svgStyle->floodColor()); + case CSSPropertyLightingColor: + return currentColorOrValidColor(style, svgStyle->lightingColor()); + case CSSPropertyStopColor: + return currentColorOrValidColor(style, svgStyle->stopColor()); + case CSSPropertyFill: + return adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle->fillPaintType(), svgStyle->fillPaintUri(), svgStyle->fillPaintColor()), style); + 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 adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle->strokePaintType(), svgStyle->strokePaintUri(), svgStyle->strokePaintColor()), style); + 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 000000000..dd738fb3c --- /dev/null +++ b/Source/WebCore/css/SVGCSSParser.cpp @@ -0,0 +1,366 @@ +/* + 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 "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::createNone(); + else if (id == CSSValueCurrentcolor) + parsedValue = SVGPaint::createCurrentColor(); + else if ((id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu) + parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id)); + else if (value->unit == CSSPrimitiveValue::CSS_URI) { + RGBA32 c = Color::transparent; + if (m_valueList->next()) { + if (parseColorFromValue(m_valueList->current(), c)) + parsedValue = SVGPaint::createURIAndColor(value->string, c); + else if (m_valueList->current()->id == CSSValueNone) + parsedValue = SVGPaint::createURIAndNone(value->string); + } + if (!parsedValue) + parsedValue = SVGPaint::createURI(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::createFromString(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::createFromString(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 { + RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId); + if (shadowValueList) { + addProperty(propId, shadowValueList.release(), important); + m_valueList->next(); + return true; + } + return false; + } + + /* 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 = CSSPrimitiveValue::createAllowingMarginQuirk(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::createUnknown(); + return SVGPaint::createColor(Color(c)); +} + +PassRefPtr<CSSValue> CSSParser::parseSVGColor() +{ + RGBA32 c = Color::transparent; + if (!parseColorFromValue(m_valueList->current(), c)) + return 0; + return SVGColor::createFromColor(Color(c)); +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/css/SVGCSSPropertyNames.in b/Source/WebCore/css/SVGCSSPropertyNames.in new file mode 100644 index 000000000..8c8c1544f --- /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 000000000..318d72b73 --- /dev/null +++ b/Source/WebCore/css/SVGCSSStyleSelector.cpp @@ -0,0 +1,607 @@ +/* + 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(); + + bool isInherit = m_parentNode && value->isInheritedValue(); + bool isInitial = value->isInitialValue() || (!m_parentNode && value->isInheritedValue()); + + // 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 CSSPropertyShapeRendering: + { + HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) + if (primitiveValue) + svgstyle->setShapeRendering(*primitiveValue); + break; + } + // end of ident only properties + case CSSPropertyFill: + { + if (isInherit) { + const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle(); + svgstyle->setFillPaint(svgParentStyle->fillPaintType(), svgParentStyle->fillPaintColor(), svgParentStyle->fillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + return; + } + if (isInitial) { + svgstyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + return; + } + if (value->isSVGPaint()) { + SVGPaint* svgPaint = static_cast<SVGPaint*>(value); + svgstyle->setFillPaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + } + break; + } + case CSSPropertyStroke: + { + if (isInherit) { + const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle(); + svgstyle->setStrokePaint(svgParentStyle->strokePaintType(), svgParentStyle->strokePaintColor(), svgParentStyle->strokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + return; + } + if (isInitial) { + svgstyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + return; + } + if (value->isSVGPaint()) { + SVGPaint* svgPaint = static_cast<SVGPaint*>(value); + svgstyle->setStrokePaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); + } + 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()) { + svgstyle->setStrokeDashArray(SVGRenderStyle::initialStrokeDashArray()); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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::fragmentIdentifierFromIRIString(s, m_element->document())); + 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(adoptPtr(m_parentStyle->svgStyle()->shadow() ? new ShadowData(*m_parentStyle->svgStyle()->shadow()) : 0)); + if (isInitial || primitiveValue) // initial | none + return svgstyle->setShadow(nullptr); + + 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->computeLength<int>(style(), m_rootElementStyle); + int y = item->y->computeLength<int>(style(), m_rootElementStyle); + int blur = item->blur ? item->blur->computeLength<int>(style(), m_rootElementStyle) : 0; + Color color; + if (item->color) + color = colorFromPrimitiveValue(item->color.get()); + + // -webkit-svg-shadow does should not have a spread or style + ASSERT(!item->spread); + ASSERT(!item->style); + + OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(x, y, blur, 0, Normal, false, color.isValid() ? color : Color::transparent)); + svgstyle->setShadow(shadowData.release()); + 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 000000000..4fac4baf8 --- /dev/null +++ b/Source/WebCore/css/SVGCSSValueKeywords.in @@ -0,0 +1,277 @@ +// 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 and evenodd part of core CSS values now. + +// 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/SelectorChecker.cpp b/Source/WebCore/css/SelectorChecker.cpp new file mode 100644 index 000000000..f74eed02c --- /dev/null +++ b/Source/WebCore/css/SelectorChecker.cpp @@ -0,0 +1,1428 @@ +/* + * 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, 2011 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/) + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (C) Research In Motion Limited 2011. 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 "SelectorChecker.h" + +#include "CSSSelector.h" +#include "CSSSelectorList.h" +#include "Document.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameSelection.h" +#include "HTMLAnchorElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLProgressElement.h" +#include "InspectorInstrumentation.h" +#include "NodeRenderStyle.h" +#include "Page.h" +#include "PageGroup.h" +#include "RenderObject.h" +#include "RenderScrollbar.h" +#include "RenderStyle.h" +#include "ScrollableArea.h" +#include "ScrollbarTheme.h" +#include "StyledElement.h" +#include "Text.h" + +#if USE(PLATFORM_STRATEGIES) +#include "PlatformStrategies.h" +#include "VisitedLinkStrategy.h" +#endif + +#if ENABLE(SVG) +#include "SVGNames.h" +#include "XLinkNames.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr); + +SelectorChecker::SelectorChecker(Document* document, bool strictParsing) + : m_document(document) + , m_strictParsing(strictParsing) + , m_documentIsHTML(document->isHTMLDocument()) + , m_isCollectingRulesOnly(false) + , m_pseudoStyle(NOPSEUDO) + , m_hasUnknownPseudoElements(false) +{ +} + +// Salt to separate otherwise identical string hashes so a class-selector like .article won't match <article> elements. +enum { TagNameSalt = 13, IdAttributeSalt = 17, ClassAttributeSalt = 19 }; + +static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes) +{ + identifierHashes.append(element->localName().impl()->existingHash() * TagNameSalt); + if (element->hasID()) + identifierHashes.append(element->idForStyleResolution().impl()->existingHash() * IdAttributeSalt); + const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0; + if (styledElement && styledElement->hasClass()) { + const SpaceSplitString& classNames = styledElement->classNames(); + size_t count = classNames.size(); + for (size_t i = 0; i < count; ++i) + identifierHashes.append(classNames[i].impl()->existingHash() * ClassAttributeSalt); + } +} + +void SelectorChecker::pushParentStackFrame(Element* parent) +{ + ASSERT(m_ancestorIdentifierFilter); + ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentOrHostElement()); + ASSERT(!m_parentStack.isEmpty() || !parent->parentOrHostElement()); + m_parentStack.append(ParentStackFrame(parent)); + ParentStackFrame& parentFrame = m_parentStack.last(); + // Mix tags, class names and ids into some sort of weird bouillabaisse. + // The filter is used for fast rejection of child and descendant selectors. + collectElementIdentifierHashes(parent, parentFrame.identifierHashes); + size_t count = parentFrame.identifierHashes.size(); + for (size_t i = 0; i < count; ++i) + m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]); +} + +void SelectorChecker::popParentStackFrame() +{ + ASSERT(!m_parentStack.isEmpty()); + ASSERT(m_ancestorIdentifierFilter); + const ParentStackFrame& parentFrame = m_parentStack.last(); + size_t count = parentFrame.identifierHashes.size(); + for (size_t i = 0; i < count; ++i) + m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]); + m_parentStack.removeLast(); + if (m_parentStack.isEmpty()) { + ASSERT(m_ancestorIdentifierFilter->likelyEmpty()); + m_ancestorIdentifierFilter.clear(); + } +} + +void SelectorChecker::pushParent(Element* parent) +{ + if (m_parentStack.isEmpty()) { + ASSERT(!m_ancestorIdentifierFilter); + m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>); + // If the element is not the root itself, build the stack starting from the root. + if (parent->parentOrHostNode()) { + Vector<Element*, 30> ancestors; + for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentOrHostElement()) + ancestors.append(ancestor); + int count = ancestors.size(); + for (int n = count - 1; n >= 0; --n) + pushParentStackFrame(ancestors[n]); + return; + } + } else if (!parent->parentOrHostElement()) { + // We are not always invoked consistently. For example, script execution can cause us to enter + // style recalc in the middle of tree building. Reset the stack if we see a new root element. + ASSERT(m_ancestorIdentifierFilter); + m_ancestorIdentifierFilter->clear(); + m_parentStack.resize(0); + } else { + ASSERT(m_ancestorIdentifierFilter); + // We may get invoked for some random elements in some wacky cases during style resolve. + // Pause maintaining the stack in this case. + if (m_parentStack.last().element != parent->parentOrHostElement()) + return; + } + pushParentStackFrame(parent); +} + +void SelectorChecker::popParent(Element* parent) +{ + if (m_parentStack.isEmpty() || m_parentStack.last().element != parent) + return; + popParentStackFrame(); +} + +static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned*& hash, const unsigned* end) +{ + switch (selector->m_match) { + case CSSSelector::Id: + if (!selector->value().isEmpty()) + (*hash++) = selector->value().impl()->existingHash() * IdAttributeSalt; + break; + case CSSSelector::Class: + if (!selector->value().isEmpty()) + (*hash++) = selector->value().impl()->existingHash() * ClassAttributeSalt; + break; + default: + break; + } + if (hash == end) + return; + const AtomicString& localName = selector->tag().localName(); + if (localName != starAtom) + (*hash++) = localName.impl()->existingHash() * TagNameSalt; +} + +void SelectorChecker::collectIdentifierHashes(const CSSSelector* selector, unsigned* identifierHashes, unsigned maximumIdentifierCount) +{ + unsigned* hash = identifierHashes; + unsigned* end = identifierHashes + maximumIdentifierCount; + CSSSelector::Relation relation = selector->relation(); + + // Skip the topmost selector. It is handled quickly by the rule hashes. + bool skipOverSubselectors = true; + for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) { + // Only collect identifiers that match ancestors. + switch (relation) { + case CSSSelector::SubSelector: + if (!skipOverSubselectors) + collectDescendantSelectorIdentifierHashes(selector, hash, end); + break; + case CSSSelector::DirectAdjacent: + case CSSSelector::IndirectAdjacent: + case CSSSelector::ShadowDescendant: + skipOverSubselectors = true; + break; + case CSSSelector::Descendant: + case CSSSelector::Child: + skipOverSubselectors = false; + collectDescendantSelectorIdentifierHashes(selector, hash, end); + break; + } + if (hash == end) + return; + relation = selector->relation(); + } + *hash = 0; +} + +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(SVG) + if (element->isSVGElement()) + return &element->getAttribute(XLinkNames::hrefAttr); +#endif + + return 0; +} + +EInsideLink SelectorChecker::determineLinkStateSlowCase(Element* element) const +{ + ASSERT(element->isLink()); + + const AtomicString* attribute = linkAttribute(element); + if (!attribute || attribute->isNull()) + return NotInsideLink; + + // An empty href refers to the document itself which is always visited. It is useful to check this explicitly so + // that visited links can be tested in platform independent manner, without explicit support in the test harness. + if (attribute->isEmpty()) + return InsideVisitedLink; + + LinkHash hash; + if (element->hasTagName(aTag)) + hash = static_cast<HTMLAnchorElement*>(element)->visitedLinkHash(); + else + hash = visitedLinkHash(m_document->baseURL(), *attribute); + + if (!hash) + return InsideUnvisitedLink; + + 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, m_document->baseURL(), *attribute) ? InsideVisitedLink : InsideUnvisitedLink; +#else + return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink; +#endif +} + +bool SelectorChecker::checkSelector(CSSSelector* sel, Element* element, bool isFastCheckableSelector) const +{ + PseudoId dynamicPseudo = NOPSEUDO; + if (isFastCheckableSelector && !element->isSVGElement()) { + if (!fastCheckRightmostSelector(sel, element, VisitedMatchDisabled)) + return false; + return fastCheckSelector(sel, element); + } + return checkSelector(sel, element, dynamicPseudo, false, VisitedMatchDisabled) == SelectorMatches; +} + +namespace { + +template <bool checkValue(const Element*, AtomicStringImpl*, const QualifiedName&), bool initAttributeName> +inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement) +{ + AtomicStringImpl* value = selector->value().impl(); + const QualifiedName& attribute = initAttributeName ? selector->attribute() : anyQName(); + for (; element; element = element->parentElement()) { + if (checkValue(element, value, attribute) && SelectorChecker::tagMatches(element, selector)) { + if (selector->relation() == CSSSelector::Descendant) + topChildOrSubselector = 0; + else if (!topChildOrSubselector) { + ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector); + topChildOrSubselector = selector; + topChildOrSubselectorMatchElement = element; + } + if (selector->relation() != CSSSelector::SubSelector) + element = element->parentElement(); + selector = selector->tagHistory(); + return true; + } + if (topChildOrSubselector) { + // Child or subselector check failed. + // If the match element is null, topChildOrSubselector was also the very topmost selector and had to match + // the original element we were checking. + if (!topChildOrSubselectorMatchElement) + return false; + // There may be other matches down the ancestor chain. + // Rewind to the topmost child or subselector and the element it matched, continue checking ancestors. + selector = topChildOrSubselector; + element = topChildOrSubselectorMatchElement->parentElement(); + topChildOrSubselector = 0; + return true; + } + } + return false; +} + +inline bool checkClassValue(const Element* element, AtomicStringImpl* value, const QualifiedName&) +{ + return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value); +} + +inline bool checkIDValue(const Element* element, AtomicStringImpl* value, const QualifiedName&) +{ + return element->hasID() && element->idForStyleResolution().impl() == value; +} + +inline bool checkExactAttributeValue(const Element* element, AtomicStringImpl* value, const QualifiedName& attributeName) +{ + return SelectorChecker::checkExactAttribute(element, attributeName, value); +} + +inline bool checkTagValue(const Element*, AtomicStringImpl*, const QualifiedName&) +{ + return true; +} + +} + +inline bool SelectorChecker::fastCheckRightmostSelector(const CSSSelector* selector, const Element* element, VisitedMatchType visitedMatchType) const +{ + ASSERT(isFastCheckableSelector(selector)); + + if (!SelectorChecker::tagMatches(element, selector)) + return false; + switch (selector->m_match) { + case CSSSelector::None: + return true; + case CSSSelector::Class: + return checkClassValue(element, selector->value().impl(), anyQName()); + case CSSSelector::Id: + return checkIDValue(element, selector->value().impl(), anyQName()); + case CSSSelector::Exact: + case CSSSelector::Set: + return checkExactAttributeValue(element, selector->value().impl(), selector->attribute()); + case CSSSelector::PseudoClass: + return commonPseudoClassSelectorMatches(element, selector, visitedMatchType); + default: + ASSERT_NOT_REACHED(); + } + return false; +} + +bool SelectorChecker::fastCheckSelector(const CSSSelector* selector, const Element* element) const +{ + ASSERT(fastCheckRightmostSelector(selector, element, VisitedMatchEnabled)); + + const CSSSelector* topChildOrSubselector = 0; + const Element* topChildOrSubselectorMatchElement = 0; + if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector) + topChildOrSubselector = selector; + + if (selector->relation() != CSSSelector::SubSelector) + element = element->parentElement(); + + selector = selector->tagHistory(); + + // We know this compound selector has descendant, child and subselector combinators only and all components are simple. + while (selector) { + switch (selector->m_match) { + case CSSSelector::Class: + if (!fastCheckSingleSelector<checkClassValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) + return false; + break; + case CSSSelector::Id: + if (!fastCheckSingleSelector<checkIDValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) + return false; + break; + case CSSSelector::None: + if (!fastCheckSingleSelector<checkTagValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) + return false; + break; + case CSSSelector::Set: + case CSSSelector::Exact: + if (!fastCheckSingleSelector<checkExactAttributeValue, true>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement)) + return false; + break; + default: + ASSERT_NOT_REACHED(); + } + } + return true; +} + +static inline bool isFastCheckableRelation(CSSSelector::Relation relation) +{ + return relation == CSSSelector::Descendant || relation == CSSSelector::Child || relation == CSSSelector::SubSelector; +} + +static inline bool isFastCheckableMatch(const CSSSelector* selector) +{ + if (selector->m_match == CSSSelector::Set) + return true; + if (selector->m_match == CSSSelector::Exact) + return !htmlAttributeHasCaseInsensitiveValue(selector->attribute()); + return selector->m_match == CSSSelector::None || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class; +} + +static inline bool isFastCheckableRightmostSelector(const CSSSelector* selector) +{ + if (!isFastCheckableRelation(selector->relation())) + return false; + return isFastCheckableMatch(selector) || SelectorChecker::isCommonPseudoClassSelector(selector); +} + +bool SelectorChecker::isFastCheckableSelector(const CSSSelector* selector) +{ + if (!isFastCheckableRightmostSelector(selector)) + return false; + for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) { + if (!isFastCheckableRelation(selector->relation())) + return false; + if (!isFastCheckableMatch(selector)) + return false; + } + return true; +} + +// Recursive check of selectors and combinators +// It can return 4 different values: +// * SelectorMatches - the selector matches the element e +// * SelectorFailsLocally - the selector fails for the element e +// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e +// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e +SelectorChecker::SelectorMatch SelectorChecker::checkSelector(CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType visitedMatchType, 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->isSVGShadowRoot()) + return SelectorFailsCompletely; +#endif + + // first selector has to match + if (!checkOneSelector(sel, e, dynamicPseudo, isSubSelector, visitedMatchType, 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; + + // Disable :visited matching when we see the first link or try to match anything else than an ancestors. + if (!isSubSelector && (e->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) + visitedMatchType = VisitedMatchDisabled; + } + + 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, dynamicPseudo, false, visitedMatchType); + if (match == SelectorMatches || match == SelectorFailsCompletely) + 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, dynamicPseudo, false, visitedMatchType); + } + case CSSSelector::DirectAdjacent: + { + if (!m_isCollectingRulesOnly && 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 SelectorFailsAllSiblings; + e = static_cast<Element*>(n); + return checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); + } + case CSSSelector::IndirectAdjacent: + if (!m_isCollectingRulesOnly && 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 SelectorFailsAllSiblings; + e = static_cast<Element*>(n); + SelectorMatch match = checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); + if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) + 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_isCollectingRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION + && !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass)) + return SelectorFailsCompletely; + return checkSelector(sel, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle); + case CSSSelector::ShadowDescendant: + { + Node* shadowHostNode = e->shadowAncestorNode(); + if (shadowHostNode == e || !shadowHostNode->isElementNode()) + return SelectorFailsCompletely; + e = static_cast<Element*>(shadowHostNode); + return checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); + } + } + + 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; +} + +bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr) +{ + static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); + bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom); + return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl()); +} + +static bool attributeValueMatches(Attribute* attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive) +{ + const AtomicString& value = attributeItem->value(); + if (value.isNull()) + return false; + + switch (match) { + case CSSSelector::Exact: + if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value)) + return false; + break; + case CSSSelector::List: + { + // Ignore empty selectors or selectors containing spaces + if (selectorValue.contains(' ') || selectorValue.isEmpty()) + return false; + + unsigned startSearchAt = 0; + while (true) { + size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive); + if (foundPos == notFound) + return false; + if (!foundPos || value[foundPos - 1] == ' ') { + unsigned endStr = foundPos + selectorValue.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(selectorValue, caseSensitive) || selectorValue.isEmpty()) + return false; + break; + case CSSSelector::Begin: + if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) + return false; + break; + case CSSSelector::End: + if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) + return false; + break; + case CSSSelector::Hyphen: + if (value.length() < selectorValue.length()) + return false; + if (!value.startsWith(selectorValue, caseSensitive)) + return false; + // It they start the same, check for exact match or following '-': + if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-') + return false; + break; + case CSSSelector::PseudoClass: + case CSSSelector::PseudoElement: + default: + break; + } + + return true; +} + +static bool anyAttributeMatches(NamedNodeMap* attributes, CSSSelector::Match match, const QualifiedName& selectorAttr, const AtomicString& selectorValue, bool caseSensitive) +{ + for (size_t i = 0; i < attributes->length(); ++i) { + Attribute* attributeItem = attributes->attributeItem(i); + + if (!SelectorChecker::attributeNameMatches(attributeItem, selectorAttr)) + continue; + + if (attributeValueMatches(attributeItem, match, selectorValue, caseSensitive)) + return true; + } + + return false; +} + +bool SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType visitedMatchType, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const +{ + ASSERT(e); + if (!SelectorChecker::tagMatches(e, sel)) + return false; + + if (sel->m_match == CSSSelector::Class) + return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value()); + + if (sel->m_match == CSSSelector::Id) + return e->hasID() && e->idForStyleResolution() == sel->value(); + + if (sel->isAttributeSelector()) { + const QualifiedName& attr = sel->attribute(); + + NamedNodeMap* attributes = e->attributes(true); + if (!attributes) + return false; + + bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr); + + if (!anyAttributeMatches(attributes, static_cast<CSSSelector::Match>(sel->m_match), attr, sel->value(), caseSensitive)) + return false; + } + + if (sel->m_match == CSSSelector::PseudoClass) { + // Handle :not up front. + if (sel->pseudoType() == CSSSelector::PseudoNot) { + ASSERT(sel->selectorList()); + for (CSSSelector* subSel = sel->selectorList()->first(); 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->pseudoType() != CSSSelector::PseudoNot); + // We select between :visited and :link when applying. We don't know which one applied (or not) yet. + if (subSel->pseudoType() == CSSSelector::PseudoVisited || (subSel->pseudoType() == CSSSelector::PseudoLink && visitedMatchType == VisitedMatchEnabled)) + return true; + if (!checkOneSelector(subSel, e, dynamicPseudo, true, visitedMatchType, 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; + } + if (n->isTextNode()) { + Text* textNode = static_cast<Text*>(n); + if (!textNode->data().isEmpty()) { + result = false; + break; + } + } + } + if (!m_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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_isCollectingRulesOnly) { + 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::PseudoAny: + for (CSSSelector* selector = sel->selectorList()->first(); selector; selector = CSSSelectorList::next(selector)) { + if (checkSelector(selector, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle) == SelectorMatches) + return true; + } + break; + case CSSSelector::PseudoAutofill: + if (!e || !e->isFormControlElement()) + break; + if (HTMLInputElement* inputElement = e->toInputElement()) + return inputElement->isAutofilled(); + break; + case CSSSelector::PseudoAnyLink: + case CSSSelector::PseudoLink: + // :visited and :link matches are separated later when applying the style. Here both classes match all links... + return e->isLink(); + case CSSSelector::PseudoVisited: + // ...except if :visited matching is disabled for ancestor/sibling matching. + return e->isLink() && visitedMatchType == VisitedMatchEnabled; + 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: + return matchesFocusPseudoClass(e); + 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() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoHover)) + 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() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoActive)) + 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. + HTMLInputElement* inputElement = e->toInputElement(); + if (inputElement && inputElement->shouldAppearChecked() && !inputElement->isIndeterminate()) + return true; + if (e->hasTagName(optionTag) && toHTMLOptionElement(e)->selected()) + return true; + break; + } + case CSSSelector::PseudoIndeterminate: + { + if (!e || !e->isFormControlElement()) + break; +#if ENABLE(PROGRESS_TAG) + if (e->hasTagName(progressTag)) { + HTMLProgressElement* progress = static_cast<HTMLProgressElement*>(e); + if (progress && !progress->isDeterminate()) + return true; + break; + } +#endif + HTMLInputElement* inputElement = e->toInputElement(); + 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->isFrameElementBase() && static_cast<HTMLFrameElementBase*>(e)->containsFullScreenElement()) + return true; + if (!e->document()->webkitIsFullScreen()) + return false; + return e == e->document()->webkitCurrentFullScreenElement(); + case CSSSelector::PseudoAnimatingFullScreenTransition: + if (e != e->document()->webkitCurrentFullScreenElement()) + return false; + return e->document()->isAnimatingFullScreen(); + case CSSSelector::PseudoFullScreenAncestor: + return e->containsFullScreenElement(); + 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_isCollectingRulesOnly) + return false; + + if (sel->isUnknownPseudoElement()) { + m_hasUnknownPseudoElements = true; + return e->shadowPseudoId() == sel->value(); + } + + PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType()); + if (pseudoId == FIRST_LETTER) { + if (Document* document = e->document()) + document->setUsesFirstLetterRules(true); + } + if (pseudoId != NOPSEUDO) + dynamicPseudo = pseudoId; + } + // ### add the rest of the checks... + return true; +} + +bool 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->scrollableArea()->isScrollCornerVisible(); + default: + return false; + } +} + +void SelectorChecker::allVisitedStateChanged() +{ + if (m_linksCheckedForVisitedState.isEmpty()) + return; + for (Node* node = m_document; node; node = node->traverseNextNode()) { + if (node->isLink()) + node->setNeedsStyleRecalc(); + } +} + +void SelectorChecker::visitedStateChanged(LinkHash visitedHash) +{ + if (!m_linksCheckedForVisitedState.contains(visitedHash)) + return; + for (Node* node = m_document; node; node = node->traverseNextNode()) { + LinkHash hash = 0; + if (node->hasTagName(aTag)) + hash = static_cast<HTMLAnchorElement*>(node)->visitedLinkHash(); + else if (const AtomicString* attr = linkAttribute(node)) + hash = visitedLinkHash(m_document->baseURL(), *attr); + if (hash == visitedHash) + node->setNeedsStyleRecalc(); + } +} + +bool SelectorChecker::commonPseudoClassSelectorMatches(const Element* element, const CSSSelector* selector, VisitedMatchType visitedMatchType) const +{ + ASSERT(isCommonPseudoClassSelector(selector)); + switch (selector->pseudoType()) { + case CSSSelector::PseudoLink: + case CSSSelector::PseudoAnyLink: + return element->isLink(); + case CSSSelector::PseudoVisited: + return element->isLink() && visitedMatchType == VisitedMatchEnabled; + case CSSSelector::PseudoFocus: + return matchesFocusPseudoClass(element); + default: + ASSERT_NOT_REACHED(); + } + return true; +} + +unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector) +{ + unsigned linkMatchType = MatchAll; + + // Statically determine if this selector will match a link in visited, unvisited or any state, or never. + // :visited never matches other elements than the innermost link element. + for (; selector; selector = selector->tagHistory()) { + switch (selector->pseudoType()) { + case CSSSelector::PseudoNot: + // :not(:visited) is equivalent to :link. Parser enforces that :not can't nest. + for (CSSSelector* subSelector = selector->selectorList()->first(); subSelector; subSelector = subSelector->tagHistory()) { + CSSSelector::PseudoType subType = subSelector->pseudoType(); + if (subType == CSSSelector::PseudoVisited) + linkMatchType &= ~SelectorChecker::MatchVisited; + else if (subType == CSSSelector::PseudoLink) + linkMatchType &= ~SelectorChecker::MatchLink; + } + break; + case CSSSelector::PseudoLink: + linkMatchType &= ~SelectorChecker::MatchVisited; + break; + case CSSSelector::PseudoVisited: + linkMatchType &= ~SelectorChecker::MatchLink; + break; + default: + // We don't support :link and :visited inside :-webkit-any. + break; + } + CSSSelector::Relation relation = selector->relation(); + if (relation == CSSSelector::SubSelector) + continue; + if (relation != CSSSelector::Descendant && relation != CSSSelector::Child) + return linkMatchType; + if (linkMatchType != MatchAll) + return linkMatchType; + } + return linkMatchType; +} + +bool SelectorChecker::isFrameFocused(const Element* element) +{ + return element->document()->frame() && element->document()->frame()->selection()->isFocusedAndActive(); +} + +bool SelectorChecker::determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes) +{ + for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { + CSSSelector* scopeSelector = 0; + // This picks the widest scope, not the narrowest, to minimize the number of found scopes. + for (CSSSelector* current = selector; current; current = current->tagHistory()) { + // Prefer ids over classes. + if (current->m_match == CSSSelector::Id) + scopeSelector = current; + else if (current->m_match == CSSSelector::Class && (!scopeSelector || scopeSelector->m_match != CSSSelector::Id)) + scopeSelector = current; + CSSSelector::Relation relation = current->relation(); + if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector) + break; + } + if (!scopeSelector) + return false; + ASSERT(scopeSelector->m_match == CSSSelector::Class || scopeSelector->m_match == CSSSelector::Id); + if (scopeSelector->m_match == CSSSelector::Id) + idScopes.add(scopeSelector->value().impl()); + else + classScopes.add(scopeSelector->value().impl()); + } + return true; +} + +} diff --git a/Source/WebCore/css/SelectorChecker.h b/Source/WebCore/css/SelectorChecker.h new file mode 100644 index 000000000..1a01306f8 --- /dev/null +++ b/Source/WebCore/css/SelectorChecker.h @@ -0,0 +1,208 @@ +/* + * 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, 2011 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/) + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (C) Research In Motion Limited 2011. 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 SelectorChecker_h +#define SelectorChecker_h + +#include "Attribute.h" +#include "CSSSelector.h" +#include "Element.h" +#include "InspectorInstrumentation.h" +#include "LinkHash.h" +#include "RenderStyleConstants.h" +#include <wtf/BloomFilter.h> +#include <wtf/HashSet.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSSelector; +class Document; +class RenderStyle; + +class SelectorChecker { + WTF_MAKE_NONCOPYABLE(SelectorChecker); +public: + SelectorChecker(Document*, bool strictParsing); + + enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsAllSiblings, SelectorFailsCompletely }; + enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled }; + bool checkSelector(CSSSelector*, Element*, bool isFastCheckableSelector = false) const; + SelectorMatch checkSelector(CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType, RenderStyle* = 0, RenderStyle* elementParentStyle = 0) const; + static bool isFastCheckableSelector(const CSSSelector*); + bool fastCheckSelector(const CSSSelector*, const Element*) const; + + template <unsigned maximumIdentifierCount> + inline bool fastRejectSelector(const unsigned* identifierHashes) const; + static void collectIdentifierHashes(const CSSSelector*, unsigned* identifierHashes, unsigned maximumIdentifierCount); + + void pushParent(Element* parent); + void popParent(Element* parent); + bool parentStackIsConsistent(ContainerNode* parentNode) const { return !m_parentStack.isEmpty() && m_parentStack.last().element == parentNode; } + + EInsideLink determineLinkState(Element*) const; + void allVisitedStateChanged(); + void visitedStateChanged(LinkHash visitedHash); + + Document* document() const { return m_document; } + bool strictParsing() const { return m_strictParsing; } + + bool isCollectingRulesOnly() const { return m_isCollectingRulesOnly; } + void setCollectingRulesOnly(bool b) { m_isCollectingRulesOnly = b; } + + PseudoId pseudoStyle() const { return m_pseudoStyle; } + void setPseudoStyle(PseudoId pseudoId) { m_pseudoStyle = pseudoId; } + + bool hasUnknownPseudoElements() const { return m_hasUnknownPseudoElements; } + void clearHasUnknownPseudoElements() { m_hasUnknownPseudoElements = false; } + + static bool tagMatches(const Element*, const CSSSelector*); + static bool attributeNameMatches(const Attribute*, const QualifiedName&); + static bool isCommonPseudoClassSelector(const CSSSelector*); + bool matchesFocusPseudoClass(const Element*) const; + static bool fastCheckRightmostAttributeSelector(const Element*, const CSSSelector*); + static bool checkExactAttribute(const Element*, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value); + + enum LinkMatchMask { MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited }; + static unsigned determineLinkMatchType(const CSSSelector*); + + // Find the ids or classes selectors are scoped to. The selectors only apply to elements in subtrees where the root element matches the scope. + static bool determineSelectorScopes(const CSSSelectorList&, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes); + +private: + bool checkOneSelector(CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType, RenderStyle*, RenderStyle* elementParentStyle) const; + bool checkScrollbarPseudoClass(CSSSelector*, PseudoId& dynamicPseudo) const; + static bool isFrameFocused(const Element*); + + bool fastCheckRightmostSelector(const CSSSelector*, const Element*, VisitedMatchType) const; + bool commonPseudoClassSelectorMatches(const Element*, const CSSSelector*, VisitedMatchType) const; + + EInsideLink determineLinkStateSlowCase(Element*) const; + + void pushParentStackFrame(Element* parent); + void popParentStackFrame(); + + Document* m_document; + bool m_strictParsing; + bool m_documentIsHTML; + bool m_isCollectingRulesOnly; + PseudoId m_pseudoStyle; + mutable bool m_hasUnknownPseudoElements; + mutable HashSet<LinkHash, LinkHashHash> m_linksCheckedForVisitedState; + + struct ParentStackFrame { + ParentStackFrame() { } + ParentStackFrame(Element* element) : element(element) { } + Element* element; + Vector<unsigned, 4> identifierHashes; + }; + Vector<ParentStackFrame> m_parentStack; + + // With 100 unique strings in the filter, 2^12 slot table has false positive rate of ~0.2%. + static const unsigned bloomFilterKeyBits = 12; + OwnPtr<BloomFilter<bloomFilterKeyBits> > m_ancestorIdentifierFilter; +}; + +inline EInsideLink SelectorChecker::determineLinkState(Element* element) const +{ + if (!element || !element->isLink()) + return NotInsideLink; + return determineLinkStateSlowCase(element); +} + +template <unsigned maximumIdentifierCount> +inline bool SelectorChecker::fastRejectSelector(const unsigned* identifierHashes) const +{ + ASSERT(m_ancestorIdentifierFilter); + for (unsigned n = 0; n < maximumIdentifierCount && identifierHashes[n]; ++n) { + if (!m_ancestorIdentifierFilter->mayContain(identifierHashes[n])) + return true; + } + return false; +} + +inline bool SelectorChecker::isCommonPseudoClassSelector(const CSSSelector* selector) +{ + if (selector->m_match != CSSSelector::PseudoClass) + return false; + CSSSelector::PseudoType pseudoType = selector->pseudoType(); + return pseudoType == CSSSelector::PseudoLink + || pseudoType == CSSSelector::PseudoAnyLink + || pseudoType == CSSSelector::PseudoVisited + || pseudoType == CSSSelector::PseudoFocus; +} + +inline bool SelectorChecker::matchesFocusPseudoClass(const Element* element) const +{ + if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(element), CSSSelector::PseudoFocus)) + return true; + return element->focused() && isFrameFocused(element); +} + +inline bool SelectorChecker::tagMatches(const Element* element, const CSSSelector* selector) +{ + if (!selector->hasTag()) + return true; + const AtomicString& localName = selector->tag().localName(); + if (localName != starAtom && localName != element->localName()) + return false; + const AtomicString& namespaceURI = selector->tag().namespaceURI(); + return namespaceURI == starAtom || namespaceURI == element->namespaceURI(); +} + +inline bool SelectorChecker::attributeNameMatches(const Attribute* attribute, const QualifiedName& selectorAttributeName) +{ + if (selectorAttributeName.localName() != attribute->localName()) + return false; + return selectorAttributeName.prefix() == starAtom || selectorAttributeName.namespaceURI() == attribute->namespaceURI(); +} + +inline bool SelectorChecker::checkExactAttribute(const Element* element, const QualifiedName& selectorAttributeName, const AtomicStringImpl* value) +{ + NamedNodeMap* attributeMap = element->attributeMap(); + if (!attributeMap) + return false; + unsigned size = attributeMap->length(); + for (unsigned i = 0; i < size; ++i) { + Attribute* attribute = attributeMap->attributeItem(i); + if (attributeNameMatches(attribute, selectorAttributeName) && (!value || attribute->value().impl() == value)) + return true; + } + return false; +} + +inline bool SelectorChecker::fastCheckRightmostAttributeSelector(const Element* element, const CSSSelector* selector) +{ + if (selector->m_match == CSSSelector::Exact || selector->m_match == CSSSelector::Set) + return checkExactAttribute(element, selector->attribute(), selector->value().impl()); + ASSERT(!selector->isAttributeSelector()); + return true; +} + +} + +#endif diff --git a/Source/WebCore/css/ShadowValue.cpp b/Source/WebCore/css/ShadowValue.cpp new file mode 100644 index 000000000..14c7cda8c --- /dev/null +++ b/Source/WebCore/css/ShadowValue.cpp @@ -0,0 +1,80 @@ +/** + * (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) + : CSSValue(ShadowClass) + , x(_x) + , y(_y) + , blur(_blur) + , spread(_spread) + , style(_style) + , color(_color) +{ +} + +String ShadowValue::customCssText() 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 000000000..21547a571 --- /dev/null +++ b/Source/WebCore/css/ShadowValue.h @@ -0,0 +1,65 @@ +/* + * (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)); + } + + String customCssText() 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); +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/StyleMedia.cpp b/Source/WebCore/css/StyleMedia.cpp new file mode 100644 index 000000000..90b574017 --- /dev/null +++ b/Source/WebCore/css/StyleMedia.cpp @@ -0,0 +1,79 @@ +/* + * 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 "Document.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 000000000..760524271 --- /dev/null +++ b/Source/WebCore/css/StyleMedia.h @@ -0,0 +1,59 @@ +/* + * 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" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Frame; + +class StyleMedia : public RefCounted<StyleMedia> { +public: + static PassRefPtr<StyleMedia> create(Frame* frame) + { + return adoptRef(new StyleMedia(frame)); + } + + Frame* frame() { return m_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 000000000..09f2ae1e5 --- /dev/null +++ b/Source/WebCore/css/StyleMedia.idl @@ -0,0 +1,34 @@ +/* + * 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 [ + GenerateIsReachable=ImplFrame + ] StyleMedia { + readonly attribute DOMString type; + boolean matchMedium(in [Optional=CallWithDefaultValue] DOMString mediaquery); + }; +} diff --git a/Source/WebCore/css/StyleSheet.cpp b/Source/WebCore/css/StyleSheet.cpp new file mode 100644 index 000000000..9813c3cf9 --- /dev/null +++ b/Source/WebCore/css/StyleSheet.cpp @@ -0,0 +1,91 @@ +/** + * (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 "CSSImportRule.h" +#include "CSSStyleSheet.h" +#include "Document.h" +#include "MediaList.h" +#include "Node.h" + +namespace WebCore { + +StyleSheet::StyleSheet(Node* parentNode, const String& originalURL, const KURL& finalURL) + : m_disabled(false) + , m_ownerRule(0) + , m_ownerNode(parentNode) + , m_originalURL(originalURL) + , m_finalURL(finalURL) +{ +} + +StyleSheet::StyleSheet(CSSImportRule* parentRule, const String& originalURL, const KURL& finalURL) + : m_disabled(false) + , m_ownerRule(parentRule) + , m_ownerNode(0) + , m_originalURL(originalURL) + , m_finalURL(finalURL) +{ +} + +StyleSheet::~StyleSheet() +{ + if (m_media) + m_media->setParentStyleSheet(0); +} + +StyleSheet* StyleSheet::parentStyleSheet() const +{ + ASSERT(isCSSStyleSheet()); + return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0; +} + +void StyleSheet::setMedia(PassRefPtr<MediaList> media) +{ + ASSERT(isCSSStyleSheet()); + ASSERT(!media->parentStyleSheet() || media->parentStyleSheet() == this); + + if (m_media) + m_media->setParentStyleSheet(0); + + m_media = media; + m_media->setParentStyleSheet(static_cast<CSSStyleSheet*>(this)); +} + +KURL StyleSheet::baseURL() const +{ + if (!m_finalURL.isNull()) + return m_finalURL; + if (StyleSheet* parentSheet = parentStyleSheet()) + return parentSheet->baseURL(); + if (!m_ownerNode) + return KURL(); + return m_ownerNode->document()->baseURL(); +} + +void StyleSheet::setDisabled(bool disabled) +{ + m_disabled = disabled; + if (isCSSStyleSheet()) + static_cast<CSSStyleSheet*>(this)->styleSheetChanged(); +} + +} diff --git a/Source/WebCore/css/StyleSheet.h b/Source/WebCore/css/StyleSheet.h new file mode 100644 index 000000000..b28749a2c --- /dev/null +++ b/Source/WebCore/css/StyleSheet.h @@ -0,0 +1,89 @@ +/* + * (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 <wtf/ListHashSet.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class CSSImportRule; +class MediaList; +class Node; + +class StyleSheet : public RefCounted<StyleSheet> { +public: + virtual ~StyleSheet(); + + bool disabled() const { return m_disabled; } + void setDisabled(bool); + + Node* ownerNode() const { return m_ownerNode; } + void clearOwnerNode() { m_ownerNode = 0; } + + CSSImportRule* ownerRule() const { return m_ownerRule; } + void clearOwnerRule() { m_ownerRule = 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 bool parseString(const String&, bool strict = true) = 0; + + virtual bool isCSSStyleSheet() const { return false; } + virtual bool isXSLStyleSheet() const { return false; } + + KURL baseURL() const; + +protected: + StyleSheet(Node* ownerNode, const String& href, const KURL& finalURL); + StyleSheet(CSSImportRule* parentRule, const String& href, const KURL& finalURL); + +private: + bool m_disabled; + CSSImportRule* m_ownerRule; + Node* m_ownerNode; + String m_originalURL; + KURL m_finalURL; + String m_strTitle; + RefPtr<MediaList> m_media; +}; + +} // namespace + +#endif diff --git a/Source/WebCore/css/StyleSheet.idl b/Source/WebCore/css/StyleSheet.idl new file mode 100644 index 000000000..6d5df8076 --- /dev/null +++ b/Source/WebCore/css/StyleSheet.idl @@ -0,0 +1,46 @@ +/* + * 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, + GenerateIsReachable, + CustomToJS, + Polymorphic, + V8DependentLifetime + ] 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 000000000..bbefd318b --- /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 000000000..4eb7d6a27 --- /dev/null +++ b/Source/WebCore/css/StyleSheetList.h @@ -0,0 +1,68 @@ +/* + * (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); + } + + Document* document() + { + return m_doc; + } + +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 000000000..a7048d998 --- /dev/null +++ b/Source/WebCore/css/StyleSheetList.idl @@ -0,0 +1,34 @@ +/* + * 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 [ + GenerateIsReachable=ImplDocument, + HasIndexGetter, + HasNameGetter, + V8DependentLifetime + ] StyleSheetList { + readonly attribute unsigned long length; + StyleSheet item(in [Optional=CallWithDefaultValue] unsigned long index); + }; + +} diff --git a/Source/WebCore/css/WebKitCSSFilterValue.cpp b/Source/WebCore/css/WebKitCSSFilterValue.cpp new file mode 100644 index 000000000..b8e39933a --- /dev/null +++ b/Source/WebCore/css/WebKitCSSFilterValue.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 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 "WebKitCSSFilterValue.h" + +#if ENABLE(CSS_FILTERS) + +#include "CSSValueList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +WebKitCSSFilterValue::WebKitCSSFilterValue(FilterOperationType operationType) + : CSSValueList(WebKitCSSFilterClass, typeUsesSpaceSeparator(operationType)) + , m_type(operationType) +{ +} + +bool WebKitCSSFilterValue::typeUsesSpaceSeparator(FilterOperationType operationType) +{ +#if ENABLE(CSS_SHADERS) + return operationType != CustomFilterOperation; +#else + return true; +#endif +} + +String WebKitCSSFilterValue::customCssText() const +{ + String result; + switch (m_type) { + case ReferenceFilterOperation: + result = "url("; + break; + case GrayscaleFilterOperation: + result = "grayscale("; + break; + case SepiaFilterOperation: + result = "sepia("; + break; + case SaturateFilterOperation: + result = "saturate("; + break; + case HueRotateFilterOperation: + result = "hue-rotate("; + break; + case InvertFilterOperation: + result = "invert("; + break; + case OpacityFilterOperation: + result = "opacity("; + break; + case BrightnessFilterOperation: + result = "brightness("; + break; + case ContrastFilterOperation: + result = "contrast("; + break; + case BlurFilterOperation: + result = "blur("; + break; + case DropShadowFilterOperation: + result = "drop-shadow("; + break; +#if ENABLE(CSS_SHADERS) + case CustomFilterOperation: + result = "custom("; + break; +#endif + default: + break; + } + + return result + CSSValueList::customCssText() + ")"; +} + +} + +#endif // ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/css/WebKitCSSFilterValue.h b/Source/WebCore/css/WebKitCSSFilterValue.h new file mode 100644 index 000000000..640ea36cb --- /dev/null +++ b/Source/WebCore/css/WebKitCSSFilterValue.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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 WebKitCSSFilterValue_h +#define WebKitCSSFilterValue_h + +#if ENABLE(CSS_FILTERS) + +#include "CSSValueList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class WebKitCSSFilterValue : public CSSValueList { +public: + // NOTE: these have to match the values in the IDL + enum FilterOperationType { + UnknownFilterOperation, + ReferenceFilterOperation, + GrayscaleFilterOperation, + SepiaFilterOperation, + SaturateFilterOperation, + HueRotateFilterOperation, + InvertFilterOperation, + OpacityFilterOperation, + BrightnessFilterOperation, + ContrastFilterOperation, + BlurFilterOperation, + DropShadowFilterOperation +#if ENABLE(CSS_SHADERS) + , CustomFilterOperation +#endif + }; + + static bool typeUsesSpaceSeparator(FilterOperationType); + + static PassRefPtr<WebKitCSSFilterValue> create(FilterOperationType type) + { + return adoptRef(new WebKitCSSFilterValue(type)); + } + + String customCssText() const; + + FilterOperationType operationType() const { return m_type; } + +private: + WebKitCSSFilterValue(FilterOperationType); + + FilterOperationType m_type; +}; + +} + +#endif // ENABLE(CSS_FILTERS) + +#endif diff --git a/Source/WebCore/css/WebKitCSSFilterValue.idl b/Source/WebCore/css/WebKitCSSFilterValue.idl new file mode 100644 index 000000000..475a80383 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSFilterValue.idl @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 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 { + + interface [ + Conditional=CSS_FILTERS, + HasIndexGetter, + DontCheckEnums + ] WebKitCSSFilterValue : CSSValueList { + + // OperationTypes + + const unsigned short CSS_FILTER_REFERENCE = 1; + const unsigned short CSS_FILTER_GRAYSCALE = 2; + const unsigned short CSS_FILTER_SEPIA = 3; + const unsigned short CSS_FILTER_SATURATE = 4; + const unsigned short CSS_FILTER_HUE_ROTATE = 5; + const unsigned short CSS_FILTER_INVERT = 6; + const unsigned short CSS_FILTER_OPACITY = 7; + const unsigned short CSS_FILTER_BRIGHTNESS = 8; + const unsigned short CSS_FILTER_CONTRAST = 9; + const unsigned short CSS_FILTER_BLUR = 10; + const unsigned short CSS_FILTER_DROP_SHADOW = 11; + +#if defined(ENABLE_CSS_SHADERS) && ENABLE_CSS_SHADERS + const unsigned short CSS_FILTER_CUSTOM = 12; +#endif + + readonly attribute unsigned short operationType; + }; +} diff --git a/Source/WebCore/css/WebKitCSSKeyframeRule.cpp b/Source/WebCore/css/WebKitCSSKeyframeRule.cpp new file mode 100644 index 000000000..23bdeca5f --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframeRule.cpp @@ -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. + */ + +#include "config.h" +#include "WebKitCSSKeyframeRule.h" + +#include "CSSMutableStyleDeclaration.h" + +namespace WebCore { + +WebKitCSSKeyframeRule::WebKitCSSKeyframeRule(CSSStyleSheet* parent) + : CSSRule(parent, CSSRule::WEBKIT_KEYFRAME_RULE) +{ +} + +WebKitCSSKeyframeRule::~WebKitCSSKeyframeRule() +{ + if (m_style) + m_style->clearParentRule(); +} + +String WebKitCSSKeyframeRule::cssText() const +{ + String result = m_key; + + result += " { "; + result += m_style->cssText(); + result += "}"; + + return result; +} + +void WebKitCSSKeyframeRule::setDeclaration(PassRefPtr<CSSMutableStyleDeclaration> style) +{ + ASSERT(style->parentRule() == this); + m_style = style; +} + +/* 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 000000000..052c86bf1 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframeRule.h @@ -0,0 +1,77 @@ +/* + * 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)); + } + + ~WebKitCSSKeyframeRule(); + + 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(); } + + String cssText() const; + + 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 000000000..f6eac7741 --- /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 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 000000000..486cf1f0d --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.cpp @@ -0,0 +1,140 @@ +/* + * 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 "WebKitCSSKeyframesRule.h" + +#include "CSSMutableStyleDeclaration.h" +#include "CSSParser.h" +#include "CSSRuleList.h" +#include "StyleSheet.h" +#include "WebKitCSSKeyframeRule.h" + +namespace WebCore { + +WebKitCSSKeyframesRule::WebKitCSSKeyframesRule(CSSStyleSheet* parent) + : CSSRule(parent, CSSRule::WEBKIT_KEYFRAMES_RULE) + , m_lstCSSRules(CSSRuleList::create()) +{ +} + +WebKitCSSKeyframesRule::~WebKitCSSKeyframesRule() +{ + for (unsigned i = 0; i < length(); ++i) { + WebKitCSSKeyframeRule* rule = item(i); + rule->setParentRule(0); + } +} + +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. + if (CSSStyleSheet* styleSheet = parentStyleSheet()) + styleSheet->styleSheetChanged(); +} + +WebKitCSSKeyframeRule* WebKitCSSKeyframesRule::item(unsigned index) +{ + CSSRule* rule = m_lstCSSRules->item(index); + ASSERT(rule->isKeyframeRule()); + return static_cast<WebKitCSSKeyframeRule*>(rule); +} + +const WebKitCSSKeyframeRule* WebKitCSSKeyframesRule::item(unsigned index) const +{ + const CSSRule* rule = m_lstCSSRules->item(index); + ASSERT(rule->isKeyframeRule()); + return static_cast<const WebKitCSSKeyframeRule*>(rule); +} + +void WebKitCSSKeyframesRule::append(WebKitCSSKeyframeRule* rule) +{ + if (!rule) + return; + + m_lstCSSRules->append(rule); + rule->setParentRule(this); +} + +void WebKitCSSKeyframesRule::insertRule(const String& rule) +{ + CSSParser p(useStrictParsing()); + RefPtr<WebKitCSSKeyframeRule> newRule = p.parseKeyframeRule(parentStyleSheet(), rule); + if (newRule) + append(newRule.get()); +} + +void WebKitCSSKeyframesRule::deleteRule(const String& s) +{ + int i = findRuleIndex(s); + if (i < 0) + return; + + WebKitCSSKeyframeRule* rule = item(i); + rule->setParentRule(0); + m_lstCSSRules->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) + result += m_lstCSSRules->rulesText(); + + result += "}"; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/WebKitCSSKeyframesRule.h b/Source/WebCore/css/WebKitCSSKeyframesRule.h new file mode 100644 index 000000000..b1a1b8f10 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.h @@ -0,0 +1,90 @@ +/* + * 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(); + + String name() const { return m_name; } + 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); + + String cssText() const; + + // Not part of the CSSOM. + unsigned length() const { return m_lstCSSRules->length(); } + WebKitCSSKeyframeRule* item(unsigned index); + const WebKitCSSKeyframeRule* item(unsigned index) const; + void append(WebKitCSSKeyframeRule*); + +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 000000000..3b081307f --- /dev/null +++ b/Source/WebCore/css/WebKitCSSKeyframesRule.idl @@ -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. + * 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 [ + HasIndexGetter + ] WebKitCSSKeyframesRule : CSSRule { + + attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString name; + readonly attribute CSSRuleList cssRules; + + void insertRule(in [Optional=CallWithDefaultValue] DOMString rule); + void deleteRule(in [Optional=CallWithDefaultValue] DOMString key); + WebKitCSSKeyframeRule findRule(in [Optional=CallWithDefaultValue] DOMString key); + }; + +} diff --git a/Source/WebCore/css/WebKitCSSMatrix.cpp b/Source/WebCore/css/WebKitCSSMatrix.cpp new file mode 100644 index 000000000..f61719e7f --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.cpp @@ -0,0 +1,188 @@ +/* + * 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 "CSSValueKeywords.h" +#include "ExceptionCode.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) +{ + RefPtr<CSSMutableStyleDeclaration> styleDeclaration = CSSMutableStyleDeclaration::create(); + if (CSSParser::parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true, true)) { + // Convert to TransformOperations. This can fail if a property + // requires style (i.e., param uses 'ems' or 'exs') + RefPtr<CSSValue> value = styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform); + + // Check for a "none" or empty transform. In these cases we can use the default identity matrix. + if (!value || (value->isPrimitiveValue() && (static_cast<CSSPrimitiveValue*>(value.get()))->getIdent() == CSSValueNone)) + return; + + TransformOperations operations; + if (!CSSStyleSelector::createTransformOperations(value.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; + + return WebKitCSSMatrix::create(TransformationMatrix(m_matrix).multiply(secondMatrix->m_matrix)); +} + +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 000000000..56b0a7bc0 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.h @@ -0,0 +1,161 @@ +/* + * 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 "PlatformString.h" +#include "TransformationMatrix.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +typedef int ExceptionCode; + +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 000000000..f2173bf19 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSMatrix.idl @@ -0,0 +1,107 @@ +/* + * 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 [ + ConstructorParameters=1, + Constructor(in [Optional=CallWithNullValue] DOMString cssValue), + ConstructorRaisesException, + ] 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 [Optional=CallWithDefaultValue] DOMString string) raises (DOMException); + + // Multiply this matrix by secondMatrix, on the right (result = this * secondMatrix) + [Immutable] WebKitCSSMatrix multiply(in [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] double x, + in [Optional=CallWithDefaultValue] double y, + in [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] double scaleX, + in [Optional=CallWithDefaultValue] double scaleY, + in [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] double rotX, + in [Optional=CallWithDefaultValue] double rotY, + in [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] double x, + in [Optional=CallWithDefaultValue] double y, + in [Optional=CallWithDefaultValue] double z, + in [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] 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 [Optional=CallWithDefaultValue] double angle); + + [DontEnum] DOMString toString(); + }; + +} diff --git a/Source/WebCore/css/WebKitCSSRegionRule.cpp b/Source/WebCore/css/WebKitCSSRegionRule.cpp new file mode 100644 index 000000000..c049ed68b --- /dev/null +++ b/Source/WebCore/css/WebKitCSSRegionRule.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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 "WebKitCSSRegionRule.h" + +#include "CSSParserValues.h" +#include "CSSRuleList.h" + +namespace WebCore { +WebKitCSSRegionRule::WebKitCSSRegionRule(CSSStyleSheet* parent, Vector<OwnPtr<CSSParserSelector> >* selectors, PassRefPtr<CSSRuleList> rules) + : CSSRule(parent, CSSRule::WEBKIT_REGION_RULE) + , m_ruleList(rules) +{ + for (unsigned index = 0; index < m_ruleList->length(); ++index) + m_ruleList->item(index)->setParentRule(this); + + m_selectorList.adoptSelectorVector(*selectors); +} + +WebKitCSSRegionRule::~WebKitCSSRegionRule() +{ + for (unsigned index = 0; index < m_ruleList->length(); ++index) + m_ruleList->item(index)->setParentRule(0); +} + +String WebKitCSSRegionRule::cssText() const +{ + String result = "@-webkit-region "; + + // First add the selectors. + result += m_selectorList.selectorsText(); + + // Then add the rules. + result += " { \n"; + + if (m_ruleList) + result += m_ruleList->rulesText(); + + result += "}"; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/WebKitCSSRegionRule.h b/Source/WebCore/css/WebKitCSSRegionRule.h new file mode 100644 index 000000000..6367b50f9 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSRegionRule.h @@ -0,0 +1,67 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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 WebKitCSSRegionRule_h +#define WebKitCSSRegionRule_h + +#include "CSSSelectorList.h" +#include "CSSStyleRule.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CSSParserSelector; +class CSSRuleList; + +class WebKitCSSRegionRule: public CSSRule { +public: + static PassRefPtr<WebKitCSSRegionRule> create(CSSStyleSheet* parent, Vector<OwnPtr<CSSParserSelector> >* selectors, PassRefPtr<CSSRuleList> rules) + { + return adoptRef(new WebKitCSSRegionRule(parent, selectors, rules)); + } + + ~WebKitCSSRegionRule(); + + String cssText() const; + const CSSSelectorList& selectorList() const { return m_selectorList; } + CSSRuleList* cssRules() const { return m_ruleList.get(); } + +private: + WebKitCSSRegionRule(CSSStyleSheet* parent, Vector<OwnPtr<CSSParserSelector> >* selectors, PassRefPtr<CSSRuleList> rules); + + CSSSelectorList m_selectorList; + RefPtr<CSSRuleList> m_ruleList; +}; + +} + +#endif diff --git a/Source/WebCore/css/WebKitCSSShaderValue.cpp b/Source/WebCore/css/WebKitCSSShaderValue.cpp new file mode 100644 index 000000000..51cf8a30f --- /dev/null +++ b/Source/WebCore/css/WebKitCSSShaderValue.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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" + +#if ENABLE(CSS_SHADERS) +#include "WebKitCSSShaderValue.h" + +#include "CachedResourceLoader.h" +#include "Document.h" +#include "StyleCachedShader.h" +#include "StylePendingShader.h" + +namespace WebCore { + +WebKitCSSShaderValue::WebKitCSSShaderValue(const String& url) + : CSSPrimitiveValue(WebKitCSSShaderClass, url, CSS_URI) + , m_accessedShader(false) +{ +} + +WebKitCSSShaderValue::~WebKitCSSShaderValue() +{ +} + +StyleCachedShader* WebKitCSSShaderValue::cachedShader(CachedResourceLoader* loader) +{ + ASSERT(loader); + + if (!m_accessedShader) { + m_accessedShader = true; + + ResourceRequest request(loader->document()->completeURL(getStringValue())); + if (CachedShader* cachedShader = loader->requestShader(request)) + m_shader = StyleCachedShader::create(cachedShader); + } + + return (m_shader && m_shader->isCachedShader()) ? static_cast<StyleCachedShader*>(m_shader.get()) : 0; +} + +StyleShader* WebKitCSSShaderValue::cachedOrPendingShader() +{ + if (!m_shader) + m_shader = StylePendingShader::create(this); + + return m_shader.get(); +} + + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) diff --git a/Source/WebCore/css/WebKitCSSShaderValue.h b/Source/WebCore/css/WebKitCSSShaderValue.h new file mode 100644 index 000000000..825482db3 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSShaderValue.h @@ -0,0 +1,63 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. 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 COPYRIGHT HOLDER “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 HOLDER 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 WebKitCSSShaderValue_h +#define WebKitCSSShaderValue_h + +#if ENABLE(CSS_SHADERS) + +#include "CachedResourceHandle.h" +#include "CSSPrimitiveValue.h" + +namespace WebCore { + +class CachedResourceLoader; +class StyleCachedShader; +class StyleShader; + +class WebKitCSSShaderValue : public CSSPrimitiveValue { +public: + static PassRefPtr<WebKitCSSShaderValue> create(const String& url) { return adoptRef(new WebKitCSSShaderValue(url)); } + ~WebKitCSSShaderValue(); + + StyleCachedShader* cachedShader(CachedResourceLoader*); + StyleShader* cachedOrPendingShader(); + +private: + WebKitCSSShaderValue(const String& url); + + RefPtr<StyleShader> m_shader; + bool m_accessedShader; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) + +#endif // WebKitCSSShaderValue_h diff --git a/Source/WebCore/css/WebKitCSSTransformValue.cpp b/Source/WebCore/css/WebKitCSSTransformValue.cpp new file mode 100644 index 000000000..6a391ac85 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSTransformValue.cpp @@ -0,0 +1,118 @@ +/* + * 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(WebKitCSSTransformClass, false) + , m_type(op) +{ +} + +String WebKitCSSTransformValue::customCssText() 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::customCssText(); + + result += ")"; + return result; +} + +} diff --git a/Source/WebCore/css/WebKitCSSTransformValue.h b/Source/WebCore/css/WebKitCSSTransformValue.h new file mode 100644 index 000000000..89e014155 --- /dev/null +++ b/Source/WebCore/css/WebKitCSSTransformValue.h @@ -0,0 +1,80 @@ +/* + * 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)); + } + + String customCssText() const; + + TransformOperationType operationType() const { return m_type; } + +private: + WebKitCSSTransformValue(TransformOperationType); + + TransformOperationType m_type; +}; + +} + +#endif diff --git a/Source/WebCore/css/WebKitCSSTransformValue.idl b/Source/WebCore/css/WebKitCSSTransformValue.idl new file mode 100644 index 000000000..007097e7c --- /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/WebKitFontFamilyNames.in b/Source/WebCore/css/WebKitFontFamilyNames.in new file mode 100644 index 000000000..f1b878e27 --- /dev/null +++ b/Source/WebCore/css/WebKitFontFamilyNames.in @@ -0,0 +1,7 @@ +cursiveFamily="-webkit-cursive" +fantasyFamily="-webkit-fantasy" +monospaceFamily="-webkit-monospace" +sansSerifFamily="-webkit-sans-serif" +serifFamily="-webkit-serif" +pictographFamily="-webkit-pictograph" +standardFamily="-webkit-standard" diff --git a/Source/WebCore/css/fullscreen.css b/Source/WebCore/css/fullscreen.css new file mode 100644 index 000000000..f4987f53f --- /dev/null +++ b/Source/WebCore/css/fullscreen.css @@ -0,0 +1,41 @@ +:-webkit-full-screen { + background-color: white; + z-index: 2147483647; +} + +:root:-webkit-full-screen-document:not(:-webkit-full-screen), :root:-webkit-full-screen-ancestor { + overflow: hidden !important; +} + +:-webkit-full-screen-ancestor:not(iframe) { + z-index: auto !important; + opacity: 1 !important; + -webkit-transform: none !important; +} + +video:-webkit-full-screen { + background-color: transparent !important; + position: static !important; + margin: 0 !important; + height: 100% !important; + width: 100% !important; + -webkit-box-flex: 1 !important; + display: block !important; +} + +img:-webkit-full-screen { + width: auto; + height: 100%; + max-width: 100%; +} + +iframe:-webkit-full-screen { + margin: 0 !important; + padding: 0 !important; + border: 0 !important; + position: fixed !important; + height: 100% !important; + width: 100% !important; + left: 0 !important; + top: 0 !important; +} diff --git a/Source/WebCore/css/fullscreenQuickTime.css b/Source/WebCore/css/fullscreenQuickTime.css new file mode 100644 index 000000000..a5559768d --- /dev/null +++ b/Source/WebCore/css/fullscreenQuickTime.css @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 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 fullscreen.css */ + +video:-webkit-full-screen::-webkit-media-controls-panel { + -webkit-box-align: start !important; + -webkit-box-pack: end !important; + -webkit-appearance: none !important; + + bottom: 50px !important; + left: 50% !important; + margin-left: -220px !important; + padding: 12px 0 0 10px !important; + width: 430px !important; + height: 48px !important; + + background-image: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0, rgba(30, 30, 30, .97)), + color-stop(0.333, rgba(45, 45, 45, .97)), + color-stop(0.35, rgba(25, 25, 25, .97)), + color-stop(0.366, rgba(25, 25, 25, .97)), + color-stop(0.366, rgba(12, 12, 12, .97)), + color-stop(1, rgba(19, 19, 19, .97)) + ) !important; + + -webkit-box-shadow: + inset 0 -1px 1px rgba(0, 0, 0, 0.5), + inset 0 1px 0 0px rgba(255, 255, 255, 0.15), + inset 0 -1px 0 0px rgba(202, 202, 202, 0.09), + 0 0 0 1px rgba(0, 0, 0, 0.5); + -webkit-border-radius: 8px !important; + + -webkit-transition: opacity 0.3s linear !important; +} + +video:-webkit-animating-full-screen-transition::-webkit-media-controls-panel { + opacity: 0 ! important; + -webkit-transition: opacity 0 ! important; +} + +video:-webkit-full-screen::-webkit-media-controls-mute-button { + display: none; +} + +video:-webkit-full-screen::-webkit-media-controls-volume-slider-container { + display: none; +} + +video:-webkit-full-screen::-webkit-media-controls-volume-slider { + display: none; +} + +video:-webkit-full-screen::-webkit-media-controls-volume-slider-mute-button { + display: none; +} + +video:-webkit-full-screen::-webkit-media-controls-fullscreen-volume-min-button { + -webkit-appearance: media-mute-button; + display: block; + position: absolute; + left: 11px; + top: 15px; + width: 14px; + height: 12px; +} + +video:-webkit-full-screen::-webkit-media-controls-fullscreen-volume-slider { + -webkit-appearance: media-slider; + display: block; + position: absolute; + left: 28px; + top: 15px; + height: 12px; + width: 50px; +} + +video:-webkit-full-screen::-webkit-media-controls-fullscreen-volume-max-button { + -webkit-appearance: media-mute-button; + display: block; + position: absolute; + left: 84px; + top: 15px; + width: 14px; + height: 12px; +} + +video:-webkit-full-screen::-webkit-media-controls-play-button { + position: absolute; + width: 22px; + height: 23px; + left: 209px; + top: 9px; +} + +video:-webkit-full-screen::-webkit-media-controls-rewind-button { + position: absolute; + left: 162px; + top: 13px; + width: 18px; + height: 18px; +} + +video:-webkit-full-screen::-webkit-media-controls-seek-back-button { + position: absolute; + display: -webkit-box; + width: 23px; + height: 16px; + left: 162px; + top: 13px; +} + +video:-webkit-full-screen::-webkit-media-controls-return-to-realtime-button { + position: absolute; + display: -webkit-box; + width: 29px; + height: 16px; + left: 262px; + top: 13px; +} + +video:-webkit-full-screen::-webkit-media-controls-seek-forward-button { + position: absolute; + display: -webkit-box; + width: 23px; + height: 16px; + left: 262px; + top: 13px; +} + +video:-webkit-full-screen::-webkit-media-controls-timeline-container { + height: auto; + width: 420px; + position: absolute; + bottom: 9px; + left: 8px; + right: 8px; +} + +video:-webkit-full-screen::-webkit-media-controls-status-display { + width: 420px; + position: absolute; + bottom: 9px; + left: 8px; + right: 8px; +} diff --git a/Source/WebCore/css/html.css b/Source/WebCore/css/html.css new file mode 100644 index 000000000..60cec9c5f --- /dev/null +++ b/Source/WebCore/css/html.css @@ -0,0 +1,1013 @@ +/* + * The default style sheet used to render HTML. + * + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1__qem; + -webkit-margin-start: 0; + -webkit-margin-end: 0; +} + +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; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; + -webkit-margin-start: 40px; + -webkit-margin-end: 40px; +} + +figcaption { + display: block +} + +figure { + display: block; + -webkit-margin-before: 1em; + -webkit-margin-after: 1em; + -webkit-margin-start: 40px; + -webkit-margin-end: 40px; +} + +q { + display: inline +} + +q:before { + content: open-quote; +} + +q:after { + content: close-quote; +} + +center { + display: block; + /* special centering to be able to emulate the html4/netscape behaviour */ + text-align: -webkit-center +} + +hr { + display: block; + -webkit-margin-before: 0.5em; + -webkit-margin-after: 0.5em; + -webkit-margin-start: auto; + -webkit-margin-end: auto; + border-style: inset; + border-width: 1px +} + +map { + display: inline +} + +/* heading elements */ + +h1 { + display: block; + font-size: 2em; + -webkit-margin-before: 0.67__qem; + -webkit-margin-after: 0.67em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + font-weight: bold +} + +:-webkit-any(article,aside,nav,section) h1 { + font-size: 1.5em; + -webkit-margin-before: 0.83__qem; + -webkit-margin-after: 0.83em; +} + +:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 { + font-size: 1.17em; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; +} + +:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 { + font-size: 1.00em; + -webkit-margin-before: 1.33__qem; + -webkit-margin-after: 1.33em; +} + +:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 { + font-size: .83em; + -webkit-margin-before: 1.67__qem; + -webkit-margin-after: 1.67em; +} + +:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 { + font-size: .67em; + -webkit-margin-before: 2.33__qem; + -webkit-margin-after: 2.33em; +} + +h2 { + display: block; + font-size: 1.5em; + -webkit-margin-before: 0.83__qem; + -webkit-margin-after: 0.83em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + font-weight: bold +} + +h3 { + display: block; + font-size: 1.17em; + -webkit-margin-before: 1__qem; + -webkit-margin-after: 1em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + font-weight: bold +} + +h4 { + display: block; + -webkit-margin-before: 1.33__qem; + -webkit-margin-after: 1.33em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + font-weight: bold +} + +h5 { + display: block; + font-size: .83em; + -webkit-margin-before: 1.67__qem; + -webkit-margin-after: 1.67em; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + font-weight: bold +} + +h6 { + display: block; + font-size: .67em; + -webkit-margin-before: 2.33__qem; + -webkit-margin-after: 2.33em; + -webkit-margin-start: 0; + -webkit-margin-end: 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; + text-align: -webkit-match-parent; +} + +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 { + 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::-webkit-textfield-decoration-container { + display: -webkit-box; + -webkit-box-align: center; +} + +input[type="search"]::-webkit-textfield-decoration-container { + direction: ltr; +} + +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: searchfield-cancel-button; + display: block; + -webkit-box-flex: 0; +} + +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: searchfield-decoration; + display: block; + -webkit-box-flex: 0; +} + +input[type="search"]::-webkit-search-results-decoration { + -webkit-appearance: searchfield-results-decoration; + display: block; + -webkit-box-flex: 0; +} + +input[type="search"]::-webkit-search-results-button { + -webkit-appearance: searchfield-results-button; + display: block; + -webkit-box-flex: 0; +} + +#if defined(ENABLE_DATALIST) && ENABLE_DATALIST +input::-webkit-input-list-button { + -webkit-appearance: list-button; + display: inline-block; +} +#endif + +input::-webkit-inner-spin-button { + -webkit-appearance: inner-spin-button; + display: block; + position: relative; + cursor: default; + vertical-align: top; + -webkit-box-flex: 0; + -webkit-user-select: none; +} + +#if defined(ENABLE_INPUT_SPEECH) && ENABLE_INPUT_SPEECH +input::-webkit-input-speech-button { + -webkit-appearance: -webkit-input-speech-button; + display: block; + vertical-align: top; + -webkit-box-flex: 0; +} +#endif + +keygen, select { + -webkit-border-radius: 5px; +} + +keygen::-webkit-keygen-select { + margin: 0px; +} + +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; +} + +::-webkit-input-placeholder { + -webkit-text-security: none; + color: darkGray; + display: block !important; + pointer-events: none !important; +} + +input::-webkit-input-placeholder, isindex::-webkit-input-placeholder { + white-space: pre; + word-wrap: normal; + overflow: hidden; + padding-left: 1px; + padding-right: 1px; +} + +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; + color: inherit; + text-align: start !important; +} + +input:-webkit-autofill { + background-color: #FAFFBD !important; + background-image:none !important; + color: #000000 !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"] { + -webkit-appearance: push-button; + white-space: pre +} + +input[type="file"]::-webkit-file-upload-button { + -webkit-appearance: push-button; + white-space: nowrap; + margin: 0; + font-size: inherit; +} + +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-container { + -webkit-box-align: center; + -webkit-box-orient: horizontal; /* This property is updated by C++ code. */ + -webkit-box-sizing: border-box; + display: -webkit-box; + height: 100%; + width: 100%; +} + +input[type="range"]::-webkit-slider-runnable-track { + -webkit-box-flex: 1; + -webkit-box-sizing: border-box; + display: block; +} + +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: sliderthumb-horizontal; + -webkit-box-sizing: border-box; + display: block; + position: relative; +} + +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 { + 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; +} + +#if defined(ENABLE_INPUT_COLOR) && ENABLE_INPUT_COLOR + +input[type="color"] { + -webkit-appearance: square-button; + width: 44px; + height: 23px; +} + +input[type="color"]::-webkit-color-swatch-wrapper { + display:-webkit-box; + padding: 4px 2px; + -webkit-box-sizing: border-box; + width: 100%; + height: 100% +} + +input[type="color"]::-webkit-color-swatch { + background-color: #000000; + border: 1px solid #777777; + -webkit-box-flex: 1; +} + +#if defined(ENABLE_DATALIST) && ENABLE_DATALIST + +input[type="color"][list] { + -webkit-appearance: menulist; + width: 88px; + height: 23px; +} + +input[type="color"][list]::-webkit-color-swatch-wrapper { + padding-left: 8px; + padding-right: 24px; +} + +input[type="color"][list]::-webkit-color-swatch { + border-color: #000000; +} + +#endif // defined(ENABLE_DATALIST) && ENABLE_DATALIST + +#endif // defined(ENABLE_INPUT_COLOR) && ENABLE_INPUT_COLOR + +select { + -webkit-appearance: menulist; + -webkit-box-sizing: border-box; + -webkit-box-align: center; + border: 1px solid; + 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; +} + +output { + display: inline; +} + +/* form validation message bubble */ + +::-webkit-validation-bubble { + display: inline-block; + z-index: 2147483647; + position: absolute; + opacity: 0.95; + line-height: 0; + margin: 0; + -webkit-text-security: none; + -webkit-transition: opacity 05.5s ease; +} + +::-webkit-validation-bubble-message { + display: -webkit-box; + position: relative; + top: -4px; + font: message-box; + color: black; + min-width: 50px; + max-width: 200px; + border: solid 2px #400; + background: -webkit-gradient(linear, left top, left bottom, from(#f8ecec), to(#e8cccc)); + padding: 8px; + -webkit-border-radius: 8px; + -webkit-box-shadow: 4px 4px 4px rgba(100,100,100,0.6), + inset -2px -2px 1px #d0c4c4, + inset 2px 2px 1px white; + line-height: normal; + white-space: normal; + z-index: 2147483644; +} + +::-webkit-validation-bubble-text-block { + -webkit-box-flex: 1; +} + +::-webkit-validation-bubble-heading { + font-weight: bold; +} + +::-webkit-validation-bubble-arrow { + display: inline-block; + position: relative; + left: 32px; + width: 16px; + height: 16px; + background-color: #f8ecec; + border-width: 2px 0 0 2px; + border-style: solid; + border-color: #400; + box-shadow: inset 2px 2px 1px white; + -webkit-transform-origin: 0 0; + -webkit-transform: rotate(45deg); + z-index: 2147483645; +} + +::-webkit-validation-bubble-arrow-clipper { + display: block; + overflow: hidden; + height: 16px; +} + +#if defined(ENABLE_METER_TAG) && ENABLE_METER_TAG +/* meter */ + +meter { + -webkit-appearance: meter; + -webkit-box-sizing: border-box; + display: inline-box; + height: 1em; + width: 5em; + vertical-align: -0.2em; +} + +meter::-webkit-meter-bar { + 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)); + height: 100%; + width: 100%; + -webkit-box-sizing: border-box; +} + +meter::-webkit-meter-optimum-value { + 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)); + height: 100%; + -webkit-box-sizing: border-box; +} + +meter::-webkit-meter-suboptimum-value { + 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)); + height: 100%; + -webkit-box-sizing: border-box; +} + +meter::-webkit-meter-even-less-good-value { + 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)); + height: 100%; + -webkit-box-sizing: border-box; +} +#endif + +#if defined(ENABLE_PROGRESS_TAG) && ENABLE_PROGRESS_TAG +/* progress */ + +progress { + -webkit-appearance: progress-bar; + -webkit-box-sizing: border-box; + display: inline-block; + height: 1em; + width: 10em; + vertical-align: -0.2em; +} + +progress::-webkit-progress-bar { + background-color: gray; + height: 100%; + width: 100%; + -webkit-box-sizing: border-box; +} + +progress::-webkit-progress-value { + background-color: green; + height: 100%; + width: 50%; /* should be removed later */ + -webkit-box-sizing: border-box; +} +#endif + +/* inline elements */ + +u, ins { + text-decoration: underline +} + +strong, b { + font-weight: bold +} + +i, cite, em, var, address, dfn { + 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 +} + +applet:focus, embed:focus, iframe:focus, object: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; + -webkit-text-emphasis: none; +} + +ruby > rt { + display: block; + font-size: 50%; + text-align: -webkit-auto; +} + +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 +} + +summary::-webkit-details-marker { + display: inline-block; + width: 0.66em; + height: 0.66em; + margin-right: 0.4em; +} + +bdi, output { + unicode-bidi: -webkit-isolate; +} + +bdo { + unicode-bidi: bidi-override; +} + +/* 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 000000000..3ac1ece4e --- /dev/null +++ b/Source/WebCore/css/make-css-file-arrays.pl @@ -0,0 +1,95 @@ +#!/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 $defines; +my $preprocessor; +GetOptions('defines=s' => \$defines, + 'preprocessor=s' => \$preprocessor); + +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. + my $text; + # We should not set --defines option and run "moc" preprocessor on Qt. + # See http://webkit.org/b/37296. + if (!$defines) { + open IN, "<", $in or die; + { local $/; $text = <IN>; } + close IN; + # Remove preprocessor directives. + $text =~ s|^#.*?$||mg; + } else { + require preprocessor; + $text = join('', applyPreprocessor($in, $defines, $preprocessor)); + } + + # 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 000000000..06faaa93d --- /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 000000000..6de7b7d56 --- /dev/null +++ b/Source/WebCore/css/makeprop.pl @@ -0,0 +1,203 @@ +#! /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 Getopt::Long; +use preprocessor; +use strict; +use warnings; + +my $defines; +my $preprocessor; +GetOptions('defines=s' => \$defines, + 'preprocessor=s' => \$preprocessor); + +my @NAMES = applyPreprocessor("CSSPropertyNames.in", $defines, $preprocessor); + +my %namesHash; +my @duplicates = (); + +my @names = (); +my @aliases = (); +foreach (@NAMES) { + next if (m/(^\s*$)/); + # Input may use a different EOL sequence than $/, so avoid chomp. + $_ =~ s/[\r\n]+$//g; + if (exists $namesHash{$_}) { + push @duplicates, $_; + } else { + $namesHash{$_} = 1; + } + if ($_ =~ /=/) { + push @aliases, $_; + } else { + push @names, $_; + } +} + +if (@duplicates > 0) { + die 'Duplicate CSS property names: ', join(', ', @duplicates) . "\n"; +} + +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 "config.h" +#include \"CSSPropertyNames.h\" +#include \"HashTools.h\" +#include <string.h> + +#include <wtf/ASCIICType.h> +#include <wtf/text/WTFString.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"; +} + +foreach my $alias (@aliases) { + $alias =~ /^([^\s]*)[\s]*=[\s]*([^\s]*)/; + my $name = $1; + my $id = $2; + $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]; +} + +WTF::String getJSPropertyName(CSSPropertyID id) +{ + char result[maxCSSPropertyNameLength + 1]; + const char* cssPropertyName = getPropertyName(id); + const char* propertyNamePointer = cssPropertyName; + if (!propertyNamePointer) + return emptyString(); + + char* resultPointer = result; + while (char character = *propertyNamePointer++) { + if (character == '-') { + char nextCharacter = *propertyNamePointer++; + if (!nextCharacter) + break; + character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter; + } + *resultPointer++ = character; + } + *resultPointer = '\\0'; + return WTF::String(result); +} + +} // 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 WTF { +class String; +} + +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); +WTF::String getJSPropertyName(CSSPropertyID); + +} // namespace WebCore + +#endif // CSSPropertyNames_h + +EOF + +close HEADER; + +system("gperf --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?"; diff --git a/Source/WebCore/css/maketokenizer b/Source/WebCore/css/maketokenizer new file mode 100644 index 000000000..d2a786f75 --- /dev/null +++ b/Source/WebCore/css/maketokenizer @@ -0,0 +1,151 @@ +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 +#define nthchild 3 + +/* 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 000000000..ced2416aa --- /dev/null +++ b/Source/WebCore/css/makevalues.pl @@ -0,0 +1,158 @@ +#! /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 Getopt::Long; +use preprocessor; +use strict; +use warnings; + +my $defines; +my $preprocessor; +GetOptions('defines=s' => \$defines, + 'preprocessor=s' => \$preprocessor); + +my @NAMES = applyPreprocessor("CSSValueKeywords.in", $defines, $preprocessor); + +my %namesHash; +my @duplicates = (); + +my @names = (); +foreach (@NAMES) { + next if (m/(^\s*$)/); + # Input may use a different EOL sequence than $/, so avoid chomp. + $_ =~ s/[\r\n]+$//g; + # CSS values need to be lower case. + $_ = lc $_; + if (exists $namesHash{$_}) { + push @duplicates, $_; + } else { + $namesHash{$_} = 1; + } + push @names, $_; +} + +if (@duplicates > 0) { + die 'Duplicate CSS value keywords values: ', join(', ', @duplicates) . "\n"; +} + +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 --output-file=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 000000000..b797b21a9 --- /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 000000000..31c9d4326 --- /dev/null +++ b/Source/WebCore/css/mediaControls.css @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2009, 2010, 2011 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 */ + +body:-webkit-full-page-media { + background-color: rgb(38, 38, 38); +} + +audio { + width: 200px; + height: 16px; +} + +::-webkit-media-controls { + width: inherit; + height: inherit; + position: relative; + display: block; + direction: ltr; +} + +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 { + margin: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + bottom: 0px; +} + +audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { + -webkit-appearance: media-mute-button; + display: -webkit-box; + width: 16px; + height: 16px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + -webkit-appearance: media-play-button; + display: -webkit-box; + width: 16px; + height: 16px; + background-color: initial; + border: initial; + color: inherit; +} + +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; + background-color: initial; + border: initial; + color: inherit; + margin: initial; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + background-color: initial; + border: initial; + color: inherit; + margin: initial; +} + +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; + background-color: initial; + border: initial; + color: inherit; +} + +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; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + -webkit-appearance: media-fullscreen-button; + display: -webkit-box; + width: 16px; + height: 16px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: none; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; + background-color: initial; + border: initial; + color: inherit; +} + +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; + background-color: initial; + border: initial; + color: inherit; +} + +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; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-fullscreen-volume-slider, video::-webkit-media-controls-fullscreen-volume-slider { + display: none; +} + +audio::-webkit-media-controls-fullscreen-volume-min-button, video::-webkit-media-controls-fullscreen-volume-min-button { + display: none; +} + +audio::-webkit-media-controls-fullscreen-volume-max-button, video::-webkit-media-controls-fullscreen-volume-max-button { + display: none; +} + +video::-webkit-media-text-track-container { + position: absolute; + width: 100%; + overflow: hidden; + + font-size: 22px; + font-family: sans-serif; + text-align: center; + color: rgba(255, 255, 255, 0); + + letter-spacing: normal; + word-spacing: normal; + text-transform: none; + text-indent: 0; + text-decoration: none; + pointer-events: none; + -webkit-user-select: none; +} + +video::-webkit-media-text-track-display { + display: inline; + background-color: rgba(0, 0, 0, 0.8); + color: yellow; + padding: 0px 2px; +} diff --git a/Source/WebCore/css/mediaControlsChromium.css b/Source/WebCore/css/mediaControlsChromium.css new file mode 100644 index 000000000..508d7445e --- /dev/null +++ b/Source/WebCore/css/mediaControlsChromium.css @@ -0,0 +1,170 @@ +/* + * 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 */ + +body:-webkit-full-page-media { + background-color: rgb(0, 0, 0); +} + +audio { + width: 300px; + height: 32px; +} + +audio:-webkit-full-page-media, video:-webkit-full-page-media { + max-height: 100%; + max-width: 100%; +} + +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: 0px; +} + +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-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-timeline, video::-webkit-media-controls-timeline { + -webkit-appearance: media-slider; + display: -webkit-box; + box-sizing: border-box; + -webkit-box-flex: 1; + + padding: 0px; + margin: 0px 6px; + height: 18px; + + 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-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/mediaControlsEfl.css b/Source/WebCore/css/mediaControlsEfl.css new file mode 100644 index 000000000..e5d58089c --- /dev/null +++ b/Source/WebCore/css/mediaControlsEfl.css @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Samsung Electronics + * + * 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. + */ + +/* EFLWebKit media controls. Extends mediaControls.css */ + +audio { + width: 300px; + height: 20px; +} + +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: 20px; + 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 { + -webkit-appearance: media-mute-button; + display: -webkit-box; + width: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + -webkit-appearance: media-play-button; + display: -webkit-box; + width: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +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: 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: 4px; + + text-align: center; + font-size: 10px; +} + +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: 20px; + padding: 0px 2px; + background-color: initial; + border: initial; + color: inherit; + margin: initial; +} + +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; + background-color: initial; + border: initial; + color: inherit; + margin: initial; +} + +audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { + -webkit-appearance: media-seek-back-button; + display: -webkit-box; + width: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + -webkit-appearance: media-seek-forward-button; + display: -webkit-box; + width: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { + -webkit-appearance: media-fullscreen-button; + display: -webkit-box; + width: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-rewind-button, video::-webkit-media-controls-rewind-button { + display: none; + background-color: initial; + border: initial; + color: inherit; +} + +audio::-webkit-media-controls-return-to-realtime-button, video::-webkit-media-controls-return-to-realtime-button { + display: none; + background-color: initial; + border: initial; + color: inherit; +} + +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: 20px; + height: 20px; + background-color: initial; + border: initial; + color: inherit; +} + +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; + background-color: initial; + border: initial; + color: inherit; +} diff --git a/Source/WebCore/css/mediaControlsGtk.css b/Source/WebCore/css/mediaControlsGtk.css new file mode 100644 index 000000000..aba4412ef --- /dev/null +++ b/Source/WebCore/css/mediaControlsGtk.css @@ -0,0 +1,105 @@ +/* + * 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 { + 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; + text-align: right; + height: 100%; +} + +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; +} + +audio::-webkit-media-controls-volume-slider-container, video::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + position: absolute; + height: 100px; + width: 20px; +} + +audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + width: 14px; + height: 95px; + + left: 3px; + top: 5px; +} diff --git a/Source/WebCore/css/mediaControlsQt.css b/Source/WebCore/css/mediaControlsQt.css new file mode 100644 index 000000000..64e0ec524 --- /dev/null +++ b/Source/WebCore/css/mediaControlsQt.css @@ -0,0 +1,260 @@ +/* + * 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 { + 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: visible; + height: 100%; + text-align: right; +} + +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 { + width: 12px; + height: 12px; + padding: 6px; + margin: 5px 5px 5px 3px; + border: none !important; +} + +video::-webkit-media-controls-mute-button { + width: 12px; + height: 12px; + padding: 6px; + margin: 5px 5px 5px 3px; + border: none !important; +} + +audio::-webkit-media-controls-play-button { + width: 9px; + height: 12px; + padding: 6px 12px 6px 11px; + margin: 5px 3px 5px 5px; + border: none !important; +} + +video::-webkit-media-controls-play-button { + width: 9px; + height: 12px; + padding: 6px 12px 6px 11px; + margin: 5px 3px 5px 5px; + border: none !important; +} + +audio::-webkit-media-controls-timeline-container { + height: 34px; +} + +video::-webkit-media-controls-timeline-container { + height: 34px; +} + +audio::-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; +} + +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 { + display: none; +} + +video::-webkit-media-controls-time-remaining-display { + display: none; +} + +audio::-webkit-media-controls-timeline { + height: 12px; /* See RenderThemeQt::adjustSliderThumbSize(). */ + padding: 6px 8px; + margin: 5px 3px; +} + +video::-webkit-media-controls-timeline { + height: 12px; /* See RenderThemeQt::adjustSliderThumbSize(). */ + padding: 6px 8px; + margin: 5px 3px; +} + +audio::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + position: absolute; + height: 103px; + width: 24px; +} + +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 { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + + width: 12px; /* See RenderThemeQt::adjustSliderThumbSize(). */ + padding: 6px; + height: 88px; + margin: 0 0 3px 0; +} + +video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: inline; + position: absolute; + + width: 12px; /* See RenderThemeQt::adjustSliderThumbSize(). */ + padding: 6px; + height: 88px; + margin: 0 0 3px 0; +} + +audio::-webkit-media-controls-seek-back-button { + display: none; +} + +video::-webkit-media-controls-seek-back-button { + display: none; +} + +audio::-webkit-media-controls-seek-forward-button { + display: none; +} + +video::-webkit-media-controls-seek-forward-button { + display: none; +} + +audio::-webkit-media-controls-fullscreen-button { + display: none; +} + +video::-webkit-media-controls-fullscreen-button { + top: 0px; + right: 0px; + width: 12px; + height: 12px; + padding: 6px; + margin: 5px 5px 5px 3px; + border: none !important; +} + +audio::-webkit-media-controls-rewind-button { + display: none; +} + +video::-webkit-media-controls-rewind-button { + display: none; +} + +audio::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +video::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +audio::-webkit-media-controls-toggle-closed-captions-button { + display: none; +} + +video::-webkit-media-controls-toggle-closed-captions-button { + display: none; +} + +::-webkit-media-controls-mute-button, +::-webkit-media-controls-play-button, +::-webkit-media-controls-timeline, +::-webkit-media-controls-volume-slider, +::-webkit-media-controls-fullscreen-button +{ + box-sizing: content-box !important; +} diff --git a/Source/WebCore/css/mediaControlsQtFullscreen.css b/Source/WebCore/css/mediaControlsQtFullscreen.css new file mode 100644 index 000000000..35cbf75d8 --- /dev/null +++ b/Source/WebCore/css/mediaControlsQtFullscreen.css @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 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. + */ +video::-webkit-media-controls-panel { +/* The control panel is only play button for full screen */ + display: -webkit-box; + -webkit-box-align: center; + -webkit-box-pack: center; + width: 100%; + height: 100%; +} + +video:-webkit-full-page-media::-webkit-media-controls-panel { + display: none; +} + +video::-webkit-media-controls-mute-button { + display: none; +} + +video::-webkit-media-controls-play-button { + display: -webkit-box; + -webkit-box-align: center; + -webkit-box-pack: center; + width: 50px; + height: 50px; + padding: 20px; +} + +video::-webkit-media-controls-timeline-container { + display: none; +} + +video::-webkit-media-controls-current-time-display { + -webkit-appearance: media-current-time-display; + -webkit-user-select: none; + display: none; +} + +video::-webkit-media-controls-time-remaining-display { + display: none; +} + +video::-webkit-media-controls-timeline { + display: none; +} + +video::-webkit-media-controls-volume-slider-container { + -webkit-appearance: media-volume-slider-container; + display: none; +} + +video::-webkit-media-controls-volume-slider { + -webkit-appearance: media-volume-slider; + display: none; +} + +video::-webkit-media-controls-seek-back-button { + display: none; +} + +video::-webkit-media-controls-seek-forward-button { + display: none; +} + +video::-webkit-media-controls-fullscreen-button { + display: none; +} + +video::-webkit-media-controls-rewind-button { + display: none; +} + +video::-webkit-media-controls-return-to-realtime-button { + display: none; +} + +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 000000000..5866a916f --- /dev/null +++ b/Source/WebCore/css/mediaControlsQuickTime.css @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2009, 2010, 2011 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: 0px; +} + +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; + border: none !important; +} + +audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { + width: 16px; + height: 16px; + margin-left: 6px; + margin-right: 1px; + border: none !important; +} + +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; + border: none !important; +} + +audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { + display: none; + width: 0px; + border: none !important; +} + +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 */ + border: none !important; +} + +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; + border: none !important; +} + +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; + border: none !important; +} + +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 */ + border: none !important; +} + +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; + border: none !important; +} diff --git a/Source/WebCore/css/mobileThemeQt.css b/Source/WebCore/css/mobileThemeQt.css new file mode 100644 index 000000000..f0378de70 --- /dev/null +++ b/Source/WebCore/css/mobileThemeQt.css @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 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="submit"], select { + font-family: "Nokia Pure Text", Arial, sans-serif; +} + +input[type="submit"]:disabled, input[type="submit"]:disabled:active, select:disabled, input[type="text"]:disabled { + color: #808080; +} + +input[type="submit"]:active { + color: white; +} diff --git a/Source/WebCore/css/quirks.css b/Source/WebCore/css/quirks.css new file mode 100644 index 000000000..52d07e678 --- /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 000000000..171c1c41f --- /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/themeChromium.css b/Source/WebCore/css/themeChromium.css new file mode 100644 index 000000000..761ddab0a --- /dev/null +++ b/Source/WebCore/css/themeChromium.css @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 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. */ + +::-webkit-validation-bubble { + opacity: 1; +} + +::-webkit-validation-bubble-message { + background: white; + border-color: #ccc #aaa #888; + border-width: 1px; + box-shadow: 2px 2px 4px rgba(100,100,100,0.3); + max-width: 300px; + top: -1px; +} + +::-webkit-validation-bubble-arrow { + background: white; + border-color: #ccc; + border-width: 1px; + box-shadow: none; +} + +::-webkit-validation-bubble-arrow-clipper { + height: 13px; +} + +::-webkit-validation-bubble-icon { + /* The image was taken from http://src.chromium.org/viewvc/chrome/trunk/src/chrome/app/theme/update_available.png?revision=50754&view=markup */ + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAACVklEQVQ4T6WRMWsUURSFv/t2ZjObZNUkREUFlYiIYGWl2Cj+AEs7wdZG0NpGwcJGxcpaWwWttbMQAmqRwoAEEiKohGTXdXdnZ+YeizebRAsbHzweXO4995zvmST+99izm+3EjOt7p+zhfDu0shQwgUAOKF4J5HVd8e10Bw8OXbp3J8mazKYN7h+fb7QOzxnNxs6glwVeFFhoYKGJ3GthQxLdtLx96NzV10mWWJo1ac+3oZWAezQyKks6xQx5coQk/05b38iaAXdAwgTTTUyj7rEQTAqmqhF2Wxa9zS7pqRssXHvH3otP2NjoURVCLrwCLwUVAEmQx+zuUUAuJFGOIEwdAWBi31EGfTHKHVzIHXdtM0u2wVVAJVSBrG7wEoCqGOIlVIXA4lI89sIuEeTILcaxKCoZAEJ1VHYc1AkQJDGCxaEq5pSJAJTDTQCK/iZVAVSCymqB2jUai9TFmg0Sk5MTdD4+5cv6JzqrSwSlBItO3PWXE9Uwq4BqJi4IIaXaWGZrZYkgY3ZfRiD+ihQXjZkEtvN5LLrARW+rx8TZm5y51+XglceMBoPIawy1nvtTpGYyFipHoMkDWNamMbtArwdloehg1wzCklG/TzqdNfAdYO7QmmyytfiUldUP/Fz7DJ6ACx9/MWMm2hMu3HrbIWQv8199ymEfzweU+YBEI/Z0lrHF52Tri8xNlViZ48Mc5Tk+yGnsP/HDWjMTJsm+fnx1uvf+0ZO5tHcmCRbGm/AdiNubEapKs2x2OH357pvm0fMvTFIKzAALwElgqpb41wmAgDVg8TfGt7U0pM19vgAAAABJRU5ErkJggg=='); + height: 17px; + margin-right: 6px; + width: 17px; +} + +::-webkit-validation-bubble-heading { + font-weight: normal; +} + +::-webkit-validation-bubble-body { + font-size: smaller; + color: #444; +} + +input:disabled, isindex:disabled, textarea:disabled { + color: #545454; /* Color::light() for #000000. See RenderTextControl.cpp:disabledTextColor */ +} + diff --git a/Source/WebCore/css/themeChromiumLinux.css b/Source/WebCore/css/themeChromiumLinux.css new file mode 100644 index 000000000..a6a88284d --- /dev/null +++ b/Source/WebCore/css/themeChromiumLinux.css @@ -0,0 +1,41 @@ +/* + * 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; +} + +select:not([size]):not([multiple]) option, +select[size="0"] option, +select[size="1"] option { + background-color: #f7f7f7; +} diff --git a/Source/WebCore/css/themeChromiumSkia.css b/Source/WebCore/css/themeChromiumSkia.css new file mode 100644 index 000000000..bcd05f0f4 --- /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/themeQtNoListboxes.css b/Source/WebCore/css/themeQtNoListboxes.css new file mode 100644 index 000000000..4c5e44ad7 --- /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 000000000..0838b1126 --- /dev/null +++ b/Source/WebCore/css/themeWin.css @@ -0,0 +1,127 @@ +/* + * 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="color"], +input[type="date"], +input[type="datetime"], +input[type="datetime-local"], +input[type="email"], +input[type="month"], +input[type="number"], +input[type="password"], +input[type="tel"], +input[type="text"], +input[type="time"], +input[type="url"], +input[type="week"] { + 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="color"]:disabled, +input[type="date"]:disabled, +input[type="datetime"]:disabled, +input[type="datetime-local"]:disabled, +input[type="email"]:disabled, +input[type="month"]:disabled, +input[type="password"]:disabled, +input[type="number"]:disabled, +input[type="search"]:disabled, +input[type="tel"]:disabled, +input[type="text"]:disabled, +input[type="time"]:disabled, +input[type="url"]:disabled, +input[type="week"]: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::-webkit-outer-spin-button { + margin: 0; +} + +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 000000000..c69b74c71 --- /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 000000000..c28dbcafa --- /dev/null +++ b/Source/WebCore/css/tokenizer.flex @@ -0,0 +1,130 @@ +%option case-insensitive +%option noyywrap +%option 8bit +%option stack +%s mediaquery +%s forkeyword +%s nthchild + +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 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" +string2 \'([^\n\r\f\\']|\\{nl}|{escape})*\' + +ident -?{nmstart}{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})? +nthfunc "nth-"("child"|"of-type"|"last-child"|"last-of-type") + +%% + +\/\*[^*]*\*+([^/*][^*]*\*+)*\/ {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;} +<nthchild>{nth} {yyTok = NTH; return yyTok;} +<nthchild>")" {BEGIN(INITIAL); yyTok = *yytext; return yyTok;} + +"#"{h}+ {yyTok = HEX; return yyTok;} +"#"{ident} {yyTok = IDSEL; 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; } +"@-webkit-region" {yyTok = WEBKIT_REGION_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}{ident}\+ {yyTok = INVALIDDIMEN; return yyTok;} +{num}%+ {yyTok = PERCENTAGE; return yyTok;} +{intnum} {yyTok = INTEGER; return yyTok;} +{num} {yyTok = FLOATTOKEN; return yyTok;} + +"-webkit-any(" {yyTok = ANYFUNCTION; return yyTok;} +"not(" {yyTok = NOTFUNCTION; return yyTok;} +"url("{w}{string}{w}")" {yyTok = URI; return yyTok;} +"url("{w}{url}{w}")" {yyTok = URI; return yyTok;} +"-webkit-calc(" {yyTok = CALCFUNCTION; return yyTok;} +"-webkit-min(" {yyTok = MINFUNCTION; return yyTok;} +"-webkit-max(" {yyTok = MAXFUNCTION; return yyTok;} +{nthfunc}"(" {BEGIN(nthchild); yyTok = FUNCTION; 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 000000000..129d28219 --- /dev/null +++ b/Source/WebCore/css/view-source.css @@ -0,0 +1,162 @@ +/* + * 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 +} + +tbody:last-child .webkit-line-content:empty:before { + content: " "; +} + +.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; +} |
