diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/html | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/html')
264 files changed, 37157 insertions, 0 deletions
diff --git a/WebCore/html/CanvasGradient.cpp b/WebCore/html/CanvasGradient.cpp new file mode 100644 index 0000000..693d8f7 --- /dev/null +++ b/WebCore/html/CanvasGradient.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.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 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 "CanvasGradient.h" + +#include "CSSParser.h" +#include "ExceptionCode.h" + +namespace WebCore { + +CanvasGradient::CanvasGradient(const FloatPoint& p0, const FloatPoint& p1) + : m_gradient(Gradient::create(p0, p1)) +{ +} + +CanvasGradient::CanvasGradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1) + : m_gradient(Gradient::create(p0, r0, p1, r1)) +{ +} + +void CanvasGradient::addColorStop(float value, const String& color, ExceptionCode& ec) +{ + if (!(value >= 0 && value <= 1.0f)) { + ec = INDEX_SIZE_ERR; + return; + } + + RGBA32 rgba = 0; + if (!CSSParser::parseColor(rgba, color)) { + ec = SYNTAX_ERR; + return; + } + + m_gradient->addColorStop(value, Color(rgba)); +} + +} // namespace diff --git a/WebCore/html/CanvasGradient.h b/WebCore/html/CanvasGradient.h new file mode 100644 index 0000000..3b81dbd --- /dev/null +++ b/WebCore/html/CanvasGradient.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.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 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 CanvasGradient_h +#define CanvasGradient_h + +#include "Gradient.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class String; + + typedef int ExceptionCode; + + class CanvasGradient : public RefCounted<CanvasGradient> { + public: + static PassRefPtr<CanvasGradient> create(const FloatPoint& p0, const FloatPoint& p1) + { + return adoptRef(new CanvasGradient(p0, p1)); + } + static PassRefPtr<CanvasGradient> create(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1) + { + return adoptRef(new CanvasGradient(p0, r0, p1, r1)); + } + + Gradient* gradient() const { return m_gradient.get(); } + + void addColorStop(float value, const String& color, ExceptionCode&); + + void getColor(float value, float* r, float* g, float* b, float* a) const { m_gradient->getColor(value, r, g, b, a); } + + private: + CanvasGradient(const FloatPoint& p0, const FloatPoint& p1); + CanvasGradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1); + + RefPtr<Gradient> m_gradient; + }; + +} //namespace + +#endif diff --git a/WebCore/html/CanvasGradient.idl b/WebCore/html/CanvasGradient.idl new file mode 100644 index 0000000..a925a26 --- /dev/null +++ b/WebCore/html/CanvasGradient.idl @@ -0,0 +1,39 @@ +/* + * 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, + * 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 html { + + interface [ + InterfaceUUID=bb1108ea-6b8c-4a08-894a-218628630cdb, + ImplementationUUID=a2942ae6-2731-4286-98cc-9d5e79e20de1 + ] CanvasGradient { + + void addColorStop(in float offset, in DOMString color) + raises (DOMException); + + }; + +} + diff --git a/WebCore/html/CanvasPattern.cpp b/WebCore/html/CanvasPattern.cpp new file mode 100644 index 0000000..62a4620 --- /dev/null +++ b/WebCore/html/CanvasPattern.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006, 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 "CanvasPattern.h" + +#include "ExceptionCode.h" +#include "PlatformString.h" + +namespace WebCore { + +void CanvasPattern::parseRepetitionType(const String& type, bool& repeatX, bool& repeatY, ExceptionCode& ec) +{ + ec = 0; + if (type.isEmpty() || type == "repeat") { + repeatX = true; + repeatY = true; + return; + } + if (type == "no-repeat") { + repeatX = false; + repeatY = false; + return; + } + if (type == "repeat-x") { + repeatX = true; + repeatY = false; + return; + } + if (type == "repeat-y") { + repeatX = false; + repeatY = true; + return; + } + ec = SYNTAX_ERR; +} + +CanvasPattern::CanvasPattern(Image* image, bool repeatX, bool repeatY, bool originClean) + : m_pattern(Pattern::create(image, repeatX, repeatY)) + , m_originClean(originClean) +{ +} + +} diff --git a/WebCore/html/CanvasPattern.h b/WebCore/html/CanvasPattern.h new file mode 100644 index 0000000..6c012d1 --- /dev/null +++ b/WebCore/html/CanvasPattern.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2006, 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 CanvasPattern_h +#define CanvasPattern_h + +#include "Pattern.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class Image; + class String; + + typedef int ExceptionCode; + + class CanvasPattern : public RefCounted<CanvasPattern> { + public: + static void parseRepetitionType(const String&, bool& repeatX, bool& repeatY, ExceptionCode&); + + static PassRefPtr<CanvasPattern> create(Image* image, bool repeatX, bool repeatY, bool originClean) + { + return adoptRef(new CanvasPattern(image, repeatX, repeatY, originClean)); + } + + Pattern* pattern() const { return m_pattern.get(); } + + bool originClean() const { return m_originClean; } + + private: + CanvasPattern(Image*, bool repeatX, bool repeatY, bool originClean); + + RefPtr<Pattern> m_pattern; + bool m_originClean; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/html/CanvasPattern.idl b/WebCore/html/CanvasPattern.idl new file mode 100644 index 0000000..1cac8f8 --- /dev/null +++ b/WebCore/html/CanvasPattern.idl @@ -0,0 +1,36 @@ +/* + * 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, + * 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 html { + + interface [ + InterfaceUUID=c2131348-6d8c-47b5-86cc-d41aff34ce15, + ImplementationUUID=82f5d713-3d17-44dd-aa4a-7766fe345940 + ] CanvasPattern { + + }; + +} + diff --git a/WebCore/html/CanvasPixelArray.cpp b/WebCore/html/CanvasPixelArray.cpp new file mode 100644 index 0000000..82bc27b --- /dev/null +++ b/WebCore/html/CanvasPixelArray.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CanvasPixelArray.h" + +namespace WebCore { + +PassRefPtr<CanvasPixelArray> CanvasPixelArray::create(unsigned size) +{ + return adoptRef(new CanvasPixelArray(size)); +} + +CanvasPixelArray::CanvasPixelArray(unsigned size) + : m_data(size) +{ + ASSERT((reinterpret_cast<size_t>(m_data.data()) & 3) == 0); +} + +} diff --git a/WebCore/html/CanvasPixelArray.h b/WebCore/html/CanvasPixelArray.h new file mode 100644 index 0000000..5560538 --- /dev/null +++ b/WebCore/html/CanvasPixelArray.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 CanvasPixelArray_h +#define CanvasPixelArray_h + +#include <wtf/MathExtras.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class CanvasPixelArray : public RefCounted<CanvasPixelArray> { + public: + static PassRefPtr<CanvasPixelArray> create(unsigned size); + + Vector<unsigned char>& data() { return m_data; } + unsigned length() const { return m_data.size(); } + + void set(unsigned index, double value) + { + if (index >= m_data.size()) + return; + if (!(value > 0)) // Clamp NaN to 0 + value = 0; + else if (value > 255) + value = 255; + m_data[index] = static_cast<unsigned char>(value + 0.5); + } + + bool get(unsigned index, unsigned char& result) const + { + if (index >= m_data.size()) + return false; + result = m_data[index]; + return true; + } + + private: + CanvasPixelArray(unsigned size); + Vector<unsigned char> m_data; + }; + +} // namespace WebCore + +#endif // CanvasPixelArray_h diff --git a/WebCore/html/CanvasPixelArray.idl b/WebCore/html/CanvasPixelArray.idl new file mode 100644 index 0000000..d4dcecb --- /dev/null +++ b/WebCore/html/CanvasPixelArray.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 html { + + interface [ + CustomHeader, + HasCustomIndexGetter, + HasCustomIndexSetter + ] CanvasPixelArray { + readonly attribute long length; + }; + +} diff --git a/WebCore/html/CanvasRenderingContext2D.cpp b/WebCore/html/CanvasRenderingContext2D.cpp new file mode 100644 index 0000000..5e3f36c --- /dev/null +++ b/WebCore/html/CanvasRenderingContext2D.cpp @@ -0,0 +1,1366 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Eric Seidel <eric@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 "CanvasRenderingContext2D.h" + +#include "AffineTransform.h" +#include "CSSParser.h" +#include "CachedImage.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasPixelArray.h" +#include "CanvasStyle.h" +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "FloatConversion.h" +#include "Frame.h" +#include "GraphicsContext.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "HTMLNames.h" +#include "ImageBuffer.h" +#include "ImageData.h" +#include "KURL.h" +#include "NotImplemented.h" +#include "Page.h" +#include "RenderHTMLCanvas.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "TextMetrics.h" +#include <kjs/interpreter.h> +#include <stdio.h> +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +const char* defaultFont = "10px sans-serif"; + +CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas) + : m_canvas(canvas) + , m_stateStack(1) +{ +} + +void CanvasRenderingContext2D::ref() +{ + m_canvas->ref(); +} + +void CanvasRenderingContext2D::deref() +{ + m_canvas->deref(); +} + +void CanvasRenderingContext2D::reset() +{ + m_stateStack.resize(1); + m_stateStack.first() = State(); +} + +CanvasRenderingContext2D::State::State() + : m_strokeStyle(CanvasStyle::create("black")) + , m_fillStyle(CanvasStyle::create("black")) + , m_lineWidth(1) + , m_lineCap(ButtCap) + , m_lineJoin(MiterJoin) + , m_miterLimit(10) + , m_shadowBlur(0) + , m_shadowColor("black") + , m_globalAlpha(1) + , m_globalComposite(CompositeSourceOver) + , m_textAlign(StartTextAlign) + , m_textBaseline(AlphabeticTextBaseline) + , m_unparsedFont(defaultFont) + , m_realizedFont(false) +{ +} + +void CanvasRenderingContext2D::save() +{ + ASSERT(m_stateStack.size() >= 1); + m_stateStack.append(state()); + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->save(); +} + +void CanvasRenderingContext2D::restore() +{ + ASSERT(m_stateStack.size() >= 1); + if (m_stateStack.size() <= 1) + return; + m_path.transform(state().m_transform); + m_stateStack.removeLast(); + m_path.transform(state().m_transform.inverse()); + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->restore(); +} + +CanvasStyle* CanvasRenderingContext2D::strokeStyle() const +{ + return state().m_strokeStyle.get(); +} + +void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style) +{ + if (!style) + return; + + if (m_canvas->originClean()) { + if (CanvasPattern* pattern = style->canvasPattern()) { + if (!pattern->originClean()) + m_canvas->setOriginTainted(); + } + } + + state().m_strokeStyle = style; + GraphicsContext* c = drawingContext(); + if (!c) + return; + state().m_strokeStyle->applyStrokeColor(c); +} + +CanvasStyle* CanvasRenderingContext2D::fillStyle() const +{ + return state().m_fillStyle.get(); +} + +void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style) +{ + if (!style) + return; + + if (m_canvas->originClean()) { + if (CanvasPattern* pattern = style->canvasPattern()) { + if (!pattern->originClean()) + m_canvas->setOriginTainted(); + } + } + + state().m_fillStyle = style; + GraphicsContext* c = drawingContext(); + if (!c) + return; + state().m_fillStyle->applyFillColor(c); +} + +float CanvasRenderingContext2D::lineWidth() const +{ + return state().m_lineWidth; +} + +void CanvasRenderingContext2D::setLineWidth(float width) +{ + if (!(width > 0)) + return; + state().m_lineWidth = width; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setStrokeThickness(width); +} + +String CanvasRenderingContext2D::lineCap() const +{ + return lineCapName(state().m_lineCap); +} + +void CanvasRenderingContext2D::setLineCap(const String& s) +{ + LineCap cap; + if (!parseLineCap(s, cap)) + return; + state().m_lineCap = cap; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setLineCap(cap); +} + +String CanvasRenderingContext2D::lineJoin() const +{ + return lineJoinName(state().m_lineJoin); +} + +void CanvasRenderingContext2D::setLineJoin(const String& s) +{ + LineJoin join; + if (!parseLineJoin(s, join)) + return; + state().m_lineJoin = join; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setLineJoin(join); +} + +float CanvasRenderingContext2D::miterLimit() const +{ + return state().m_miterLimit; +} + +void CanvasRenderingContext2D::setMiterLimit(float limit) +{ + if (!(limit > 0)) + return; + state().m_miterLimit = limit; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setMiterLimit(limit); +} + +float CanvasRenderingContext2D::shadowOffsetX() const +{ + return state().m_shadowOffset.width(); +} + +void CanvasRenderingContext2D::setShadowOffsetX(float x) +{ + state().m_shadowOffset.setWidth(x); + applyShadow(); +} + +float CanvasRenderingContext2D::shadowOffsetY() const +{ + return state().m_shadowOffset.height(); +} + +void CanvasRenderingContext2D::setShadowOffsetY(float y) +{ + state().m_shadowOffset.setHeight(y); + applyShadow(); +} + +float CanvasRenderingContext2D::shadowBlur() const +{ + return state().m_shadowBlur; +} + +void CanvasRenderingContext2D::setShadowBlur(float blur) +{ + state().m_shadowBlur = blur; + applyShadow(); +} + +String CanvasRenderingContext2D::shadowColor() const +{ + // FIXME: What should this return if you called setShadow with a non-string color? + return state().m_shadowColor; +} + +void CanvasRenderingContext2D::setShadowColor(const String& color) +{ + state().m_shadowColor = color; + applyShadow(); +} + +float CanvasRenderingContext2D::globalAlpha() const +{ + return state().m_globalAlpha; +} + +void CanvasRenderingContext2D::setGlobalAlpha(float alpha) +{ + if (!(alpha >= 0 && alpha <= 1)) + return; + state().m_globalAlpha = alpha; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setAlpha(alpha); +} + +String CanvasRenderingContext2D::globalCompositeOperation() const +{ + return compositeOperatorName(state().m_globalComposite); +} + +void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation) +{ + CompositeOperator op; + if (!parseCompositeOperator(operation, op)) + return; + state().m_globalComposite = op; + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setCompositeOperation(op); +} + +void CanvasRenderingContext2D::scale(float sx, float sy) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->scale(FloatSize(sx, sy)); + state().m_transform.scale(sx, sy); + m_path.transform(AffineTransform().scale(1.0/sx, 1.0/sy)); +} + +void CanvasRenderingContext2D::rotate(float angleInRadians) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->rotate(angleInRadians); + state().m_transform.rotate(angleInRadians / piDouble * 180.0); + m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0)); +} + +void CanvasRenderingContext2D::translate(float tx, float ty) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->translate(tx, ty); + state().m_transform.translate(tx, ty); + m_path.transform(AffineTransform().translate(-tx, -ty)); +} + +void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + + // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers + if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | + !isfinite(m12) | !isfinite(m22) | !isfinite(dy)) + return; + AffineTransform transform(m11, m12, m21, m22, dx, dy); + c->concatCTM(transform); + state().m_transform.multiply(transform); + m_path.transform(transform.inverse()); +} + +void CanvasRenderingContext2D::setStrokeColor(const String& color) +{ + setStrokeStyle(CanvasStyle::create(color)); +} + +void CanvasRenderingContext2D::setStrokeColor(float grayLevel) +{ + setStrokeStyle(CanvasStyle::create(grayLevel, 1)); +} + +void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha) +{ + setStrokeStyle(CanvasStyle::create(color, alpha)); +} + +void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha) +{ + setStrokeStyle(CanvasStyle::create(grayLevel, alpha)); +} + +void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a) +{ + setStrokeStyle(CanvasStyle::create(r, g, b, a)); +} + +void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a) +{ + setStrokeStyle(CanvasStyle::create(c, m, y, k, a)); +} + +void CanvasRenderingContext2D::setFillColor(const String& color) +{ + setFillStyle(CanvasStyle::create(color)); +} + +void CanvasRenderingContext2D::setFillColor(float grayLevel) +{ + setFillStyle(CanvasStyle::create(grayLevel, 1)); +} + +void CanvasRenderingContext2D::setFillColor(const String& color, float alpha) +{ + setFillStyle(CanvasStyle::create(color, 1)); +} + +void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha) +{ + setFillStyle(CanvasStyle::create(grayLevel, alpha)); +} + +void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a) +{ + setFillStyle(CanvasStyle::create(r, g, b, a)); +} + +void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a) +{ + setFillStyle(CanvasStyle::create(c, m, y, k, a)); +} + +void CanvasRenderingContext2D::beginPath() +{ + m_path.clear(); +} + +void CanvasRenderingContext2D::closePath() +{ + m_path.closeSubpath(); +} + +void CanvasRenderingContext2D::moveTo(float x, float y) +{ + if (!isfinite(x) | !isfinite(y)) + return; + m_path.moveTo(FloatPoint(x, y)); +} + +void CanvasRenderingContext2D::lineTo(float x, float y) +{ + if (!isfinite(x) | !isfinite(y)) + return; + m_path.addLineTo(FloatPoint(x, y)); +} + +void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y) +{ + if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y)) + return; + m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y)); +} + +void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) +{ + if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y)) + return; + m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y)); +} + +void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec) +{ + ec = 0; + if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinite(r)) + return; + + if (r < 0) { + ec = INDEX_SIZE_ERR; + return; + } + + m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r); +} + +void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec) +{ + ec = 0; + if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea)) + return; + + if (r < 0) { + ec = INDEX_SIZE_ERR; + return; + } + + m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise); +} + +static bool validateRectForCanvas(float& x, float& y, float& width, float& height) +{ + if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height)) + return false; + + if (width < 0) { + width = -width; + x -= width; + } + + if (height < 0) { + height = -height; + y -= height; + } + + return true; +} + +void CanvasRenderingContext2D::rect(float x, float y, float width, float height) +{ + if (!validateRectForCanvas(x, y, width, height)) + return; + + m_path.addRect(FloatRect(x, y, width, height)); +} + +#if ENABLE(DASHBOARD_SUPPORT) +void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode() +{ + if (Settings* settings = m_canvas->document()->settings()) + if (settings->usesDashboardBackwardCompatibilityMode()) + m_path.clear(); +} +#endif + +void CanvasRenderingContext2D::fill() +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + + c->beginPath(); + c->addPath(m_path); + if (!m_path.isEmpty()) + willDraw(m_path.boundingRect()); + + c->fillPath(); + +#if ENABLE(DASHBOARD_SUPPORT) + clearPathForDashboardBackwardCompatibilityMode(); +#endif +} + +void CanvasRenderingContext2D::stroke() +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->beginPath(); + c->addPath(m_path); + + if (!m_path.isEmpty()) { + // FIXME: This is insufficient, need to use CGContextReplacePathWithStrokedPath to expand to required bounds + float lineWidth = state().m_lineWidth; + float inset = lineWidth / 2; + FloatRect boundingRect = m_path.boundingRect(); + boundingRect.inflate(inset); + willDraw(boundingRect); + } + + c->strokePath(); + +#if ENABLE(DASHBOARD_SUPPORT) + clearPathForDashboardBackwardCompatibilityMode(); +#endif +} + +void CanvasRenderingContext2D::clip() +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->clip(m_path); +#if ENABLE(DASHBOARD_SUPPORT) + clearPathForDashboardBackwardCompatibilityMode(); +#endif +} + +bool CanvasRenderingContext2D::isPointInPath(const float x, const float y) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return false; + FloatPoint point(x, y); + // We have to invert the current transform to ensure we correctly handle the + // transforms applied to the current path. + AffineTransform ctm = state().m_transform; + if (!ctm.isInvertible()) + return false; + FloatPoint transformedPoint = ctm.inverse().mapPoint(point); + return m_path.contains(transformedPoint); +} + +void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height) +{ + if (!validateRectForCanvas(x, y, width, height)) + return; + GraphicsContext* c = drawingContext(); + if (!c) + return; + FloatRect rect(x, y, width, height); + willDraw(rect); + c->clearRect(rect); +} + +void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height) +{ + if (!validateRectForCanvas(x, y, width, height)) + return; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + + FloatRect rect(x, y, width, height); + willDraw(rect); + + c->save(); + c->fillRect(rect); + c->restore(); +} + +void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height) +{ + if (!validateRectForCanvas(x, y, width, height)) + return; + strokeRect(x, y, width, height, state().m_lineWidth); +} + +void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth) +{ + if (!validateRectForCanvas(x, y, width, height)) + return; + + if (!(lineWidth >= 0)) + return; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + + FloatRect rect(x, y, width, height); + + FloatRect boundingRect = rect; + boundingRect.inflate(lineWidth / 2); + willDraw(boundingRect); + + c->strokeRect(rect, lineWidth); +} + +#if PLATFORM(CG) +static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height) +{ + // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated + // to the desired integer. + static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128); + if (width > 0) + width += extraShadowOffset; + else if (width < 0) + width -= extraShadowOffset; + + if (height > 0) + height += extraShadowOffset; + else if (height < 0) + height -= extraShadowOffset; + + return CGSizeMake(width, height); +} +#endif + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = ""; + applyShadow(); +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = color; + applyShadow(); +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = ""; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + const CGFloat components[2] = { grayLevel, 1 }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGColorRef color = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color); + CGColorRelease(color); +#endif +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = color; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + RGBA32 rgba = 0; // default is transparent black + CSSParser::parseColor(rgba, color); + const CGFloat components[4] = { + ((rgba >> 16) & 0xFF) / 255.0f, + ((rgba >> 8) & 0xFF) / 255.0f, + (rgba & 0xFF) / 255.0f, + alpha + }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGColorRef shadowColor = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); + CGColorRelease(shadowColor); +#endif +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = ""; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + const CGFloat components[2] = { grayLevel, alpha }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGColorRef color = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color); + CGColorRelease(color); +#endif +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = ""; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + const CGFloat components[4] = { r, g, b, a }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGColorRef shadowColor = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); + CGColorRelease(shadowColor); +#endif +} + +void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a) +{ + state().m_shadowOffset = FloatSize(width, height); + state().m_shadowBlur = blur; + state().m_shadowColor = ""; + + GraphicsContext* dc = drawingContext(); + if (!dc) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + const CGFloat components[5] = { c, m, y, k, a }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK(); + CGColorRef shadowColor = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); + CGColorRelease(shadowColor); +#endif +} + +void CanvasRenderingContext2D::clearShadow() +{ + state().m_shadowOffset = FloatSize(); + state().m_shadowBlur = 0; + state().m_shadowColor = ""; + applyShadow(); +} + +void CanvasRenderingContext2D::applyShadow() +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + // FIXME: Do this through platform-independent GraphicsContext API. +#if PLATFORM(CG) + RGBA32 rgba = 0; // default is transparent black + if (!state().m_shadowColor.isEmpty()) + CSSParser::parseColor(rgba, state().m_shadowColor); + const CGFloat components[4] = { + ((rgba >> 16) & 0xFF) / 255.0f, + ((rgba >> 8) & 0xFF) / 255.0f, + (rgba & 0xFF) / 255.0f, + ((rgba >> 24) & 0xFF) / 255.0f + }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGColorRef color = CGColorCreate(colorSpace, components); + CGColorSpaceRelease(colorSpace); + + CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(state().m_shadowOffset.width(), -state().m_shadowOffset.height()), state().m_shadowBlur, color); + CGColorRelease(color); +#endif +} + +static IntSize size(HTMLImageElement* image) +{ + if (CachedImage* cachedImage = image->cachedImage()) + return cachedImage->imageSize(1.0f); // FIXME: Not sure about this. + return IntSize(); +} + +static inline FloatRect normalizeRect(const FloatRect& rect) +{ + return FloatRect(min(rect.x(), rect.right()), + min(rect.y(), rect.bottom()), + max(rect.width(), -rect.width()), + max(rect.height(), -rect.height())); +} + +void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y) +{ + ASSERT(image); + IntSize s = size(image); + ExceptionCode ec; + drawImage(image, x, y, s.width(), s.height(), ec); +} + +void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, + float x, float y, float width, float height, ExceptionCode& ec) +{ + ASSERT(image); + IntSize s = size(image); + drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec); +} + +void CanvasRenderingContext2D::checkOrigin(const KURL& url) +{ + RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); + if (!m_canvas->document()->securityOrigin()->canAccess(origin.get())) + m_canvas->setOriginTainted(); +} + +void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, + ExceptionCode& ec) +{ + ASSERT(image); + + ec = 0; + + FloatRect imageRect = FloatRect(FloatPoint(), size(image)); + if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) { + ec = INDEX_SIZE_ERR; + return; + } + + if (!dstRect.width() || !dstRect.height()) + return; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + + CachedImage* cachedImage = image->cachedImage(); + if (!cachedImage) + return; + + if (m_canvas->originClean()) + checkOrigin(cachedImage->response().url()); + + if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin()) + m_canvas->setOriginTainted(); + + FloatRect sourceRect = c->roundToDevicePixels(srcRect); + FloatRect destRect = c->roundToDevicePixels(dstRect); + willDraw(destRect); +#if PLATFORM(SGL) + // this seems like a bug fix as well. + // can't see how the std code can use destRect/sourceRect, since they are scaled by matrix + c->drawImage(cachedImage->image(), dstRect, srcRect, state().m_globalComposite); +#else + c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite); +#endif +} + +void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y) +{ + ASSERT(canvas); + ExceptionCode ec; + drawImage(canvas, x, y, canvas->width(), canvas->height(), ec); +} + +void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, + float x, float y, float width, float height, ExceptionCode& ec) +{ + ASSERT(canvas); + drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec); +} + +void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect, + const FloatRect& dstRect, ExceptionCode& ec) +{ + ASSERT(canvas); + + ec = 0; + + FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size()); + if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) { + ec = INDEX_SIZE_ERR; + return; + } + + if (!dstRect.width() || !dstRect.height()) + return; + + GraphicsContext* c = drawingContext(); + if (!c) + return; + + FloatRect sourceRect = c->roundToDevicePixels(srcRect); + FloatRect destRect = c->roundToDevicePixels(dstRect); + + // FIXME: Do this through platform-independent GraphicsContext API. + ImageBuffer* buffer = canvas->buffer(); + if (!buffer) + return; + + if (!canvas->originClean()) + m_canvas->setOriginTainted(); + + c->drawImage(buffer->image(), destRect, sourceRect, state().m_globalComposite); + willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty. + // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this. +} + +// FIXME: Why isn't this just another overload of drawImage? Why have a different name? +void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, + float sx, float sy, float sw, float sh, + float dx, float dy, float dw, float dh, + const String& compositeOperation) +{ + if (!image) + return; + + CachedImage* cachedImage = image->cachedImage(); + if (!cachedImage) + return; + + if (m_canvas->originClean()) + checkOrigin(cachedImage->response().url()); + + if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin()) + m_canvas->setOriginTainted(); + + GraphicsContext* c = drawingContext(); + if (!c) + return; + + CompositeOperator op; + if (!parseCompositeOperator(compositeOperation, op)) + op = CompositeSourceOver; + + FloatRect destRect = FloatRect(dx, dy, dw, dh); + willDraw(destRect); + c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op); +} + +void CanvasRenderingContext2D::setAlpha(float alpha) +{ + setGlobalAlpha(alpha); +} + +void CanvasRenderingContext2D::setCompositeOperation(const String& operation) +{ + setGlobalCompositeOperation(operation); +} + +PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec) +{ + if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) { + ec = NOT_SUPPORTED_ERR; + return 0; + } + + return CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1)); +} + +PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec) +{ + if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || + !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) { + ec = NOT_SUPPORTED_ERR; + return 0; + } + return CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); +} + +PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image, + const String& repetitionType, ExceptionCode& ec) +{ + bool repeatX, repeatY; + ec = 0; + CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec); + if (ec) + return 0; + + if (!image->complete()) { + ec = INVALID_STATE_ERR; + return 0; + } + + CachedImage* cachedImage = image->cachedImage(); + if (!cachedImage || !image->cachedImage()->image()) + return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true); + + KURL url(cachedImage->url()); + RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); + bool originClean = m_canvas->document()->securityOrigin()->canAccess(origin.get()); + return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean); +} + +PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas, + const String& repetitionType, ExceptionCode& ec) +{ + if (!canvas->width() || !canvas->height()) { + ec = INVALID_STATE_ERR; + return 0; + } + + bool repeatX, repeatY; + ec = 0; + CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec); + if (ec) + return 0; + return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean()); +} + +void CanvasRenderingContext2D::willDraw(const FloatRect& r) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + + m_canvas->willDraw(c->getCTM().mapRect(r)); +} + +GraphicsContext* CanvasRenderingContext2D::drawingContext() const +{ + return m_canvas->drawingContext(); +} + +static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size) +{ + PassRefPtr<ImageData> data = ImageData::create(size.width(), size.height()); + memset(data->data()->data().data(), 0, data->data()->length()); + return data; +} + +PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh) const +{ + FloatSize unscaledSize(sw, sh); + IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize); + if (scaledSize.width() < 1) + scaledSize.setWidth(1); + if (scaledSize.height() < 1) + scaledSize.setHeight(1); + + return createEmptyImageData(scaledSize); +} + +PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const +{ + if (!m_canvas->originClean()) { + ec = SECURITY_ERR; + return 0; + } + + FloatRect unscaledRect(sx, sy, sw, sh); + IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect); + if (scaledRect.width() < 1) + scaledRect.setWidth(1); + if (scaledRect.height() < 1) + scaledRect.setHeight(1); + ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0; + if (!buffer) + return createEmptyImageData(scaledRect.size()); + return buffer->getImageData(scaledRect); +} + +void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec) +{ + if (!data) { + ec = TYPE_MISMATCH_ERR; + return; + } + putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec); +} + +void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, + float dirtyWidth, float dirtyHeight, ExceptionCode& ec) +{ + if (!data) { + ec = TYPE_MISMATCH_ERR; + return; + } + if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || + !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) { + ec = INDEX_SIZE_ERR; + return; + } + + ImageBuffer* buffer = m_canvas->buffer(); + if (!buffer) + return; + + if (dirtyWidth < 0) { + dirtyX += dirtyWidth; + dirtyWidth = -dirtyWidth; + } + + if (dirtyHeight < 0) { + dirtyY += dirtyHeight; + dirtyHeight = -dirtyHeight; + } + + FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight); + clipRect.intersect(IntRect(0, 0, data->width(), data->height())); + IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy)); + IntRect sourceRect = enclosingIntRect(clipRect); + sourceRect.move(destOffset); + sourceRect.intersect(IntRect(IntPoint(), buffer->size())); + if (sourceRect.isEmpty()) + return; + willDraw(sourceRect); + sourceRect.move(-destOffset); + IntPoint destPoint(destOffset.width(), destOffset.height()); + + buffer->putImageData(data, sourceRect, destPoint); +} + +String CanvasRenderingContext2D::font() const +{ + return state().m_unparsedFont; +} + +void CanvasRenderingContext2D::setFont(const String& newFont) +{ + RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create(); + CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS. + + String declarationText("font: "); + declarationText += newFont; + parser.parseDeclaration(tempDecl.get(), declarationText); + if (!tempDecl->length()) + return; + + // The parse succeeded. + state().m_unparsedFont = newFont; + + // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work + // relative to the canvas. + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + if (m_canvas->computedStyle()) + newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription()); + + // Now map the font property into the style. + CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector(); + styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get()); + + state().m_font = newStyle->font(); + state().m_font.update(styleSelector->fontSelector()); + state().m_realizedFont = true; + + // Set the font in the graphics context. + GraphicsContext* c = drawingContext(); + if (!c) + return; + c->setFont(state().m_font); +} + +String CanvasRenderingContext2D::textAlign() const +{ + return textAlignName(state().m_textAlign); +} + +void CanvasRenderingContext2D::setTextAlign(const String& s) +{ + TextAlign align; + if (!parseTextAlign(s, align)) + return; + state().m_textAlign = align; +} + +String CanvasRenderingContext2D::textBaseline() const +{ + return textBaselineName(state().m_textBaseline); +} + +void CanvasRenderingContext2D::setTextBaseline(const String& s) +{ + TextBaseline baseline; + if (!parseTextBaseline(s, baseline)) + return; + state().m_textBaseline = baseline; +} + +void CanvasRenderingContext2D::fillText(const String& text, float x, float y) +{ + drawTextInternal(text, x, y, true); +} + +void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth) +{ + drawTextInternal(text, x, y, true, maxWidth, true); +} + +void CanvasRenderingContext2D::strokeText(const String& text, float x, float y) +{ + drawTextInternal(text, x, y, false); +} + +void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth) +{ + drawTextInternal(text, x, y, false, maxWidth, true); +} + +PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text) +{ + RefPtr<TextMetrics> metrics = TextMetrics::create(); + metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length()))); + return metrics; +} + +void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth) +{ + GraphicsContext* c = drawingContext(); + if (!c) + return; + + const Font& font = accessFont(); + + // FIXME: Handle maxWidth. + // FIXME: Need to turn off font smoothing. + + bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction() == RTL : false; + bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unicodeBidi() == Override : false; + + unsigned length = text.length(); + const UChar* string = text.characters(); + TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false); + + // Draw the item text at the correct point. + FloatPoint location(x, y); + switch (state().m_textBaseline) { + case TopTextBaseline: + case HangingTextBaseline: + location.setY(y + font.ascent()); + break; + case BottomTextBaseline: + case IdeographicTextBaseline: + location.setY(y - font.descent()); + break; + case MiddleTextBaseline: + location.setY(y - font.descent() + font.height() / 2); + break; + case AlphabeticTextBaseline: + default: + // Do nothing. + break; + } + + float width = font.width(TextRun(text, false, 0, 0, rtl, override)); + + TextAlign align = state().m_textAlign; + if (align == StartTextAlign) + align = rtl ? RightTextAlign : LeftTextAlign; + else if (align == EndTextAlign) + align = rtl ? LeftTextAlign : RightTextAlign; + + switch (align) { + case CenterTextAlign: + location.setX(location.x() - width / 2); + break; + case RightTextAlign: + location.setX(location.x() - width); + break; + default: + break; + } + + // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text. + FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(), + width + font.height(), font.lineSpacing()); + if (!fill) + textRect.inflate(c->strokeThickness() / 2); + + CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get(); + if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) { + IntRect maskRect = enclosingIntRect(textRect); + + auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); + + GraphicsContext* maskImageContext = maskImage->context(); + + if (fill) + maskImageContext->setFillColor(Color::black); + else { + maskImageContext->setStrokeColor(Color::black); + maskImageContext->setStrokeThickness(c->strokeThickness()); + } + + maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke); + maskImageContext->translate(-maskRect.x(), -maskRect.y()); + + maskImageContext->setFont(font); + maskImageContext->drawBidiText(textRun, location); + + c->save(); + c->clipToImageBuffer(maskRect, maskImage.get()); + drawStyle->applyFillColor(c); + c->fillRect(maskRect); + c->restore(); + + return; + } + + c->setTextDrawingMode(fill ? cTextFill : cTextStroke); + c->drawBidiText(textRun, location); +} + +const Font& CanvasRenderingContext2D::accessFont() +{ + if (!state().m_realizedFont) + setFont(state().m_unparsedFont); + return state().m_font; +} + +} // namespace WebCore diff --git a/WebCore/html/CanvasRenderingContext2D.h b/WebCore/html/CanvasRenderingContext2D.h new file mode 100644 index 0000000..e720f21 --- /dev/null +++ b/WebCore/html/CanvasRenderingContext2D.h @@ -0,0 +1,251 @@ +/* + * 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. + */ + +#ifndef CanvasRenderingContext2D_h +#define CanvasRenderingContext2D_h + +#include "AffineTransform.h" +#include "FloatSize.h" +#include "Font.h" +#include "GraphicsTypes.h" +#include "Path.h" +#include "PlatformString.h" +#include <wtf/Vector.h> + +#if PLATFORM(CG) +#include <ApplicationServices/ApplicationServices.h> +#endif + +namespace WebCore { + + class CanvasGradient; + class CanvasPattern; + class CanvasStyle; + class FloatRect; + class GraphicsContext; + class HTMLCanvasElement; + class HTMLImageElement; + class ImageData; + class KURL; + class TextMetrics; + + typedef int ExceptionCode; + + class CanvasRenderingContext2D : Noncopyable { + public: + CanvasRenderingContext2D(HTMLCanvasElement*); + + void ref(); + void deref(); + + HTMLCanvasElement* canvas() const { return m_canvas; } + + CanvasStyle* strokeStyle() const; + void setStrokeStyle(PassRefPtr<CanvasStyle>); + + CanvasStyle* fillStyle() const; + void setFillStyle(PassRefPtr<CanvasStyle>); + + float lineWidth() const; + void setLineWidth(float); + + String lineCap() const; + void setLineCap(const String&); + + String lineJoin() const; + void setLineJoin(const String&); + + float miterLimit() const; + void setMiterLimit(float); + + float shadowOffsetX() const; + void setShadowOffsetX(float); + + float shadowOffsetY() const; + void setShadowOffsetY(float); + + float shadowBlur() const; + void setShadowBlur(float); + + String shadowColor() const; + void setShadowColor(const String&); + + float globalAlpha() const; + void setGlobalAlpha(float); + + String globalCompositeOperation() const; + void setGlobalCompositeOperation(const String&); + + void save(); + void restore(); + + void scale(float sx, float sy); + void rotate(float angleInRadians); + void translate(float tx, float ty); + void transform(float m11, float m12, float m21, float m22, float dx, float dy); + + void setStrokeColor(const String& color); + void setStrokeColor(float grayLevel); + void setStrokeColor(const String& color, float alpha); + void setStrokeColor(float grayLevel, float alpha); + void setStrokeColor(float r, float g, float b, float a); + void setStrokeColor(float c, float m, float y, float k, float a); + + void setFillColor(const String& color); + void setFillColor(float grayLevel); + void setFillColor(const String& color, float alpha); + void setFillColor(float grayLevel, float alpha); + void setFillColor(float r, float g, float b, float a); + void setFillColor(float c, float m, float y, float k, float a); + + void beginPath(); + void closePath(); + + void moveTo(float x, float y); + void lineTo(float x, float y); + void quadraticCurveTo(float cpx, float cpy, float x, float y); + void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y); + void arcTo(float x0, float y0, float x1, float y1, float radius, ExceptionCode&); + void arc(float x, float y, float r, float sa, float ea, bool clockwise, ExceptionCode&); + void rect(float x, float y, float width, float height); + + void fill(); + void stroke(); + void clip(); + + bool isPointInPath(const float x, const float y); + + void clearRect(float x, float y, float width, float height); + void fillRect(float x, float y, float width, float height); + void strokeRect(float x, float y, float width, float height); + void strokeRect(float x, float y, float width, float height, float lineWidth); + + void setShadow(float width, float height, float blur); + void setShadow(float width, float height, float blur, const String& color); + void setShadow(float width, float height, float blur, float grayLevel); + void setShadow(float width, float height, float blur, const String& color, float alpha); + void setShadow(float width, float height, float blur, float grayLevel, float alpha); + void setShadow(float width, float height, float blur, float r, float g, float b, float a); + void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a); + + void clearShadow(); + + void drawImage(HTMLImageElement*, float x, float y); + void drawImage(HTMLImageElement*, float x, float y, float width, float height, ExceptionCode&); + void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); + void drawImage(HTMLCanvasElement*, float x, float y); + void drawImage(HTMLCanvasElement*, float x, float y, float width, float height, ExceptionCode&); + void drawImage(HTMLCanvasElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); + + void drawImageFromRect(HTMLImageElement*, float sx, float sy, float sw, float sh, + float dx, float dy, float dw, float dh, const String& compositeOperation); + + void setAlpha(float); + + void setCompositeOperation(const String&); + + PassRefPtr<CanvasGradient> createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode&); + PassRefPtr<CanvasGradient> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode&); + PassRefPtr<CanvasPattern> createPattern(HTMLImageElement*, const String& repetitionType, ExceptionCode&); + PassRefPtr<CanvasPattern> createPattern(HTMLCanvasElement*, const String& repetitionType, ExceptionCode&); + + PassRefPtr<ImageData> createImageData(float width, float height) const; + PassRefPtr<ImageData> getImageData(float sx, float sy, float sw, float sh, ExceptionCode&) const; + void putImageData(ImageData*, float dx, float dy, ExceptionCode&); + void putImageData(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&); + + void reset(); + + String font() const; + void setFont(const String&); + + String textAlign() const; + void setTextAlign(const String&); + + String textBaseline() const; + void setTextBaseline(const String&); + + void fillText(const String& text, float x, float y); + void fillText(const String& text, float x, float y, float maxWidth); + void strokeText(const String& text, float x, float y); + void strokeText(const String& text, float x, float y, float maxWidth); + PassRefPtr<TextMetrics> measureText(const String& text); + + private: + struct State { + State(); + + RefPtr<CanvasStyle> m_strokeStyle; + RefPtr<CanvasStyle> m_fillStyle; + float m_lineWidth; + LineCap m_lineCap; + LineJoin m_lineJoin; + float m_miterLimit; + FloatSize m_shadowOffset; + float m_shadowBlur; + String m_shadowColor; + float m_globalAlpha; + CompositeOperator m_globalComposite; + AffineTransform m_transform; + + // Text state. + TextAlign m_textAlign; + TextBaseline m_textBaseline; + + String m_unparsedFont; + Font m_font; + bool m_realizedFont; + }; + Path m_path; + + State& state() { return m_stateStack.last(); } + const State& state() const { return m_stateStack.last(); } + + void applyShadow(); + + void willDraw(const FloatRect&); + + GraphicsContext* drawingContext() const; + + void applyStrokePattern(); + void applyFillPattern(); + + void drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth = 0, bool useMaxWidth = false); + + const Font& accessFont(); + +#if ENABLE(DASHBOARD_SUPPORT) + void clearPathForDashboardBackwardCompatibilityMode(); +#endif + + void checkOrigin(const KURL&); + + HTMLCanvasElement* m_canvas; + Vector<State, 1> m_stateStack; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/html/CanvasRenderingContext2D.idl b/WebCore/html/CanvasRenderingContext2D.idl new file mode 100644 index 0000000..29c9a7a --- /dev/null +++ b/WebCore/html/CanvasRenderingContext2D.idl @@ -0,0 +1,122 @@ +/* + * 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, + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=98fb48ae-7216-489c-862b-8e1217fc4443, + ImplementationUUID=ab4f0781-152f-450e-9546-5b3987491a54 + ] CanvasRenderingContext2D { + + // Web Applications 1.0 draft + + readonly attribute HTMLCanvasElement canvas; + + void save(); + void restore(); + + void scale(in float sx, in float sy); + void rotate(in float angle); + void translate(in float tx, in float ty); + void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); + + attribute float globalAlpha; + attribute [ConvertNullToNullString] DOMString globalCompositeOperation; + + CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1) + raises (DOMException); + CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1) + raises (DOMException); + + attribute float lineWidth; + attribute [ConvertNullToNullString] DOMString lineCap; + attribute [ConvertNullToNullString] DOMString lineJoin; + attribute float miterLimit; + + attribute float shadowOffsetX; + attribute float shadowOffsetY; + attribute float shadowBlur; + attribute [ConvertNullToNullString] DOMString shadowColor; + + void clearRect(in float x, in float y, in float width, in float height); + void fillRect(in float x, in float y, in float width, in float height); + + void beginPath(); + void closePath(); + void moveTo(in float x, in float y); + void lineTo(in float x, in float y); + void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y); + void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y); + void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius) + raises (DOMException); + void rect(in float x, in float y, in float width, in float height); + void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise) + raises (DOMException); + void fill(); + void stroke(); + void clip(); + boolean isPointInPath(in float x, in float y); + + // text + attribute DOMString font; + attribute DOMString textAlign; + attribute DOMString textBaseline; + [Custom] void fillText(/* 4 */); + [Custom] void strokeText(/* 4 */); + TextMetrics measureText(in DOMString text); + + // other + + void setAlpha(in float alpha); + void setCompositeOperation(in DOMString compositeOperation); + + void setLineWidth(in float width); + void setLineCap(in DOMString cap); + void setLineJoin(in DOMString join); + void setMiterLimit(in float limit); + + void clearShadow(); + + [Custom] void setStrokeColor(/* 1 */); + [Custom] void setFillColor(/* 1 */); + [Custom] void strokeRect(/* 4 */); + [Custom] void drawImage(/* 3 */); + [Custom] void drawImageFromRect(/* 10 */); + [Custom] void setShadow(/* 3 */); + [Custom] void createPattern(/* 2 */); + + attribute [Custom] custom strokeStyle; + attribute [Custom] custom fillStyle; + + // pixel manipulation + ImageData createImageData(in float sw, in float sh); + ImageData getImageData(in float sx, in float sy, in float sw, in float sh) + raises(DOMException); + [Custom] void putImageData(/* in ImageData imagedata, in float dx, in float dy [, in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight] */); + }; + +} + diff --git a/WebCore/html/CanvasStyle.cpp b/WebCore/html/CanvasStyle.cpp new file mode 100644 index 0000000..27d8a84 --- /dev/null +++ b/WebCore/html/CanvasStyle.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Eric Seidel <eric@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 "CanvasStyle.h" + +#include "CSSParser.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "GraphicsContext.h" +#include <wtf/PassRefPtr.h> + +#if PLATFORM(CG) +#include <CoreGraphics/CGContext.h> +#endif + +#if PLATFORM(QT) +#include <QPainter> +#include <QBrush> +#include <QPen> +#include <QColor> +#elif PLATFORM(CAIRO) +#include "NotImplemented.h" +#endif + +namespace WebCore { + +CanvasStyle::CanvasStyle(const String& color) + : m_type(ColorString) + , m_color(color) +{ +} + +CanvasStyle::CanvasStyle(float grayLevel) + : m_type(GrayLevel) + , m_alpha(1) + , m_grayLevel(grayLevel) +{ +} + +CanvasStyle::CanvasStyle(const String& color, float alpha) + : m_type(ColorStringWithAlpha) + , m_color(color) + , m_alpha(alpha) +{ +} + +CanvasStyle::CanvasStyle(float grayLevel, float alpha) + : m_type(GrayLevel) + , m_alpha(alpha) + , m_grayLevel(grayLevel) +{ +} + +CanvasStyle::CanvasStyle(float r, float g, float b, float a) + : m_type(RGBA), m_alpha(a), m_red(r), m_green(g), m_blue(b) +{ +} + +CanvasStyle::CanvasStyle(float c, float m, float y, float k, float a) + : m_type(CMYKA), m_alpha(a), m_cyan(c), m_magenta(m), m_yellow(y), m_black(k) +{ +} + +CanvasStyle::CanvasStyle(PassRefPtr<CanvasGradient> gradient) + : m_type(gradient ? Gradient : ColorString) + , m_gradient(gradient) +{ +} + +CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern) + : m_type(pattern ? ImagePattern : ColorString) + , m_pattern(pattern) +{ +} + +void CanvasStyle::applyStrokeColor(GraphicsContext* context) +{ + if (!context) + return; + switch (m_type) { + case ColorString: { + RGBA32 color = 0; // default is transparant black + if (CSSParser::parseColor(color, m_color)) + context->setStrokeColor(color); + break; + } + case ColorStringWithAlpha: { + RGBA32 color = 0; // default is transparant black + if (CSSParser::parseColor(color, m_color)) + context->setStrokeColor(colorWithOverrideAlpha(color, m_alpha)); + break; + } + case GrayLevel: + // We're only supporting 255 levels of gray here. Since this isn't + // even part of HTML5, I don't expect anyone will care. If they do + // we'll make a fancier Color abstraction. + context->setStrokeColor(Color(m_grayLevel, m_grayLevel, m_grayLevel, m_alpha)); + break; + case RGBA: + context->setStrokeColor(Color(m_red, m_green, m_blue, m_alpha)); + break; + case CMYKA: { + // FIXME: Do this through platform-independent GraphicsContext API. + // We'll need a fancier Color abstraction to support CYMKA correctly +#if PLATFORM(CG) + CGContextSetCMYKStrokeColor(context->platformContext(), m_cyan, m_magenta, m_yellow, m_black, m_alpha); +#elif PLATFORM(QT) + QPen currentPen = context->platformContext()->pen(); + QColor clr; + clr.setCmykF(m_cyan, m_magenta, m_yellow, m_black, m_alpha); + currentPen.setColor(clr); + context->platformContext()->setPen(currentPen); +#elif PLATFORM(CAIRO) + notImplemented(); +#elif PLATFORM(SGL) + context->setCMYKAStrokeColor(m_cyan, m_magenta, m_yellow, m_black, m_alpha); +#endif + break; + } + case Gradient: + context->setStrokeGradient(canvasGradient()->gradient()); + break; + case ImagePattern: + context->setStrokePattern(canvasPattern()->pattern()); + break; + } +} + +void CanvasStyle::applyFillColor(GraphicsContext* context) +{ + if (!context) + return; + switch (m_type) { + case ColorString: { + RGBA32 rgba = 0; // default is transparant black + if (CSSParser::parseColor(rgba, m_color)) + context->setFillColor(rgba); + break; + } + case ColorStringWithAlpha: { + RGBA32 color = 0; // default is transparant black + if (CSSParser::parseColor(color, m_color)) + context->setFillColor(colorWithOverrideAlpha(color, m_alpha)); + break; + } + case GrayLevel: + // We're only supporting 255 levels of gray here. Since this isn't + // even part of HTML5, I don't expect anyone will care. If they do + // we'll make a fancier Color abstraction. + context->setFillColor(Color(m_grayLevel, m_grayLevel, m_grayLevel, m_alpha)); + break; + case RGBA: + context->setFillColor(Color(m_red, m_green, m_blue, m_alpha)); + break; + case CMYKA: { + // FIXME: Do this through platform-independent GraphicsContext API. + // We'll need a fancier Color abstraction to support CYMKA correctly +#if PLATFORM(CG) + CGContextSetCMYKFillColor(context->platformContext(), m_cyan, m_magenta, m_yellow, m_black, m_alpha); +#elif PLATFORM(QT) + QBrush currentBrush = context->platformContext()->brush(); + QColor clr; + clr.setCmykF(m_cyan, m_magenta, m_yellow, m_black, m_alpha); + currentBrush.setColor(clr); + context->platformContext()->setBrush(currentBrush); +#elif PLATFORM(SGL) + context->setCMYKAFillColor(m_cyan, m_magenta, m_yellow, m_black, m_alpha); +#endif + break; + } + case Gradient: + context->setFillGradient(canvasGradient()->gradient()); + break; + case ImagePattern: + context->setFillPattern(canvasPattern()->pattern()); + break; + } +} + +} diff --git a/WebCore/html/CanvasStyle.h b/WebCore/html/CanvasStyle.h new file mode 100644 index 0000000..fe01bd1 --- /dev/null +++ b/WebCore/html/CanvasStyle.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2006, 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 CanvasStyle_h +#define CanvasStyle_h + +#include "PlatformString.h" + +namespace WebCore { + + class CanvasGradient; + class CanvasPattern; + class GraphicsContext; + + class CanvasStyle : public RefCounted<CanvasStyle> { + public: + static PassRefPtr<CanvasStyle> create(const String& color) { return adoptRef(new CanvasStyle(color)); } + static PassRefPtr<CanvasStyle> create(float grayLevel) { return adoptRef(new CanvasStyle(grayLevel)); } + static PassRefPtr<CanvasStyle> create(const String& color, float alpha) { return adoptRef(new CanvasStyle(color, alpha)); } + static PassRefPtr<CanvasStyle> create(float grayLevel, float alpha) { return adoptRef(new CanvasStyle(grayLevel, alpha)); } + static PassRefPtr<CanvasStyle> create(float r, float g, float b, float a) { return adoptRef(new CanvasStyle(r, g, b, a)); } + static PassRefPtr<CanvasStyle> create(float c, float m, float y, float k, float a) { return adoptRef(new CanvasStyle(c, m, y, k, a)); } + static PassRefPtr<CanvasStyle> create(PassRefPtr<CanvasGradient> gradient) { return adoptRef(new CanvasStyle(gradient)); } + static PassRefPtr<CanvasStyle> create(PassRefPtr<CanvasPattern> pattern) { return adoptRef(new CanvasStyle(pattern)); } + + String color() const { return m_color; } + CanvasGradient* canvasGradient() const { return m_gradient.get(); } + CanvasPattern* canvasPattern() const { return m_pattern.get(); } + + void applyFillColor(GraphicsContext*); + void applyStrokeColor(GraphicsContext*); + + private: + CanvasStyle(const String& color); + CanvasStyle(float grayLevel); + CanvasStyle(const String& color, float alpha); + CanvasStyle(float grayLevel, float alpha); + CanvasStyle(float r, float g, float b, float a); + CanvasStyle(float c, float m, float y, float k, float a); + CanvasStyle(PassRefPtr<CanvasGradient>); + CanvasStyle(PassRefPtr<CanvasPattern>); + + enum Type { ColorString, ColorStringWithAlpha, GrayLevel, RGBA, CMYKA, Gradient, ImagePattern }; + + Type m_type; + + String m_color; + RefPtr<CanvasGradient> m_gradient; + RefPtr<CanvasPattern> m_pattern; + + float m_alpha; + + float m_grayLevel; + + float m_red; + float m_green; + float m_blue; + + float m_cyan; + float m_magenta; + float m_yellow; + float m_black; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/html/DocTypeStrings.gperf b/WebCore/html/DocTypeStrings.gperf new file mode 100644 index 0000000..398626e --- /dev/null +++ b/WebCore/html/DocTypeStrings.gperf @@ -0,0 +1,89 @@ +struct PubIDInfo { + enum eMode { + eQuirks, + eQuirks3, + eAlmostStandards + }; + + const char* name; + eMode mode_if_no_sysid; + eMode mode_if_sysid; +} +%% +"+//silmaril//dtd html pro v0r11 19970101//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//advasoft ltd//dtd html 3.0 aswedit + extensions//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//as//dtd html 3.0 aswedit + extensions//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0 level 1//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0 level 2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0 strict level 1//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0 strict level 2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0 strict//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 2.1e//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 3.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 3.0//en//", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 3.2 final//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 3.2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html 3//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 0//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 1//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 1//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 2//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 3//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html level 3//en//3.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 0//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 1//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 1//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 2//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 3//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict level 3//en//3.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html strict//en//3.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html//en//2.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//ietf//dtd html//en//3.0", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//metrius//dtd metrius presentational//en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"-//microsoft//dtd internet explorer 2.0 html strict//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//microsoft//dtd internet explorer 2.0 html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//microsoft//dtd internet explorer 2.0 tables//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//microsoft//dtd internet explorer 3.0 html strict//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//microsoft//dtd internet explorer 3.0 html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//microsoft//dtd internet explorer 3.0 tables//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//netscape comm. corp.//dtd html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//netscape comm. corp.//dtd strict html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//o'reilly and associates//dtd html 2.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//o'reilly and associates//dtd html extended 1.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//o'reilly and associates//dtd html extended relaxed 1.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"-//spyglass//dtd html 2.0 extended//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//sq//dtd html 2.0 hotmetal + extensions//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//sun microsystems corp.//dtd hotjava html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//sun microsystems corp.//dtd hotjava strict html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w30//dtd w3 html 2.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 3 1995-03-24//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 3.2 draft//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 3.2 final//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 3.2//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 3.2s draft//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html 4.0 frameset//en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"-//w3c//dtd html 4.0 transitional//en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"-//w3c//dtd html 4.01 frameset//en", PubIDInfo::eQuirks, PubIDInfo::eAlmostStandards +"-//w3c//dtd html 4.01 transitional//en", PubIDInfo::eQuirks, PubIDInfo::eAlmostStandards +"-//w3c//dtd html experimental 19960712//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd html experimental 970421//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd w3 html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3c//dtd xhtml 1.0 frameset//en", PubIDInfo::eAlmostStandards, PubIDInfo::eAlmostStandards +"-//w3c//dtd xhtml 1.0 transitional//en", PubIDInfo::eAlmostStandards, PubIDInfo::eAlmostStandards +"-//w3o//dtd w3 html 3.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3o//dtd w3 html 3.0//en//", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//w3o//dtd w3 html strict 3.0//en//", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//webtechs//dtd mozilla html 2.0//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-//webtechs//dtd mozilla html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +"-/w3c/dtd html 4.0 transitional/en", PubIDInfo::eQuirks, PubIDInfo::eQuirks +"html", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 diff --git a/WebCore/html/File.cpp b/WebCore/html/File.cpp new file mode 100644 index 0000000..dbbbfa6 --- /dev/null +++ b/WebCore/html/File.cpp @@ -0,0 +1,51 @@ +/* + * 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 "File.h" + +#include "FileSystem.h" +#include "PlatformString.h" + +namespace WebCore { + +File::File(const String& path) + : m_path(path) + , m_fileName(pathGetFileName(path)) +{ +} + +unsigned long long File::fileSize() +{ + // FIXME: Should we cache this? + // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to + // come up with an exception to throw if file size is not represetable. + long long size; + if (!getFileSize(m_path, size)) + return 0; + return size; +} + +} // namespace WebCore diff --git a/WebCore/html/File.h b/WebCore/html/File.h new file mode 100644 index 0000000..7d79aa5 --- /dev/null +++ b/WebCore/html/File.h @@ -0,0 +1,56 @@ +/* + * 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 File_h +#define File_h + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class File : public RefCounted<File> { + public: + static PassRefPtr<File> create(const String& path) + { + return adoptRef(new File(path)); + } + + const String& fileName() const { return m_fileName; } + unsigned long long fileSize(); + + const String& path() const { return m_path; } + + private: + File(const String& path); + + String m_path; + String m_fileName; + }; + +} // namespace WebCore + +#endif // FileList_h diff --git a/WebCore/html/File.idl b/WebCore/html/File.idl new file mode 100644 index 0000000..ada9f0c --- /dev/null +++ b/WebCore/html/File.idl @@ -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 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 html { + + interface [ + GenerateConstructor + ] File { + readonly attribute DOMString fileName; + readonly attribute unsigned long long fileSize; + }; + +} diff --git a/WebCore/html/FileList.cpp b/WebCore/html/FileList.cpp new file mode 100644 index 0000000..ba81087 --- /dev/null +++ b/WebCore/html/FileList.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 "FileList.h" + +#include "File.h" + +namespace WebCore { + +FileList::FileList() +{ +} + +File* FileList::item(unsigned index) const +{ + if (index >= m_files.size()) + return 0; + return m_files[index].get(); +} + +} // namespace WebCore diff --git a/WebCore/html/FileList.h b/WebCore/html/FileList.h new file mode 100644 index 0000000..e078191 --- /dev/null +++ b/WebCore/html/FileList.h @@ -0,0 +1,59 @@ +/* + * 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 FileList_h +#define FileList_h + +#include "File.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class FileList : public RefCounted<FileList> { + public: + static PassRefPtr<FileList> create() + { + return adoptRef(new FileList); + } + + unsigned length() const { return m_files.size(); } + File* item(unsigned index) const; + + bool isEmpty() const { return m_files.isEmpty(); } + void clear() { m_files.clear(); } + void append(PassRefPtr<File> file) { m_files.append(file); } + + private: + FileList(); + + Vector<RefPtr<File> > m_files; + }; + +} // namespace WebCore + +#endif // FileList_h diff --git a/WebCore/html/FileList.idl b/WebCore/html/FileList.idl new file mode 100644 index 0000000..01c286e --- /dev/null +++ b/WebCore/html/FileList.idl @@ -0,0 +1,36 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + HasIndexGetter + ] FileList { + readonly attribute unsigned long length; + File item(in [IsIndex] unsigned long index); + }; + +} diff --git a/WebCore/html/FormDataList.cpp b/WebCore/html/FormDataList.cpp new file mode 100644 index 0000000..281c9fe --- /dev/null +++ b/WebCore/html/FormDataList.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 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 "FormDataList.h" + +namespace WebCore { + +FormDataList::FormDataList(const TextEncoding& c) + : m_encoding(c) +{ +} + +void FormDataList::appendString(const CString& s) +{ + m_list.append(s); +} + +// Change plain CR and plain LF to CRLF pairs. +static CString fixLineBreaks(const CString& s) +{ + // Compute the length. + unsigned newLen = 0; + const char* p = s.data(); + while (char c = *p++) { + if (c == '\r') { + // Safe to look ahead because of trailing '\0'. + if (*p != '\n') { + // Turn CR into CRLF. + newLen += 2; + } + } else if (c == '\n') { + // Turn LF into CRLF. + newLen += 2; + } else { + // Leave other characters alone. + newLen += 1; + } + } + if (newLen == s.length()) { + return s; + } + + // Make a copy of the string. + p = s.data(); + char* q; + CString result = CString::newUninitialized(newLen, q); + while (char c = *p++) { + if (c == '\r') { + // Safe to look ahead because of trailing '\0'. + if (*p != '\n') { + // Turn CR into CRLF. + *q++ = '\r'; + *q++ = '\n'; + } + } else if (c == '\n') { + // Turn LF into CRLF. + *q++ = '\r'; + *q++ = '\n'; + } else { + // Leave other characters alone. + *q++ = c; + } + } + return result; +} + +void FormDataList::appendString(const String& s) +{ + CString cstr = fixLineBreaks(m_encoding.encode(s.characters(), s.length(), EntitiesForUnencodables)); + m_list.append(cstr); +} + +} // namespace diff --git a/WebCore/html/FormDataList.h b/WebCore/html/FormDataList.h new file mode 100644 index 0000000..aec1a52 --- /dev/null +++ b/WebCore/html/FormDataList.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 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 FormDataList_h +#define FormDataList_h + +#include "CString.h" +#include "File.h" +#include "TextEncoding.h" + +namespace WebCore { + +class FormDataList { +public: + FormDataList(const TextEncoding&); + + void appendData(const String& key, const String& value) + { appendString(key); appendString(value); } + void appendData(const String& key, const CString& value) + { appendString(key); appendString(value); } + void appendData(const String& key, int value) + { appendString(key); appendString(String::number(value)); } + void appendFile(const String& key, PassRefPtr<File> file) + { appendString(key); m_list.append(file); } + + class Item { + public: + Item() { } + Item(const CString& data) : m_data(data) { } + Item(PassRefPtr<File> file) : m_file(file) { } + + const CString& data() const { return m_data; } + File* file() const { return m_file.get(); } + + private: + CString m_data; + RefPtr<File> m_file; + }; + + const Vector<Item>& list() const { return m_list; } + +private: + void appendString(const CString&); + void appendString(const String&); + + TextEncoding m_encoding; + Vector<Item> m_list; +}; + +} // namespace WebCore + +#endif // FormDataList_h diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp new file mode 100644 index 0000000..0e09b5d --- /dev/null +++ b/WebCore/html/HTMLAnchorElement.cpp @@ -0,0 +1,508 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Graham Dennis (graham.dennis@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. + */ + +#include "config.h" +#include "HTMLAnchorElement.h" + +#include "CSSHelper.h" +#include "DNS.h" +#include "Document.h" +#include "Event.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "HTMLImageElement.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "MutationEvent.h" +#include "RenderFlow.h" +#include "RenderImage.h" +#include "ResourceRequest.h" +#include "SelectionController.h" +#include "Settings.h" +#include "UIEvent.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLAnchorElement::HTMLAnchorElement(Document* doc) + : HTMLElement(aTag, doc) + , m_rootEditableElementForSelectionOnMouseDown(0) + , m_wasShiftKeyDownOnMouseDown(false) +{ +} + +HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) + , m_rootEditableElementForSelectionOnMouseDown(0) + , m_wasShiftKeyDownOnMouseDown(false) +{ +} + +HTMLAnchorElement::~HTMLAnchorElement() +{ +} + +bool HTMLAnchorElement::supportsFocus() const +{ + if (isContentEditable()) + return HTMLElement::supportsFocus(); + return isFocusable() || (isLink() && document() && !document()->haveStylesheetsLoaded()); +} + +bool HTMLAnchorElement::isFocusable() const +{ + if (isContentEditable()) + return HTMLElement::isFocusable(); + + // FIXME: Even if we are not visible, we might have a child that is visible. + // Dave wants to fix that some day with a "has visible content" flag or the like. + if (!(isLink() && renderer() && renderer()->style()->visibility() == VISIBLE)) + return false; + + return true; +} + +bool HTMLAnchorElement::isMouseFocusable() const +{ +#if PLATFORM(GTK) + return HTMLElement::isMouseFocusable(); +#else + return false; +#endif +} + +bool HTMLAnchorElement::isKeyboardFocusable(KeyboardEvent* event) const +{ + if (!isFocusable()) + return false; + + if (!document()->frame()) + return false; + + if (!document()->frame()->eventHandler()->tabsToLinks(event)) + return false; + + // Before calling absoluteRects, check for the common case where the renderer + // or one of the continuations is non-empty, since this is a faster check and + // almost always returns true. + for (RenderObject* r = renderer(); r; r = r->continuation()) + if (r->width() > 0 && r->height() > 0) + return true; + + Vector<IntRect> rects; + int x, y; + renderer()->absolutePosition(x, y); + renderer()->absoluteRects(rects, x, y); + size_t n = rects.size(); + for (size_t i = 0; i < n; ++i) + if (!rects[i].isEmpty()) + return true; + + return false; +} + +void HTMLAnchorElement::defaultEventHandler(Event* evt) +{ + // React on clicks and on keypresses. + // Don't make this KEYUP_EVENT again, it makes khtml follow links it shouldn't, + // when pressing Enter in the combo. + if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == eventNames().keydownEvent && focused()))) { + MouseEvent* e = 0; + if (evt->type() == eventNames().clickEvent && evt->isMouseEvent()) + e = static_cast<MouseEvent*>(evt); + + KeyboardEvent* k = 0; + if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) + k = static_cast<KeyboardEvent*>(evt); + + if (e && e->button() == RightButton) { + HTMLElement::defaultEventHandler(evt); + return; + } + + // If the link is editable, then we need to check the settings to see whether or not to follow the link + if (isContentEditable()) { + EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; + if (Settings* settings = document()->settings()) + editableLinkBehavior = settings->editableLinkBehavior(); + + switch (editableLinkBehavior) { + // Always follow the link (Safari 2.0 behavior) + default: + case EditableLinkDefaultBehavior: + case EditableLinkAlwaysLive: + break; + + case EditableLinkNeverLive: + HTMLElement::defaultEventHandler(evt); + return; + + // If the selection prior to clicking on this link resided in the same editable block as this link, + // and the shift key isn't pressed, we don't want to follow the link + case EditableLinkLiveWhenNotFocused: + if (e && !e->shiftKey() && m_rootEditableElementForSelectionOnMouseDown == rootEditableElement()) { + HTMLElement::defaultEventHandler(evt); + return; + } + break; + + // Only follow the link if the shift key is down (WinIE/Firefox behavior) + case EditableLinkOnlyLiveWithShiftKey: + if (e && !e->shiftKey()) { + HTMLElement::defaultEventHandler(evt); + return; + } + break; + } + } + + if (k) { + if (k->keyIdentifier() != "Enter") { + HTMLElement::defaultEventHandler(evt); + return; + } + evt->setDefaultHandled(); + dispatchSimulatedClick(evt); + return; + } + + String url = parseURL(getAttribute(hrefAttr)); + + ASSERT(evt->target()); + ASSERT(evt->target()->toNode()); + if (evt->target()->toNode()->hasTagName(imgTag)) { + HTMLImageElement* img = static_cast<HTMLImageElement*>(evt->target()->toNode()); + if (img && img->isServerMap()) { + RenderImage* r = static_cast<RenderImage*>(img->renderer()); + if (r && e) { + int absx, absy; + r->absolutePosition(absx, absy); + int x = e->pageX() - absx; + int y = e->pageY() - absy; + url += "?"; + url += String::number(x); + url += ","; + url += String::number(y); + } else { + evt->setDefaultHandled(); + HTMLElement::defaultEventHandler(evt); + return; + } + } + } + + if (!evt->defaultPrevented() && document()->frame()) + document()->frame()->loader()->urlSelected(document()->completeURL(url), getAttribute(targetAttr), evt, false, true); + + evt->setDefaultHandled(); + } else if (isLink() && isContentEditable()) { + // This keeps track of the editable block that the selection was in (if it was in one) just before the link was clicked + // for the LiveWhenNotFocused editable link behavior + if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() != RightButton && document()->frame() && document()->frame()->selection()) { + MouseEvent* e = static_cast<MouseEvent*>(evt); + + m_rootEditableElementForSelectionOnMouseDown = document()->frame()->selection()->rootEditableElement(); + m_wasShiftKeyDownOnMouseDown = e && e->shiftKey(); + } else if (evt->type() == eventNames().mouseoverEvent) { + // These are cleared on mouseover and not mouseout because their values are needed for drag events, but these happen + // after mouse out events. + m_rootEditableElementForSelectionOnMouseDown = 0; + m_wasShiftKeyDownOnMouseDown = false; + } + } + + HTMLElement::defaultEventHandler(evt); +} + +void HTMLAnchorElement::setActive(bool down, bool pause) +{ + if (isContentEditable()) { + EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; + if (Settings* settings = document()->settings()) + editableLinkBehavior = settings->editableLinkBehavior(); + + switch(editableLinkBehavior) { + default: + case EditableLinkDefaultBehavior: + case EditableLinkAlwaysLive: + break; + + case EditableLinkNeverLive: + return; + + // Don't set the link to be active if the current selection is in the same editable block as + // this link + case EditableLinkLiveWhenNotFocused: + if (down && document()->frame() && document()->frame()->selection() && + document()->frame()->selection()->rootEditableElement() == rootEditableElement()) + return; + break; + + case EditableLinkOnlyLiveWithShiftKey: + return; + } + + } + + ContainerNode::setActive(down, pause); +} + +void HTMLAnchorElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == hrefAttr) { + bool wasLink = isLink(); + setIsLink(!attr->isNull()); + if (wasLink != isLink()) + setChanged(); + if (isLink() && document()->isDNSPrefetchEnabled()) { + String value = attr->value(); + if (protocolIs(value, "http") || protocolIs(value, "https") || value.startsWith("//")) + prefetchDNS(document()->completeURL(value).host()); + } + } else if (attr->name() == nameAttr || + attr->name() == titleAttr || + attr->name() == relAttr) { + // Do nothing. + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLAnchorElement::accessKeyAction(bool sendToAnyElement) +{ + // send the mouse button events if the caller specified sendToAnyElement + dispatchSimulatedClick(0, sendToAnyElement); +} + +bool HTMLAnchorElement::isURLAttribute(Attribute *attr) const +{ + return attr->name() == hrefAttr; +} + +bool HTMLAnchorElement::canStartSelection() const +{ + // FIXME: We probably want this same behavior in SVGAElement too + if (!isLink()) + return HTMLElement::canStartSelection(); + return isContentEditable(); +} + +String HTMLAnchorElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLAnchorElement::setAccessKey(const String &value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLAnchorElement::charset() const +{ + return getAttribute(charsetAttr); +} + +void HTMLAnchorElement::setCharset(const String &value) +{ + setAttribute(charsetAttr, value); +} + +String HTMLAnchorElement::coords() const +{ + return getAttribute(coordsAttr); +} + +void HTMLAnchorElement::setCoords(const String &value) +{ + setAttribute(coordsAttr, value); +} + +KURL HTMLAnchorElement::href() const +{ + return document()->completeURL(getAttribute(hrefAttr)); +} + +void HTMLAnchorElement::setHref(const String &value) +{ + setAttribute(hrefAttr, value); +} + +String HTMLAnchorElement::hreflang() const +{ + return getAttribute(hreflangAttr); +} + +void HTMLAnchorElement::setHreflang(const String &value) +{ + setAttribute(hreflangAttr, value); +} + +String HTMLAnchorElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLAnchorElement::setName(const String &value) +{ + setAttribute(nameAttr, value); +} + +String HTMLAnchorElement::rel() const +{ + return getAttribute(relAttr); +} + +void HTMLAnchorElement::setRel(const String &value) +{ + setAttribute(relAttr, value); +} + +String HTMLAnchorElement::rev() const +{ + return getAttribute(revAttr); +} + +void HTMLAnchorElement::setRev(const String &value) +{ + setAttribute(revAttr, value); +} + +String HTMLAnchorElement::shape() const +{ + return getAttribute(shapeAttr); +} + +void HTMLAnchorElement::setShape(const String &value) +{ + setAttribute(shapeAttr, value); +} + +short HTMLAnchorElement::tabIndex() const +{ + // Skip the supportsFocus check in HTMLElement. + return Element::tabIndex(); +} + +String HTMLAnchorElement::target() const +{ + return getAttribute(targetAttr); +} + +void HTMLAnchorElement::setTarget(const String &value) +{ + setAttribute(targetAttr, value); +} + +String HTMLAnchorElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLAnchorElement::setType(const String &value) +{ + setAttribute(typeAttr, value); +} + +String HTMLAnchorElement::hash() const +{ + return "#" + href().ref(); +} + +String HTMLAnchorElement::host() const +{ + return href().host(); +} + +String HTMLAnchorElement::hostname() const +{ + const KURL& url = href(); + if (url.port() == 0) + return url.host(); + return url.host() + ":" + String::number(url.port()); +} + +String HTMLAnchorElement::pathname() const +{ + return href().path(); +} + +String HTMLAnchorElement::port() const +{ + return String::number(href().port()); +} + +String HTMLAnchorElement::protocol() const +{ + return href().protocol() + ":"; +} + +String HTMLAnchorElement::search() const +{ + return href().query(); +} + +String HTMLAnchorElement::text() const +{ + return innerText(); +} + +String HTMLAnchorElement::toString() const +{ + return href().string(); +} + +bool HTMLAnchorElement::isLiveLink() const +{ + if (!isLink()) + return false; + if (!isContentEditable()) + return true; + + EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; + if (Settings* settings = document()->settings()) + editableLinkBehavior = settings->editableLinkBehavior(); + + switch(editableLinkBehavior) { + default: + case EditableLinkDefaultBehavior: + case EditableLinkAlwaysLive: + return true; + + case EditableLinkNeverLive: + return false; + + // Don't set the link to be live if the current selection is in the same editable block as + // this link or if the shift key is down + case EditableLinkLiveWhenNotFocused: + return m_wasShiftKeyDownOnMouseDown || m_rootEditableElementForSelectionOnMouseDown != rootEditableElement(); + + case EditableLinkOnlyLiveWithShiftKey: + return m_wasShiftKeyDownOnMouseDown; + } +} + +} diff --git a/WebCore/html/HTMLAnchorElement.h b/WebCore/html/HTMLAnchorElement.h new file mode 100644 index 0000000..2457acb --- /dev/null +++ b/WebCore/html/HTMLAnchorElement.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 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 HTMLAnchorElement_h +#define HTMLAnchorElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLAnchorElement : public HTMLElement { +public: + HTMLAnchorElement(Document*); + HTMLAnchorElement(const QualifiedName&, Document*); + ~HTMLAnchorElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + virtual bool supportsFocus() const; + virtual bool isMouseFocusable() const; + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isFocusable() const; + virtual void parseMappedAttribute(MappedAttribute*); + virtual void defaultEventHandler(Event*); + virtual void setActive(bool active = true, bool pause = false); + virtual void accessKeyAction(bool fullAction); + virtual bool isURLAttribute(Attribute*) const; + + virtual bool canStartSelection() const; + + String accessKey() const; + void setAccessKey(const String&); + + String charset() const; + void setCharset(const String&); + + String coords() const; + void setCoords(const String&); + + KURL href() const; + void setHref(const String&); + + String hreflang() const; + void setHreflang(const String&); + + String name() const; + void setName(const String&); + + String rel() const; + void setRel(const String&); + + String rev() const; + void setRev(const String&); + + String shape() const; + void setShape(const String&); + + virtual short tabIndex() const; + + virtual String target() const; + void setTarget(const String&); + + String type() const; + void setType(const String&); + + String hash() const; + String host() const; + String hostname() const; + String pathname() const; + String port() const; + String protocol() const; + String search() const; + String text() const; + + String toString() const; + + bool isLiveLink() const; + +private: + Element* m_rootEditableElementForSelectionOnMouseDown; + bool m_wasShiftKeyDownOnMouseDown; +}; + +} // namespace WebCore + +#endif // HTMLAnchorElement_h diff --git a/WebCore/html/HTMLAnchorElement.idl b/WebCore/html/HTMLAnchorElement.idl new file mode 100644 index 0000000..f3a15ee --- /dev/null +++ b/WebCore/html/HTMLAnchorElement.idl @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=0c74cef8-b1f7-4b44-83a9-8deeb376a257, + ImplementationUUID=30f797d5-d145-498e-a126-d8e9ddeedea3 + ] HTMLAnchorElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString accessKey; + attribute [ConvertNullToNullString] DOMString charset; + attribute [ConvertNullToNullString] DOMString coords; + attribute [ConvertNullToNullString] DOMString href; + attribute [ConvertNullToNullString] DOMString hreflang; + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString rel; + attribute [ConvertNullToNullString] DOMString rev; + attribute [ConvertNullToNullString] DOMString shape; + attribute [ConvertNullToNullString] DOMString target; + attribute [ConvertNullToNullString] DOMString type; + + // IE Extensions + readonly attribute DOMString hash; + readonly attribute DOMString host; + readonly attribute DOMString hostname; + readonly attribute DOMString pathname; + readonly attribute DOMString port; + readonly attribute DOMString protocol; + readonly attribute DOMString search; + readonly attribute DOMString text; + +#if defined(LANGUAGE_JAVASCRIPT) + [DontEnum] DOMString toString(); +#endif + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute URL absoluteLinkURL; +#endif + }; + +} diff --git a/WebCore/html/HTMLAppletElement.cpp b/WebCore/html/HTMLAppletElement.cpp new file mode 100644 index 0000000..bdb1cca --- /dev/null +++ b/WebCore/html/HTMLAppletElement.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * 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. + */ + +#include "config.h" +#include "HTMLAppletElement.h" + +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLNames.h" +#include "RenderApplet.h" +#include "RenderInline.h" +#include "Settings.h" +#include "ScriptController.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLAppletElement::HTMLAppletElement(Document* doc) + : HTMLPlugInElement(appletTag, doc) +{ +} + +HTMLAppletElement::~HTMLAppletElement() +{ +} + +void HTMLAppletElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == altAttr || + attr->name() == archiveAttr || + attr->name() == codeAttr || + attr->name() == codebaseAttr || + attr->name() == mayscriptAttr || + attr->name() == objectAttr) { + // Do nothing. + } else if (attr->name() == nameAttr) { + const AtomicString& newName = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(newName); + } + m_name = newName; + } else if (attr->name() == idAttr) { + const AtomicString& newId = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeExtraNamedItem(m_id); + document->addExtraNamedItem(newId); + } + m_id = newId; + // also call superclass + HTMLPlugInElement::parseMappedAttribute(attr); + } else + HTMLPlugInElement::parseMappedAttribute(attr); +} + +void HTMLAppletElement::insertedIntoDocument() +{ + if (document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } + + HTMLPlugInElement::insertedIntoDocument(); +} + +void HTMLAppletElement::removedFromDocument() +{ + if (document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + + HTMLPlugInElement::removedFromDocument(); +} + +bool HTMLAppletElement::rendererIsNeeded(RenderStyle* style) +{ + return !getAttribute(codeAttr).isNull(); +} + +RenderObject* HTMLAppletElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + Settings* settings = document()->settings(); + + if (settings && settings->isJavaEnabled()) { + HashMap<String, String> args; + + args.set("code", getAttribute(codeAttr)); + const AtomicString& codeBase = getAttribute(codebaseAttr); + if(!codeBase.isNull()) + args.set("codeBase", codeBase); + const AtomicString& name = getAttribute(document()->isHTMLDocument() ? nameAttr : idAttr); + if (!name.isNull()) + args.set("name", name); + const AtomicString& archive = getAttribute(archiveAttr); + if (!archive.isNull()) + args.set("archive", archive); + + args.set("baseURL", document()->baseURL().string()); + + const AtomicString& mayScript = getAttribute(mayscriptAttr); + if (!mayScript.isNull()) + args.set("mayScript", mayScript); + + // Other arguments (from <PARAM> tags) are added later. + + return new (document()->renderArena()) RenderApplet(this, args); + } + + return RenderObject::createObject(this, style); +} + +RenderWidget* HTMLAppletElement::renderWidgetForJSBindings() const +{ + Settings* settings = document()->settings(); + if (!settings || !settings->isJavaEnabled()) + return 0; + + RenderApplet* applet = static_cast<RenderApplet*>(renderer()); + if (applet) + applet->createWidgetIfNecessary(); + + return applet; +} + +void HTMLAppletElement::finishParsingChildren() +{ + // The parser just reached </applet>, so all the params are available now. + HTMLPlugInElement::finishParsingChildren(); + if (renderer()) + renderer()->setNeedsLayout(true); // This will cause it to create its widget & the Java applet +} + +String HTMLAppletElement::alt() const +{ + return getAttribute(altAttr); +} + +void HTMLAppletElement::setAlt(const String &value) +{ + setAttribute(altAttr, value); +} + +String HTMLAppletElement::archive() const +{ + return getAttribute(archiveAttr); +} + +void HTMLAppletElement::setArchive(const String &value) +{ + setAttribute(archiveAttr, value); +} + +String HTMLAppletElement::code() const +{ + return getAttribute(codeAttr); +} + +void HTMLAppletElement::setCode(const String &value) +{ + setAttribute(codeAttr, value); +} + +String HTMLAppletElement::codeBase() const +{ + return getAttribute(codebaseAttr); +} + +void HTMLAppletElement::setCodeBase(const String &value) +{ + setAttribute(codebaseAttr, value); +} + +String HTMLAppletElement::hspace() const +{ + return getAttribute(hspaceAttr); +} + +void HTMLAppletElement::setHspace(const String &value) +{ + setAttribute(hspaceAttr, value); +} + +String HTMLAppletElement::object() const +{ + return getAttribute(objectAttr); +} + +void HTMLAppletElement::setObject(const String &value) +{ + setAttribute(objectAttr, value); +} + +String HTMLAppletElement::vspace() const +{ + return getAttribute(vspaceAttr); +} + +void HTMLAppletElement::setVspace(const String &value) +{ + setAttribute(vspaceAttr, value); +} + +} diff --git a/WebCore/html/HTMLAppletElement.h b/WebCore/html/HTMLAppletElement.h new file mode 100644 index 0000000..6c23170 --- /dev/null +++ b/WebCore/html/HTMLAppletElement.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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 HTMLAppletElement_h +#define HTMLAppletElement_h + +#include "HTMLPlugInElement.h" + +namespace WebCore { + +class HTMLFormElement; +class HTMLImageLoader; + +class HTMLAppletElement : public HTMLPlugInElement +{ +public: + HTMLAppletElement(Document*); + ~HTMLAppletElement(); + + virtual int tagPriority() const { return 1; } + + virtual void parseMappedAttribute(MappedAttribute*); + + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void finishParsingChildren(); + + virtual RenderWidget* renderWidgetForJSBindings() const; + + String alt() const; + void setAlt(const String&); + + String archive() const; + void setArchive(const String&); + + String code() const; + void setCode(const String&); + + String codeBase() const; + void setCodeBase(const String&); + + String hspace() const; + void setHspace(const String&); + + String object() const; + void setObject(const String&); + + String vspace() const; + void setVspace(const String&); + + void setupApplet() const; + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + +private: + AtomicString m_id; +}; + +} + +#endif diff --git a/WebCore/html/HTMLAppletElement.idl b/WebCore/html/HTMLAppletElement.idl new file mode 100644 index 0000000..794f000 --- /dev/null +++ b/WebCore/html/HTMLAppletElement.idl @@ -0,0 +1,53 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + CustomPutFunction, + CustomGetOwnPropertySlot, + CustomCall, + HasOverridingNameGetter, + InterfaceUUID=9b5cb4a8-c156-4b55-afdb-c60938a4d1b1, + ImplementationUUID=56544372-675e-40dd-ba39-fa708a4c7678 + ] HTMLAppletElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString alt; + attribute [ConvertNullToNullString] DOMString archive; + attribute [ConvertNullToNullString] DOMString code; + attribute [ConvertNullToNullString] DOMString codeBase; + attribute [ConvertNullToNullString] DOMString height; +#if defined(LANGUAGE_JAVASCRIPT) + attribute [ConvertNullToNullString] DOMString hspace; +#else + attribute [ConvertFromString] long hspace; +#endif + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString object; +#if defined(LANGUAGE_JAVASCRIPT) + attribute [ConvertNullToNullString] DOMString vspace; +#else + attribute [ConvertFromString] long vspace; +#endif + attribute [ConvertNullToNullString] DOMString width; + }; + +} diff --git a/WebCore/html/HTMLAreaElement.cpp b/WebCore/html/HTMLAreaElement.cpp new file mode 100644 index 0000000..a865122 --- /dev/null +++ b/WebCore/html/HTMLAreaElement.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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 "HTMLAreaElement.h" + +#include "Document.h" +#include "FloatRect.h" +#include "HTMLNames.h" +#include "HitTestResult.h" +#include "Length.h" +#include "RenderObject.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLAreaElement::HTMLAreaElement(Document *doc) + : HTMLAnchorElement(areaTag, doc) + , m_coords(0) + , m_coordsLen(0) + , m_lastSize(-1, -1) + , m_shape(Unknown) +{ +} + +HTMLAreaElement::~HTMLAreaElement() +{ + delete [] m_coords; +} + +void HTMLAreaElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == shapeAttr) { + if (equalIgnoringCase(attr->value(), "default")) + m_shape = Default; + else if (equalIgnoringCase(attr->value(), "circle")) + m_shape = Circle; + else if (equalIgnoringCase(attr->value(), "poly")) + m_shape = Poly; + else if (equalIgnoringCase(attr->value(), "rect")) + m_shape = Rect; + } else if (attr->name() == coordsAttr) { + delete [] m_coords; + m_coords = newCoordsArray(attr->value().string(), m_coordsLen); + } else if (attr->name() == altAttr || attr->name() == accesskeyAttr) { + // Do nothing. + } else + HTMLAnchorElement::parseMappedAttribute(attr); +} + +bool HTMLAreaElement::mapMouseEvent(int x, int y, const IntSize& size, HitTestResult& result) +{ + if (m_lastSize != size) { + region = getRegion(size); + m_lastSize = size; + } + + if (!region.contains(IntPoint(x, y))) + return false; + + result.setInnerNode(this); + result.setURLElement(this); + return true; +} + +IntRect HTMLAreaElement::getRect(RenderObject* obj) const +{ + int dx, dy; + obj->absolutePosition(dx, dy); + Path p = getRegion(m_lastSize); + p.translate(IntSize(dx, dy)); + return enclosingIntRect(p.boundingRect()); +} + +Path HTMLAreaElement::getRegion(const IntSize& size) const +{ + if (!m_coords && m_shape != Default) + return Path(); + + int width = size.width(); + int height = size.height(); + + // If element omits the shape attribute, select shape based on number of coordinates. + Shape shape = m_shape; + if (shape == Unknown) { + if (m_coordsLen == 3) + shape = Circle; + else if (m_coordsLen == 4) + shape = Rect; + else if (m_coordsLen >= 6) + shape = Poly; + } + + Path path; + switch (shape) { + case Poly: + if (m_coordsLen >= 6) { + int numPoints = m_coordsLen / 2; + path.moveTo(FloatPoint(m_coords[0].calcMinValue(width), m_coords[1].calcMinValue(height))); + for (int i = 1; i < numPoints; ++i) + path.addLineTo(FloatPoint(m_coords[i * 2].calcMinValue(width), m_coords[i * 2 + 1].calcMinValue(height))); + path.closeSubpath(); + } + break; + case Circle: + if (m_coordsLen >= 3) { + Length radius = m_coords[2]; + int r = min(radius.calcMinValue(width), radius.calcMinValue(height)); + path.addEllipse(FloatRect(m_coords[0].calcMinValue(width) - r, m_coords[1].calcMinValue(height) - r, 2 * r, 2 * r)); + } + break; + case Rect: + if (m_coordsLen >= 4) { + int x0 = m_coords[0].calcMinValue(width); + int y0 = m_coords[1].calcMinValue(height); + int x1 = m_coords[2].calcMinValue(width); + int y1 = m_coords[3].calcMinValue(height); + path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0)); + } + break; + case Default: + path.addRect(FloatRect(0, 0, width, height)); + break; + case Unknown: + break; + } + + return path; +} + +String HTMLAreaElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLAreaElement::setAccessKey(const String& value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLAreaElement::alt() const +{ + return getAttribute(altAttr); +} + +void HTMLAreaElement::setAlt(const String& value) +{ + setAttribute(altAttr, value); +} + +String HTMLAreaElement::coords() const +{ + return getAttribute(coordsAttr); +} + +void HTMLAreaElement::setCoords(const String& value) +{ + setAttribute(coordsAttr, value); +} + +KURL HTMLAreaElement::href() const +{ + return document()->completeURL(getAttribute(hrefAttr)); +} + +void HTMLAreaElement::setHref(const String& value) +{ + setAttribute(hrefAttr, value); +} + +bool HTMLAreaElement::noHref() const +{ + return !getAttribute(nohrefAttr).isNull(); +} + +void HTMLAreaElement::setNoHref(bool noHref) +{ + setAttribute(nohrefAttr, noHref ? "" : 0); +} + +String HTMLAreaElement::shape() const +{ + return getAttribute(shapeAttr); +} + +void HTMLAreaElement::setShape(const String& value) +{ + setAttribute(shapeAttr, value); +} + +bool HTMLAreaElement::isFocusable() const +{ + return HTMLElement::isFocusable(); +} + +String HTMLAreaElement::target() const +{ + return getAttribute(targetAttr); +} + +void HTMLAreaElement::setTarget(const String& value) +{ + setAttribute(targetAttr, value); +} + +} diff --git a/WebCore/html/HTMLAreaElement.h b/WebCore/html/HTMLAreaElement.h new file mode 100644 index 0000000..986116b --- /dev/null +++ b/WebCore/html/HTMLAreaElement.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 HTMLAreaElement_h +#define HTMLAreaElement_h + +#include "HTMLAnchorElement.h" +#include "IntSize.h" +#include "Path.h" + +namespace WebCore { + +class HitTestResult; + +class HTMLAreaElement : public HTMLAnchorElement { +public: + HTMLAreaElement(Document*); + ~HTMLAreaElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void parseMappedAttribute(MappedAttribute*); + + bool isDefault() const { return m_shape == Default; } + + bool mapMouseEvent(int x, int y, const IntSize&, HitTestResult&); + + virtual IntRect getRect(RenderObject*) const; + + String accessKey() const; + void setAccessKey(const String&); + + String alt() const; + void setAlt(const String&); + + String coords() const; + void setCoords(const String&); + + KURL href() const; + void setHref(const String&); + + bool noHref() const; + void setNoHref(bool); + + String shape() const; + void setShape(const String&); + + virtual bool isFocusable() const; + + virtual String target() const; + void setTarget(const String&); + +private: + enum Shape { Default, Poly, Rect, Circle, Unknown }; + Path getRegion(const IntSize&) const; + Path region; + Length* m_coords; + int m_coordsLen; + IntSize m_lastSize; + Shape m_shape; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLAreaElement.idl b/WebCore/html/HTMLAreaElement.idl new file mode 100644 index 0000000..39cc719 --- /dev/null +++ b/WebCore/html/HTMLAreaElement.idl @@ -0,0 +1,51 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=aac98729-47d3-4623-8c5b-004783af5bd6, + ImplementationUUID=f0631a41-5f55-40e5-a879-c09e663c26ba + ] HTMLAreaElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString accessKey; + attribute [ConvertNullToNullString] DOMString alt; + attribute [ConvertNullToNullString] DOMString coords; + attribute [ConvertNullToNullString] DOMString href; + attribute boolean noHref; + attribute [ConvertNullToNullString] DOMString shape; + attribute [ConvertNullToNullString] DOMString target; + + // IE Extensions + readonly attribute DOMString hash; + readonly attribute DOMString host; + readonly attribute DOMString hostname; + readonly attribute DOMString pathname; + readonly attribute DOMString port; + readonly attribute DOMString protocol; + readonly attribute DOMString search; + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute URL absoluteLinkURL; +#endif + }; + +} diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in new file mode 100644 index 0000000..3b70aee --- /dev/null +++ b/WebCore/html/HTMLAttributeNames.in @@ -0,0 +1,215 @@ +namespace="HTML" +namespacePrefix="xhtml" +namespaceURI="http://www.w3.org/1999/xhtml" +attrsNullNamespace="1" + +abbr +accept_charset +accept +accesskey +action +align +alink +alt +archive +aria-activedescendant +aria-checked +aria-describedby +aria-labeledby +aria-labelledby +aria-level +aria-pressed +aria-valuemax +aria-valuemin +aria-valuenow +autocomplete +autofocus +autoplay +autosave +axis +background +behavior +bgcolor +bgproperties +border +bordercolor +cellpadding +cellspacing +char +challenge +charoff +charset +checked +cellborder +cite +class exportString="1" +classid +clear +code +codebase +codetype +color +cols +colspan +compact +composite +content +contenteditable +controls +coords +data +datetime +declare +defer +dir +direction +disabled +enctype +end +face +for +frame +frameborder +headers +height +hidden +href +hreflang +hspace +http_equiv +id +incremental +ismap +keytype +label +lang +language +left +leftmargin +link +longdesc +loop +playcount +loopend +loopstart +lowsrc +manifest +marginheight +marginwidth +max +maxlength +mayscript +media +method +min +multiple +name +nohref +noresize +noshade +nowrap +object +onabort +onbeforecopy +onbeforecut +onbeforepaste +onbeforeunload +onblur +onchange +onclick +oncontextmenu +oncopy +oncut +ondblclick +ondrag +ondragend +ondragenter +ondragleave +ondragover +ondragstart +ondrop +onerror +onfocus +oninput +onkeydown +onkeypress +onkeyup +onload +onmousedown +onmousemove +onmouseout +onmouseover +onmouseup +onmousewheel +onpaste +onreset +onresize +onscroll +onsearch +onselect +onselectstart +onstorage +onsubmit +/* #if ENABLE(TOUCH_EVENTS) // Android */ +ontouchstart +ontouchmove +ontouchend +ontouchcancel +/* #endif */ +onunload +onwebkitanimationstart +onwebkitanimationiteration +onwebkitanimationend +onwebkittransitionend +pagex +pagey +placeholder +plain +pluginpage +pluginspage +pluginurl +poster +precision +profile +prompt +readonly +rel +results +rev +role +rows +rowspan +rules +scheme +scope +scrollamount +scrolldelay +scrolling +selected +shape +size +span +src +standby +start +style +summary +tabindex +tableborder +target +text +title +top +topmargin +truespeed +type +usemap +valign +value +valuetype +version +viewsource +vlink +vspace +width +wrap diff --git a/WebCore/html/HTMLAudioElement.cpp b/WebCore/html/HTMLAudioElement.cpp new file mode 100644 index 0000000..101eb3e --- /dev/null +++ b/WebCore/html/HTMLAudioElement.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 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. + */ + +#include "config.h" + +#if ENABLE(VIDEO) +#include "HTMLAudioElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLAudioElement::HTMLAudioElement(Document* doc) + : HTMLMediaElement(HTMLNames::audioTag, doc) +{ +} + +} +#endif diff --git a/WebCore/html/HTMLAudioElement.h b/WebCore/html/HTMLAudioElement.h new file mode 100644 index 0000000..7796af8 --- /dev/null +++ b/WebCore/html/HTMLAudioElement.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 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. + */ + +#ifndef HTMLAudioElement_h +#define HTMLAudioElement_h + +#if ENABLE(VIDEO) + +#include "HTMLMediaElement.h" + +namespace WebCore { + +class HTMLAudioElement : public HTMLMediaElement +{ +public: + HTMLAudioElement(Document*); + + virtual int tagPriority() const { return 5; } +}; + +} //namespace + +#endif +#endif diff --git a/WebCore/html/HTMLAudioElement.idl b/WebCore/html/HTMLAudioElement.idl new file mode 100644 index 0000000..f335d86 --- /dev/null +++ b/WebCore/html/HTMLAudioElement.idl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 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 html { + interface [GenerateConstructor, Conditional=VIDEO] HTMLAudioElement : HTMLMediaElement { + + }; +} diff --git a/WebCore/html/HTMLBRElement.cpp b/WebCore/html/HTMLBRElement.cpp new file mode 100644 index 0000000..75ee30c --- /dev/null +++ b/WebCore/html/HTMLBRElement.cpp @@ -0,0 +1,87 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 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 "HTMLBRElement.h" + +#include "CSSPropertyNames.h" +#include "HTMLNames.h" +#include "RenderBR.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLBRElement::HTMLBRElement(Document *doc) : HTMLElement(brTag, doc) +{ +} + +HTMLBRElement::~HTMLBRElement() +{ +} + +bool HTMLBRElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == clearAttr) { + result = eUniversal; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLBRElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == clearAttr) { + // If the string is empty, then don't add the clear property. + // <br clear> and <br clear=""> are just treated like <br> by Gecko, Mac IE, etc. -dwh + const AtomicString& str = attr->value(); + if (!str.isEmpty()) { + if (equalIgnoringCase(str, "all")) + addCSSProperty(attr, CSSPropertyClear, "both"); + else + addCSSProperty(attr, CSSPropertyClear, str); + } + } else + HTMLElement::parseMappedAttribute(attr); +} + +RenderObject* HTMLBRElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (style->contentData()) + return RenderObject::createObject(this, style); + + return new (arena) RenderBR(this); +} + +String HTMLBRElement::clear() const +{ + return getAttribute(clearAttr); +} + +void HTMLBRElement::setClear(const String &value) +{ + setAttribute(clearAttr, value); +} + +} diff --git a/WebCore/html/HTMLBRElement.h b/WebCore/html/HTMLBRElement.h new file mode 100644 index 0000000..c3d6439 --- /dev/null +++ b/WebCore/html/HTMLBRElement.h @@ -0,0 +1,53 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ +#ifndef HTMLBRElement_h +#define HTMLBRElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class String; + +class HTMLBRElement : public HTMLElement +{ +public: + HTMLBRElement(Document*); + ~HTMLBRElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute *attr); + + virtual RenderObject *createRenderer(RenderArena*, RenderStyle*); + + String clear() const; + void setClear(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLBRElement.idl b/WebCore/html/HTMLBRElement.idl new file mode 100644 index 0000000..79e05ed --- /dev/null +++ b/WebCore/html/HTMLBRElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=e84b14bc-b0aa-431f-83c4-fcc297e354b0, + ImplementationUUID=c10d45a4-b042-45d0-b170-6ac7173ee823 + ] HTMLBRElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString clear; + }; + +} diff --git a/WebCore/html/HTMLBaseElement.cpp b/WebCore/html/HTMLBaseElement.cpp new file mode 100644 index 0000000..4de62f9 --- /dev/null +++ b/WebCore/html/HTMLBaseElement.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 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 "HTMLBaseElement.h" + +#include "CSSHelper.h" +#include "Document.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLNames.h" +#include "KURL.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLBaseElement::HTMLBaseElement(Document* doc) + : HTMLElement(baseTag, doc) +{ +} + +HTMLBaseElement::~HTMLBaseElement() +{ +} + +void HTMLBaseElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == hrefAttr) { + m_href = parseURL(attr->value()); + process(); + } else if (attr->name() == targetAttr) { + m_target = attr->value(); + process(); + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLBaseElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + process(); +} + +void HTMLBaseElement::removedFromDocument() +{ + HTMLElement::removedFromDocument(); + + // Since the document doesn't have a base element... + // (This will break in the case of multiple base elements, but that's not valid anyway (?)) + document()->setBaseElementURL(KURL()); + document()->setBaseElementTarget(String()); +} + +void HTMLBaseElement::process() +{ + if (!inDocument()) + return; + + if (!m_href.isEmpty()) + document()->setBaseElementURL(KURL(document()->url(), m_href)); + + if (!m_target.isEmpty()) + document()->setBaseElementTarget(m_target); + + // ### should changing a document's base URL dynamically automatically update all images, stylesheets etc? +} + +void HTMLBaseElement::setHref(const String &value) +{ + setAttribute(hrefAttr, value); +} + +void HTMLBaseElement::setTarget(const String &value) +{ + setAttribute(targetAttr, value); +} + +} diff --git a/WebCore/html/HTMLBaseElement.h b/WebCore/html/HTMLBaseElement.h new file mode 100644 index 0000000..66cc49a --- /dev/null +++ b/WebCore/html/HTMLBaseElement.h @@ -0,0 +1,59 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 HTMLBaseElement_h +#define HTMLBaseElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLBaseElement : public HTMLElement +{ +public: + HTMLBaseElement(Document*); + ~HTMLBaseElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + String href() const { return m_href; } + virtual String target() const { return m_target; } + + virtual void parseMappedAttribute(MappedAttribute*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + void process(); + + void setHref(const String&); + void setTarget(const String&); + +protected: + String m_href; + String m_target; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLBaseElement.idl b/WebCore/html/HTMLBaseElement.idl new file mode 100644 index 0000000..76025fa --- /dev/null +++ b/WebCore/html/HTMLBaseElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=e4112bea-13de-40f6-93d0-41e285ae1491, + ImplementationUUID=23cec074-660f-490a-996d-167d66c164d5 + ] HTMLBaseElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString href; + attribute [ConvertNullToNullString] DOMString target; + }; + +} diff --git a/WebCore/html/HTMLBaseFontElement.cpp b/WebCore/html/HTMLBaseFontElement.cpp new file mode 100644 index 0000000..114f250 --- /dev/null +++ b/WebCore/html/HTMLBaseFontElement.cpp @@ -0,0 +1,67 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLBaseFontElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLBaseFontElement::HTMLBaseFontElement(Document *doc) + : HTMLElement(basefontTag, doc) +{ +} + +String HTMLBaseFontElement::color() const +{ + return getAttribute(colorAttr); +} + +void HTMLBaseFontElement::setColor(const String &value) +{ + setAttribute(colorAttr, value); +} + +String HTMLBaseFontElement::face() const +{ + return getAttribute(faceAttr); +} + +void HTMLBaseFontElement::setFace(const String &value) +{ + setAttribute(faceAttr, value); +} + +int HTMLBaseFontElement::size() const +{ + return getAttribute(sizeAttr).toInt(); +} + +void HTMLBaseFontElement::setSize(int value) +{ + setAttribute(sizeAttr, String::number(value)); +} + +} diff --git a/WebCore/html/HTMLBaseFontElement.h b/WebCore/html/HTMLBaseFontElement.h new file mode 100644 index 0000000..f7e9320 --- /dev/null +++ b/WebCore/html/HTMLBaseFontElement.h @@ -0,0 +1,51 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLBaseFontElement_h +#define HTMLBaseFontElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLBaseFontElement : public HTMLElement +{ +public: + HTMLBaseFontElement(Document *doc); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + String color() const; + void setColor(const String &); + + String face() const; + void setFace(const String &); + + int size() const; + void setSize(int); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLBaseFontElement.idl b/WebCore/html/HTMLBaseFontElement.idl new file mode 100644 index 0000000..a94f3ab --- /dev/null +++ b/WebCore/html/HTMLBaseFontElement.idl @@ -0,0 +1,35 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=434b1be5-408e-45b5-be83-c70e11e9bb37, + ImplementationUUID=1dc8508e-53c4-4e7e-93c0-16772372b2dc + ] HTMLBaseFontElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString color; + attribute [ConvertNullToNullString] DOMString face; +#if defined(LANGUAGE_OBJECTIVE_C) + attribute [ConvertToString] DOMString size; // this changed to a long, but our existing API is a string +#else + attribute long size; +#endif + }; +} diff --git a/WebCore/html/HTMLBlockquoteElement.cpp b/WebCore/html/HTMLBlockquoteElement.cpp new file mode 100644 index 0000000..877eb34 --- /dev/null +++ b/WebCore/html/HTMLBlockquoteElement.cpp @@ -0,0 +1,52 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLBlockquoteElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLBlockquoteElement::HTMLBlockquoteElement(Document* doc) + : HTMLElement(blockquoteTag, doc) +{ +} + +HTMLBlockquoteElement::~HTMLBlockquoteElement() +{ +} + +String HTMLBlockquoteElement::cite() const +{ + return getAttribute(citeAttr); +} + +void HTMLBlockquoteElement::setCite(const String &value) +{ + setAttribute(citeAttr, value); +} + +} diff --git a/WebCore/html/HTMLBlockquoteElement.h b/WebCore/html/HTMLBlockquoteElement.h new file mode 100644 index 0000000..0b72b18 --- /dev/null +++ b/WebCore/html/HTMLBlockquoteElement.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLBlockquoteElement_h +#define HTMLBlockquoteElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLBlockquoteElement : public HTMLElement { +public: + HTMLBlockquoteElement(Document*); + ~HTMLBlockquoteElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + String cite() const; + void setCite(const String&); +}; + +} // namespace WebCore + +#endif // HTMLBlockquoteElement_h diff --git a/WebCore/html/HTMLBlockquoteElement.idl b/WebCore/html/HTMLBlockquoteElement.idl new file mode 100644 index 0000000..d135fcd --- /dev/null +++ b/WebCore/html/HTMLBlockquoteElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=902d9011-c6d6-4363-b6fe-bd2d28ef553b, + ImplementationUUID=345db946-ba9c-44b9-87fd-06083aa472e4 + ] HTMLBlockquoteElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString cite; + }; + +} diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp new file mode 100644 index 0000000..7dca064 --- /dev/null +++ b/WebCore/html/HTMLBodyElement.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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 "HTMLBodyElement.h" + +#include "CSSHelper.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "CSSStyleSheet.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "EventNames.h" +#include "FrameView.h" +#include "HTMLFrameElementBase.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLBodyElement::HTMLBodyElement(Document* doc) + : HTMLElement(bodyTag, doc) +{ +} + +HTMLBodyElement::~HTMLBodyElement() +{ + if (m_linkDecl) { + m_linkDecl->setNode(0); + m_linkDecl->setParent(0); + } +} + +void HTMLBodyElement::createLinkDecl() +{ + m_linkDecl = CSSMutableStyleDeclaration::create(); + m_linkDecl->setParent(document()->elementSheet()); + m_linkDecl->setNode(this); + m_linkDecl->setStrictParsing(!document()->inCompatMode()); +} + +bool HTMLBodyElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == backgroundAttr) { + result = (MappedAttributeEntry)(eLastEntry + document()->docID()); + return false; + } + + if (attrName == bgcolorAttr || + attrName == textAttr || + attrName == marginwidthAttr || + attrName == leftmarginAttr || + attrName == marginheightAttr || + attrName == topmarginAttr || + attrName == bgpropertiesAttr) { + result = eUniversal; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLBodyElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == backgroundAttr) { + String url = parseURL(attr->value()); + if (!url.isEmpty()) + addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); + } else if (attr->name() == marginwidthAttr || attr->name() == leftmarginAttr) { + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + } else if (attr->name() == marginheightAttr || attr->name() == topmarginAttr) { + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + } else if (attr->name() == bgcolorAttr) { + addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); + } else if (attr->name() == textAttr) { + addCSSColor(attr, CSSPropertyColor, attr->value()); + } else if (attr->name() == bgpropertiesAttr) { + if (equalIgnoringCase(attr->value(), "fixed")) + addCSSProperty(attr, CSSPropertyBackgroundAttachment, CSSValueFixed); + } else if (attr->name() == vlinkAttr || + attr->name() == alinkAttr || + attr->name() == linkAttr) { + if (attr->isNull()) { + if (attr->name() == linkAttr) + document()->resetLinkColor(); + else if (attr->name() == vlinkAttr) + document()->resetVisitedLinkColor(); + else + document()->resetActiveLinkColor(); + } else { + if (!m_linkDecl) + createLinkDecl(); + m_linkDecl->setProperty(CSSPropertyColor, attr->value(), false, false); + RefPtr<CSSValue> val = m_linkDecl->getPropertyCSSValue(CSSPropertyColor); + if (val && val->isPrimitiveValue()) { + Color col = document()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValue*>(val.get())); + if (attr->name() == linkAttr) + document()->setLinkColor(col); + else if (attr->name() == vlinkAttr) + document()->setVisitedLinkColor(col); + else + document()->setActiveLinkColor(col); + } + } + + if (attached()) + document()->recalcStyle(Force); + } else if (attr->name() == onloadAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + else if (attr->name() == onbeforeunloadAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + else if (attr->name() == onunloadAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().unloadEvent, attr); + else if (attr->name() == onblurAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + else if (attr->name() == onfocusAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + else if (attr->name() == onresizeAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().resizeEvent, attr); + else if (attr->name() == onscrollAttr) + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().scrollEvent, attr); + else if (attr->name() == onstorageAttr) { + // The HTML5 spec currently specifies that storage events are fired only at the body element of + // an HTMLDocument, which is why the onstorage attribute differs from the ones before it. + // The spec might change on this, and then so should we! + setInlineEventListenerForTypeAndAttribute(eventNames().storageEvent, attr); + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLBodyElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + + // FIXME: Perhaps this code should be in attach() instead of here. + Element* ownerElement = document()->ownerElement(); + if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) { + HTMLFrameElementBase* ownerFrameElement = static_cast<HTMLFrameElementBase*>(ownerElement); + int marginWidth = ownerFrameElement->getMarginWidth(); + if (marginWidth != -1) + setAttribute(marginwidthAttr, String::number(marginWidth)); + int marginHeight = ownerFrameElement->getMarginHeight(); + if (marginHeight != -1) + setAttribute(marginheightAttr, String::number(marginHeight)); + } + + // FIXME: This call to scheduleRelayout should not be needed here. + // But without it we hang during WebKit tests; need to fix that and remove this. + if (FrameView* view = document()->view()) + view->scheduleRelayout(); +} + +bool HTMLBodyElement::isURLAttribute(Attribute *attr) const +{ + return attr->name() == backgroundAttr; +} + +String HTMLBodyElement::aLink() const +{ + return getAttribute(alinkAttr); +} + +void HTMLBodyElement::setALink(const String& value) +{ + setAttribute(alinkAttr, value); +} + +String HTMLBodyElement::background() const +{ + return getAttribute(backgroundAttr); +} + +void HTMLBodyElement::setBackground(const String& value) +{ + setAttribute(backgroundAttr, value); +} + +String HTMLBodyElement::bgColor() const +{ + return getAttribute(bgcolorAttr); +} + +void HTMLBodyElement::setBgColor(const String& value) +{ + setAttribute(bgcolorAttr, value); +} + +String HTMLBodyElement::link() const +{ + return getAttribute(linkAttr); +} + +void HTMLBodyElement::setLink(const String& value) +{ + setAttribute(linkAttr, value); +} + +String HTMLBodyElement::text() const +{ + return getAttribute(textAttr); +} + +void HTMLBodyElement::setText(const String& value) +{ + setAttribute(textAttr, value); +} + +String HTMLBodyElement::vLink() const +{ + return getAttribute(vlinkAttr); +} + +void HTMLBodyElement::setVLink(const String& value) +{ + setAttribute(vlinkAttr, value); +} + +int HTMLBodyElement::scrollLeft() const +{ + // Update the document's layout. + Document* doc = document(); + doc->updateLayoutIgnorePendingStylesheets(); + FrameView* view = doc->view(); + return view ? view->scrollX() : 0; +} + +void HTMLBodyElement::setScrollLeft(int scrollLeft) +{ + FrameView* sview = ownerDocument()->view(); + if (sview) { + // Update the document's layout + document()->updateLayoutIgnorePendingStylesheets(); + sview->setScrollPosition(IntPoint(scrollLeft, sview->scrollY())); + } +} + +int HTMLBodyElement::scrollTop() const +{ + // Update the document's layout. + Document* doc = document(); + doc->updateLayoutIgnorePendingStylesheets(); + FrameView* view = doc->view(); + return view ? view->scrollY() : 0; +} + +void HTMLBodyElement::setScrollTop(int scrollTop) +{ + FrameView* sview = ownerDocument()->view(); + if (sview) { + // Update the document's layout + document()->updateLayoutIgnorePendingStylesheets(); + sview->setScrollPosition(IntPoint(sview->scrollX(), scrollTop)); + } +} + +int HTMLBodyElement::scrollHeight() const +{ + // Update the document's layout. + Document* doc = document(); + doc->updateLayoutIgnorePendingStylesheets(); + FrameView* view = doc->view(); + return view ? view->contentsHeight() : 0; +} + +int HTMLBodyElement::scrollWidth() const +{ + // Update the document's layout. + Document* doc = document(); + doc->updateLayoutIgnorePendingStylesheets(); + FrameView* view = doc->view(); + return view ? view->contentsWidth() : 0; +} + +void HTMLBodyElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(background()); +} + +} diff --git a/WebCore/html/HTMLBodyElement.h b/WebCore/html/HTMLBodyElement.h new file mode 100644 index 0000000..2c5ce98 --- /dev/null +++ b/WebCore/html/HTMLBodyElement.h @@ -0,0 +1,81 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ + +#ifndef HTMLBodyElement_h +#define HTMLBodyElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLBodyElement : public HTMLElement +{ +public: + HTMLBodyElement(Document*); + ~HTMLBodyElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 10; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void insertedIntoDocument(); + + void createLinkDecl(); + + virtual bool isURLAttribute(Attribute*) const; + + String aLink() const; + void setALink(const String&); + String background() const; + void setBackground(const String&); + String bgColor() const; + void setBgColor(const String&); + String link() const; + void setLink(const String&); + String text() const; + void setText(const String&); + String vLink() const; + void setVLink(const String&); + + int scrollLeft() const; + void setScrollLeft(int scrollLeft); + + int scrollTop() const; + void setScrollTop(int scrollTop); + + int scrollHeight() const; + int scrollWidth() const; + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +protected: + RefPtr<CSSMutableStyleDeclaration> m_linkDecl; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLBodyElement.idl b/WebCore/html/HTMLBodyElement.idl new file mode 100644 index 0000000..41d20d6 --- /dev/null +++ b/WebCore/html/HTMLBodyElement.idl @@ -0,0 +1,42 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=4789afc6-2d9e-4f3b-8c27-12abc9d4a014, + ImplementationUUID=d2e16911-2f7e-4d58-a92c-94700d445b38 + ] HTMLBodyElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString aLink; + attribute [ConvertNullToNullString] DOMString background; + attribute [ConvertNullToNullString] DOMString bgColor; + attribute [ConvertNullToNullString] DOMString link; + attribute [ConvertNullToNullString] DOMString text; + attribute [ConvertNullToNullString] DOMString vLink; + + // IE Extensions + attribute long scrollLeft; + attribute long scrollTop; + readonly attribute long scrollWidth; + readonly attribute long scrollHeight; + }; + +} diff --git a/WebCore/html/HTMLButtonElement.cpp b/WebCore/html/HTMLButtonElement.cpp new file mode 100644 index 0000000..f65e748 --- /dev/null +++ b/WebCore/html/HTMLButtonElement.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2007 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 "HTMLButtonElement.h" + +#include "EventNames.h" +#include "FormDataList.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "RenderButton.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLButtonElement::HTMLButtonElement(Document* doc, HTMLFormElement* form) + : HTMLFormControlElement(buttonTag, doc, form) + , m_type(SUBMIT) + , m_activeSubmit(false) +{ +} + +HTMLButtonElement::~HTMLButtonElement() +{ +} + +RenderObject* HTMLButtonElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + return new (arena) RenderButton(this); +} + +const AtomicString& HTMLButtonElement::type() const +{ + switch (m_type) { + case SUBMIT: { + static const AtomicString submit("submit"); + return submit; + } + case BUTTON: { + static const AtomicString button("button"); + return button; + } + case RESET: { + static const AtomicString reset("reset"); + return reset; + } + } + + ASSERT_NOT_REACHED(); + return emptyAtom; +} + +void HTMLButtonElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == typeAttr) { + if (equalIgnoringCase(attr->value(), "reset")) + m_type = RESET; + else if (equalIgnoringCase(attr->value(), "button")) + m_type = BUTTON; + else + m_type = SUBMIT; + } else if (attr->name() == alignAttr) { + // Don't map 'align' attribute. This matches what Firefox and IE do, but not Opera. + // See http://bugs.webkit.org/show_bug.cgi?id=12071 + } else if (attr->name() == onfocusAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + } else if (attr->name() == onblurAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + } else + HTMLFormControlElement::parseMappedAttribute(attr); +} + +void HTMLButtonElement::defaultEventHandler(Event* evt) +{ + if (evt->type() == eventNames().DOMActivateEvent && !disabled()) { + if (form() && m_type == SUBMIT) { + m_activeSubmit = true; + form()->prepareSubmit(evt); + m_activeSubmit = false; // in case we were canceled + } + if (form() && m_type == RESET) + form()->reset(); + } + + if (evt->isKeyboardEvent()) { + if (evt->type() == eventNames().keydownEvent && static_cast<KeyboardEvent*>(evt)->keyIdentifier() == "U+0020") { + setActive(true, true); + // No setDefaultHandled() - IE dispatches a keypress in this case. + return; + } + if (evt->type() == eventNames().keypressEvent) { + switch (static_cast<KeyboardEvent*>(evt)->charCode()) { + case '\r': + dispatchSimulatedClick(evt); + evt->setDefaultHandled(); + return; + case ' ': + // Prevent scrolling down the page. + evt->setDefaultHandled(); + return; + default: + break; + } + } + if (evt->type() == eventNames().keyupEvent && static_cast<KeyboardEvent*>(evt)->keyIdentifier() == "U+0020") { + if (active()) + dispatchSimulatedClick(evt); + evt->setDefaultHandled(); + return; + } + } + + HTMLFormControlElement::defaultEventHandler(evt); +} + +bool HTMLButtonElement::isSuccessfulSubmitButton() const +{ + // HTML spec says that buttons must have names to be considered successful. + // However, other browsers do not impose this constraint. + return m_type == SUBMIT && !disabled(); +} + +bool HTMLButtonElement::isActivatedSubmit() const +{ + return m_activeSubmit; +} + +void HTMLButtonElement::setActivatedSubmit(bool flag) +{ + m_activeSubmit = flag; +} + +bool HTMLButtonElement::appendFormData(FormDataList& formData, bool) +{ + if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit) + return false; + formData.appendData(name(), value()); + return true; +} + +void HTMLButtonElement::accessKeyAction(bool sendToAnyElement) +{ + focus(); + // send the mouse button events iff the caller specified sendToAnyElement + dispatchSimulatedClick(0, sendToAnyElement); +} + +String HTMLButtonElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLButtonElement::setAccessKey(const String &value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLButtonElement::value() const +{ + return getAttribute(valueAttr); +} + +void HTMLButtonElement::setValue(const String &value) +{ + setAttribute(valueAttr, value); +} + +} // namespace diff --git a/WebCore/html/HTMLButtonElement.h b/WebCore/html/HTMLButtonElement.h new file mode 100644 index 0000000..4d55ba5 --- /dev/null +++ b/WebCore/html/HTMLButtonElement.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLButtonElement_h +#define HTMLButtonElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class HTMLButtonElement : public HTMLFormControlElement { +public: + HTMLButtonElement(Document*, HTMLFormElement* = 0); + virtual ~HTMLButtonElement(); + + virtual const AtomicString& type() const; + + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + virtual void parseMappedAttribute(MappedAttribute*); + virtual void defaultEventHandler(Event*); + virtual bool appendFormData(FormDataList&, bool); + + virtual bool isEnumeratable() const { return true; } + + virtual bool isSuccessfulSubmitButton() const; + virtual bool isActivatedSubmit() const; + virtual void setActivatedSubmit(bool flag); + + virtual void accessKeyAction(bool sendToAnyElement); + + virtual bool canStartSelection() const { return false; } + + String accessKey() const; + void setAccessKey(const String&); + + String value() const; + void setValue(const String&); + + virtual bool willValidate() const { return false; } + +private: + enum Type { SUBMIT, RESET, BUTTON }; + + Type m_type; + bool m_activeSubmit; +}; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLButtonElement.idl b/WebCore/html/HTMLButtonElement.idl new file mode 100644 index 0000000..028e92b --- /dev/null +++ b/WebCore/html/HTMLButtonElement.idl @@ -0,0 +1,39 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=b9715643-5591-442d-ab65-e05309607271, + ImplementationUUID=1be13b5f-40df-4550-b70e-8c805e546cad + ] HTMLButtonElement : HTMLElement { + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString accessKey; + attribute boolean disabled; + attribute boolean autofocus; + attribute [ConvertNullToNullString] DOMString name; + readonly attribute DOMString type; + attribute [ConvertNullToNullString] DOMString value; + readonly attribute boolean willValidate; + void click(); + }; + +} diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp new file mode 100644 index 0000000..f3ca1fd --- /dev/null +++ b/WebCore/html/HTMLCanvasElement.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.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 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 "HTMLCanvasElement.h" + +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "Chrome.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "GraphicsContext.h" +#include "HTMLNames.h" +#include "ImageBuffer.h" +#include "MIMETypeRegistry.h" +#include "Page.h" +#include "RenderHTMLCanvas.h" +#include "Settings.h" +#include <kjs/interpreter.h> +#include <math.h> +#include <stdio.h> + +namespace WebCore { + +using namespace HTMLNames; + +// These values come from the WhatWG spec. +static const int defaultWidth = 300; +static const int defaultHeight = 150; + +// Firefox limits width/height to 32767 pixels, but slows down dramatically before it +// reaches that limit. We limit by area instead, giving us larger maximum dimensions, +// in exchange for a smaller maximum canvas size. +const float HTMLCanvasElement::MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels + +HTMLCanvasElement::HTMLCanvasElement(Document* doc) + : HTMLElement(canvasTag, doc) + , m_size(defaultWidth, defaultHeight) + , m_observer(0) + , m_originClean(true) + , m_ignoreReset(false) + , m_createdImageBuffer(false) +{ +} + +HTMLCanvasElement::~HTMLCanvasElement() +{ +} + +#if ENABLE(DASHBOARD_SUPPORT) + +HTMLTagStatus HTMLCanvasElement::endTagRequirement() const +{ + Settings* settings = document()->settings(); + if (settings && settings->usesDashboardBackwardCompatibilityMode()) + return TagStatusForbidden; + + return HTMLElement::endTagRequirement(); +} + +int HTMLCanvasElement::tagPriority() const +{ + Settings* settings = document()->settings(); + if (settings && settings->usesDashboardBackwardCompatibilityMode()) + return 0; + + return HTMLElement::tagPriority(); +} + +#endif + +void HTMLCanvasElement::parseMappedAttribute(MappedAttribute* attr) +{ + const QualifiedName& attrName = attr->name(); + if (attrName == widthAttr || attrName == heightAttr) + reset(); + HTMLElement::parseMappedAttribute(attr); +} + +RenderObject* HTMLCanvasElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + Settings* settings = document()->settings(); + if (settings && settings->isJavaScriptEnabled()) { + m_rendererIsCanvas = true; + return new (arena) RenderHTMLCanvas(this); + } + + m_rendererIsCanvas = false; + return HTMLElement::createRenderer(arena, style); +} + +void HTMLCanvasElement::setHeight(int value) +{ + setAttribute(heightAttr, String::number(value)); +} + +void HTMLCanvasElement::setWidth(int value) +{ + setAttribute(widthAttr, String::number(value)); +} + +String HTMLCanvasElement::toDataURL(const String& mimeType, ExceptionCode& ec) +{ + if (!m_originClean) { + ec = SECURITY_ERR; + return String(); + } + + if (m_size.isEmpty()) + return String("data:,"); + + if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)) + return buffer()->toDataURL("image/png"); + + return buffer()->toDataURL(mimeType); +} + +CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type) +{ + if (type == "2d") { + if (!m_2DContext) + m_2DContext.set(new CanvasRenderingContext2D(this)); + return m_2DContext.get(); + } + return 0; +} + +void HTMLCanvasElement::willDraw(const FloatRect& rect) +{ + m_imageBuffer->clearImage(); + + if (RenderObject* ro = renderer()) { +#ifdef CANVAS_INCREMENTAL_REPAINT + // Handle CSS triggered scaling + float widthScale = static_cast<float>(ro->width()) / static_cast<float>(m_size.width()); + float heightScale = static_cast<float>(ro->height()) / static_cast<float>(m_size.height()); + FloatRect r(rect.x() * widthScale, rect.y() * heightScale, rect.width() * widthScale, rect.height() * heightScale); + ro->repaintRectangle(enclosingIntRect(r)); +#else + ro->repaint(); +#endif + } + + if (m_observer) + m_observer->canvasChanged(this, rect); +} + +void HTMLCanvasElement::reset() +{ + if (m_ignoreReset) + return; + + bool ok; + int w = getAttribute(widthAttr).toInt(&ok); + if (!ok) + w = defaultWidth; + int h = getAttribute(heightAttr).toInt(&ok); + if (!ok) + h = defaultHeight; + + IntSize oldSize = m_size; + m_size = IntSize(w, h); + + bool hadImageBuffer = m_createdImageBuffer; + m_createdImageBuffer = false; + m_imageBuffer.clear(); + if (m_2DContext) + m_2DContext->reset(); + + if (RenderObject* ro = renderer()) + if (m_rendererIsCanvas) { + if (oldSize != m_size) + static_cast<RenderHTMLCanvas*>(ro)->canvasSizeChanged(); + if (hadImageBuffer) + ro->repaint(); + } + + if (m_observer) + m_observer->canvasResized(this); +} + +void HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r) +{ + if (context->paintingDisabled()) + return; + + if (m_imageBuffer) { + Image* image = m_imageBuffer->image(); + if (image) + context->drawImage(image, r); + } +} + +IntRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const +{ + return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size())); +} + +IntSize HTMLCanvasElement::convertLogicalToDevice(const FloatSize& logicalSize) const +{ + float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f; + float wf = ceilf(logicalSize.width() * pageScaleFactor); + float hf = ceilf(logicalSize.height() * pageScaleFactor); + + if (!(wf >= 1 && hf >= 1 && wf * hf <= MaxCanvasArea)) + return IntSize(); + + return IntSize(static_cast<unsigned>(wf), static_cast<unsigned>(hf)); +} + +IntPoint HTMLCanvasElement::convertLogicalToDevice(const FloatPoint& logicalPos) const +{ + float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f; + float xf = logicalPos.x() * pageScaleFactor; + float yf = logicalPos.y() * pageScaleFactor; + + return IntPoint(static_cast<unsigned>(xf), static_cast<unsigned>(yf)); +} + +void HTMLCanvasElement::createImageBuffer() const +{ + ASSERT(!m_imageBuffer); + + m_createdImageBuffer = true; + + FloatSize unscaledSize(width(), height()); + IntSize size = convertLogicalToDevice(unscaledSize); + if (!size.width() || !size.height()) + return; + m_imageBuffer.set(ImageBuffer::create(size, false).release()); +} + +GraphicsContext* HTMLCanvasElement::drawingContext() const +{ + return buffer() ? m_imageBuffer->context() : 0; +} + +ImageBuffer* HTMLCanvasElement::buffer() const +{ + if (!m_createdImageBuffer) + createImageBuffer(); + return m_imageBuffer.get(); +} + +} diff --git a/WebCore/html/HTMLCanvasElement.h b/WebCore/html/HTMLCanvasElement.h new file mode 100644 index 0000000..a118364 --- /dev/null +++ b/WebCore/html/HTMLCanvasElement.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.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 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 HTMLCanvasElement_h +#define HTMLCanvasElement_h + +#include "HTMLElement.h" +#include "IntSize.h" + +namespace WebCore { + +class CanvasRenderingContext2D; +typedef CanvasRenderingContext2D CanvasRenderingContext; +class FloatPoint; +class FloatRect; +class FloatSize; +class GraphicsContext; +class HTMLCanvasElement; +class ImageBuffer; +class IntPoint; +class InttRect; +class IntSize; + +class CanvasObserver { +public: + virtual ~CanvasObserver() {}; + + virtual void canvasChanged(HTMLCanvasElement* element, const FloatRect& changedRect) = 0; + virtual void canvasResized(HTMLCanvasElement* element) = 0; +}; + +class HTMLCanvasElement : public HTMLElement { +public: + HTMLCanvasElement(Document*); + virtual ~HTMLCanvasElement(); + +#if ENABLE(DASHBOARD_SUPPORT) + virtual HTMLTagStatus endTagRequirement() const; + virtual int tagPriority() const; +#endif + + int width() const { return m_size.width(); } + int height() const { return m_size.height(); } + void setWidth(int); + void setHeight(int); + + String toDataURL(const String& mimeType, ExceptionCode&); + + CanvasRenderingContext* getContext(const String&); + + virtual void parseMappedAttribute(MappedAttribute*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + IntSize size() const { return m_size; } + void setSize(const IntSize& size) + { + if (size == m_size) + return; + m_ignoreReset = true; + setWidth(size.width()); + setHeight(size.height()); + m_ignoreReset = false; + reset(); + } + + void willDraw(const FloatRect&); + + void paint(GraphicsContext*, const IntRect&); + + GraphicsContext* drawingContext() const; + + ImageBuffer* buffer() const; + + IntRect convertLogicalToDevice(const FloatRect&) const; + IntSize convertLogicalToDevice(const FloatSize&) const; + IntPoint convertLogicalToDevice(const FloatPoint&) const; + + void setOriginTainted() { m_originClean = false; } + bool originClean() const { return m_originClean; } + + static const float MaxCanvasArea; + + void setObserver(CanvasObserver* o) { m_observer = o; } + +private: + void createImageBuffer() const; + void reset(); + + bool m_rendererIsCanvas; + + OwnPtr<CanvasRenderingContext2D> m_2DContext; + IntSize m_size; + CanvasObserver* m_observer; + + bool m_originClean; + bool m_ignoreReset; + + // m_createdImageBuffer means we tried to malloc the buffer. We didn't necessarily get it. + mutable bool m_createdImageBuffer; + mutable OwnPtr<ImageBuffer> m_imageBuffer; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLCanvasElement.idl b/WebCore/html/HTMLCanvasElement.idl new file mode 100644 index 0000000..e457c15 --- /dev/null +++ b/WebCore/html/HTMLCanvasElement.idl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006, 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=a14d88c8-c6af-4e34-ad17-659700c77a10, + ImplementationUUID=7ae731bc-c264-4ee3-a4b4-5d4540af26c3 + ] HTMLCanvasElement : HTMLElement { + + attribute long width; + attribute long height; + + DOMString toDataURL(in [ConvertUndefinedOrNullToNullString] DOMString type) + raises(DOMException); + +#if !defined(LANGUAGE_OBJECTIVE_C) + DOMObject getContext(in DOMString contextId); +#endif + + }; + +} diff --git a/WebCore/html/HTMLCollection.cpp b/WebCore/html/HTMLCollection.cpp new file mode 100644 index 0000000..44b84a0 --- /dev/null +++ b/WebCore/html/HTMLCollection.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "HTMLCollection.h" + +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" +#include "NodeList.h" + +#include <utility> + +namespace WebCore { + +using namespace HTMLNames; + +HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type) + : m_idsDone(false) + , m_base(base) + , m_type(type) + , m_info(m_base->isDocumentNode() ? static_cast<Document*>(m_base.get())->collectionInfo(type) : 0) + , m_ownsInfo(false) +{ +} + +HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type, CollectionInfo* info) + : m_idsDone(false) + , m_base(base) + , m_type(type) + , m_info(info) + , m_ownsInfo(false) +{ +} + +PassRefPtr<HTMLCollection> HTMLCollection::create(PassRefPtr<Node> base, Type type) +{ + return adoptRef(new HTMLCollection(base, type)); +} + +HTMLCollection::~HTMLCollection() +{ + if (m_ownsInfo) + delete m_info; +} + +HTMLCollection::CollectionInfo::CollectionInfo() + : version(0) +{ + reset(); +} + +inline void HTMLCollection::CollectionInfo::copyCacheMap(NodeCacheMap& dest, const NodeCacheMap& src) +{ + ASSERT(dest.isEmpty()); + NodeCacheMap::const_iterator end = src.end(); + for (NodeCacheMap::const_iterator it = src.begin(); it != end; ++it) + dest.add(it->first, new Vector<Element*>(*it->second)); +} + +HTMLCollection::CollectionInfo::CollectionInfo(const CollectionInfo& other) + : version(other.version) + , current(other.current) + , position(other.position) + , length(other.length) + , elementsArrayPosition(other.elementsArrayPosition) + , hasLength(other.hasLength) + , hasNameCache(other.hasNameCache) +{ + copyCacheMap(idCache, other.idCache); + copyCacheMap(nameCache, other.nameCache); +} + +void HTMLCollection::CollectionInfo::swap(CollectionInfo& other) +{ + std::swap(version, other.version); + std::swap(current, other.current); + std::swap(position, other.position); + std::swap(length, other.length); + std::swap(elementsArrayPosition, other.elementsArrayPosition); + + idCache.swap(other.idCache); + nameCache.swap(other.nameCache); + + std::swap(hasLength, other.hasLength); + std::swap(hasNameCache, other.hasNameCache); +} + +HTMLCollection::CollectionInfo::~CollectionInfo() +{ + deleteAllValues(idCache); + deleteAllValues(nameCache); +} + +void HTMLCollection::CollectionInfo::reset() +{ + current = 0; + position = 0; + length = 0; + hasLength = false; + elementsArrayPosition = 0; + deleteAllValues(idCache); + idCache.clear(); + deleteAllValues(nameCache); + nameCache.clear(); + hasNameCache = false; +} + +void HTMLCollection::resetCollectionInfo() const +{ + unsigned docversion = static_cast<HTMLDocument*>(m_base->document())->domTreeVersion(); + + if (!m_info) { + m_info = new CollectionInfo; + m_ownsInfo = true; + m_info->version = docversion; + return; + } + + if (m_info->version != docversion) { + m_info->reset(); + m_info->version = docversion; + } +} + +static Node* nextNodeOrSibling(Node* base, Node* node, bool includeChildren) +{ + return includeChildren ? node->traverseNextNode(base) : node->traverseNextSibling(base); +} + +Element* HTMLCollection::itemAfter(Element* previous) const +{ + bool deep = true; + + switch (m_type) { + case DocAll: + case DocAnchors: + case DocApplets: + case DocEmbeds: + case DocForms: + case DocImages: + case DocLinks: + case DocObjects: + case DocScripts: + case DocumentNamedItems: + case MapAreas: + case Other: + case SelectOptions: + case WindowNamedItems: + break; + case NodeChildren: + case TRCells: + case TSectionRows: + case TableTBodies: + deep = false; + break; + } + + Node* current; + if (!previous) + current = m_base->firstChild(); + else + current = nextNodeOrSibling(m_base.get(), previous, deep); + + for (; current; current = nextNodeOrSibling(m_base.get(), current, deep)) { + if (!current->isElementNode()) + continue; + Element* e = static_cast<Element*>(current); + switch (m_type) { + case DocImages: + if (e->hasLocalName(imgTag)) + return e; + break; + case DocScripts: + if (e->hasLocalName(scriptTag)) + return e; + break; + case DocForms: + if (e->hasLocalName(formTag)) + return e; + break; + case TableTBodies: + if (e->hasLocalName(tbodyTag)) + return e; + break; + case TRCells: + if (e->hasLocalName(tdTag) || e->hasLocalName(thTag)) + return e; + break; + case TSectionRows: + if (e->hasLocalName(trTag)) + return e; + break; + case SelectOptions: + if (e->hasLocalName(optionTag)) + return e; + break; + case MapAreas: + if (e->hasLocalName(areaTag)) + return e; + break; + case DocApplets: // all <applet> elements and <object> elements that contain Java Applets + if (e->hasLocalName(appletTag)) + return e; + if (e->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(e)->containsJavaApplet()) + return e; + break; + case DocEmbeds: + if (e->hasLocalName(embedTag)) + return e; + break; + case DocObjects: + if (e->hasLocalName(objectTag)) + return e; + break; + case DocLinks: // all <a> and <area> elements with a value for href + if ((e->hasLocalName(aTag) || e->hasLocalName(areaTag)) && (!e->getAttribute(hrefAttr).isNull())) + return e; + break; + case DocAnchors: // all <a> elements with a value for name + if (e->hasLocalName(aTag) && !e->getAttribute(nameAttr).isNull()) + return e; + break; + case DocAll: + case NodeChildren: + return e; + case DocumentNamedItems: + case Other: + case WindowNamedItems: + ASSERT_NOT_REACHED(); + break; + } + } + + return 0; +} + +unsigned HTMLCollection::calcLength() const +{ + unsigned len = 0; + for (Element* current = itemAfter(0); current; current = itemAfter(current)) + ++len; + return len; +} + +// since the collections are to be "live", we have to do the +// calculation every time if anything has changed +unsigned HTMLCollection::length() const +{ + resetCollectionInfo(); + if (!m_info->hasLength) { + m_info->length = calcLength(); + m_info->hasLength = true; + } + return m_info->length; +} + +Node* HTMLCollection::item(unsigned index) const +{ + resetCollectionInfo(); + if (m_info->current && m_info->position == index) + return m_info->current; + if (m_info->hasLength && m_info->length <= index) + return 0; + if (!m_info->current || m_info->position > index) { + m_info->current = itemAfter(0); + m_info->position = 0; + if (!m_info->current) + return 0; + } + Element* e = m_info->current; + for (unsigned pos = m_info->position; e && pos < index; pos++) + e = itemAfter(e); + m_info->current = e; + m_info->position = index; + return m_info->current; +} + +Node* HTMLCollection::firstItem() const +{ + return item(0); +} + +Node* HTMLCollection::nextItem() const +{ + resetCollectionInfo(); + +#ifdef ANDROID_FIX + // resetCollectionInfo() can set info->current to be 0. If this is the + // case, we need to go back to the firstItem. Otherwise traverseNextItem + // will crash. + if (!m_info->current) + return firstItem(); +#endif + + // Look for the 'second' item. The first one is currentItem, already given back. + Element* retval = itemAfter(m_info->current); + m_info->current = retval; + m_info->position++; + return retval; +} + +bool HTMLCollection::checkForNameMatch(Element* element, bool checkName, const String& name, bool caseSensitive) const +{ + if (!element->isHTMLElement()) + return false; + + HTMLElement* e = static_cast<HTMLElement*>(element); + if (caseSensitive) { + if (checkName) { + // document.all returns only images, forms, applets, objects and embeds + // by name (though everything by id) + if (m_type == DocAll && + !(e->hasLocalName(imgTag) || e->hasLocalName(formTag) || + e->hasLocalName(appletTag) || e->hasLocalName(objectTag) || + e->hasLocalName(embedTag) || e->hasLocalName(inputTag) || + e->hasLocalName(selectTag))) + return false; + + return e->getAttribute(nameAttr) == name && e->getAttribute(idAttr) != name; + } else + return e->getAttribute(idAttr) == name; + } else { + if (checkName) { + // document.all returns only images, forms, applets, objects and embeds + // by name (though everything by id) + if (m_type == DocAll && + !(e->hasLocalName(imgTag) || e->hasLocalName(formTag) || + e->hasLocalName(appletTag) || e->hasLocalName(objectTag) || + e->hasLocalName(embedTag) || e->hasLocalName(inputTag) || + e->hasLocalName(selectTag))) + return false; + + return equalIgnoringCase(e->getAttribute(nameAttr), name) + && !equalIgnoringCase(e->getAttribute(idAttr), name); + } else + return equalIgnoringCase(e->getAttribute(idAttr), name); + } +} + + +Node *HTMLCollection::namedItem(const String &name, bool caseSensitive) const +{ + // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp + // This method first searches for an object with a matching id + // attribute. If a match is not found, the method then searches for an + // object with a matching name attribute, but only on those elements + // that are allowed a name attribute. + resetCollectionInfo(); + m_idsDone = false; + + for (Element* e = itemAfter(0); e; e = itemAfter(e)) { + if (checkForNameMatch(e, m_idsDone, name, caseSensitive)) { + m_info->current = e; + return e; + } + } + + m_idsDone = true; + + for (Element* e = itemAfter(0); e; e = itemAfter(e)) { + if (checkForNameMatch(e, m_idsDone, name, caseSensitive)) { + m_info->current = e; + return e; + } + } + + m_info->current = 0; + return 0; +} + +void HTMLCollection::updateNameCache() const +{ + if (m_info->hasNameCache) + return; + + for (Element* element = itemAfter(0); element; element = itemAfter(element)) { + if (!element->isHTMLElement()) + continue; + HTMLElement* e = static_cast<HTMLElement*>(element); + const AtomicString& idAttrVal = e->getAttribute(idAttr); + const AtomicString& nameAttrVal = e->getAttribute(nameAttr); + if (!idAttrVal.isEmpty()) { + // add to id cache + Vector<Element*>* idVector = m_info->idCache.get(idAttrVal.impl()); + if (!idVector) { + idVector = new Vector<Element*>; + m_info->idCache.add(idAttrVal.impl(), idVector); + } + idVector->append(e); + } + if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal + && (m_type != DocAll || + (e->hasLocalName(imgTag) || e->hasLocalName(formTag) || + e->hasLocalName(appletTag) || e->hasLocalName(objectTag) || + e->hasLocalName(embedTag) || e->hasLocalName(inputTag) || + e->hasLocalName(selectTag)))) { + // add to name cache + Vector<Element*>* nameVector = m_info->nameCache.get(nameAttrVal.impl()); + if (!nameVector) { + nameVector = new Vector<Element*>; + m_info->nameCache.add(nameAttrVal.impl(), nameVector); + } + nameVector->append(e); + } + } + + m_info->hasNameCache = true; +} + +void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Node> >& result) const +{ + ASSERT(result.isEmpty()); + + if (name.isEmpty()) + return; + + resetCollectionInfo(); + updateNameCache(); + + Vector<Element*>* idResults = m_info->idCache.get(name.impl()); + Vector<Element*>* nameResults = m_info->nameCache.get(name.impl()); + + for (unsigned i = 0; idResults && i < idResults->size(); ++i) + result.append(idResults->at(i)); + + for (unsigned i = 0; nameResults && i < nameResults->size(); ++i) + result.append(nameResults->at(i)); +} + + +Node* HTMLCollection::nextNamedItem(const String& name) const +{ + resetCollectionInfo(); + + for (Element* e = itemAfter(m_info->current); e; e = itemAfter(e)) { + if (checkForNameMatch(e, m_idsDone, name, true)) { + m_info->current = e; + return e; + } + } + + if (m_idsDone) { + m_info->current = 0; + return 0; + } + m_idsDone = true; + + for (Element* e = itemAfter(m_info->current); e; e = itemAfter(e)) { + if (checkForNameMatch(e, m_idsDone, name, true)) { + m_info->current = e; + return e; + } + } + + return 0; +} + +PassRefPtr<NodeList> HTMLCollection::tags(const String& name) +{ + return m_base->getElementsByTagName(name); +} + +} // namespace WebCore diff --git a/WebCore/html/HTMLCollection.h b/WebCore/html/HTMLCollection.h new file mode 100644 index 0000000..3d75108 --- /dev/null +++ b/WebCore/html/HTMLCollection.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef HTMLCollection_h +#define HTMLCollection_h + +#include <wtf/RefCounted.h> +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AtomicString; +class AtomicStringImpl; +class Element; +class Node; +class NodeList; +class String; + +class HTMLCollection : public RefCounted<HTMLCollection> { +public: + enum Type { + // unnamed collection types cached in the document + + DocImages, // all <img> elements in the document + DocApplets, // all <object> and <applet> elements + DocEmbeds, // all <embed> elements + DocObjects, // all <object> elements + DocForms, // all <form> elements + DocLinks, // all <a> _and_ <area> elements with a value for href + DocAnchors, // all <a> elements with a value for name + DocScripts, // all <script> elements + + DocAll, // "all" elements (IE) + NodeChildren, // first-level children (IE) + + // named collection types cached in the document + + WindowNamedItems, + DocumentNamedItems, + + // types not cached in the document; these are types that can't be used on a document + + TableTBodies, // all <tbody> elements in this table + TSectionRows, // all row elements in this table section + TRCells, // all cells in this row + SelectOptions, + MapAreas, + + Other + }; + + static const Type FirstUnnamedDocumentCachedType = DocImages; + static const unsigned NumUnnamedDocumentCachedTypes = NodeChildren - DocImages + 1; + + static const Type FirstNamedDocumentCachedType = WindowNamedItems; + static const unsigned NumNamedDocumentCachedTypes = DocumentNamedItems - WindowNamedItems + 1; + + static PassRefPtr<HTMLCollection> create(PassRefPtr<Node> base, Type); + virtual ~HTMLCollection(); + + unsigned length() const; + + virtual Node* item(unsigned index) const; + virtual Node* nextItem() const; + + virtual Node* namedItem(const String& name, bool caseSensitive = true) const; + virtual Node* nextNamedItem(const String& name) const; // In case of multiple items named the same way + + Node* firstItem() const; + + void namedItems(const AtomicString& name, Vector<RefPtr<Node> >&) const; + + PassRefPtr<NodeList> tags(const String&); + + Node* base() const { return m_base.get(); } + Type type() const { return m_type; } + + // FIXME: This class name is a bad in two ways. First, "info" is much too vague, + // and doesn't convey the job of this class (caching collection state). + // Second, since this is a member of HTMLCollection, it doesn't need "collection" + // in its name. + struct CollectionInfo { + CollectionInfo(); + CollectionInfo(const CollectionInfo&); + CollectionInfo& operator=(const CollectionInfo& other) + { + CollectionInfo tmp(other); + swap(tmp); + return *this; + } + ~CollectionInfo(); + + void reset(); + void swap(CollectionInfo&); + + typedef HashMap<AtomicStringImpl*, Vector<Element*>*> NodeCacheMap; + + unsigned version; + Element* current; + unsigned position; + unsigned length; + int elementsArrayPosition; + NodeCacheMap idCache; + NodeCacheMap nameCache; + bool hasLength; + bool hasNameCache; + + private: + static void copyCacheMap(NodeCacheMap&, const NodeCacheMap&); + }; + +protected: + HTMLCollection(PassRefPtr<Node> base, Type, CollectionInfo*); + + CollectionInfo* info() const { return m_info; } + virtual void resetCollectionInfo() const; + + mutable bool m_idsDone; // for nextNamedItem() + +private: + HTMLCollection(PassRefPtr<Node> base, Type); + + virtual Element* itemAfter(Element*) const; + virtual unsigned calcLength() const; + virtual void updateNameCache() const; + + bool checkForNameMatch(Element*, bool checkName, const String &name, bool caseSensitive) const; + + RefPtr<Node> m_base; + Type m_type; + + mutable CollectionInfo* m_info; + mutable bool m_ownsInfo; +}; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLCollection.idl b/WebCore/html/HTMLCollection.idl new file mode 100644 index 0000000..8290e1a --- /dev/null +++ b/WebCore/html/HTMLCollection.idl @@ -0,0 +1,40 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + HasIndexGetter, + HasNameGetter, + CustomCall, + CustomToJS, + InterfaceUUID=b0d215ff-6f9c-4d1f-86c3-f200a65a5134, + ImplementationUUID=8e81b17f-7f74-4121-8f2f-a339a7e66447 + ] HTMLCollection { + readonly attribute unsigned long length; + [Custom] Node item(in unsigned long index); + [Custom] Node namedItem(in DOMString name); + + // Extensions + NodeList tags(in DOMString name); + }; + +} diff --git a/WebCore/html/HTMLDListElement.cpp b/WebCore/html/HTMLDListElement.cpp new file mode 100644 index 0000000..1573065 --- /dev/null +++ b/WebCore/html/HTMLDListElement.cpp @@ -0,0 +1,47 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ +#include "config.h" +#include "HTMLDListElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLDListElement::HTMLDListElement(Document* doc) + : HTMLElement(HTMLNames::dlTag, doc) +{ +} + +bool HTMLDListElement::compact() const +{ + return !getAttribute(compactAttr).isNull(); +} + +void HTMLDListElement::setCompact(bool b) +{ + setAttribute(compactAttr, b ? "" : 0); +} + +} diff --git a/WebCore/html/HTMLDListElement.h b/WebCore/html/HTMLDListElement.h new file mode 100644 index 0000000..88d9050 --- /dev/null +++ b/WebCore/html/HTMLDListElement.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLDListElement_h +#define HTMLDListElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLDListElement : public HTMLElement +{ +public: + HTMLDListElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + bool compact() const; + void setCompact(bool); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLDListElement.idl b/WebCore/html/HTMLDListElement.idl new file mode 100644 index 0000000..1578dfd --- /dev/null +++ b/WebCore/html/HTMLDListElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=5665c589-aea9-4322-844f-d3395fd5839e, + ImplementationUUID=99ac26a3-224b-4bc6-b287-89946a6de9a7 + ] HTMLDListElement : HTMLElement { + attribute boolean compact; + }; + +} diff --git a/WebCore/html/HTMLDirectoryElement.cpp b/WebCore/html/HTMLDirectoryElement.cpp new file mode 100644 index 0000000..4153ed4 --- /dev/null +++ b/WebCore/html/HTMLDirectoryElement.cpp @@ -0,0 +1,47 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ +#include "config.h" +#include "HTMLDirectoryElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLDirectoryElement::HTMLDirectoryElement(Document* doc) + : HTMLElement(HTMLNames::dirTag, doc) +{ +} + +bool HTMLDirectoryElement::compact() const +{ + return !getAttribute(compactAttr).isNull(); +} + +void HTMLDirectoryElement::setCompact(bool b) +{ + setAttribute(compactAttr, b ? "" : 0); +} + +} diff --git a/WebCore/html/HTMLDirectoryElement.h b/WebCore/html/HTMLDirectoryElement.h new file mode 100644 index 0000000..38414d5 --- /dev/null +++ b/WebCore/html/HTMLDirectoryElement.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLDirectoryElement_h +#define HTMLDirectoryElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLDirectoryElement : public HTMLElement +{ +public: + HTMLDirectoryElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + bool compact() const; + void setCompact(bool); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLDirectoryElement.idl b/WebCore/html/HTMLDirectoryElement.idl new file mode 100644 index 0000000..308e30d --- /dev/null +++ b/WebCore/html/HTMLDirectoryElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=49292c6b-2b2e-49cb-98b6-20d4cd806bd2, + ImplementationUUID=45749798-4afe-4884-a42a-a2c8b3d98795 + ] HTMLDirectoryElement : HTMLElement { + attribute boolean compact; + }; + +} diff --git a/WebCore/html/HTMLDivElement.cpp b/WebCore/html/HTMLDivElement.cpp new file mode 100644 index 0000000..3aab91b --- /dev/null +++ b/WebCore/html/HTMLDivElement.cpp @@ -0,0 +1,79 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLDivElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLDivElement::HTMLDivElement(Document *doc) + : HTMLElement(divTag, doc) +{ +} + +HTMLDivElement::~HTMLDivElement() +{ +} + +bool HTMLDivElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == alignAttr) { + result = eBlock; + return false; + } + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLDivElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == alignAttr) { + String v = attr->value(); + if (equalIgnoringCase(attr->value(), "middle") || equalIgnoringCase(attr->value(), "center")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitCenter); + else if (equalIgnoringCase(attr->value(), "left")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitLeft); + else if (equalIgnoringCase(attr->value(), "right")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitRight); + else + addCSSProperty(attr, CSSPropertyTextAlign, v); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLDivElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLDivElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +} diff --git a/WebCore/html/HTMLDivElement.h b/WebCore/html/HTMLDivElement.h new file mode 100644 index 0000000..4d2bd47 --- /dev/null +++ b/WebCore/html/HTMLDivElement.h @@ -0,0 +1,48 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLDivElement_h +#define HTMLDivElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLDivElement : public HTMLElement { +public: + HTMLDivElement(Document*); + ~HTMLDivElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + String align() const; + void setAlign(const String&); +}; + +} // namespace WebCore + +#endif // HTMLDivElement_h diff --git a/WebCore/html/HTMLDivElement.idl b/WebCore/html/HTMLDivElement.idl new file mode 100644 index 0000000..41cc327 --- /dev/null +++ b/WebCore/html/HTMLDivElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=46fb9095-b485-4925-b6fd-2622935fd8bf, + ImplementationUUID=5f8661b7-96ad-4a8b-864a-85d544319fd2 + ] HTMLDivElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; + }; + +} diff --git a/WebCore/html/HTMLDocument.cpp b/WebCore/html/HTMLDocument.cpp new file mode 100644 index 0000000..97557f9 --- /dev/null +++ b/WebCore/html/HTMLDocument.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Portions are Copyright (C) 2002 Netscape Communications Corporation. + * Other contributors: David Baron <dbaron@fas.harvard.edu> + * + * 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.1 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 + * + * Alternatively, the document type parsing portions of this file may be used + * under the terms of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "HTMLDocument.h" + +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "CString.h" +#include "CookieJar.h" +#include "DocumentLoader.h" +#include "DocumentType.h" +#include "ExceptionCode.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLBodyElement.h" +#include "HTMLElement.h" +#include "HTMLElementFactory.h" +#include "HTMLNames.h" +#include "HTMLTokenizer.h" +#include "InspectorController.h" +#include "KURL.h" +#include "Page.h" + +#include "DocTypeStrings.cpp" + +#ifdef ANDROID_META_SUPPORT +#include "FrameTree.h" +#include "Settings.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +HTMLDocument::HTMLDocument(Frame* frame) + : Document(frame, false) +{ + clearXMLVersion(); + setParseMode(Compat); +} + +HTMLDocument::~HTMLDocument() +{ +} + +int HTMLDocument::width() +{ + updateLayoutIgnorePendingStylesheets(); + FrameView* frameView = view(); + return frameView ? frameView->contentsWidth() : 0; +} + +int HTMLDocument::height() +{ + updateLayoutIgnorePendingStylesheets(); + FrameView* frameView = view(); + return frameView ? frameView->contentsHeight() : 0; +} + +String HTMLDocument::dir() +{ + HTMLElement* b = body(); + if (!b) + return String(); + return b->dir(); +} + +void HTMLDocument::setDir(const String& value) +{ + HTMLElement* b = body(); + if (b) + b->setDir(value); +} + +String HTMLDocument::designMode() const +{ + return inDesignMode() ? "on" : "off"; +} + +void HTMLDocument::setDesignMode(const String& value) +{ + InheritedBool mode; + if (equalIgnoringCase(value, "on")) + mode = on; + else if (equalIgnoringCase(value, "off")) + mode = off; + else + mode = inherit; + Document::setDesignMode(mode); +} + +String HTMLDocument::compatMode() const +{ + return inCompatMode() ? "BackCompat" : "CSS1Compat"; +} + +Element* HTMLDocument::activeElement() +{ + if (Node* node = focusedNode()) + if (node->isElementNode()) + return static_cast<Element*>(node); + return body(); +} + +bool HTMLDocument::hasFocus() +{ + if (!page()->focusController()->isActive()) + return false; + if (Frame* focusedFrame = page()->focusController()->focusedFrame()) { + if (focusedFrame->tree()->isDescendantOf(frame())) + return true; + } + return false; +} + +String HTMLDocument::bgColor() +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (!bodyElement) + return String(); + return bodyElement->bgColor(); +} + +void HTMLDocument::setBgColor(const String& value) +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (bodyElement) + bodyElement->setBgColor(value); +} + +String HTMLDocument::fgColor() +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (!bodyElement) + return String(); + return bodyElement->text(); +} + +void HTMLDocument::setFgColor(const String& value) +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (bodyElement) + bodyElement->setText(value); +} + +String HTMLDocument::alinkColor() +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (!bodyElement) + return String(); + return bodyElement->aLink(); +} + +void HTMLDocument::setAlinkColor(const String& value) +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (bodyElement) { + // This check is a bit silly, but some benchmarks like to set the + // document's link colors over and over to the same value and we + // don't want to incur a style update each time. + if (bodyElement->aLink() != value) + bodyElement->setALink(value); + } +} + +String HTMLDocument::linkColor() +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (!bodyElement) + return String(); + return bodyElement->link(); +} + +void HTMLDocument::setLinkColor(const String& value) +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (bodyElement) { + // This check is a bit silly, but some benchmarks like to set the + // document's link colors over and over to the same value and we + // don't want to incur a style update each time. + if (bodyElement->link() != value) + bodyElement->setLink(value); + } +} + +String HTMLDocument::vlinkColor() +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (!bodyElement) + return String(); + return bodyElement->vLink(); +} + +void HTMLDocument::setVlinkColor(const String& value) +{ + HTMLElement* b = body(); + HTMLBodyElement* bodyElement = (b && b->hasTagName(bodyTag)) ? static_cast<HTMLBodyElement*>(b) : 0; + + if (bodyElement) { + // This check is a bit silly, but some benchmarks like to set the + // document's link colors over and over to the same value and we + // don't want to incur a style update each time. + if (bodyElement->vLink() != value) + bodyElement->setVLink(value); + } +} + +void HTMLDocument::captureEvents() +{ +} + +void HTMLDocument::releaseEvents() +{ +} + +Tokenizer *HTMLDocument::createTokenizer() +{ + bool reportErrors = false; + if (frame()) + if (Page* page = frame()->page()) + reportErrors = page->inspectorController()->windowVisible(); + + return new HTMLTokenizer(this, reportErrors); +} + +// -------------------------------------------------------------------------- +// not part of the DOM +// -------------------------------------------------------------------------- + +bool HTMLDocument::childAllowed(Node *newChild) +{ + return newChild->hasTagName(htmlTag) || newChild->isCommentNode() || (newChild->nodeType() == DOCUMENT_TYPE_NODE && !doctype()); +} + +PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec) +{ + if (!isValidName(name)) { + ec = INVALID_CHARACTER_ERR; + return 0; + } + AtomicString lowerName = name.string().impl()->isLower() ? name : AtomicString(name.string().lower()); + return HTMLElementFactory::createHTMLElement(lowerName, this, 0, false); +} + +static void addItemToMap(HTMLDocument::NameCountMap& map, const AtomicString& name) +{ + if (name.isEmpty()) + return; + + HTMLDocument::NameCountMap::iterator it = map.find(name.impl()); + if (it == map.end()) + map.set(name.impl(), 1); + else + ++(it->second); +} + +static void removeItemFromMap(HTMLDocument::NameCountMap& map, const AtomicString& name) +{ + if (name.isEmpty()) + return; + + HTMLDocument::NameCountMap::iterator it = map.find(name.impl()); + if (it == map.end()) + return; + + int oldVal = it->second; + ASSERT(oldVal != 0); + int newVal = oldVal - 1; + if (newVal == 0) + map.remove(it); + else + it->second = newVal; +} + +void HTMLDocument::addNamedItem(const AtomicString& name) +{ + addItemToMap(m_namedItemCounts, name); +} + +void HTMLDocument::removeNamedItem(const AtomicString &name) +{ + removeItemFromMap(m_namedItemCounts, name); +} + +void HTMLDocument::addExtraNamedItem(const AtomicString& name) +{ + addItemToMap(m_extraNamedItemCounts, name); +} + +void HTMLDocument::removeExtraNamedItem(const AtomicString& name) +{ + removeItemFromMap(m_extraNamedItemCounts, name); +} + +void HTMLDocument::determineParseMode() +{ + // FIXME: It's terrible that this code runs separately and isn't just built in to the + // HTML tokenizer/parser. + + // This code more or less mimics Mozilla's implementation (specifically the + // doctype parsing implemented by David Baron in Mozilla's nsParser.cpp). + // + // There are three possible parse modes: + // COMPAT - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can + // be omitted from numbers. + // ALMOST STRICT - This mode is identical to strict mode except for its treatment of line-height in the inline box model. For + // now (until the inline box model is re-written), this mode is identical to STANDARDS mode. + // STRICT - no quirks apply. Web pages will obey the specifications to the letter. + bool wasInCompatMode = inCompatMode(); + DocumentType* docType = doctype(); + if (!docType || !equalIgnoringCase(docType->name(), "html")) + // No doctype found at all or the doctype is not HTML. Default to quirks mode and Html4. + setParseMode(Compat); + else if (!doctype()->systemId().isEmpty() && equalIgnoringCase(docType->systemId(), "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")) + // Assume quirks mode for this particular system ID. In the HTML5 spec, this is the only + // system identifier that is examined. + setParseMode(Compat); + else if (docType->publicId().isEmpty()) + // A doctype without a public ID means use strict mode. + setParseMode(Strict); + else { + // We have to check a list of public IDs to see what we + // should do. + String lowerPubID = docType->publicId().lower(); + CString pubIDStr = lowerPubID.latin1(); + +#ifdef ANDROID_META_SUPPORT + if ((!frame()->tree() || !frame()->tree()->parent()) && + strstr(pubIDStr.data(), "-//wapforum//dtd xhtml mobile 1.") == pubIDStr.data()) { + // fit mobile sites directly in the screen + frame()->settings()->setMetadataSettings("width", "device-width"); + } +#endif + // Look up the entry in our gperf-generated table. + const PubIDInfo* doctypeEntry = findDoctypeEntry(pubIDStr.data(), pubIDStr.length()); + if (!doctypeEntry) + // The DOCTYPE is not in the list. Assume strict mode. + setParseMode(Strict); + else { + switch (docType->systemId().isEmpty() ? + doctypeEntry->mode_if_no_sysid : + doctypeEntry->mode_if_sysid) { + case PubIDInfo::eQuirks3: + case PubIDInfo::eQuirks: + setParseMode(Compat); + break; + case PubIDInfo::eAlmostStandards: + setParseMode(AlmostStrict); + break; + default: + ASSERT(false); + } + } + } + + if (inCompatMode() != wasInCompatMode) + updateStyleSelector(); +} + +void HTMLDocument::clear() +{ + // FIXME: This does nothing, and that seems unlikely to be correct. + // We've long had a comment saying that IE doesn't support this. + // But I do see it in the documentation for Mozilla. +} + +} diff --git a/WebCore/html/HTMLDocument.h b/WebCore/html/HTMLDocument.h new file mode 100644 index 0000000..de84c70 --- /dev/null +++ b/WebCore/html/HTMLDocument.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 HTMLDocument_h +#define HTMLDocument_h + +#include "CachedResourceClient.h" +#include "Document.h" + +namespace WebCore { + +class FrameView; +class HTMLElement; + +class HTMLDocument : public Document, public CachedResourceClient { +public: + static PassRefPtr<HTMLDocument> create(Frame* frame) + { + return new HTMLDocument(frame); + } + virtual ~HTMLDocument(); + + int width(); + int height(); + + String dir(); + void setDir(const String&); + + String designMode() const; + void setDesignMode(const String&); + + String compatMode() const; + + Element* activeElement(); + bool hasFocus(); + + String bgColor(); + void setBgColor(const String&); + String fgColor(); + void setFgColor(const String&); + String alinkColor(); + void setAlinkColor(const String&); + String linkColor(); + void setLinkColor(const String&); + String vlinkColor(); + void setVlinkColor(const String&); + + void clear(); + + void captureEvents(); + void releaseEvents(); + + virtual bool childAllowed(Node*); + + virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&); + + void addNamedItem(const AtomicString& name); + void removeNamedItem(const AtomicString& name); + bool hasNamedItem(AtomicStringImpl* name); + + void addExtraNamedItem(const AtomicString& name); + void removeExtraNamedItem(const AtomicString& name); + bool hasExtraNamedItem(AtomicStringImpl* name); + + typedef HashMap<AtomicStringImpl*, int> NameCountMap; + +protected: + HTMLDocument(Frame*); + +private: + virtual bool isHTMLDocument() const { return true; } + virtual Tokenizer* createTokenizer(); + virtual void determineParseMode(); + + NameCountMap m_namedItemCounts; + NameCountMap m_extraNamedItemCounts; +}; + +inline bool HTMLDocument::hasNamedItem(AtomicStringImpl* name) +{ + ASSERT(name); + return m_namedItemCounts.contains(name); +} + +inline bool HTMLDocument::hasExtraNamedItem(AtomicStringImpl* name) +{ + ASSERT(name); + return m_extraNamedItemCounts.contains(name); +} + +} // namespace + +#endif diff --git a/WebCore/html/HTMLDocument.idl b/WebCore/html/HTMLDocument.idl new file mode 100644 index 0000000..4345195 --- /dev/null +++ b/WebCore/html/HTMLDocument.idl @@ -0,0 +1,67 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + HasOverridingNameGetter, + InterfaceUUID=a183339c-8d74-412a-933d-6f6a4ad6266e, + ImplementationUUID=d0f7d966-033c-4cbf-847c-1461dacc2f6a + ] HTMLDocument : Document { + [Custom] void open(); + void close(); + [Custom] void write(in DOMString text); + [Custom] void writeln(in DOMString text); + + readonly attribute HTMLCollection embeds; + readonly attribute HTMLCollection plugins; + readonly attribute HTMLCollection scripts; + + // Extensions + +#if defined(LANGUAGE_JAVASCRIPT) + // FIXME: This should eventually be available (if they are wanted) for all languages. + attribute [Custom, Deletable] HTMLCollection all; +#endif + + void clear(); + + void captureEvents(); + void releaseEvents(); + + readonly attribute long width; + readonly attribute long height; + attribute [ConvertNullToNullString] DOMString dir; + attribute [ConvertNullToNullString] DOMString designMode; + readonly attribute DOMString compatMode; + + readonly attribute Element activeElement; + boolean hasFocus(); + + // Deprecated attributes + attribute [ConvertNullToNullString] DOMString bgColor; + attribute [ConvertNullToNullString] DOMString fgColor; + attribute [ConvertNullToNullString] DOMString alinkColor; + attribute [ConvertNullToNullString] DOMString linkColor; + attribute [ConvertNullToNullString] DOMString vlinkColor; + }; + +} diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp new file mode 100644 index 0000000..572a7a5 --- /dev/null +++ b/WebCore/html/HTMLElement.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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 "HTMLElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "DocumentFragment.h" +#include "Event.h" +#include "EventListener.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "HTMLBRElement.h" +#include "HTMLDocument.h" +#include "HTMLElementFactory.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" +#include "HTMLTokenizer.h" +#include "RenderWordBreak.h" +#include "Settings.h" +#include "Text.h" +#include "TextIterator.h" +#include "XMLTokenizer.h" +#include "markup.h" + +namespace WebCore { + +using namespace HTMLNames; + +using std::min; +using std::max; + +HTMLElement::HTMLElement(const QualifiedName& tagName, Document *doc) + : StyledElement(tagName, doc) +{ +} + +HTMLElement::~HTMLElement() +{ +} + +String HTMLElement::nodeName() const +{ + // FIXME: Would be nice to have an atomicstring lookup based off uppercase chars that does not have to copy + // the string on a hit in the hash. + if (document()->isHTMLDocument()) + return tagQName().localName().string().upper(); + return Element::nodeName(); +} + +HTMLTagStatus HTMLElement::endTagRequirement() const +{ + if (hasLocalName(wbrTag)) + return TagStatusForbidden; + if (hasLocalName(dtTag) || hasLocalName(ddTag)) + return TagStatusOptional; + + // Same values as <span>. This way custom tag name elements will behave like inline spans. + return TagStatusRequired; +} + +int HTMLElement::tagPriority() const +{ + if (hasLocalName(wbrTag)) + return 0; + if (hasLocalName(addressTag) || hasLocalName(ddTag) || hasLocalName(dtTag) || hasLocalName(noscriptTag)) + return 3; + if (hasLocalName(centerTag) || hasLocalName(nobrTag)) + return 5; + if (hasLocalName(noembedTag) || hasLocalName(noframesTag)) + return 10; + + // Same values as <span>. This way custom tag name elements will behave like inline spans. + return 1; +} + +PassRefPtr<Node> HTMLElement::cloneNode(bool deep) +{ + RefPtr<HTMLElement> clone = HTMLElementFactory::createHTMLElement(tagQName().localName(), document(), 0, false); + if (!clone) + return 0; + + if (namedAttrMap) + clone->attributes()->setAttributes(*namedAttrMap); + + clone->copyNonAttributeProperties(this); + + if (deep) + cloneChildNodes(clone.get()); + + return clone.release(); +} + +bool HTMLElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == alignAttr || + attrName == contenteditableAttr) { + result = eUniversal; + return false; + } + if (attrName == dirAttr) { + result = hasLocalName(bdoTag) ? eBDO : eUniversal; + return false; + } + + return StyledElement::mapToEntry(attrName, result); +} + +void HTMLElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == idAttr || attr->name() == classAttr || attr->name() == styleAttr) + return StyledElement::parseMappedAttribute(attr); + + String indexstring; + if (attr->name() == alignAttr) { + if (equalIgnoringCase(attr->value(), "middle")) + addCSSProperty(attr, CSSPropertyTextAlign, "center"); + else + addCSSProperty(attr, CSSPropertyTextAlign, attr->value()); + } else if (attr->name() == contenteditableAttr) { + setContentEditable(attr); + } else if (attr->name() == tabindexAttr) { + indexstring = getAttribute(tabindexAttr); + if (indexstring.length()) { + bool parsedOK; + int tabindex = indexstring.toIntStrict(&parsedOK); + if (parsedOK) + // Clamp tabindex to the range of 'short' to match Firefox's behavior. + setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max())))); + } + } else if (attr->name() == langAttr) { + // FIXME: Implement + } else if (attr->name() == dirAttr) { + addCSSProperty(attr, CSSPropertyDirection, attr->value()); + addCSSProperty(attr, CSSPropertyUnicodeBidi, hasLocalName(bdoTag) ? CSSValueBidiOverride : CSSValueEmbed); + } +// standard events + else if (attr->name() == onclickAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().clickEvent, attr); + } else if (attr->name() == oncontextmenuAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().contextmenuEvent, attr); + } else if (attr->name() == ondblclickAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dblclickEvent, attr); + } else if (attr->name() == onmousedownAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mousedownEvent, attr); + } else if (attr->name() == onmousemoveAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mousemoveEvent, attr); + } else if (attr->name() == onmouseoutAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mouseoutEvent, attr); + } else if (attr->name() == onmouseoverAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mouseoverEvent, attr); + } else if (attr->name() == onmouseupAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mouseupEvent, attr); + } else if (attr->name() == onmousewheelAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().mousewheelEvent, attr); + } else if (attr->name() == onfocusAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + } else if (attr->name() == onblurAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + } else if (attr->name() == onkeydownAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().keydownEvent, attr); + } else if (attr->name() == onkeypressAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().keypressEvent, attr); + } else if (attr->name() == onkeyupAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().keyupEvent, attr); + } else if (attr->name() == onscrollAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().scrollEvent, attr); + } else if (attr->name() == onbeforecutAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().beforecutEvent, attr); + } else if (attr->name() == oncutAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().cutEvent, attr); + } else if (attr->name() == onbeforecopyAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().beforecopyEvent, attr); + } else if (attr->name() == oncopyAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().copyEvent, attr); + } else if (attr->name() == onbeforepasteAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().beforepasteEvent, attr); + } else if (attr->name() == onpasteAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().pasteEvent, attr); + } else if (attr->name() == ondragenterAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragenterEvent, attr); + } else if (attr->name() == ondragoverAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragoverEvent, attr); + } else if (attr->name() == ondragleaveAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragleaveEvent, attr); + } else if (attr->name() == ondropAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dropEvent, attr); + } else if (attr->name() == ondragstartAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragstartEvent, attr); + } else if (attr->name() == ondragAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragEvent, attr); + } else if (attr->name() == ondragendAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().dragendEvent, attr); + } else if (attr->name() == onselectstartAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().selectstartEvent, attr); + } else if (attr->name() == onsubmitAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().submitEvent, attr); + } else if (attr->name() == onerrorAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().errorEvent, attr); + } else if (attr->name() == onwebkitanimationstartAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationStartEvent, attr); + } else if (attr->name() == onwebkitanimationiterationAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationIterationEvent, attr); + } else if (attr->name() == onwebkitanimationendAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationEndEvent, attr); + } else if (attr->name() == onwebkittransitionendAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().webkitTransitionEndEvent, attr); +#if ENABLE(TOUCH_EVENTS) // Android + } else if (attr->name() == ontouchstartAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().touchstartEvent, attr); + } else if (attr->name() == ontouchendAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().touchendEvent, attr); + } else if (attr->name() == ontouchmoveAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().touchmoveEvent, attr); + } else if (attr->name() == ontouchcancelAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().touchcancelEvent, attr); +#endif + } +} + +String HTMLElement::innerHTML() const +{ + return createMarkup(this, ChildrenOnly); +} + +String HTMLElement::outerHTML() const +{ + return createMarkup(this); +} + +PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String &html) +{ + // the following is in accordance with the definition as used by IE + if (endTagRequirement() == TagStatusForbidden) + return 0; + + if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) || + hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag)) + return 0; + + RefPtr<DocumentFragment> fragment = new DocumentFragment(document()); + + if (document()->isHTMLDocument()) + parseHTMLDocumentFragment(html, fragment.get()); + else { + if (!parseXMLDocumentFragment(html, fragment.get(), this)) + // FIXME: We should propagate a syntax error exception out here. + return 0; + } + + // Exceptions are ignored because none ought to happen here. + int ignoredExceptionCode; + + // we need to pop <html> and <body> elements and remove <head> to + // accommodate folks passing complete HTML documents to make the + // child of an element. + + RefPtr<Node> nextNode; + for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { + nextNode = node->nextSibling(); + if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) { + Node *firstChild = node->firstChild(); + if (firstChild) + nextNode = firstChild; + RefPtr<Node> nextChild; + for (RefPtr<Node> child = firstChild; child; child = nextChild) { + nextChild = child->nextSibling(); + node->removeChild(child.get(), ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + fragment->insertBefore(child, node.get(), ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + } + fragment->removeChild(node.get(), ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + } else if (node->hasTagName(headTag)) { + fragment->removeChild(node.get(), ignoredExceptionCode); + ASSERT(!ignoredExceptionCode); + } + } + + return fragment.release(); +} + +static inline bool hasOneChild(ContainerNode* node) +{ + Node* firstChild = node->firstChild(); + return firstChild && !firstChild->nextSibling(); +} + +static inline bool hasOneTextChild(ContainerNode* node) +{ + return hasOneChild(node) && node->firstChild()->isTextNode(); +} + +static void replaceChildrenWithFragment(HTMLElement* element, PassRefPtr<DocumentFragment> fragment, ExceptionCode& ec) +{ + if (!fragment->firstChild()) { + element->removeChildren(); + return; + } + + if (hasOneTextChild(element) && hasOneTextChild(fragment.get())) { + static_cast<Text*>(element->firstChild())->setData(static_cast<Text*>(fragment->firstChild())->string(), ec); + return; + } + + if (hasOneChild(element)) { + element->replaceChild(fragment, element->firstChild(), ec); + return; + } + + element->removeChildren(); + element->appendChild(fragment, ec); +} + +static void replaceChildrenWithText(HTMLElement* element, const String& text, ExceptionCode& ec) +{ + if (hasOneTextChild(element)) { + static_cast<Text*>(element->firstChild())->setData(text, ec); + return; + } + + RefPtr<Text> textNode = new Text(element->document(), text); + + if (hasOneChild(element)) { + element->replaceChild(textNode.release(), element->firstChild(), ec); + return; + } + + element->removeChildren(); + element->appendChild(textNode.release(), ec); +} + +void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec) +{ + RefPtr<DocumentFragment> fragment = createContextualFragment(html); + if (!fragment) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + replaceChildrenWithFragment(this, fragment.release(), ec); +} + +void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec) +{ + Node* p = parent(); + if (!p || !p->isHTMLElement()) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + HTMLElement* parent = static_cast<HTMLElement*>(p); + RefPtr<DocumentFragment> fragment = parent->createContextualFragment(html); + if (!fragment) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + // FIXME: Why doesn't this have code to merge neighboring text nodes the way setOuterText does? + + parent->replaceChild(fragment.release(), this, ec); +} + +void HTMLElement::setInnerText(const String& text, ExceptionCode& ec) +{ + // follow the IE specs about when this is allowed + if (endTagRequirement() == TagStatusForbidden) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) || + hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || + hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) || + hasLocalName(trTag)) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + // FIXME: This doesn't take whitespace collapsing into account at all. + + if (!text.contains('\n') && !text.contains('\r')) { + if (text.isEmpty()) { + removeChildren(); + return; + } + replaceChildrenWithText(this, text, ec); + return; + } + + // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer? + // FIXME: Can the renderer be out of date here? Do we need to call updateRendering? + // For example, for the contents of textarea elements that are display:none? + RenderObject* r = renderer(); + if (r && r->style()->preserveNewline()) { + if (!text.contains('\r')) { + replaceChildrenWithText(this, text, ec); + return; + } + String textWithConsistentLineBreaks = text; + textWithConsistentLineBreaks.replace("\r\n", "\n"); + textWithConsistentLineBreaks.replace('\r', '\n'); + replaceChildrenWithText(this, textWithConsistentLineBreaks, ec); + return; + } + + // Add text nodes and <br> elements. + ec = 0; + RefPtr<DocumentFragment> fragment = new DocumentFragment(document()); + int lineStart = 0; + UChar prev = 0; + int length = text.length(); + for (int i = 0; i < length; ++i) { + UChar c = text[i]; + if (c == '\n' || c == '\r') { + if (i > lineStart) { + fragment->appendChild(new Text(document(), text.substring(lineStart, i - lineStart)), ec); + if (ec) + return; + } + if (!(c == '\n' && i != 0 && prev == '\r')) { + fragment->appendChild(new HTMLBRElement(document()), ec); + if (ec) + return; + } + lineStart = i + 1; + } + prev = c; + } + if (length > lineStart) + fragment->appendChild(new Text(document(), text.substring(lineStart, length - lineStart)), ec); + replaceChildrenWithFragment(this, fragment.release(), ec); +} + +void HTMLElement::setOuterText(const String &text, ExceptionCode& ec) +{ + // follow the IE specs about when this is allowed + if (endTagRequirement() == TagStatusForbidden) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) || + hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || + hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) || + hasLocalName(trTag)) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + Node* parent = parentNode(); + if (!parent) { + ec = NO_MODIFICATION_ALLOWED_ERR; + return; + } + + // FIXME: This creates a new text node even when the text is empty. + // FIXME: This creates a single text node even when the text has CR and LF + // characters in it. Instead it should create <br> elements. + RefPtr<Text> t = new Text(document(), text); + ec = 0; + parent->replaceChild(t, this, ec); + if (ec) + return; + + // is previous node a text node? if so, merge into it + Node* prev = t->previousSibling(); + if (prev && prev->isTextNode()) { + Text* textPrev = static_cast<Text*>(prev); + textPrev->appendData(t->data(), ec); + if (ec) + return; + t->remove(ec); + if (ec) + return; + t = textPrev; + } + + // is next node a text node? if so, merge it in + Node* next = t->nextSibling(); + if (next && next->isTextNode()) { + Text* textNext = static_cast<Text*>(next); + t->appendData(textNext->data(), ec); + if (ec) + return; + textNext->remove(ec); + if (ec) + return; + } +} + +Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, ExceptionCode& ec) +{ + // In Internet Explorer if the element has no parent and where is "beforeBegin" or "afterEnd", + // a document fragment is created and the elements appended in the correct order. This document + // fragment isn't returned anywhere. + // + // This is impossible for us to implement as the DOM tree does not allow for such structures, + // Opera also appears to disallow such usage. + + if (equalIgnoringCase(where, "beforeBegin")) { + if (Node* p = parent()) + return p->insertBefore(newChild, this, ec) ? newChild : 0; + return 0; + } + + if (equalIgnoringCase(where, "afterBegin")) + return insertBefore(newChild, firstChild(), ec) ? newChild : 0; + + if (equalIgnoringCase(where, "beforeEnd")) + return appendChild(newChild, ec) ? newChild : 0; + + if (equalIgnoringCase(where, "afterEnd")) { + if (Node* p = parent()) + return p->insertBefore(newChild, nextSibling(), ec) ? newChild : 0; + return 0; + } + + // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative + ec = NOT_SUPPORTED_ERR; + return 0; +} + +Element* HTMLElement::insertAdjacentElement(const String& where, Element* newChild, ExceptionCode& ec) +{ + if (!newChild) { + // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative + ec = TYPE_MISMATCH_ERR; + return 0; + } + + Node* returnValue = insertAdjacent(where, newChild, ec); + ASSERT(!returnValue || returnValue->isElementNode()); + return static_cast<Element*>(returnValue); +} + +void HTMLElement::insertAdjacentHTML(const String& where, const String& html, ExceptionCode& ec) +{ + RefPtr<DocumentFragment> fragment = document()->createDocumentFragment(); + if (document()->isHTMLDocument()) + parseHTMLDocumentFragment(html, fragment.get()); + else { + if (!parseXMLDocumentFragment(html, fragment.get(), this)) + // FIXME: We should propagate a syntax error exception out here. + return; + } + + insertAdjacent(where, fragment.get(), ec); +} + +void HTMLElement::insertAdjacentText(const String& where, const String& text, ExceptionCode& ec) +{ + RefPtr<Text> textNode = document()->createTextNode(text); + insertAdjacent(where, textNode.get(), ec); +} + +void HTMLElement::addHTMLAlignment(MappedAttribute* attr) +{ + // vertical alignment with respect to the current baseline of the text + // right or left means floating images + int propfloat = -1; + int propvalign = -1; + const AtomicString& alignment = attr->value(); + if (equalIgnoringCase(alignment, "absmiddle")) { + propvalign = CSSValueMiddle; + } else if (equalIgnoringCase(alignment, "absbottom")) { + propvalign = CSSValueBottom; + } else if (equalIgnoringCase(alignment, "left")) { + propfloat = CSSValueLeft; + propvalign = CSSValueTop; + } else if (equalIgnoringCase(alignment, "right")) { + propfloat = CSSValueRight; + propvalign = CSSValueTop; + } else if (equalIgnoringCase(alignment, "top")) { + propvalign = CSSValueTop; + } else if (equalIgnoringCase(alignment, "middle")) { + propvalign = CSSValueWebkitBaselineMiddle; + } else if (equalIgnoringCase(alignment, "center")) { + propvalign = CSSValueMiddle; + } else if (equalIgnoringCase(alignment, "bottom")) { + propvalign = CSSValueBaseline; + } else if (equalIgnoringCase(alignment, "texttop")) { + propvalign = CSSValueTextTop; + } + + if ( propfloat != -1 ) + addCSSProperty( attr, CSSPropertyFloat, propfloat ); + if ( propvalign != -1 ) + addCSSProperty( attr, CSSPropertyVerticalAlign, propvalign ); +} + +bool HTMLElement::isFocusable() const +{ + return Element::isFocusable() || (isContentEditable() && parent() && !parent()->isContentEditable()); +} + +bool HTMLElement::isContentEditable() const +{ + if (document()->frame() && document()->frame()->isContentEditable()) + return true; + + document()->updateRendering(); + + if (!renderer()) { + if (parentNode()) + return parentNode()->isContentEditable(); + else + return false; + } + + return renderer()->style()->userModify() == READ_WRITE || renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY; +} + +bool HTMLElement::isContentRichlyEditable() const +{ + if (document()->frame() && document()->frame()->isContentEditable()) + return true; + + document()->updateRendering(); + + if (!renderer()) { + if (parentNode()) + return parentNode()->isContentEditable(); + else + return false; + } + + return renderer()->style()->userModify() == READ_WRITE; +} + +String HTMLElement::contentEditable() const +{ + document()->updateRendering(); + + if (!renderer()) + return "false"; + + switch (renderer()->style()->userModify()) { + case READ_WRITE: + return "true"; + case READ_ONLY: + return "false"; + case READ_WRITE_PLAINTEXT_ONLY: + return "plaintext-only"; + default: + return "inherit"; + } +} + +void HTMLElement::setContentEditable(MappedAttribute* attr) +{ + const AtomicString& enabled = attr->value(); + if (enabled.isEmpty() || equalIgnoringCase(enabled, "true")) { + addCSSProperty(attr, CSSPropertyWebkitUserModify, CSSValueReadWrite); + addCSSProperty(attr, CSSPropertyWordWrap, CSSValueBreakWord); + addCSSProperty(attr, CSSPropertyWebkitNbspMode, CSSValueSpace); + addCSSProperty(attr, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace); + } else if (equalIgnoringCase(enabled, "false")) { + addCSSProperty(attr, CSSPropertyWebkitUserModify, CSSValueReadOnly); + attr->decl()->removeProperty(CSSPropertyWordWrap, false); + attr->decl()->removeProperty(CSSPropertyWebkitNbspMode, false); + attr->decl()->removeProperty(CSSPropertyWebkitLineBreak, false); + } else if (equalIgnoringCase(enabled, "inherit")) { + addCSSProperty(attr, CSSPropertyWebkitUserModify, CSSValueInherit); + attr->decl()->removeProperty(CSSPropertyWordWrap, false); + attr->decl()->removeProperty(CSSPropertyWebkitNbspMode, false); + attr->decl()->removeProperty(CSSPropertyWebkitLineBreak, false); + } else if (equalIgnoringCase(enabled, "plaintext-only")) { + addCSSProperty(attr, CSSPropertyWebkitUserModify, CSSValueReadWritePlaintextOnly); + addCSSProperty(attr, CSSPropertyWordWrap, CSSValueBreakWord); + addCSSProperty(attr, CSSPropertyWebkitNbspMode, CSSValueSpace); + addCSSProperty(attr, CSSPropertyWebkitLineBreak, CSSValueAfterWhiteSpace); + } +} + +void HTMLElement::setContentEditable(const String &enabled) +{ + if (enabled == "inherit") { + ExceptionCode ec; + removeAttribute(contenteditableAttr, ec); + } + else + setAttribute(contenteditableAttr, enabled.isEmpty() ? "true" : enabled); +} + +void HTMLElement::click() +{ + dispatchSimulatedClick(0, false, false); +} + +// accessKeyAction is used by the accessibility support code +// to send events to elements that our JavaScript caller does +// does not. The elements JS is interested in have subclasses +// that override this method to direct the click appropriately. +// Here in the base class, then, we only send the click if +// the caller wants it to go to any HTMLElement, and we say +// to send the mouse events in addition to the click. +void HTMLElement::accessKeyAction(bool sendToAnyElement) +{ + if (sendToAnyElement) + dispatchSimulatedClick(0, true); +} + +String HTMLElement::id() const +{ + return getAttribute(idAttr); +} + +void HTMLElement::setId(const String& value) +{ + setAttribute(idAttr, value); +} + +String HTMLElement::title() const +{ + return getAttribute(titleAttr); +} + +void HTMLElement::setTitle(const String& value) +{ + setAttribute(titleAttr, value); +} + +String HTMLElement::lang() const +{ + return getAttribute(langAttr); +} + +void HTMLElement::setLang(const String& value) +{ + setAttribute(langAttr, value); +} + +String HTMLElement::dir() const +{ + return getAttribute(dirAttr); +} + +void HTMLElement::setDir(const String &value) +{ + setAttribute(dirAttr, value); +} + +String HTMLElement::className() const +{ + return getAttribute(classAttr); +} + +void HTMLElement::setClassName(const String &value) +{ + setAttribute(classAttr, value); +} + +short HTMLElement::tabIndex() const +{ + if (supportsFocus()) + return Element::tabIndex(); + return -1; +} + +void HTMLElement::setTabIndex(int value) +{ + setAttribute(tabindexAttr, String::number(value)); +} + +PassRefPtr<HTMLCollection> HTMLElement::children() +{ + return HTMLCollection::create(this, HTMLCollection::NodeChildren); +} + +// DOM Section 1.1.1 +bool HTMLElement::childAllowed(Node *newChild) +{ + if (!Element::childAllowed(newChild)) + return false; + + // For XML documents, we are non-validating and do not check against a DTD, even for HTML elements. + if (!document()->isHTMLDocument()) + return true; + + // Future-proof for XML content inside HTML documents (we may allow this some day). + if (newChild->isElementNode() && !newChild->isHTMLElement()) + return true; + + // Elements with forbidden tag status can never have children + if (endTagRequirement() == TagStatusForbidden) + return false; + + // Comment nodes are always allowed. + if (newChild->isCommentNode()) + return true; + + // Now call checkDTD. + return checkDTD(newChild); +} + +// DTD Stuff +// This unfortunate function is only needed when checking against the DTD. Other languages (like SVG) won't need this. +bool HTMLElement::isRecognizedTagName(const QualifiedName& tagName) +{ + static HashSet<AtomicStringImpl*> tagList; + if (tagList.isEmpty()) { + size_t tagCount = 0; + WebCore::QualifiedName** tags = HTMLNames::getHTMLTags(&tagCount); + for (size_t i = 0; i < tagCount; i++) + tagList.add(tags[i]->localName().impl()); + } + return tagList.contains(tagName.localName().impl()); +} + +// The terms inline and block are used here loosely. Don't make the mistake of assuming all inlines or all blocks +// need to be in these two lists. +HashSet<AtomicStringImpl*>* inlineTagList() +{ + static HashSet<AtomicStringImpl*> tagList; + if (tagList.isEmpty()) { + tagList.add(ttTag.localName().impl()); + tagList.add(iTag.localName().impl()); + tagList.add(bTag.localName().impl()); + tagList.add(uTag.localName().impl()); + tagList.add(sTag.localName().impl()); + tagList.add(strikeTag.localName().impl()); + tagList.add(bigTag.localName().impl()); + tagList.add(smallTag.localName().impl()); + tagList.add(emTag.localName().impl()); + tagList.add(strongTag.localName().impl()); + tagList.add(dfnTag.localName().impl()); + tagList.add(codeTag.localName().impl()); + tagList.add(sampTag.localName().impl()); + tagList.add(kbdTag.localName().impl()); + tagList.add(varTag.localName().impl()); + tagList.add(citeTag.localName().impl()); + tagList.add(abbrTag.localName().impl()); + tagList.add(acronymTag.localName().impl()); + tagList.add(aTag.localName().impl()); + tagList.add(canvasTag.localName().impl()); + tagList.add(imgTag.localName().impl()); + tagList.add(appletTag.localName().impl()); + tagList.add(objectTag.localName().impl()); + tagList.add(embedTag.localName().impl()); + tagList.add(fontTag.localName().impl()); + tagList.add(basefontTag.localName().impl()); + tagList.add(brTag.localName().impl()); + tagList.add(scriptTag.localName().impl()); + tagList.add(styleTag.localName().impl()); + tagList.add(linkTag.localName().impl()); + tagList.add(mapTag.localName().impl()); + tagList.add(qTag.localName().impl()); + tagList.add(subTag.localName().impl()); + tagList.add(supTag.localName().impl()); + tagList.add(spanTag.localName().impl()); + tagList.add(bdoTag.localName().impl()); + tagList.add(iframeTag.localName().impl()); + tagList.add(inputTag.localName().impl()); + tagList.add(keygenTag.localName().impl()); + tagList.add(selectTag.localName().impl()); + tagList.add(textareaTag.localName().impl()); + tagList.add(labelTag.localName().impl()); + tagList.add(buttonTag.localName().impl()); + tagList.add(insTag.localName().impl()); + tagList.add(delTag.localName().impl()); + tagList.add(nobrTag.localName().impl()); + tagList.add(wbrTag.localName().impl()); +#if ENABLE(VIDEO) + tagList.add(audioTag.localName().impl()); + tagList.add(videoTag.localName().impl()); +#endif + } + return &tagList; +} + +HashSet<AtomicStringImpl*>* blockTagList() +{ + static HashSet<AtomicStringImpl*> tagList; + if (tagList.isEmpty()) { + tagList.add(addressTag.localName().impl()); + tagList.add(blockquoteTag.localName().impl()); + tagList.add(centerTag.localName().impl()); + tagList.add(ddTag.localName().impl()); + tagList.add(dirTag.localName().impl()); + tagList.add(divTag.localName().impl()); + tagList.add(dlTag.localName().impl()); + tagList.add(dtTag.localName().impl()); + tagList.add(fieldsetTag.localName().impl()); + tagList.add(formTag.localName().impl()); + tagList.add(h1Tag.localName().impl()); + tagList.add(h2Tag.localName().impl()); + tagList.add(h3Tag.localName().impl()); + tagList.add(h4Tag.localName().impl()); + tagList.add(h5Tag.localName().impl()); + tagList.add(h6Tag.localName().impl()); + tagList.add(hrTag.localName().impl()); + tagList.add(isindexTag.localName().impl()); + tagList.add(layerTag.localName().impl()); + tagList.add(liTag.localName().impl()); + tagList.add(listingTag.localName().impl()); + tagList.add(marqueeTag.localName().impl()); + tagList.add(menuTag.localName().impl()); + tagList.add(noembedTag.localName().impl()); + tagList.add(noframesTag.localName().impl()); + tagList.add(nolayerTag.localName().impl()); + tagList.add(noscriptTag.localName().impl()); + tagList.add(olTag.localName().impl()); + tagList.add(pTag.localName().impl()); + tagList.add(plaintextTag.localName().impl()); + tagList.add(preTag.localName().impl()); + tagList.add(tableTag.localName().impl()); + tagList.add(ulTag.localName().impl()); + tagList.add(xmpTag.localName().impl()); + } + return &tagList; +} + +bool HTMLElement::inEitherTagList(const Node* newChild) +{ + if (newChild->isTextNode()) + return true; + + if (newChild->isHTMLElement()) { + const HTMLElement* child = static_cast<const HTMLElement*>(newChild); + if (inlineTagList()->contains(child->tagQName().localName().impl())) + return true; + if (blockTagList()->contains(child->tagQName().localName().impl())) + return true; + return !isRecognizedTagName(child->tagQName()); // Accept custom html tags + } + + return false; +} + +bool HTMLElement::inInlineTagList(const Node* newChild) +{ + if (newChild->isTextNode()) + return true; + + if (newChild->isHTMLElement()) { + const HTMLElement* child = static_cast<const HTMLElement*>(newChild); + if (inlineTagList()->contains(child->tagQName().localName().impl())) + return true; + return !isRecognizedTagName(child->tagQName()); // Accept custom html tags + } + + return false; +} + +bool HTMLElement::inBlockTagList(const Node* newChild) +{ + if (newChild->isTextNode()) + return true; + + if (newChild->isHTMLElement()) { + const HTMLElement* child = static_cast<const HTMLElement*>(newChild); + return (blockTagList()->contains(child->tagQName().localName().impl())); + } + + return false; +} + +bool HTMLElement::checkDTD(const Node* newChild) +{ + if (hasLocalName(addressTag) && newChild->hasTagName(pTag)) + return true; + return inEitherTagList(newChild); +} + +bool HTMLElement::rendererIsNeeded(RenderStyle *style) +{ + if (hasLocalName(noscriptTag)) { + Settings* settings = document()->settings(); + if (settings && settings->isJavaScriptEnabled()) + return false; + } + return (document()->documentElement() == this) || (style->display() != NONE); +} + +RenderObject* HTMLElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (hasLocalName(wbrTag)) + return new (arena) RenderWordBreak(this); + return RenderObject::createObject(this, style); +} + +HTMLFormElement* HTMLElement::findFormAncestor() const +{ + for (Node* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) + if (ancestor->hasTagName(formTag)) + return static_cast<HTMLFormElement*>(ancestor); + return 0; +} + +HTMLFormElement* HTMLElement::virtualForm() const +{ + return findFormAncestor(); +} + +} // namespace WebCore + +#ifndef NDEBUG +void dumpInnerHTML(WebCore::HTMLElement* element) +{ + printf("%s\n", element->innerHTML().ascii().data()); +} +#endif diff --git a/WebCore/html/HTMLElement.h b/WebCore/html/HTMLElement.h new file mode 100644 index 0000000..1fba130 --- /dev/null +++ b/WebCore/html/HTMLElement.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLElement_h +#define HTMLElement_h + +#include "StyledElement.h" + +namespace WebCore { + +class DocumentFragment; +class HTMLCollection; +class HTMLFormElement; + +enum HTMLTagStatus { TagStatusOptional, TagStatusRequired, TagStatusForbidden }; + +class HTMLElement : public StyledElement { +public: + HTMLElement(const QualifiedName& tagName, Document*); + virtual ~HTMLElement(); + + virtual bool isHTMLElement() const { return true; } + + virtual String nodeName() const; + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual PassRefPtr<Node> cloneNode(bool deep); + + PassRefPtr<HTMLCollection> children(); + + String id() const; + void setId(const String&); + virtual String title() const; + void setTitle(const String&); + String lang() const; + void setLang(const String&); + String dir() const; + void setDir(const String&); + String className() const; + void setClassName(const String&); + virtual short tabIndex() const; + void setTabIndex(int); + + String innerHTML() const; + String outerHTML() const; + PassRefPtr<DocumentFragment> createContextualFragment(const String&); + void setInnerHTML(const String&, ExceptionCode&); + void setOuterHTML(const String&, ExceptionCode&); + void setInnerText(const String&, ExceptionCode&); + void setOuterText(const String&, ExceptionCode&); + + Element* insertAdjacentElement(const String& where, Element* newChild, ExceptionCode&); + void insertAdjacentHTML(const String& where, const String& html, ExceptionCode&); + void insertAdjacentText(const String& where, const String& text, ExceptionCode&); + + virtual bool isFocusable() const; + virtual bool isContentEditable() const; + virtual bool isContentRichlyEditable() const; + virtual String contentEditable() const; + virtual void setContentEditable(MappedAttribute*); + virtual void setContentEditable(const String&); + + void click(); + + virtual void accessKeyAction(bool sendToAnyElement); + + virtual bool isGenericFormElement() const { return false; } + + virtual HTMLTagStatus endTagRequirement() const; + virtual int tagPriority() const; + virtual bool childAllowed(Node* newChild); // Error-checking during parsing that checks the DTD + + // Helper function to check the DTD for a given child node. + virtual bool checkDTD(const Node*); + static bool inEitherTagList(const Node*); + static bool inInlineTagList(const Node*); + static bool inBlockTagList(const Node*); + static bool isRecognizedTagName(const QualifiedName&); + + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + HTMLFormElement* form() const { return virtualForm(); } + HTMLFormElement* findFormAncestor() const; + +protected: + void addHTMLAlignment(MappedAttribute*); + +private: + virtual HTMLFormElement* virtualForm() const; + Node* insertAdjacent(const String& where, Node* newChild, ExceptionCode&); +}; + +} // namespace WebCore + +#endif // HTMLElement_h diff --git a/WebCore/html/HTMLElement.idl b/WebCore/html/HTMLElement.idl new file mode 100644 index 0000000..8ce5542 --- /dev/null +++ b/WebCore/html/HTMLElement.idl @@ -0,0 +1,72 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + GenerateNativeConverter, + CustomPushEventHandlerScope, + InterfaceUUID=b2f172f1-d209-446f-8143-5f21de678f95, + ImplementationUUID=c81b0e16-a2b9-448b-ad0a-81c9346d6f8a + ] HTMLElement : Element { + // iht.com relies on id returning the empty string when no id is present. + // Other browsers do this as well. So we don't convert null to JS null. + attribute [ConvertNullToNullString] DOMString id; + attribute [ConvertNullToNullString] DOMString title; + attribute [ConvertNullToNullString] DOMString lang; + attribute [ConvertNullToNullString] DOMString dir; + attribute [ConvertNullToNullString] DOMString className; + + attribute long tabIndex; + void blur(); + void focus(); + + // Extensions + attribute [ConvertNullToNullString] DOMString innerHTML + setter raises(DOMException); + attribute [ConvertNullToNullString] DOMString innerText + setter raises(DOMException); + attribute [ConvertNullToNullString] DOMString outerHTML + setter raises(DOMException); + attribute [ConvertNullToNullString] DOMString outerText + setter raises(DOMException); + + Element insertAdjacentElement(in DOMString where, + in Element element) + raises(DOMException); + void insertAdjacentHTML(in DOMString where, + in DOMString html) + raises(DOMException); + void insertAdjacentText(in DOMString where, + in DOMString text) + raises(DOMException); + + readonly attribute HTMLCollection children; + + attribute [ConvertNullToNullString] DOMString contentEditable; + readonly attribute boolean isContentEditable; + +#if defined(LANGUAGE_OBJECTIVE_C) + readonly attribute DOMString titleDisplayString; +#endif + }; + +} diff --git a/WebCore/html/HTMLElementFactory.cpp b/WebCore/html/HTMLElementFactory.cpp new file mode 100644 index 0000000..1b9b0cc --- /dev/null +++ b/WebCore/html/HTMLElementFactory.cpp @@ -0,0 +1,520 @@ +/* + * This file is part of the HTML DOM implementation for KDE. + * + * 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" +#include "HTMLElementFactory.h" + +#include "HTMLAnchorElement.h" +#include "HTMLAppletElement.h" +#include "HTMLAreaElement.h" +#include "HTMLAudioElement.h" +#include "HTMLBRElement.h" +#include "HTMLBaseElement.h" +#include "HTMLBaseFontElement.h" +#include "HTMLBlockquoteElement.h" +#include "HTMLBodyElement.h" +#include "HTMLButtonElement.h" +#include "HTMLCanvasElement.h" +#include "HTMLDListElement.h" +#include "HTMLDirectoryElement.h" +#include "HTMLDivElement.h" +#include "HTMLDocument.h" +#include "HTMLEmbedElement.h" +#include "HTMLFieldSetElement.h" +#include "HTMLFontElement.h" +#include "HTMLFormElement.h" +#include "HTMLFrameElement.h" +#include "HTMLFrameSetElement.h" +#include "HTMLHRElement.h" +#include "HTMLHeadElement.h" +#include "HTMLHeadingElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLIFrameElement.h" +#include "HTMLImageElement.h" +#include "HTMLIsIndexElement.h" +#include "HTMLKeygenElement.h" +#include "HTMLLIElement.h" +#include "HTMLLabelElement.h" +#include "HTMLLegendElement.h" +#include "HTMLLinkElement.h" +#include "HTMLMapElement.h" +#include "HTMLMarqueeElement.h" +#include "HTMLMenuElement.h" +#include "HTMLMetaElement.h" +#include "HTMLModElement.h" +#include "HTMLNames.h" +#include "HTMLOListElement.h" +#include "HTMLObjectElement.h" +#include "HTMLOptGroupElement.h" +#include "HTMLOptionElement.h" +#include "HTMLParagraphElement.h" +#include "HTMLParamElement.h" +#include "HTMLPreElement.h" +#include "HTMLQuoteElement.h" +#include "HTMLScriptElement.h" +#include "HTMLSelectElement.h" +#include "HTMLSourceElement.h" +#include "HTMLStyleElement.h" +#include "HTMLTableCaptionElement.h" +#include "HTMLTableCellElement.h" +#include "HTMLTableColElement.h" +#include "HTMLTableElement.h" +#include "HTMLTableRowElement.h" +#include "HTMLTableSectionElement.h" +#include "HTMLTextAreaElement.h" +#include "HTMLTitleElement.h" +#include "HTMLUListElement.h" +#include "HTMLVideoElement.h" + +namespace WebCore { + +using namespace HTMLNames; + +typedef PassRefPtr<HTMLElement> (*ConstructorFunc)(const AtomicString& tagName, Document*, HTMLFormElement*, bool createdByParser); +typedef HashMap<AtomicStringImpl*, ConstructorFunc> FunctionMap; +static FunctionMap* gFunctionMap; + +static PassRefPtr<HTMLElement> htmlConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLHtmlElement(doc); +} + +static PassRefPtr<HTMLElement> headConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLHeadElement(doc); +} + +static PassRefPtr<HTMLElement> bodyConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLBodyElement(doc); +} + +static PassRefPtr<HTMLElement> baseConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLBaseElement(doc); +} + +static PassRefPtr<HTMLElement> linkConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLLinkElement> link = new HTMLLinkElement(doc); + link->setCreatedByParser(createdByParser); + return link.release(); +} + +static PassRefPtr<HTMLElement> metaConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLMetaElement(doc); +} + +static PassRefPtr<HTMLElement> styleConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLStyleElement> style = new HTMLStyleElement(doc); + style->setCreatedByParser(createdByParser); + return style.release(); +} + +static PassRefPtr<HTMLElement> titleConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTitleElement(doc); +} + +static PassRefPtr<HTMLElement> frameConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLFrameElement> frame = new HTMLFrameElement(doc); + frame->setCreatedByParser(createdByParser); + return frame.release(); +} + +static PassRefPtr<HTMLElement> framesetConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLFrameSetElement(doc); +} + +static PassRefPtr<HTMLElement> iframeConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLIFrameElement> iFrame = new HTMLIFrameElement(doc); + iFrame->setCreatedByParser(createdByParser); + return iFrame.release(); +} + +static PassRefPtr<HTMLElement> formConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLFormElement(doc); +} + +static PassRefPtr<HTMLElement> buttonConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLButtonElement(doc, form); +} + +static PassRefPtr<HTMLElement> inputConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLInputElement(doc, form); +} + +static PassRefPtr<HTMLElement> isindexConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLIsIndexElement(doc, form); +} + +static PassRefPtr<HTMLElement> fieldsetConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLFieldSetElement(doc, form); +} + +static PassRefPtr<HTMLElement> keygenConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLKeygenElement(doc, form); +} + +static PassRefPtr<HTMLElement> labelConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLLabelElement(doc); +} + +static PassRefPtr<HTMLElement> legendConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLLegendElement(doc, form); +} + +static PassRefPtr<HTMLElement> optgroupConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLOptGroupElement(doc, form); +} + +static PassRefPtr<HTMLElement> optionConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLOptionElement(doc, form); +} + +static PassRefPtr<HTMLElement> selectConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLSelectElement(doc, form); +} + +static PassRefPtr<HTMLElement> textareaConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLTextAreaElement(doc, form); +} + +static PassRefPtr<HTMLElement> dlConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLDListElement(doc); +} + +static PassRefPtr<HTMLElement> ulConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLUListElement(doc); +} + +static PassRefPtr<HTMLElement> olConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLOListElement(doc); +} + +static PassRefPtr<HTMLElement> dirConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLDirectoryElement(doc); +} + +static PassRefPtr<HTMLElement> menuConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLMenuElement(doc); +} + +static PassRefPtr<HTMLElement> liConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLLIElement(doc); +} + +static PassRefPtr<HTMLElement> blockquoteConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLBlockquoteElement(doc); +} + +static PassRefPtr<HTMLElement> divConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLDivElement(doc); +} + +static PassRefPtr<HTMLElement> headingConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLHeadingElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> hrConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLHRElement(doc); +} + +static PassRefPtr<HTMLElement> paragraphConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLParagraphElement(doc); +} + +static PassRefPtr<HTMLElement> preConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLPreElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> basefontConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLBaseFontElement(doc); +} + +static PassRefPtr<HTMLElement> fontConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLFontElement(doc); +} + +static PassRefPtr<HTMLElement> modConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLModElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> anchorConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLAnchorElement(doc); +} + +static PassRefPtr<HTMLElement> imageConstructor(const AtomicString&, Document* doc, HTMLFormElement* form, bool) +{ + return new HTMLImageElement(doc, form); +} + +static PassRefPtr<HTMLElement> mapConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLMapElement(doc); +} + +static PassRefPtr<HTMLElement> areaConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLAreaElement(doc); +} + +static PassRefPtr<HTMLElement> canvasConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLCanvasElement(doc); +} + +static PassRefPtr<HTMLElement> appletConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLAppletElement(doc); +} + +static PassRefPtr<HTMLElement> embedConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLEmbedElement(doc); +} + +static PassRefPtr<HTMLElement> objectConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLObjectElement> object = new HTMLObjectElement(doc, createdByParser); + return object.release(); +} + +static PassRefPtr<HTMLElement> paramConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLParamElement(doc); +} + +static PassRefPtr<HTMLElement> scriptConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool createdByParser) +{ + RefPtr<HTMLScriptElement> script = new HTMLScriptElement(doc); + script->setCreatedByParser(createdByParser); + return script.release(); +} + +static PassRefPtr<HTMLElement> tableConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableElement(doc); +} + +static PassRefPtr<HTMLElement> tableCaptionConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableCaptionElement(doc); +} + +static PassRefPtr<HTMLElement> tableColConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableColElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> tableRowConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableRowElement(doc); +} + +static PassRefPtr<HTMLElement> tableCellConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableCellElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> tableSectionConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLTableSectionElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +static PassRefPtr<HTMLElement> brConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLBRElement(doc); +} + +static PassRefPtr<HTMLElement> quoteConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLQuoteElement(doc); +} + +static PassRefPtr<HTMLElement> marqueeConstructor(const AtomicString&, Document* doc, HTMLFormElement*, bool) +{ + return new HTMLMarqueeElement(doc); +} + +#if ENABLE(VIDEO) +static PassRefPtr<HTMLElement> audioConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + if (!MediaPlayer::isAvailable()) + return new HTMLElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); + return new HTMLAudioElement(doc); +} + +static PassRefPtr<HTMLElement> videoConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + if (!MediaPlayer::isAvailable()) + return new HTMLElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); + return new HTMLVideoElement(doc); +} + +static PassRefPtr<HTMLElement> sourceConstructor(const AtomicString& tagName, Document* doc, HTMLFormElement*, bool) +{ + if (!MediaPlayer::isAvailable()) + return new HTMLElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); + return new HTMLSourceElement(doc); +} +#endif + +static void addTag(const QualifiedName& tag, ConstructorFunc func) +{ + gFunctionMap->set(tag.localName().impl(), func); +} + +static void createFunctionMap() +{ + // Create the table. + gFunctionMap = new FunctionMap; + + // Populate it with constructor functions. + addTag(aTag, anchorConstructor); + addTag(appletTag, appletConstructor); + addTag(areaTag, areaConstructor); + addTag(baseTag, baseConstructor); + addTag(basefontTag, basefontConstructor); + addTag(blockquoteTag, blockquoteConstructor); + addTag(bodyTag, bodyConstructor); + addTag(brTag, brConstructor); + addTag(buttonTag, buttonConstructor); + addTag(canvasTag, canvasConstructor); + addTag(captionTag, tableCaptionConstructor); + addTag(colTag, tableColConstructor); + addTag(colgroupTag, tableColConstructor); + addTag(delTag, modConstructor); + addTag(dirTag, dirConstructor); + addTag(divTag, divConstructor); + addTag(dlTag, dlConstructor); + addTag(embedTag, embedConstructor); + addTag(fieldsetTag, fieldsetConstructor); + addTag(fontTag, fontConstructor); + addTag(formTag, formConstructor); + addTag(frameTag, frameConstructor); + addTag(framesetTag, framesetConstructor); + addTag(h1Tag, headingConstructor); + addTag(h2Tag, headingConstructor); + addTag(h3Tag, headingConstructor); + addTag(h4Tag, headingConstructor); + addTag(h5Tag, headingConstructor); + addTag(h6Tag, headingConstructor); + addTag(headTag, headConstructor); + addTag(hrTag, hrConstructor); + addTag(htmlTag, htmlConstructor); + addTag(iframeTag, iframeConstructor); + addTag(imageTag, imageConstructor); + addTag(imgTag, imageConstructor); + addTag(inputTag, inputConstructor); + addTag(insTag, modConstructor); + addTag(isindexTag, isindexConstructor); + addTag(keygenTag, keygenConstructor); + addTag(labelTag, labelConstructor); + addTag(legendTag, legendConstructor); + addTag(liTag, liConstructor); + addTag(linkTag, linkConstructor); + addTag(listingTag, preConstructor); + addTag(mapTag, mapConstructor); + addTag(marqueeTag, marqueeConstructor); + addTag(menuTag, menuConstructor); + addTag(metaTag, metaConstructor); + addTag(objectTag, objectConstructor); + addTag(olTag, olConstructor); + addTag(optgroupTag, optgroupConstructor); + addTag(optionTag, optionConstructor); + addTag(pTag, paragraphConstructor); + addTag(paramTag, paramConstructor); + addTag(preTag, preConstructor); + addTag(qTag, quoteConstructor); + addTag(scriptTag, scriptConstructor); + addTag(selectTag, selectConstructor); + addTag(styleTag, styleConstructor); + addTag(tableTag, tableConstructor); + addTag(tbodyTag, tableSectionConstructor); + addTag(tdTag, tableCellConstructor); + addTag(textareaTag, textareaConstructor); + addTag(tfootTag, tableSectionConstructor); + addTag(thTag, tableCellConstructor); + addTag(theadTag, tableSectionConstructor); + addTag(titleTag, titleConstructor); + addTag(trTag, tableRowConstructor); + addTag(ulTag, ulConstructor); + addTag(xmpTag, preConstructor); +#if ENABLE(VIDEO) + addTag(audioTag, audioConstructor); + addTag(sourceTag, sourceConstructor); + addTag(videoTag, videoConstructor); +#endif +} + +PassRefPtr<HTMLElement> HTMLElementFactory::createHTMLElement(const AtomicString& tagName, Document* doc, HTMLFormElement* form, bool createdByParser) +{ + if (!doc) + return 0; // Don't allow elements to ever be made without having a doc. + + if (!gFunctionMap) + createFunctionMap(); + + ConstructorFunc func = gFunctionMap->get(tagName.impl()); + if (func) + return func(tagName, doc, form, createdByParser); + + // elements with no special representation in the DOM + return new HTMLElement(QualifiedName(nullAtom, tagName, xhtmlNamespaceURI), doc); +} + +} + diff --git a/WebCore/html/HTMLElementFactory.h b/WebCore/html/HTMLElementFactory.h new file mode 100644 index 0000000..986036d --- /dev/null +++ b/WebCore/html/HTMLElementFactory.h @@ -0,0 +1,47 @@ +/* + * This file is part of the HTML DOM implementation for KDE. + * + * 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. + * + */ + +#ifndef HTMLElementFactory_h +#define HTMLElementFactory_h + +#include <wtf/Forward.h> + +namespace WebCore { + +class AtomicString; +class Document; +class Element; +class HTMLElement; +class HTMLFormElement; +class QualifiedName; + +// The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense elements. +// In a compound document world, the generic createElement function (will end up being virtual) will be called. +class HTMLElementFactory { +public: + PassRefPtr<Element> createElement(const QualifiedName&, Document*, bool createdByParser = true); + static PassRefPtr<HTMLElement> createHTMLElement(const AtomicString& tagName, Document*, HTMLFormElement* = 0, bool createdByParser = true); +}; + +} + +#endif diff --git a/WebCore/html/HTMLEmbedElement.cpp b/WebCore/html/HTMLEmbedElement.cpp new file mode 100644 index 0000000..1beb563 --- /dev/null +++ b/WebCore/html/HTMLEmbedElement.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * 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. + */ + +#include "config.h" +#include "HTMLEmbedElement.h" + +#include "CSSHelper.h" +#include "CSSPropertyNames.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLImageLoader.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" +#include "RenderImage.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "ScriptController.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLEmbedElement::HTMLEmbedElement(Document* doc) + : HTMLPlugInImageElement(embedTag, doc) + , m_needWidgetUpdate(false) +{ +} + +HTMLEmbedElement::~HTMLEmbedElement() +{ +} + +static inline RenderWidget* findWidgetRenderer(const Node* n) +{ + if (!n->renderer()) + do + n = n->parentNode(); + while (n && !n->hasTagName(objectTag)); + + if (n && n->renderer() && n->renderer()->isWidget()) + return static_cast<RenderWidget*>(n->renderer()); + + return 0; +} + +RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const +{ + RenderWidget* renderWidget = findWidgetRenderer(this); + if (renderWidget && !renderWidget->widget()) { + document()->updateLayoutIgnorePendingStylesheets(); + renderWidget = findWidgetRenderer(this); + } + return renderWidget; +} + +bool HTMLEmbedElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == hiddenAttr) { + result = eUniversal; + return false; + } + + return HTMLPlugInElement::mapToEntry(attrName, result); +} + +void HTMLEmbedElement::parseMappedAttribute(MappedAttribute* attr) +{ + const AtomicString& value = attr->value(); + + if (attr->name() == typeAttr) { + m_serviceType = value.string().lower(); + int pos = m_serviceType.find(";"); + if (pos != -1) + m_serviceType = m_serviceType.left(pos); + if (!isImageType() && m_imageLoader) + m_imageLoader.clear(); + } else if (attr->name() == codeAttr) + m_url = parseURL(value.string()); + else if (attr->name() == srcAttr) { + m_url = parseURL(value.string()); + if (renderer() && isImageType()) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + } + } else if (attr->name() == pluginpageAttr || attr->name() == pluginspageAttr) + m_pluginPage = value; + else if (attr->name() == hiddenAttr) { + if (equalIgnoringCase(value.string(), "yes") || equalIgnoringCase(value.string(), "true")) { + // FIXME: Not dynamic, since we add this but don't remove it, but it may be OK for now + // that this rarely-used attribute won't work properly if you remove it. + addCSSLength(attr, CSSPropertyWidth, "0"); + addCSSLength(attr, CSSPropertyHeight, "0"); + } + } else if (attr->name() == nameAttr) { + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(value); + } + m_name = value; + } else + HTMLPlugInElement::parseMappedAttribute(attr); +} + +bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style) +{ + if (isImageType()) + return HTMLPlugInElement::rendererIsNeeded(style); + + Frame* frame = document()->frame(); + if (!frame) + return false; + + Node* p = parentNode(); + if (p && p->hasTagName(objectTag)) { + ASSERT(p->renderer()); + return false; + } + + return true; +} + +RenderObject* HTMLEmbedElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (isImageType()) + return new (arena) RenderImage(this); + return new (arena) RenderPartObject(this); +} + +void HTMLEmbedElement::attach() +{ + m_needWidgetUpdate = true; + + bool isImage = isImageType(); + + if (!isImage) + queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this); + + HTMLPlugInElement::attach(); + + if (isImage && renderer()) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + + if (renderer()) + static_cast<RenderImage*>(renderer())->setCachedImage(m_imageLoader->image()); + } +} + +void HTMLEmbedElement::updateWidget() +{ + document()->updateRendering(); + if (m_needWidgetUpdate && renderer() && !isImageType()) + static_cast<RenderPartObject*>(renderer())->updateWidget(true); +} + +void HTMLEmbedElement::insertedIntoDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->addNamedItem(m_name); + + String width = getAttribute(widthAttr); + String height = getAttribute(heightAttr); + if (!width.isEmpty() || !height.isEmpty()) { + Node* n = parent(); + while (n && !n->hasTagName(objectTag)) + n = n->parent(); + if (n) { + if (!width.isEmpty()) + static_cast<HTMLObjectElement*>(n)->setAttribute(widthAttr, width); + if (!height.isEmpty()) + static_cast<HTMLObjectElement*>(n)->setAttribute(heightAttr, height); + } + } + + HTMLPlugInElement::insertedIntoDocument(); +} + +void HTMLEmbedElement::removedFromDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->removeNamedItem(m_name); + + HTMLPlugInElement::removedFromDocument(); +} + +void HTMLEmbedElement::attributeChanged(Attribute* attr, bool preserveDecls) +{ + HTMLPlugInElement::attributeChanged(attr, preserveDecls); + + if ((attr->name() == widthAttr || attr->name() == heightAttr) && !attr->isEmpty()) { + Node* n = parent(); + while (n && !n->hasTagName(objectTag)) + n = n->parent(); + if (n) + static_cast<HTMLObjectElement*>(n)->setAttribute(attr->name(), attr->value()); + } +} + +bool HTMLEmbedElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == srcAttr; +} + +const QualifiedName& HTMLEmbedElement::imageSourceAttributeName() const +{ + return srcAttr; +} + +String HTMLEmbedElement::src() const +{ + return getAttribute(srcAttr); +} + +void HTMLEmbedElement::setSrc(const String& value) +{ + setAttribute(srcAttr, value); +} + +String HTMLEmbedElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLEmbedElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} + +void HTMLEmbedElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(src()); +} + +} diff --git a/WebCore/html/HTMLEmbedElement.h b/WebCore/html/HTMLEmbedElement.h new file mode 100644 index 0000000..2f45998 --- /dev/null +++ b/WebCore/html/HTMLEmbedElement.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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 HTMLEmbedElement_h +#define HTMLEmbedElement_h + +#include "HTMLPlugInImageElement.h" + +namespace WebCore { + +class HTMLEmbedElement : public HTMLPlugInImageElement { +public: + HTMLEmbedElement(Document*); + ~HTMLEmbedElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void attach(); + virtual bool canLazyAttach() { return false; } + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void attributeChanged(Attribute*, bool preserveDecls = false); + + virtual bool isURLAttribute(Attribute*) const; + virtual const QualifiedName& imageSourceAttributeName() const; + + virtual void updateWidget(); + void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; } + + virtual RenderWidget* renderWidgetForJSBindings() const; + + String src() const; + void setSrc(const String&); + + String type() const; + void setType(const String&); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +private: + String m_pluginPage; + bool m_needWidgetUpdate; +}; + +} + +#endif diff --git a/WebCore/html/HTMLEmbedElement.idl b/WebCore/html/HTMLEmbedElement.idl new file mode 100644 index 0000000..10c3007 --- /dev/null +++ b/WebCore/html/HTMLEmbedElement.idl @@ -0,0 +1,55 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + CustomPutFunction, + CustomGetOwnPropertySlot, + CustomCall, + HasOverridingNameGetter, + InterfaceUUID=18f9bd58-6bb3-4b5c-aa30-6da13adfc91e, + ImplementationUUID=93e0407a-8380-4ff0-978d-f773f2dee6a3 + ] HTMLEmbedElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; +#if defined(LANGUAGE_JAVASCRIPT) + attribute [ConvertNullToNullString] DOMString height; +#else + attribute [ConvertFromString] long height; +#endif + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString src; + attribute [ConvertNullToNullString] DOMString type; +#if defined(LANGUAGE_JAVASCRIPT) + attribute [ConvertNullToNullString] DOMString width; +#else + attribute [ConvertFromString] long width; +#endif + +#if !defined(LANGUAGE_COM) +#if ENABLE_SVG + [SVGCheckSecurityDocument] SVGDocument getSVGDocument() + raises(DOMException); +#endif +#endif + }; + +} diff --git a/WebCore/html/HTMLEntityNames.gperf b/WebCore/html/HTMLEntityNames.gperf new file mode 100644 index 0000000..780c12a --- /dev/null +++ b/WebCore/html/HTMLEntityNames.gperf @@ -0,0 +1,297 @@ +%{ +/* This file is part of the KDE libraries + + Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de) + + 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. + + ---------------------------------------------------------------------------- + + HTMLEntityNames.gperf: input file to generate a hash table for entities + HTMLEntityNames.c: DO NOT EDIT! generated by the command + "gperf -a -L "ANSI-C" -C -G -c -o -t -k '*' -NfindEntity -D -s 2 HTMLEntityNames.gperf > entities.c" + from HTMLEntityNames.gperf + +*/ +%} +struct Entity { + const char *name; + int code; +}; +%% +AElig, 0x00c6 +AMP, 38 +Aacute, 0x00c1 +Acirc, 0x00c2 +Agrave, 0x00c0 +Alpha, 0x0391 +Aring, 0x00c5 +Atilde, 0x00c3 +Auml, 0x00c4 +Beta, 0x0392 +COPY, 0x00a9 +Ccedil, 0x00c7 +Chi, 0x03a7 +Dagger, 0x2021 +Delta, 0x0394 +ETH, 0x00d0 +Eacute, 0x00c9 +Ecirc, 0x00ca +Egrave, 0x00c8 +Epsilon, 0x0395 +Eta, 0x0397 +Euml, 0x00cb +GT, 62 +Gamma, 0x0393 +Iacute, 0x00cd +Icirc, 0x00ce +Igrave, 0x00cc +Iota, 0x0399 +Iuml, 0x00cf +Kappa, 0x039a +LT, 60 +Lambda, 0x039b +Mu, 0x039c +Ntilde, 0x00d1 +Nu, 0x039d +OElig, 0x0152 +Oacute, 0x00d3 +Ocirc, 0x00d4 +Ograve, 0x00d2 +Omega, 0x03a9 +Omicron, 0x039f +Oslash, 0x00d8 +Otilde, 0x00d5 +Ouml, 0x00d6 +Phi, 0x03a6 +Pi, 0x03a0 +Prime, 0x2033 +Psi, 0x03a8 +QUOT, 34 +REG, 0x00ae +Rho, 0x03a1 +Scaron, 0x0160 +Sigma, 0x03a3 +THORN, 0x00de +Tau, 0x03a4 +Theta, 0x0398 +Uacute, 0x00da +Ucirc, 0x00db +Ugrave, 0x00d9 +Upsilon, 0x03a5 +Uuml, 0x00dc +Xi, 0x039e +Yacute, 0x00dd +Yuml, 0x0178 +Zeta, 0x0396 +aacute, 0x00e1 +acirc, 0x00e2 +acute, 0x00b4 +aelig, 0x00e6 +agrave, 0x00e0 +alefsym, 0x2135 +alpha, 0x03b1 +amp, 38 +and, 0x2227 +ang, 0x2220 +apos, 0x0027 +aring, 0x00e5 +asymp, 0x2248 +atilde, 0x00e3 +auml, 0x00e4 +bdquo, 0x201e +beta, 0x03b2 +brvbar, 0x00a6 +bull, 0x2022 +cap, 0x2229 +ccedil, 0x00e7 +cedil, 0x00b8 +cent, 0x00a2 +chi, 0x03c7 +circ, 0x02c6 +clubs, 0x2663 +cong, 0x2245 +copy, 0x00a9 +crarr, 0x21b5 +cup, 0x222a +curren, 0x00a4 +dArr, 0x21d3 +dagger, 0x2020 +darr, 0x2193 +deg, 0x00b0 +delta, 0x03b4 +diams, 0x2666 +divide, 0x00f7 +eacute, 0x00e9 +ecirc, 0x00ea +egrave, 0x00e8 +empty, 0x2205 +emsp, 0x2003 +ensp, 0x2002 +epsilon, 0x03b5 +equiv, 0x2261 +eta, 0x03b7 +eth, 0x00f0 +euml, 0x00eb +euro, 0x20ac +exist, 0x2203 +fnof, 0x0192 +forall, 0x2200 +frac12, 0x00bd +frac14, 0x00bc +frac34, 0x00be +frasl, 0x2044 +gamma, 0x03b3 +ge, 0x2265 +gt, 62 +hArr, 0x21d4 +harr, 0x2194 +hearts, 0x2665 +hellip, 0x2026 +iacute, 0x00ed +icirc, 0x00ee +iexcl, 0x00a1 +igrave, 0x00ec +image, 0x2111 +infin, 0x221e +int, 0x222b +iota, 0x03b9 +iquest, 0x00bf +isin, 0x2208 +iuml, 0x00ef +kappa, 0x03ba +lArr, 0x21d0 +lambda, 0x03bb +lang, 0x3008 +laquo, 0x00ab +larr, 0x2190 +lceil, 0x2308 +ldquo, 0x201c +le, 0x2264 +lfloor, 0x230a +lowast, 0x2217 +loz, 0x25ca +lrm, 0x200e +lsaquo, 0x2039 +lsquo, 0x2018 +lt, 60 +macr, 0x00af +mdash, 0x2014 +micro, 0x00b5 +middot, 0x00b7 +minus, 0x2212 +mu, 0x03bc +nabla, 0x2207 +nbsp, 0x00a0 +ndash, 0x2013 +ne, 0x2260 +ni, 0x220b +not, 0x00ac +notin, 0x2209 +nsub, 0x2284 +nsup, 0x2285 +ntilde, 0x00f1 +nu, 0x03bd +oacute, 0x00f3 +ocirc, 0x00f4 +oelig, 0x0153 +ograve, 0x00f2 +oline, 0x203e +omega, 0x03c9 +omicron, 0x03bf +oplus, 0x2295 +or, 0x2228 +ordf, 0x00aa +ordm, 0x00ba +oslash, 0x00f8 +otilde, 0x00f5 +otimes, 0x2297 +ouml, 0x00f6 +para, 0x00b6 +part, 0x2202 +percnt, 0x0025 +permil, 0x2030 +perp, 0x22a5 +phi, 0x03c6 +pi, 0x03c0 +piv, 0x03d6 +plusmn, 0x00b1 +pound, 0x00a3 +prime, 0x2032 +prod, 0x220f +prop, 0x221d +psi, 0x03c8 +quot, 34 +rArr, 0x21d2 +radic, 0x221a +rang, 0x3009 +raquo, 0x00bb +rarr, 0x2192 +rceil, 0x2309 +rdquo, 0x201d +real, 0x211c +reg, 0x00ae +rfloor, 0x230b +rho, 0x03c1 +rlm, 0x200f +rsaquo, 0x203a +rsquo, 0x2019 +sbquo, 0x201a +scaron, 0x0161 +sdot, 0x22c5 +sect, 0x00a7 +shy, 0x00ad +sigma, 0x03c3 +sigmaf, 0x03c2 +sim, 0x223c +spades, 0x2660 +sub, 0x2282 +sube, 0x2286 +sum, 0x2211 +sup, 0x2283 +sup1, 0x00b9 +sup2, 0x00b2 +sup3, 0x00b3 +supe, 0x2287 +supl, 0x00b9 +szlig, 0x00df +tau, 0x03c4 +there4, 0x2234 +theta, 0x03b8 +thetasym, 0x03d1 +thinsp, 0x2009 +thorn, 0x00fe +tilde, 0x02dc +times, 0x00d7 +trade, 0x2122 +uArr, 0x21d1 +uacute, 0x00fa +uarr, 0x2191 +ucirc, 0x00fb +ugrave, 0x00f9 +uml, 0x00a8 +upsih, 0x03d2 +upsilon, 0x03c5 +uuml, 0x00fc +weierp, 0x2118 +xi, 0x03be +yacute, 0x00fd +yen, 0x00a5 +yuml, 0x00ff +zeta, 0x03b6 +zwj, 0x200d +zwnj, 0x200c +%% diff --git a/WebCore/html/HTMLFieldSetElement.cpp b/WebCore/html/HTMLFieldSetElement.cpp new file mode 100644 index 0000000..c4594de --- /dev/null +++ b/WebCore/html/HTMLFieldSetElement.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLFieldSetElement.h" + +#include "HTMLNames.h" +#include "RenderFieldset.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFieldSetElement::HTMLFieldSetElement(Document *doc, HTMLFormElement *f) + : HTMLFormControlElement(fieldsetTag, doc, f) +{ +} + +HTMLFieldSetElement::~HTMLFieldSetElement() +{ +} + +bool HTMLFieldSetElement::checkDTD(const Node* newChild) +{ + return newChild->hasTagName(legendTag) || HTMLElement::checkDTD(newChild); +} + +bool HTMLFieldSetElement::isFocusable() const +{ + return HTMLElement::isFocusable(); +} + +const AtomicString& HTMLFieldSetElement::type() const +{ + static const AtomicString fieldset("fieldset"); + return fieldset; +} + +RenderObject* HTMLFieldSetElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + return new (arena) RenderFieldset(this); +} + +} // namespace diff --git a/WebCore/html/HTMLFieldSetElement.h b/WebCore/html/HTMLFieldSetElement.h new file mode 100644 index 0000000..637a2ff --- /dev/null +++ b/WebCore/html/HTMLFieldSetElement.h @@ -0,0 +1,58 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLFieldSetElement_h +#define HTMLFieldSetElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + class RenderStyle; +} + +namespace WebCore { + +class HTMLFormElement; +class Document; +class Node; + +class HTMLFieldSetElement : public HTMLFormControlElement { +public: + HTMLFieldSetElement(Document*, HTMLFormElement* = 0); + virtual ~HTMLFieldSetElement(); + + virtual int tagPriority() const { return 3; } + virtual bool checkDTD(const Node* newChild); + + virtual bool isFocusable() const; + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual const AtomicString& type() const; + + virtual bool willValidate() const { return false; } +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLFieldSetElement.idl b/WebCore/html/HTMLFieldSetElement.idl new file mode 100644 index 0000000..c48f8d6 --- /dev/null +++ b/WebCore/html/HTMLFieldSetElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=cf9e4c4c-a1c9-4740-ad6c-6e5ea94a51a5, + ImplementationUUID=93573758-96db-415d-9bdc-ee7238604094 + ] HTMLFieldSetElement : HTMLElement { + readonly attribute HTMLFormElement form; + readonly attribute boolean willValidate; + }; + +} diff --git a/WebCore/html/HTMLFontElement.cpp b/WebCore/html/HTMLFontElement.cpp new file mode 100644 index 0000000..b32f492 --- /dev/null +++ b/WebCore/html/HTMLFontElement.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 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 "HTMLFontElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" + +using namespace WTF; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFontElement::HTMLFontElement(Document* document) + : HTMLElement(fontTag, document) +{ +} + +// Allows leading spaces. +// Allows trailing nonnumeric characters. +// Returns 10 for any size greater than 9. +static bool parseFontSizeNumber(const String& s, int& size) +{ + unsigned pos = 0; + + // Skip leading spaces. + while (isSpaceOrNewline(s[pos])) + ++pos; + + // Skip a plus or minus. + bool sawPlus = false; + bool sawMinus = false; + if (s[pos] == '+') { + ++pos; + sawPlus = true; + } else if (s[pos] == '-') { + ++pos; + sawMinus = true; + } + + // Parse a single digit. + if (!isASCIIDigit(s[pos])) + return false; + int num = s[pos++] - '0'; + + // Check for an additional digit. + if (isASCIIDigit(s[pos])) + num = 10; + + if (sawPlus) { + size = num + 3; + return true; + } + + // Don't return 0 (which means 3) or a negative number (which means the same as 1). + if (sawMinus) { + size = num == 1 ? 2 : 1; + return true; + } + + size = num; + return true; +} + +bool HTMLFontElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == sizeAttr || + attrName == colorAttr || + attrName == faceAttr) { + result = eUniversal; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +bool HTMLFontElement::cssValueFromFontSizeNumber(const String& s, int& size) +{ + int num; + if (!parseFontSizeNumber(s, num)) + return false; + + switch (num) { + case 2: + size = CSSValueSmall; + break; + case 0: // treat 0 the same as 3, because people expect it to be between -1 and +1 + case 3: + size = CSSValueMedium; + break; + case 4: + size = CSSValueLarge; + break; + case 5: + size = CSSValueXLarge; + break; + case 6: + size = CSSValueXxLarge; + break; + default: + if (num > 6) + size = CSSValueWebkitXxxLarge; + else + size = CSSValueXSmall; + } + return true; +} + +void HTMLFontElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == sizeAttr) { + int size; + if (cssValueFromFontSizeNumber(attr->value(), size)) + addCSSProperty(attr, CSSPropertyFontSize, size); + } else if (attr->name() == colorAttr) { + addCSSColor(attr, CSSPropertyColor, attr->value()); + } else if (attr->name() == faceAttr) { + addCSSProperty(attr, CSSPropertyFontFamily, attr->value()); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLFontElement::color() const +{ + return getAttribute(colorAttr); +} + +void HTMLFontElement::setColor(const String& value) +{ + setAttribute(colorAttr, value); +} + +String HTMLFontElement::face() const +{ + return getAttribute(faceAttr); +} + +void HTMLFontElement::setFace(const String& value) +{ + setAttribute(faceAttr, value); +} + +String HTMLFontElement::size() const +{ + return getAttribute(sizeAttr); +} + +void HTMLFontElement::setSize(const String& value) +{ + setAttribute(sizeAttr, value); +} + +} diff --git a/WebCore/html/HTMLFontElement.h b/WebCore/html/HTMLFontElement.h new file mode 100644 index 0000000..272f63c --- /dev/null +++ b/WebCore/html/HTMLFontElement.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ +#ifndef HTMLFontElement_h +#define HTMLFontElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLFontElement : public HTMLElement { +public: + HTMLFontElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + String color() const; + void setColor(const String&); + + String face() const; + void setFace(const String&); + + String size() const; + void setSize(const String&); + + static bool cssValueFromFontSizeNumber(const String&, int&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLFontElement.idl b/WebCore/html/HTMLFontElement.idl new file mode 100644 index 0000000..cb9cbbe --- /dev/null +++ b/WebCore/html/HTMLFontElement.idl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=f6a11dbe-7f40-49dc-a304-7997b25b2cb9, + ImplementationUUID=a37453b9-f7ba-4896-8e91-37d1ecc5b7ce + ] HTMLFontElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString color; + attribute [ConvertNullToNullString] DOMString face; + attribute [ConvertNullToNullString] DOMString size; + }; + +} diff --git a/WebCore/html/HTMLFormCollection.cpp b/WebCore/html/HTMLFormCollection.cpp new file mode 100644 index 0000000..823291a --- /dev/null +++ b/WebCore/html/HTMLFormCollection.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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 "HTMLFormCollection.h" + +#include "HTMLFormControlElement.h" +#include "HTMLFormElement.h" +#include "HTMLImageElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +// Since the collections are to be "live", we have to do the +// calculation every time if anything has changed. + +inline HTMLCollection::CollectionInfo* HTMLFormCollection::formCollectionInfo(HTMLFormElement* form) +{ + if (!form->collectionInfo) + form->collectionInfo = new CollectionInfo; + return form->collectionInfo; +} + +HTMLFormCollection::HTMLFormCollection(PassRefPtr<HTMLFormElement> form) + : HTMLCollection(form.get(), Other, formCollectionInfo(form.get())) +{ +} + +PassRefPtr<HTMLFormCollection> HTMLFormCollection::create(PassRefPtr<HTMLFormElement> form) +{ + return adoptRef(new HTMLFormCollection(form)); +} + +HTMLFormCollection::~HTMLFormCollection() +{ +} + +unsigned HTMLFormCollection::calcLength() const +{ + return static_cast<HTMLFormElement*>(base())->length(); +} + +Node* HTMLFormCollection::item(unsigned index) const +{ + resetCollectionInfo(); + + if (info()->current && info()->position == index) + return info()->current; + + if (info()->hasLength && info()->length <= index) + return 0; + + if (!info()->current || info()->position > index) { + info()->current = 0; + info()->position = 0; + info()->elementsArrayPosition = 0; + } + + Vector<HTMLFormControlElement*>& l = static_cast<HTMLFormElement*>(base())->formElements; + unsigned currentIndex = info()->position; + + for (unsigned i = info()->elementsArrayPosition; i < l.size(); i++) { + if (l[i]->isEnumeratable() ) { + if (index == currentIndex) { + info()->position = index; + info()->current = l[i]; + info()->elementsArrayPosition = i; + return l[i]; + } + + currentIndex++; + } + } + + return 0; +} + +Element* HTMLFormCollection::getNamedItem(const QualifiedName& attrName, const String& name, bool caseSensitive) const +{ + info()->position = 0; + return getNamedFormItem(attrName, name, 0, caseSensitive); +} + +Element* HTMLFormCollection::getNamedFormItem(const QualifiedName& attrName, const String& name, int duplicateNumber, bool caseSensitive) const +{ + HTMLFormElement* form = static_cast<HTMLFormElement*>(base()); + + bool foundInputElements = false; + for (unsigned i = 0; i < form->formElements.size(); ++i) { + HTMLFormControlElement* e = form->formElements[i]; + if (e->isEnumeratable()) { + bool found; + if (caseSensitive) + found = e->getAttribute(attrName) == name; + else + found = equalIgnoringCase(e->getAttribute(attrName), name); + if (found) { + foundInputElements = true; + if (!duplicateNumber) + return e; + --duplicateNumber; + } + } + } + + if (!foundInputElements) { + for (unsigned i = 0; i < form->imgElements.size(); ++i) { + HTMLImageElement* e = form->imgElements[i]; + bool found; + if (caseSensitive) + found = e->getAttribute(attrName) == name; + else + found = equalIgnoringCase(e->getAttribute(attrName), name); + if (found) { + if (!duplicateNumber) + return e; + --duplicateNumber; + } + } + } + + return 0; +} + +Node* HTMLFormCollection::nextItem() const +{ + return item(info()->position + 1); +} + +Element* HTMLFormCollection::nextNamedItemInternal(const String &name) const +{ + Element* retval = getNamedFormItem(m_idsDone ? nameAttr : idAttr, name, ++info()->position, true); + if (retval) + return retval; + if (m_idsDone) // we're done + return 0; + // After doing id, do name + m_idsDone = true; + return getNamedItem(nameAttr, name, true); +} + +Node* HTMLFormCollection::namedItem(const String& name, bool caseSensitive) const +{ + // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp + // This method first searches for an object with a matching id + // attribute. If a match is not found, the method then searches for an + // object with a matching name attribute, but only on those elements + // that are allowed a name attribute. + resetCollectionInfo(); + m_idsDone = false; + info()->current = getNamedItem(idAttr, name, true); + if (info()->current) + return info()->current; + m_idsDone = true; + info()->current = getNamedItem(nameAttr, name, true); + return info()->current; +} + +Node* HTMLFormCollection::nextNamedItem(const String& name) const +{ + // The nextNamedItemInternal function can return the same item twice if it has + // both an id and name that are equal to the name parameter. So this function + // checks if we are on the nameAttr half of the iteration and skips over any + // that also have the same idAttr. + Element* impl = nextNamedItemInternal(name); + if (m_idsDone) + while (impl && impl->getAttribute(idAttr) == name) + impl = nextNamedItemInternal(name); + return impl; +} + +void HTMLFormCollection::updateNameCache() const +{ + if (info()->hasNameCache) + return; + + HashSet<AtomicStringImpl*> foundInputElements; + + HTMLFormElement* f = static_cast<HTMLFormElement*>(base()); + + for (unsigned i = 0; i < f->formElements.size(); ++i) { + HTMLFormControlElement* e = f->formElements[i]; + if (e->isEnumeratable()) { + const AtomicString& idAttrVal = e->getAttribute(idAttr); + const AtomicString& nameAttrVal = e->getAttribute(nameAttr); + if (!idAttrVal.isEmpty()) { + // add to id cache + Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl()); + if (!idVector) { + idVector = new Vector<Element*>; + info()->idCache.add(idAttrVal.impl(), idVector); + } + idVector->append(e); + foundInputElements.add(idAttrVal.impl()); + } + if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal) { + // add to name cache + Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl()); + if (!nameVector) { + nameVector = new Vector<Element*>; + info()->nameCache.add(nameAttrVal.impl(), nameVector); + } + nameVector->append(e); + foundInputElements.add(nameAttrVal.impl()); + } + } + } + + for (unsigned i = 0; i < f->imgElements.size(); ++i) { + HTMLImageElement* e = f->imgElements[i]; + const AtomicString& idAttrVal = e->getAttribute(idAttr); + const AtomicString& nameAttrVal = e->getAttribute(nameAttr); + if (!idAttrVal.isEmpty() && !foundInputElements.contains(idAttrVal.impl())) { + // add to id cache + Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl()); + if (!idVector) { + idVector = new Vector<Element*>; + info()->idCache.add(idAttrVal.impl(), idVector); + } + idVector->append(e); + } + if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && !foundInputElements.contains(nameAttrVal.impl())) { + // add to name cache + Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl()); + if (!nameVector) { + nameVector = new Vector<Element*>; + info()->nameCache.add(nameAttrVal.impl(), nameVector); + } + nameVector->append(e); + } + } + + info()->hasNameCache = true; +} + +} diff --git a/WebCore/html/HTMLFormCollection.h b/WebCore/html/HTMLFormCollection.h new file mode 100644 index 0000000..b81138f --- /dev/null +++ b/WebCore/html/HTMLFormCollection.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef HTMLFormCollection_h +#define HTMLFormCollection_h + +#include "HTMLCollection.h" + +namespace WebCore { + +class HTMLFormElement; +class QualifiedName; + +// This class is just a big hack to find form elements even in malformed HTML elements. +// The famous <table><tr><form><td> problem. + +class HTMLFormCollection : public HTMLCollection { +public: + static PassRefPtr<HTMLFormCollection> create(PassRefPtr<HTMLFormElement>); + + virtual ~HTMLFormCollection(); + + virtual Node* item(unsigned index) const; + virtual Node* nextItem() const; + + virtual Node* namedItem(const String& name, bool caseSensitive = true) const; + virtual Node* nextNamedItem(const String& name) const; + +private: + HTMLFormCollection(PassRefPtr<HTMLFormElement>); + + virtual void updateNameCache() const; + virtual unsigned calcLength() const; + + static CollectionInfo* formCollectionInfo(HTMLFormElement*); + + Element* getNamedItem(const QualifiedName& attrName, const String& name, bool caseSensitive) const; + Element* nextNamedItemInternal(const String& name) const; + + Element* getNamedFormItem(const QualifiedName& attrName, const String& name, int duplicateNumber, bool caseSensitive) const; + + mutable int currentPos; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp new file mode 100644 index 0000000..8e879fd --- /dev/null +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLFormControlElement.h" + +#include "Document.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "Frame.h" +#include "HTMLFormElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLParser.h" +#include "HTMLTokenizer.h" +#include "RenderTheme.h" +#include "Tokenizer.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) + : HTMLElement(tagName, doc) + , m_form(f) + , m_disabled(false) + , m_readOnly(false) + , m_valueMatchesRenderer(false) +{ + if (!m_form) + m_form = findFormAncestor(); + if (m_form) + m_form->registerFormElement(this); +} + +HTMLFormControlElement::~HTMLFormControlElement() +{ + if (m_form) + m_form->removeFormElement(this); +} + +void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == nameAttr) { + // Do nothing. + } else if (attr->name() == disabledAttr) { + bool oldDisabled = m_disabled; + m_disabled = !attr->isNull(); + if (oldDisabled != m_disabled) { + setChanged(); + if (renderer() && renderer()->style()->hasAppearance()) + theme()->stateChanged(renderer(), EnabledState); + } + } else if (attr->name() == readonlyAttr) { + bool oldReadOnly = m_readOnly; + m_readOnly = !attr->isNull(); + if (oldReadOnly != m_readOnly) { + setChanged(); + if (renderer() && renderer()->style()->hasAppearance()) + theme()->stateChanged(renderer(), ReadOnlyState); + } + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLFormControlElement::attach() +{ + ASSERT(!attached()); + + HTMLElement::attach(); + + // The call to updateFromElement() needs to go after the call through + // to the base class's attach() because that can sometimes do a close + // on the renderer. + if (renderer()) + renderer()->updateFromElement(); + + // Focus the element if it should honour its autofocus attribute. + // We have to determine if the element is a TextArea/Input/Button/Select, + // if input type hidden ignore autofocus. So if disabled or readonly. + if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyControl() && + ((hasTagName(inputTag) && !isInputTypeHidden()) || hasTagName(selectTag) || + hasTagName(buttonTag) || hasTagName(textareaTag))) + focus(); +} + +void HTMLFormControlElement::insertedIntoTree(bool deep) +{ + if (!m_form) { + // This handles the case of a new form element being created by + // JavaScript and inserted inside a form. In the case of the parser + // setting a form, we will already have a non-null value for m_form, + // and so we don't need to do anything. + m_form = findFormAncestor(); + if (m_form) + m_form->registerFormElement(this); + else + document()->checkedRadioButtons().addButton(this); + } + + HTMLElement::insertedIntoTree(deep); +} + +static inline Node* findRoot(Node* n) +{ + Node* root = n; + for (; n; n = n->parentNode()) + root = n; + return root; +} + +void HTMLFormControlElement::removedFromTree(bool deep) +{ + // If the form and element are both in the same tree, preserve the connection to the form. + // Otherwise, null out our form and remove ourselves from the form's list of elements. + HTMLParser* parser = 0; + if (Tokenizer* tokenizer = document()->tokenizer()) + if (tokenizer->isHTMLTokenizer()) + parser = static_cast<HTMLTokenizer*>(tokenizer)->htmlParser(); + + if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) { + m_form->removeFormElement(this); + m_form = 0; + } + + HTMLElement::removedFromTree(deep); +} + +const AtomicString& HTMLFormControlElement::name() const +{ + const AtomicString& n = getAttribute(nameAttr); + return n.isNull() ? emptyAtom : n; +} + +void HTMLFormControlElement::setName(const AtomicString &value) +{ + setAttribute(nameAttr, value); +} + +void HTMLFormControlElement::onChange() +{ + dispatchEventForType(eventNames().changeEvent, true, false); +} + +bool HTMLFormControlElement::disabled() const +{ + return m_disabled; +} + +void HTMLFormControlElement::setDisabled(bool b) +{ + setAttribute(disabledAttr, b ? "" : 0); +} + +void HTMLFormControlElement::setReadOnly(bool b) +{ + setAttribute(readonlyAttr, b ? "" : 0); +} + +bool HTMLFormControlElement::autofocus() const +{ + return hasAttribute(autofocusAttr); +} + +void HTMLFormControlElement::setAutofocus(bool b) +{ + setAttribute(autofocusAttr, b ? "autofocus" : 0); +} + +void HTMLFormControlElement::recalcStyle(StyleChange change) +{ + HTMLElement::recalcStyle(change); + + if (renderer()) + renderer()->updateFromElement(); +} + +bool HTMLFormControlElement::isFocusable() const +{ + if (disabled() || !renderer() || + (renderer()->style() && renderer()->style()->visibility() != VISIBLE) || + renderer()->width() == 0 || renderer()->height() == 0) + return false; + return true; +} + +bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const +{ + if (isFocusable()) + if (document()->frame()) + return document()->frame()->eventHandler()->tabsToAllControls(event); + return false; +} + +bool HTMLFormControlElement::isMouseFocusable() const +{ +#if PLATFORM(GTK) + return HTMLElement::isMouseFocusable(); +#else + return false; +#endif +} + +short HTMLFormControlElement::tabIndex() const +{ + // Skip the supportsFocus check in HTMLElement. + return Element::tabIndex(); +} + +bool HTMLFormControlElement::willValidate() const +{ + // FIXME: Implementation shall be completed with these checks: + // The control does not have a repetition template as an ancestor. + // The control does not have a datalist element as an ancestor. + // The control is not an output element. + return form() && name().length() && !disabled() && !isReadOnlyControl(); +} + +bool HTMLFormControlElement::supportsFocus() const +{ + return isFocusable() || (!disabled() && !document()->haveStylesheetsLoaded()); +} + +HTMLFormElement* HTMLFormControlElement::virtualForm() const +{ + return m_form; +} + +void HTMLFormControlElement::removeFromForm() +{ + if (!m_form) + return; + m_form->removeFormElement(this); + m_form = 0; +} + +HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) + : HTMLFormControlElement(tagName, doc, f) +{ + doc->registerFormElementWithState(this); +} + +HTMLFormControlElementWithState::~HTMLFormControlElementWithState() +{ + document()->unregisterFormElementWithState(this); +} + +void HTMLFormControlElementWithState::willMoveToNewOwnerDocument() +{ + document()->unregisterFormElementWithState(this); + HTMLFormControlElement::willMoveToNewOwnerDocument(); +} + +void HTMLFormControlElementWithState::didMoveToNewOwnerDocument() +{ + document()->registerFormElementWithState(this); + HTMLFormControlElement::didMoveToNewOwnerDocument(); +} + +void HTMLFormControlElementWithState::finishParsingChildren() +{ + HTMLFormControlElement::finishParsingChildren(); + Document* doc = document(); + if (doc->hasStateForNewFormElements()) { + String state; + if (doc->takeStateForFormElement(name().impl(), type().impl(), state)) + restoreState(state); + } +} + +} // namespace Webcore diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h new file mode 100644 index 0000000..0978a90 --- /dev/null +++ b/WebCore/html/HTMLFormControlElement.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLFormControlElement_h +#define HTMLFormControlElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class FormDataList; +class HTMLFormElement; + +class HTMLFormControlElement : public HTMLElement { +public: + HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*); + virtual ~HTMLFormControlElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + HTMLFormElement* form() const { return m_form; } + + virtual const AtomicString& type() const = 0; + + virtual bool isControl() const { return true; } + virtual bool isEnabled() const { return !disabled(); } + + virtual void parseMappedAttribute(MappedAttribute*); + virtual void attach(); + virtual void insertedIntoTree(bool deep); + virtual void removedFromTree(bool deep); + + virtual void reset() {} + + bool valueMatchesRenderer() const { return m_valueMatchesRenderer; } + void setValueMatchesRenderer(bool b = true) const { m_valueMatchesRenderer = b; } + + void onChange(); + + bool disabled() const; + void setDisabled(bool); + + virtual bool supportsFocus() const; + virtual bool isFocusable() const; + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isMouseFocusable() const; + virtual bool isEnumeratable() const { return false; } + + virtual bool isReadOnlyControl() const { return m_readOnly; } + void setReadOnly(bool); + + // Determines whether or not a control will be automatically focused + virtual bool autofocus() const; + void setAutofocus(bool); + + virtual void recalcStyle(StyleChange); + + virtual const AtomicString& name() const; + void setName(const AtomicString& name); + + virtual bool isGenericFormElement() const { return true; } + virtual bool isRadioButton() const { return false; } + + /* Override in derived classes to get the encoded name=value pair for submitting. + * Return true for a successful control (see HTML4-17.13.2). + */ + virtual bool appendFormData(FormDataList&, bool) { return false; } + + virtual bool isSuccessfulSubmitButton() const { return false; } + virtual bool isActivatedSubmit() const { return false; } + virtual void setActivatedSubmit(bool flag) { } + + virtual short tabIndex() const; + + virtual bool willValidate() const; + + void formDestroyed() { m_form = 0; } + +protected: + void removeFromForm(); + +private: + virtual HTMLFormElement* virtualForm() const; + + HTMLFormElement* m_form; + bool m_disabled; + bool m_readOnly; + mutable bool m_valueMatchesRenderer; +}; + +class HTMLFormControlElementWithState : public HTMLFormControlElement { +public: + HTMLFormControlElementWithState(const QualifiedName& tagName, Document*, HTMLFormElement*); + virtual ~HTMLFormControlElementWithState(); + + virtual void finishParsingChildren(); + + virtual bool saveState(String& value) const = 0; + +protected: + virtual void willMoveToNewOwnerDocument(); + virtual void didMoveToNewOwnerDocument(); + +private: + virtual void restoreState(const String& value) = 0; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp new file mode 100644 index 0000000..0e4d88e --- /dev/null +++ b/WebCore/html/HTMLFormElement.cpp @@ -0,0 +1,805 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLFormElement.h" + +#include "CSSHelper.h" +#include "ChromeClient.h" +#include "Document.h" +#include "Event.h" +#include "EventNames.h" +#include "FileList.h" +#include "FileSystem.h" +#include "FormData.h" +#include "FormDataList.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLDocument.h" +#include "HTMLFormCollection.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "MIMETypeRegistry.h" +#include "Page.h" +#include "RenderTextControl.h" + +#if PLATFORM(QT) +#include <QtCore/QFileInfo> +#endif + +#if PLATFORM(WX) +#include <wx/defs.h> +#include <wx/filename.h> +#endif + +#if PLATFORM(WIN_OS) +#include <shlwapi.h> +#endif + +namespace WebCore { + +using namespace HTMLNames; + +static const char hexDigits[17] = "0123456789ABCDEF"; + +HTMLFormElement::HTMLFormElement(Document* doc) + : HTMLElement(formTag, doc) + , m_elementAliases(0) + , collectionInfo(0) + , m_enctype("application/x-www-form-urlencoded") + , m_post(false) + , m_multipart(false) + , m_autocomplete(true) + , m_insubmit(false) + , m_doingsubmit(false) + , m_inreset(false) + , m_malformed(false) +{ +} + +HTMLFormElement::~HTMLFormElement() +{ + if (!m_autocomplete) + document()->unregisterForDocumentActivationCallbacks(this); + + delete m_elementAliases; + delete collectionInfo; + + for (unsigned i = 0; i < formElements.size(); ++i) + formElements[i]->formDestroyed(); + for (unsigned i = 0; i < imgElements.size(); ++i) + imgElements[i]->m_form = 0; +} + +bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url) +{ + return document()->completeURL(url).protocolIs("https"); +} + +void HTMLFormElement::attach() +{ + HTMLElement::attach(); +} + +void HTMLFormElement::insertedIntoDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->addNamedItem(m_name); + + HTMLElement::insertedIntoDocument(); +} + +void HTMLFormElement::removedFromDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->removeNamedItem(m_name); + + HTMLElement::removedFromDocument(); +} + +void HTMLFormElement::handleLocalEvents(Event* event, bool useCapture) +{ + EventTargetNode* targetNode = event->target()->toNode(); + if (!useCapture && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) { + event->stopPropagation(); + return; + } + HTMLElement::handleLocalEvents(event, useCapture); +} + +unsigned HTMLFormElement::length() const +{ + int len = 0; + for (unsigned i = 0; i < formElements.size(); ++i) + if (formElements[i]->isEnumeratable()) + ++len; + + return len; +} + +Node* HTMLFormElement::item(unsigned index) +{ + return elements()->item(index); +} + +void HTMLFormElement::submitClick(Event* event) +{ + bool submitFound = false; + for (unsigned i = 0; i < formElements.size(); ++i) { + if (formElements[i]->hasLocalName(inputTag)) { + HTMLInputElement* element = static_cast<HTMLInputElement*>(formElements[i]); + if (element->isSuccessfulSubmitButton() && element->renderer()) { + submitFound = true; + element->dispatchSimulatedClick(event); + break; + } + } + } + if (!submitFound) // submit the form without a submit or image input + prepareSubmit(event); +} + +static void appendString(Vector<char>& buffer, const char* string) +{ + buffer.append(string, strlen(string)); +} + +static void appendString(Vector<char>& buffer, const CString& string) +{ + buffer.append(string.data(), string.length()); +} + +static void appendEncodedString(Vector<char>& buffer, const CString& string) +{ + // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 + int length = string.length(); + for (int i = 0; i < length; i++) { + unsigned char c = string.data()[i]; + + // Same safe characters as Netscape for compatibility. + static const char safe[] = "-._*"; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr(safe, c)) + buffer.append(c); + else if (c == ' ') + buffer.append('+'); + else if (c == '\n' || (c == '\r' && (i + 1 >= length || string.data()[i + 1] != '\n'))) + appendString(buffer, "%0D%0A"); + else if (c != '\r') { + buffer.append('%'); + buffer.append(hexDigits[c >> 4]); + buffer.append(hexDigits[c & 0xF]); + } + } +} + +// FIXME: Move to platform directory? +static int randomNumber() +{ + static bool randomSeeded = false; + +#if PLATFORM(DARWIN) + if (!randomSeeded) { + srandomdev(); + randomSeeded = true; + } + return random(); +#else + if (!randomSeeded) { + srand(static_cast<unsigned>(time(0))); + randomSeeded = true; + } + return rand(); +#endif +} + +TextEncoding HTMLFormElement::dataEncoding() const +{ + if (isMailtoForm()) + return UTF8Encoding(); + + TextEncoding encoding; + String str = m_acceptcharset; + str.replace(',', ' '); + Vector<String> charsets; + str.split(' ', charsets); + Vector<String>::const_iterator end = charsets.end(); + for (Vector<String>::const_iterator it = charsets.begin(); it != end; ++it) + if ((encoding = TextEncoding(*it)).isValid()) + return encoding; + if (Frame* frame = document()->frame()) + return frame->loader()->encoding(); + return Latin1Encoding(); +} + +PassRefPtr<FormData> HTMLFormElement::formData(const char* boundary) const +{ + Vector<char> encodedData; + TextEncoding encoding = dataEncoding(); + + RefPtr<FormData> result = FormData::create(); + + for (unsigned i = 0; i < formElements.size(); ++i) { + HTMLFormControlElement* control = formElements[i]; + FormDataList list(encoding); + + if (!control->disabled() && control->appendFormData(list, m_multipart)) { + size_t formDataListSize = list.list().size(); + ASSERT(formDataListSize % 2 == 0); + for (size_t j = 0; j < formDataListSize; j += 2) { + const FormDataList::Item& key = list.list()[j]; + const FormDataList::Item& value = list.list()[j + 1]; + if (!m_multipart) { + // Omit the name "isindex" if it's the first form data element. + // FIXME: Why is this a good rule? Is this obsolete now? + if (encodedData.isEmpty() && key.data() == "isindex") + appendEncodedString(encodedData, value.data()); + else { + if (!encodedData.isEmpty()) + encodedData.append('&'); + appendEncodedString(encodedData, key.data()); + encodedData.append('='); + appendEncodedString(encodedData, value.data()); + } + } else { + Vector<char> header; + appendString(header, "--"); + appendString(header, boundary); + appendString(header, "\r\n"); + appendString(header, "Content-Disposition: form-data; name=\""); + header.append(key.data().data(), key.data().length()); + header.append('"'); + + bool shouldGenerateFile = false; + // if the current type is FILE, then we also need to + // include the filename + if (value.file()) { + const String& path = value.file()->path(); + String filename = value.file()->fileName(); + + // Let the application specify a filename if it's going to generate a replacement file for the upload. + if (!path.isEmpty()) { + if (Page* page = document()->page()) { + String generatedFilename; + shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFilename); + if (shouldGenerateFile) + filename = generatedFilename; + } + } + + // FIXME: This won't work if the filename includes a " mark, + // or control characters like CR or LF. This also does strange + // things if the filename includes characters you can't encode + // in the website's character set. + appendString(header, "; filename=\""); + appendString(header, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables)); + header.append('"'); + + if (!filename.isEmpty()) { + // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path, + // not just a basename. But filename is not the path. But note that it's not safe to + // just use path instead since in the generated-file case it will not reflect the + // MIME type of the generated file. + String mimeType = MIMETypeRegistry::getMIMETypeForPath(filename); + if (!mimeType.isEmpty()) { + appendString(header, "\r\nContent-Type: "); + appendString(header, mimeType.latin1()); + } + } + } + + appendString(header, "\r\n\r\n"); + + // append body + result->appendData(header.data(), header.size()); + if (size_t dataSize = value.data().length()) + result->appendData(value.data().data(), dataSize); + else if (value.file() && !value.file()->path().isEmpty()) + result->appendFile(value.file()->path(), shouldGenerateFile); + result->appendData("\r\n", 2); + } + } + } + } + + + if (m_multipart) { + appendString(encodedData, "--"); + appendString(encodedData, boundary); + appendString(encodedData, "--\r\n"); + } + + result->appendData(encodedData.data(), encodedData.size()); + return result; +} + +void HTMLFormElement::parseEnctype(const String& type) +{ + if(type.contains("multipart", false) || type.contains("form-data", false)) { + m_enctype = "multipart/form-data"; + m_multipart = true; + } else if (type.contains("text", false) || type.contains("plain", false)) { + m_enctype = "text/plain"; + m_multipart = false; + } else { + m_enctype = "application/x-www-form-urlencoded"; + m_multipart = false; + } +} + +bool HTMLFormElement::isMailtoForm() const +{ + return protocolIs(m_url, "mailto"); +} + +bool HTMLFormElement::prepareSubmit(Event* event) +{ + Frame* frame = document()->frame(); + if (m_insubmit || !frame) + return m_insubmit; + + m_insubmit = true; + m_doingsubmit = false; + + if (dispatchEventForType(eventNames().submitEvent, true, true) && !m_doingsubmit) + m_doingsubmit = true; + + m_insubmit = false; + + if (m_doingsubmit) + submit(event, true); + + return m_doingsubmit; +} + +void HTMLFormElement::submit() +{ + submit(0, false); +} + +// Returns a 0-terminated C string in the vector. +static void getUniqueBoundaryString(Vector<char>& boundary) +{ + // The RFC 2046 spec says the AlphaNumeric characters plus the following characters + // are legal for boundaries: '()+_,-./:=? + // However the following characters, though legal, cause some sites to fail: + // (),./:= + // http://bugs.webkit.org/show_bug.cgi?id=13352 + static const char AlphaNumericEncMap[64] = + { + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x41 + // FIXME <rdar://problem/5252577> gmail does not accept legal characters in the form boundary + // As stated above, some legal characters cause, sites to fail. Specifically + // the / character which was the last character in the above array. I have + // replaced the last character with another character already in the array + // (notice the first and last values are both 0x41, A). Instead of picking + // another unique legal character for boundary strings that, because it has + // never been tested, may or may not break other sites, I simply + // replaced / with A. This means A is twice as likely to occur in our boundary + // strings than any other character but I think this is fine for the time being. + // The FIXME here is about restoring the / character once the aforementioned + // radar has been resolved. + }; + + // Start with an informative prefix. + const char boundaryPrefix[] = "----WebKitFormBoundary"; + boundary.append(boundaryPrefix, strlen(boundaryPrefix)); + + // Append 16 random 7bit ascii AlphaNumeric characters. + Vector<char> randomBytes; + + for (int i = 0; i < 4; ++i) { + int randomness = randomNumber(); + randomBytes.append(AlphaNumericEncMap[(randomness >> 24) & 0x3F]); + randomBytes.append(AlphaNumericEncMap[(randomness >> 16) & 0x3F]); + randomBytes.append(AlphaNumericEncMap[(randomness >> 8) & 0x3F]); + randomBytes.append(AlphaNumericEncMap[randomness & 0x3F]); + } + + boundary.append(randomBytes); + boundary.append(0); // Add a 0 at the end so we can use this as a C-style string. +} + +void HTMLFormElement::submit(Event* event, bool activateSubmitButton) +{ + FrameView* view = document()->view(); + Frame* frame = document()->frame(); + if (!view || !frame) + return; + + if (m_insubmit) { + m_doingsubmit = true; + return; + } + + m_insubmit = true; + + HTMLFormControlElement* firstSuccessfulSubmitButton = 0; + bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button? + + frame->loader()->clearRecordedFormValues(); + frame->loader()->setFormAboutToBeSubmitted(this); + for (unsigned i = 0; i < formElements.size(); ++i) { + HTMLFormControlElement* control = formElements[i]; + if (control->hasLocalName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(control); + if (input->isTextField()) { + frame->loader()->recordFormValue(input->name(), input->value()); + if (input->isSearchField()) + input->addSearchResult(); + } + } + if (needButtonActivation) { + if (control->isActivatedSubmit()) + needButtonActivation = false; + else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton()) + firstSuccessfulSubmitButton = control; + } + } + + if (needButtonActivation && firstSuccessfulSubmitButton) + firstSuccessfulSubmitButton->setActivatedSubmit(true); + + if (m_url.isEmpty()) + m_url = document()->url().string(); + + if (m_post) { + if (m_multipart && isMailtoForm()) { + setEnctype("application/x-www-form-urlencoded"); + m_multipart = false; + } + + if (!m_multipart) { + RefPtr<FormData> data = formData(0); + if (isMailtoForm()) { + String body = data->flattenToString(); + if (equalIgnoringCase(enctype(), "text/plain")) { + // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20. + body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n"); + } + Vector<char> bodyData; + appendString(bodyData, "body="); + appendEncodedString(bodyData, body.utf8()); + data = FormData::create(String(bodyData.data(), bodyData.size()).replace('+', "%20").latin1()); + } + frame->loader()->submitForm("POST", m_url, data, m_target, enctype(), String(), event); + } else { + Vector<char> boundary; + getUniqueBoundaryString(boundary); + frame->loader()->submitForm("POST", m_url, formData(boundary.data()), m_target, enctype(), boundary.data(), event); + } + } else { + m_multipart = false; + frame->loader()->submitForm("GET", m_url, formData(0), m_target, String(), String(), event); + } + + if (needButtonActivation && firstSuccessfulSubmitButton) + firstSuccessfulSubmitButton->setActivatedSubmit(false); + + m_doingsubmit = m_insubmit = false; +} + +void HTMLFormElement::reset() +{ + Frame* frame = document()->frame(); + if (m_inreset || !frame) + return; + + m_inreset = true; + + // ### DOM2 labels this event as not cancelable, however + // common browsers( sick! ) allow it be cancelled. + if ( !dispatchEventForType(eventNames().resetEvent,true, true) ) { + m_inreset = false; + return; + } + + for (unsigned i = 0; i < formElements.size(); ++i) + formElements[i]->reset(); + + m_inreset = false; +} + +void HTMLFormElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == actionAttr) + m_url = parseURL(attr->value()); + else if (attr->name() == targetAttr) + m_target = attr->value(); + else if (attr->name() == methodAttr) { + if (equalIgnoringCase(attr->value(), "post")) + m_post = true; + else if (equalIgnoringCase(attr->value(), "get")) + m_post = false; + } else if (attr->name() == enctypeAttr) + parseEnctype(attr->value()); + else if (attr->name() == accept_charsetAttr) + // space separated list of charsets the server + // accepts - see rfc2045 + m_acceptcharset = attr->value(); + else if (attr->name() == acceptAttr) { + // ignore this one for the moment... + } else if (attr->name() == autocompleteAttr) { + m_autocomplete = !equalIgnoringCase(attr->value(), "off"); + if (!m_autocomplete) + document()->registerForDocumentActivationCallbacks(this); + else + document()->unregisterForDocumentActivationCallbacks(this); + } else if (attr->name() == onsubmitAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().submitEvent, attr); + else if (attr->name() == onresetAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().resetEvent, attr); + else if (attr->name() == nameAttr) { + const AtomicString& newName = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(newName); + } + m_name = newName; + } else + HTMLElement::parseMappedAttribute(attr); +} + +template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item) +{ + size_t size = vec.size(); + for (size_t i = 0; i != size; ++i) + if (vec[i] == item) { + vec.remove(i); + break; + } +} + +unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e) +{ + // Check for the special case where this element is the very last thing in + // the form's tree of children; we don't want to walk the entire tree in that + // common case that occurs during parsing; instead we'll just return a value + // that says "add this form element to the end of the array". + if (e->traverseNextNode(this)) { + unsigned i = 0; + for (Node* node = this; node; node = node->traverseNextNode(this)) { + if (node == e) + return i; + if (node->isHTMLElement() + && static_cast<HTMLElement*>(node)->isGenericFormElement() + && static_cast<HTMLFormControlElement*>(node)->form() == this) + ++i; + } + } + return formElements.size(); +} + +void HTMLFormElement::registerFormElement(HTMLFormControlElement* e) +{ + document()->checkedRadioButtons().removeButton(e); + m_checkedRadioButtons.addButton(e); + formElements.insert(formElementIndex(e), e); +} + +void HTMLFormElement::removeFormElement(HTMLFormControlElement* e) +{ + m_checkedRadioButtons.removeButton(e); + removeFromVector(formElements, e); +} + +bool HTMLFormElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == actionAttr; +} + +void HTMLFormElement::registerImgElement(HTMLImageElement* e) +{ + imgElements.append(e); +} + +void HTMLFormElement::removeImgElement(HTMLImageElement* e) +{ + removeFromVector(imgElements, e); +} + +PassRefPtr<HTMLCollection> HTMLFormElement::elements() +{ + return HTMLFormCollection::create(this); +} + +String HTMLFormElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLFormElement::setName(const String &value) +{ + setAttribute(nameAttr, value); +} + +String HTMLFormElement::acceptCharset() const +{ + return getAttribute(accept_charsetAttr); +} + +void HTMLFormElement::setAcceptCharset(const String &value) +{ + setAttribute(accept_charsetAttr, value); +} + +String HTMLFormElement::action() const +{ + return getAttribute(actionAttr); +} + +void HTMLFormElement::setAction(const String &value) +{ + setAttribute(actionAttr, value); +} + +void HTMLFormElement::setEnctype(const String &value) +{ + setAttribute(enctypeAttr, value); +} + +String HTMLFormElement::method() const +{ + return getAttribute(methodAttr); +} + +void HTMLFormElement::setMethod(const String &value) +{ + setAttribute(methodAttr, value); +} + +String HTMLFormElement::target() const +{ + return getAttribute(targetAttr); +} + +void HTMLFormElement::setTarget(const String &value) +{ + setAttribute(targetAttr, value); +} + +PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias) +{ + if (alias.isEmpty() || !m_elementAliases) + return 0; + return m_elementAliases->get(alias.impl()); +} + +void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias) +{ + if (alias.isEmpty()) + return; + if (!m_elementAliases) + m_elementAliases = new AliasMap; + m_elementAliases->set(alias.impl(), element); +} + +void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems) +{ + elements()->namedItems(name, namedItems); + + // see if we have seen something with this name before + RefPtr<HTMLFormControlElement> aliasElem; + if (aliasElem = elementForAlias(name)) { + bool found = false; + for (unsigned n = 0; n < namedItems.size(); n++) { + if (namedItems[n] == aliasElem.get()) { + found = true; + break; + } + } + if (!found) + // we have seen it before but it is gone now. still, we need to return it. + namedItems.append(aliasElem.get()); + } + // name has been accessed, remember it + if (namedItems.size() && aliasElem != namedItems.first()) + addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name); +} + +void HTMLFormElement::documentDidBecomeActive() +{ + ASSERT(!m_autocomplete); + + for (unsigned i = 0; i < formElements.size(); ++i) + formElements[i]->reset(); +} + +void HTMLFormElement::willMoveToNewOwnerDocument() +{ + if (!m_autocomplete) + document()->unregisterForDocumentActivationCallbacks(this); +} + +void HTMLFormElement::didMoveToNewOwnerDocument() +{ + if(m_autocomplete) + document()->registerForDocumentActivationCallbacks(this); +} + +void HTMLFormElement::CheckedRadioButtons::addButton(HTMLFormControlElement* element) +{ + // We only want to add radio buttons. + if (!element->isRadioButton()) + return; + + // Without a name, there is no group. + if (element->name().isEmpty()) + return; + + HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element); + + // We only track checked buttons. + if (!inputElement->checked()) + return; + + if (!m_nameToCheckedRadioButtonMap) + m_nameToCheckedRadioButtonMap.set(new NameToInputMap); + + pair<NameToInputMap::iterator, bool> result = m_nameToCheckedRadioButtonMap->add(element->name().impl(), inputElement); + if (result.second) + return; + + HTMLInputElement* oldCheckedButton = result.first->second; + if (oldCheckedButton == inputElement) + return; + + result.first->second = inputElement; + oldCheckedButton->setChecked(false); +} + +HTMLInputElement* HTMLFormElement::CheckedRadioButtons::checkedButtonForGroup(const AtomicString& name) const +{ + if (!m_nameToCheckedRadioButtonMap) + return 0; + + return m_nameToCheckedRadioButtonMap->get(name.impl()); +} + +void HTMLFormElement::CheckedRadioButtons::removeButton(HTMLFormControlElement* element) +{ + if (element->name().isEmpty() || !m_nameToCheckedRadioButtonMap) + return; + + NameToInputMap::iterator it = m_nameToCheckedRadioButtonMap->find(element->name().impl()); + if (it == m_nameToCheckedRadioButtonMap->end() || it->second != element) + return; + + ASSERT(element->isRadioButton()); + ASSERT(element->isChecked()); + + m_nameToCheckedRadioButtonMap->remove(it); + if (m_nameToCheckedRadioButtonMap->isEmpty()) + m_nameToCheckedRadioButtonMap.clear(); +} + +} // namespace diff --git a/WebCore/html/HTMLFormElement.h b/WebCore/html/HTMLFormElement.h new file mode 100644 index 0000000..464a53c --- /dev/null +++ b/WebCore/html/HTMLFormElement.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLFormElement_h +#define HTMLFormElement_h + +#include "HTMLCollection.h" +#include "HTMLElement.h" + +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class Event; +class FormData; +class HTMLFormControlElement; +class HTMLImageElement; +class HTMLInputElement; +class HTMLFormCollection; +class TextEncoding; + +class HTMLFormElement : public HTMLElement { +public: + HTMLFormElement(Document*); + virtual ~HTMLFormElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 3; } + + virtual void attach(); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + virtual void handleLocalEvents(Event*, bool useCapture); + + PassRefPtr<HTMLCollection> elements(); + void getNamedElements(const AtomicString&, Vector<RefPtr<Node> >&); + + unsigned length() const; + Node* item(unsigned index); + + String enctype() const { return m_enctype; } + void setEnctype(const String&); + + String encoding() const { return m_enctype; } + void setEncoding(const String& enctype) { setEnctype(enctype); } + + bool autoComplete() const { return m_autocomplete; } + + virtual void parseMappedAttribute(MappedAttribute*); + + void registerFormElement(HTMLFormControlElement*); + void removeFormElement(HTMLFormControlElement*); + void registerImgElement(HTMLImageElement*); + void removeImgElement(HTMLImageElement*); + + bool prepareSubmit(Event*); + void submit(); + void submit(Event*, bool activateSubmitButton = false); + void reset(); + + // Used to indicate a malformed state to keep from applying the bottom margin of the form. + void setMalformed(bool malformed) { m_malformed = malformed; } + bool isMalformed() const { return m_malformed; } + + virtual bool isURLAttribute(Attribute*) const; + + void submitClick(Event*); + bool formWouldHaveSecureSubmission(const String& url); + + String name() const; + void setName(const String&); + + String acceptCharset() const; + void setAcceptCharset(const String&); + + String action() const; + void setAction(const String&); + + String method() const; + void setMethod(const String&); + + virtual String target() const; + void setTarget(const String&); + + PassRefPtr<HTMLFormControlElement> elementForAlias(const AtomicString&); + void addElementAlias(HTMLFormControlElement*, const AtomicString& alias); + + // FIXME: Change this to be private after getting rid of all the clients. + Vector<HTMLFormControlElement*> formElements; + + class CheckedRadioButtons { + public: + void addButton(HTMLFormControlElement*); + void removeButton(HTMLFormControlElement*); + HTMLInputElement* checkedButtonForGroup(const AtomicString& name) const; + + private: + typedef HashMap<AtomicStringImpl*, HTMLInputElement*> NameToInputMap; + OwnPtr<NameToInputMap> m_nameToCheckedRadioButtonMap; + }; + + CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; } + + virtual void documentDidBecomeActive(); + +protected: + virtual void willMoveToNewOwnerDocument(); + virtual void didMoveToNewOwnerDocument(); + +private: + void parseEnctype(const String&); + bool isMailtoForm() const; + TextEncoding dataEncoding() const; + PassRefPtr<FormData> formData(const char* boundary) const; + unsigned formElementIndex(HTMLFormControlElement*); + + friend class HTMLFormCollection; + + typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<HTMLFormControlElement> > AliasMap; + + AliasMap* m_elementAliases; + HTMLCollection::CollectionInfo* collectionInfo; + + CheckedRadioButtons m_checkedRadioButtons; + + Vector<HTMLImageElement*> imgElements; + String m_url; + String m_target; + String m_enctype; + String m_acceptcharset; + bool m_post : 1; + bool m_multipart : 1; + bool m_autocomplete : 1; + bool m_insubmit : 1; + bool m_doingsubmit : 1; + bool m_inreset : 1; + bool m_malformed : 1; + AtomicString m_name; +}; + +} // namespace WebCore + +#endif // HTMLFormElement_h diff --git a/WebCore/html/HTMLFormElement.idl b/WebCore/html/HTMLFormElement.idl new file mode 100644 index 0000000..39db70c --- /dev/null +++ b/WebCore/html/HTMLFormElement.idl @@ -0,0 +1,43 @@ +/* + * 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 html { + + interface [ + HasIndexGetter, + HasOverridingNameGetter, + GenerateConstructor, + InterfaceUUID=c7e79252-3b6d-4636-9efb-0667192ca5c3, + ImplementationUUID=3561288f-5f67-4c45-9290-de4191d4c9c9 + ] HTMLFormElement : HTMLElement { + readonly attribute HTMLCollection elements; + readonly attribute long length; + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString acceptCharset; + attribute [ConvertNullToNullString] DOMString action; + attribute [ConvertNullToNullString] DOMString encoding; /* Netscape/Firefox legacy attribute. Same as enctype. */ + attribute [ConvertNullToNullString] DOMString enctype; + attribute [ConvertNullToNullString] DOMString method; + attribute [ConvertNullToNullString] DOMString target; + + void submit(); + void reset(); + }; +} diff --git a/WebCore/html/HTMLFrameElement.cpp b/WebCore/html/HTMLFrameElement.cpp new file mode 100644 index 0000000..3b91d37 --- /dev/null +++ b/WebCore/html/HTMLFrameElement.cpp @@ -0,0 +1,86 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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 "HTMLFrameElement.h" + +#include "Frame.h" +#include "HTMLFrameSetElement.h" +#include "HTMLNames.h" +#include "RenderFrame.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFrameElement::HTMLFrameElement(Document* doc) + : HTMLFrameElementBase(frameTag, doc) + , m_frameBorder(true) + , m_frameBorderSet(false) +{ +} + +bool HTMLFrameElement::rendererIsNeeded(RenderStyle* style) +{ + // For compatibility, frames render even when display: none is set. + return isURLAllowed(m_URL); +} + +RenderObject* HTMLFrameElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + return new (arena) RenderFrame(this); +} + +static inline HTMLFrameSetElement* containingFrameSetElement(Node* node) +{ + while ((node = node->parentNode())) + if (node->hasTagName(framesetTag)) + return static_cast<HTMLFrameSetElement*>(node); + return 0; +} + +void HTMLFrameElement::attach() +{ + HTMLFrameElementBase::attach(); + + if (HTMLFrameSetElement* frameSetElement = containingFrameSetElement(this)) { + if (!m_frameBorderSet) + m_frameBorder = frameSetElement->hasFrameBorder(); + if (!m_noResize) + m_noResize = frameSetElement->noResize(); + } +} + +void HTMLFrameElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == frameborderAttr) { + m_frameBorder = attr->value().toInt(); + m_frameBorderSet = !attr->isNull(); + // FIXME: If we are already attached, this has no effect. + } else + HTMLFrameElementBase::parseMappedAttribute(attr); +} + +} // namespace WebCore diff --git a/WebCore/html/HTMLFrameElement.h b/WebCore/html/HTMLFrameElement.h new file mode 100644 index 0000000..fbb9761 --- /dev/null +++ b/WebCore/html/HTMLFrameElement.h @@ -0,0 +1,62 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ + +#ifndef HTMLFrameElement_h +#define HTMLFrameElement_h + +#include "HTMLFrameElementBase.h" + +namespace WebCore { + +class Document; +class RenderObject; +class RenderArena; +class RenderStyle; + +class HTMLFrameElement : public HTMLFrameElementBase +{ +public: + HTMLFrameElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void attach(); + + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + virtual void parseMappedAttribute(MappedAttribute*); + + bool hasFrameBorder() const { return m_frameBorder; } + +private: + bool m_frameBorder; + bool m_frameBorderSet; +}; + +} // namespace WebCore + +#endif // HTMLFrameElement_h diff --git a/WebCore/html/HTMLFrameElement.idl b/WebCore/html/HTMLFrameElement.idl new file mode 100644 index 0000000..bc512ff --- /dev/null +++ b/WebCore/html/HTMLFrameElement.idl @@ -0,0 +1,57 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=0795de43-e0cb-429e-ae0b-d38dbb641fd7, + ImplementationUUID=38c9e3c8-3384-40b6-a484-cb845c48b67d + ] HTMLFrameElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString frameBorder; + attribute [ConvertNullToNullString] DOMString longDesc; + attribute [ConvertNullToNullString] DOMString marginHeight; + attribute [ConvertNullToNullString] DOMString marginWidth; + attribute [ConvertNullToNullString] DOMString name; + attribute boolean noResize; + attribute [ConvertNullToNullString] DOMString scrolling; + attribute [ConvertNullToNullString, CustomSetter] DOMString src; + + // Introduced in DOM Level 2: + readonly attribute [CheckFrameSecurity] Document contentDocument; + +#if !defined(LANGUAGE_COM) + // Extensions + readonly attribute DOMWindow contentWindow; + +#if ENABLE_SVG + [SVGCheckSecurityDocument] SVGDocument getSVGDocument() + raises(DOMException); +#endif +#endif + + attribute [ConvertNullToNullString, CustomSetter] DOMString location; + readonly attribute long width; + readonly attribute long height; + + }; + +} diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp new file mode 100644 index 0000000..1c80155 --- /dev/null +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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. + */ + +#include "config.h" +#include "HTMLFrameElementBase.h" + +#include "CSSHelper.h" +#include "Document.h" +#include "EventNames.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLFrameSetElement.h" +#include "HTMLNames.h" +#include "KURL.h" +#include "Page.h" +#include "RenderFrame.h" +#include "Settings.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document *doc) + : HTMLFrameOwnerElement(tagName, doc) + , m_scrolling(ScrollbarAuto) + , m_marginWidth(-1) + , m_marginHeight(-1) + , m_noResize(false) + , m_viewSource(false) + , m_shouldOpenURLAfterAttach(false) +{ +} + +bool HTMLFrameElementBase::isURLAllowed(const AtomicString& URLString) const +{ + if (URLString.isEmpty()) + return true; + + const KURL& completeURL = document()->completeURL(URLString); + + // Don't allow more than 200 total frames in a set. This seems + // like a reasonable upper bound, and otherwise mutually recursive + // frameset pages can quickly bring the program to its knees with + // exponential growth in the number of frames. + // FIXME: This limit could be higher, but because WebKit has some + // algorithms that happen while loading which appear to be N^2 or + // worse in the number of frames, we'll keep it at 200 for now. + if (Frame* parentFrame = document()->frame()) { + if (parentFrame->page()->frameCount() > 200) + return false; + } + + // We allow one level of self-reference because some sites depend on that. + // But we don't allow more than one. + bool foundSelfReference = false; + for (Frame* frame = document()->frame(); frame; frame = frame->tree()->parent()) { + if (equalIgnoringRef(frame->loader()->url(), completeURL)) { + if (foundSelfReference) + return false; + foundSelfReference = true; + } + } + + return true; +} + +void HTMLFrameElementBase::openURL() +{ + ASSERT(!m_frameName.isEmpty()); + + if (!isURLAllowed(m_URL)) + return; + + if (m_URL.isEmpty()) + m_URL = blankURL().string(); + + Frame* parentFrame = document()->frame(); + if (!parentFrame) + return; + + parentFrame->loader()->requestFrame(this, m_URL, m_frameName); + if (contentFrame()) + contentFrame()->setInViewSourceMode(viewSourceMode()); +} + +void HTMLFrameElementBase::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == srcAttr) + setLocation(parseURL(attr->value())); + else if (attr->name() == idAttr) { + // Important to call through to base for the id attribute so the hasID bit gets set. + HTMLFrameOwnerElement::parseMappedAttribute(attr); + m_frameName = attr->value(); + } else if (attr->name() == nameAttr) { + m_frameName = attr->value(); + // FIXME: If we are already attached, this doesn't actually change the frame's name. + // FIXME: If we are already attached, this doesn't check for frame name + // conflicts and generate a unique frame name. + } else if (attr->name() == marginwidthAttr) { + m_marginWidth = attr->value().toInt(); + // FIXME: If we are already attached, this has no effect. + } else if (attr->name() == marginheightAttr) { + m_marginHeight = attr->value().toInt(); + // FIXME: If we are already attached, this has no effect. + } else if (attr->name() == noresizeAttr) { + m_noResize = true; + // FIXME: If we are already attached, this has no effect. + } else if (attr->name() == scrollingAttr) { + // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling." + if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes")) + m_scrolling = ScrollbarAuto; + else if (equalIgnoringCase(attr->value(), "no")) + m_scrolling = ScrollbarAlwaysOff; + // FIXME: If we are already attached, this has no effect. + } else if (attr->name() == viewsourceAttr) { + m_viewSource = !attr->isNull(); + if (contentFrame()) + contentFrame()->setInViewSourceMode(viewSourceMode()); + } else if (attr->name() == onloadAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + } else if (attr->name() == onbeforeunloadAttr) { + // FIXME: should <frame> elements have beforeunload handlers? + setInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + } else + HTMLFrameOwnerElement::parseMappedAttribute(attr); +} + +void HTMLFrameElementBase::setNameAndOpenURL() +{ + m_frameName = getAttribute(nameAttr); + if (m_frameName.isNull()) + m_frameName = getAttribute(idAttr); + + if (Frame* parentFrame = document()->frame()) + m_frameName = parentFrame->tree()->uniqueChildName(m_frameName); + + openURL(); +} + +void HTMLFrameElementBase::setNameAndOpenURLCallback(Node* n) +{ + static_cast<HTMLFrameElementBase*>(n)->setNameAndOpenURL(); +} + +void HTMLFrameElementBase::insertedIntoDocument() +{ + HTMLFrameOwnerElement::insertedIntoDocument(); + + // We delay frame loading until after the render tree is fully constructed. + // Othewise, a synchronous load that executed JavaScript would see incorrect + // (0) values for the frame's renderer-dependent properties, like width. + m_shouldOpenURLAfterAttach = true; +} + +void HTMLFrameElementBase::removedFromDocument() +{ + m_shouldOpenURLAfterAttach = false; + + HTMLFrameOwnerElement::removedFromDocument(); +} + +void HTMLFrameElementBase::attach() +{ + if (m_shouldOpenURLAfterAttach) { + m_shouldOpenURLAfterAttach = false; + queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this); + } + + HTMLFrameOwnerElement::attach(); + + if (RenderPart* renderPart = static_cast<RenderPart*>(renderer())) + if (Frame* frame = contentFrame()) + renderPart->setWidget(frame->view()); +} + +KURL HTMLFrameElementBase::location() const +{ + return src(); +} + +void HTMLFrameElementBase::setLocation(const String& str) +{ + Settings* settings = document()->settings(); + if (settings && settings->needsAcrobatFrameReloadingQuirk() && m_URL == str) + return; + + m_URL = AtomicString(str); + + if (inDocument()) + openURL(); +} + +bool HTMLFrameElementBase::isFocusable() const +{ + return renderer(); +} + +void HTMLFrameElementBase::setFocus(bool received) +{ + HTMLFrameOwnerElement::setFocus(received); + if (Page* page = document()->page()) + page->focusController()->setFocusedFrame(received ? contentFrame() : 0); +} + +bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const +{ + return attr->name() == srcAttr; +} + +String HTMLFrameElementBase::frameBorder() const +{ + return getAttribute(frameborderAttr); +} + +void HTMLFrameElementBase::setFrameBorder(const String &value) +{ + setAttribute(frameborderAttr, value); +} + +String HTMLFrameElementBase::longDesc() const +{ + return getAttribute(longdescAttr); +} + +void HTMLFrameElementBase::setLongDesc(const String &value) +{ + setAttribute(longdescAttr, value); +} + +String HTMLFrameElementBase::marginHeight() const +{ + return getAttribute(marginheightAttr); +} + +void HTMLFrameElementBase::setMarginHeight(const String &value) +{ + setAttribute(marginheightAttr, value); +} + +String HTMLFrameElementBase::marginWidth() const +{ + return getAttribute(marginwidthAttr); +} + +void HTMLFrameElementBase::setMarginWidth(const String &value) +{ + setAttribute(marginwidthAttr, value); +} + +String HTMLFrameElementBase::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLFrameElementBase::setName(const String &value) +{ + setAttribute(nameAttr, value); +} + +void HTMLFrameElementBase::setNoResize(bool noResize) +{ + setAttribute(noresizeAttr, noResize ? "" : 0); +} + +String HTMLFrameElementBase::scrolling() const +{ + return getAttribute(scrollingAttr); +} + +void HTMLFrameElementBase::setScrolling(const String &value) +{ + setAttribute(scrollingAttr, value); +} + +KURL HTMLFrameElementBase::src() const +{ + return document()->completeURL(getAttribute(srcAttr)); +} + +void HTMLFrameElementBase::setSrc(const String &value) +{ + setAttribute(srcAttr, value); +} + +int HTMLFrameElementBase::width() const +{ + if (!renderer()) + return 0; + + document()->updateLayoutIgnorePendingStylesheets(); + return renderer()->width(); +} + +int HTMLFrameElementBase::height() const +{ + if (!renderer()) + return 0; + + document()->updateLayoutIgnorePendingStylesheets(); + return renderer()->height(); +} + +} // namespace WebCore diff --git a/WebCore/html/HTMLFrameElementBase.h b/WebCore/html/HTMLFrameElementBase.h new file mode 100644 index 0000000..4a24451 --- /dev/null +++ b/WebCore/html/HTMLFrameElementBase.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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 HTMLFrameElementBase_h +#define HTMLFrameElementBase_h + +#include "HTMLFrameOwnerElement.h" +#include "ScrollTypes.h" + +namespace WebCore { + +class HTMLFrameElementBase : public HTMLFrameOwnerElement { +public: + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + virtual void attach(); + virtual bool canLazyAttach() { return false; } + + KURL location() const; + void setLocation(const String&); + + virtual bool isFocusable() const; + virtual void setFocus(bool); + + virtual bool isURLAttribute(Attribute*) const; + + virtual ScrollbarMode scrollingMode() const { return m_scrolling; } + + int getMarginWidth() const { return m_marginWidth; } + int getMarginHeight() const { return m_marginHeight; } + + String frameBorder() const; + void setFrameBorder(const String&); + + String longDesc() const; + void setLongDesc(const String&); + + String marginHeight() const; + void setMarginHeight(const String&); + + String marginWidth() const; + void setMarginWidth(const String&); + + String name() const; + void setName(const String&); + + bool noResize() const { return m_noResize; } + void setNoResize(bool); + + String scrolling() const; + void setScrolling(const String&); + + KURL src() const; + void setSrc(const String&); + + int width() const; + int height() const; + + bool viewSourceMode() const { return m_viewSource; } + +protected: + HTMLFrameElementBase(const QualifiedName&, Document*); + + bool isURLAllowed(const AtomicString&) const; + void setNameAndOpenURL(); + void openURL(); + + static void setNameAndOpenURLCallback(Node*); + + AtomicString m_URL; + AtomicString m_frameName; + + ScrollbarMode m_scrolling; + + int m_marginWidth; + int m_marginHeight; + + bool m_noResize; + bool m_viewSource; + + bool m_shouldOpenURLAfterAttach; +}; + +} // namespace WebCore + +#endif // HTMLFrameElementBase_h diff --git a/WebCore/html/HTMLFrameOwnerElement.cpp b/WebCore/html/HTMLFrameOwnerElement.cpp new file mode 100644 index 0000000..f1681e6 --- /dev/null +++ b/WebCore/html/HTMLFrameOwnerElement.cpp @@ -0,0 +1,80 @@ +/* + * 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. + * + */ + +#include "config.h" +#include "HTMLFrameOwnerElement.h" + +#include "DOMWindow.h" +#include "Frame.h" +#include "FrameLoader.h" + +#if ENABLE(SVG) +#include "ExceptionCode.h" +#include "SVGDocument.h" +#endif + +namespace WebCore { + +HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document* document) + : HTMLElement(tagName, document) + , m_contentFrame(0) + , m_createdByParser(false) +{ +} + +void HTMLFrameOwnerElement::willRemove() +{ + if (Frame* frame = contentFrame()) { + frame->disconnectOwnerElement(); + frame->loader()->frameDetached(); + } + + HTMLElement::willRemove(); +} + +HTMLFrameOwnerElement::~HTMLFrameOwnerElement() +{ + if (m_contentFrame) + m_contentFrame->disconnectOwnerElement(); +} + +Document* HTMLFrameOwnerElement::contentDocument() const +{ + return m_contentFrame ? m_contentFrame->document() : 0; +} + +DOMWindow* HTMLFrameOwnerElement::contentWindow() const +{ + return m_contentFrame ? m_contentFrame->domWindow() : 0; +} + +#if ENABLE(SVG) +SVGDocument* HTMLFrameOwnerElement::getSVGDocument(ExceptionCode& ec) const +{ + Document* doc = contentDocument(); + if (doc && doc->isSVGDocument()) + return static_cast<SVGDocument*>(doc); + // Spec: http://www.w3.org/TR/SVG/struct.html#InterfaceGetSVGDocument + ec = NOT_SUPPORTED_ERR; + return 0; +} +#endif + +} // namespace WebCore diff --git a/WebCore/html/HTMLFrameOwnerElement.h b/WebCore/html/HTMLFrameOwnerElement.h new file mode 100644 index 0000000..bc87d73 --- /dev/null +++ b/WebCore/html/HTMLFrameOwnerElement.h @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#ifndef HTMLFrameOwnerElement_h +#define HTMLFrameOwnerElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class DOMWindow; +class Frame; +class KeyboardEvent; + +#if ENABLE(SVG) +class SVGDocument; +#endif + +class HTMLFrameOwnerElement : public HTMLElement { +protected: + HTMLFrameOwnerElement(const QualifiedName& tagName, Document*); + +public: + virtual ~HTMLFrameOwnerElement(); + + virtual void willRemove(); + + Frame* contentFrame() const { return m_contentFrame; } + DOMWindow* contentWindow() const; + Document* contentDocument() const; + + virtual bool isFrameOwnerElement() const { return true; } + virtual bool isKeyboardFocusable(KeyboardEvent*) const { return m_contentFrame; } + + bool createdByParser() const { return m_createdByParser; } + void setCreatedByParser(bool createdByParser) { m_createdByParser = createdByParser; } + + virtual ScrollbarMode scrollingMode() const { return ScrollbarAuto; } + +#if ENABLE(SVG) + SVGDocument* getSVGDocument(ExceptionCode&) const; +#endif + +private: + friend class Frame; + Frame* m_contentFrame; + bool m_createdByParser; +}; + +} // namespace WebCore + +#endif // HTMLFrameOwnerElement_h diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp new file mode 100644 index 0000000..75fd516 --- /dev/null +++ b/WebCore/html/HTMLFrameSetElement.cpp @@ -0,0 +1,220 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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 "HTMLFrameSetElement.h" + +#include "CSSPropertyNames.h" +#include "Document.h" +#include "Event.h" +#include "EventNames.h" +#include "HTMLNames.h" +#include "Length.h" +#include "Length.h" +#include "MouseEvent.h" +#include "RenderFrameSet.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLFrameSetElement::HTMLFrameSetElement(Document *doc) + : HTMLElement(framesetTag, doc) + , m_rows(0) + , m_cols(0) + , m_totalRows(1) + , m_totalCols(1) + , m_border(6) + , m_borderSet(false) + , m_borderColorSet(false) + , frameborder(true) + , frameBorderSet(false) + , noresize(false) +{ +} + +HTMLFrameSetElement::~HTMLFrameSetElement() +{ + if (m_rows) + delete [] m_rows; + if (m_cols) + delete [] m_cols; +} + +bool HTMLFrameSetElement::checkDTD(const Node* newChild) +{ + // FIXME: Old code had adjacent double returns and seemed to want to do something with NOFRAMES (but didn't). + // What is the correct behavior? + if (newChild->isTextNode()) + return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); + return newChild->hasTagName(framesetTag) || newChild->hasTagName(frameTag); +} + +bool HTMLFrameSetElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == bordercolorAttr) { + result = eUniversal; + return true; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLFrameSetElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == rowsAttr) { + if (!attr->isNull()) { + if (m_rows) delete [] m_rows; + m_rows = newLengthArray(attr->value().string(), m_totalRows); + setChanged(); + } + } else if (attr->name() == colsAttr) { + if (!attr->isNull()) { + delete [] m_cols; + m_cols = newLengthArray(attr->value().string(), m_totalCols); + setChanged(); + } + } else if (attr->name() == frameborderAttr) { + if (!attr->isNull()) { + // false or "no" or "0".. + if (attr->value().toInt() == 0) { + frameborder = false; + m_border = 0; + } + frameBorderSet = true; + } else { + frameborder = false; + frameBorderSet = false; + } + } else if (attr->name() == noresizeAttr) { + noresize = true; + } else if (attr->name() == borderAttr) { + if (!attr->isNull()) { + m_border = attr->value().toInt(); + if (!m_border) + frameborder = false; + m_borderSet = true; + } else + m_borderSet = false; + } else if (attr->name() == bordercolorAttr) { + m_borderColorSet = attr->decl(); + if (!attr->decl() && !attr->isEmpty()) { + addCSSColor(attr, CSSPropertyBorderColor, attr->value()); + m_borderColorSet = true; + } + } else if (attr->name() == onloadAttr) { + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + } else if (attr->name() == onbeforeunloadAttr) { + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + } else if (attr->name() == onunloadAttr) { + document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().unloadEvent, attr); + } else + HTMLElement::parseMappedAttribute(attr); +} + +bool HTMLFrameSetElement::rendererIsNeeded(RenderStyle *style) +{ + // For compatibility, frames render even when display: none is set. + // However, we delay creating a renderer until stylesheets have loaded. + return style->isStyleAvailable(); +} + +RenderObject *HTMLFrameSetElement::createRenderer(RenderArena *arena, RenderStyle *style) +{ + if (style->contentData()) + return RenderObject::createObject(this, style); + + return new (arena) RenderFrameSet(this); +} + +void HTMLFrameSetElement::attach() +{ + // Inherit default settings from parent frameset + // FIXME: This is not dynamic. + for (Node* node = parentNode(); node; node = node->parentNode()) { + if (node->hasTagName(framesetTag)) { + HTMLFrameSetElement* frameset = static_cast<HTMLFrameSetElement*>(node); + if (!frameBorderSet) + frameborder = frameset->hasFrameBorder(); + if (frameborder) { + if (!m_borderSet) + m_border = frameset->border(); + if (!m_borderColorSet) + m_borderColorSet = frameset->hasBorderColor(); + } + if (!noresize) + noresize = frameset->noResize(); + break; + } + } + + HTMLElement::attach(); +} + +void HTMLFrameSetElement::defaultEventHandler(Event* evt) +{ + if (evt->isMouseEvent() && !noresize && renderer()) { + if (static_cast<RenderFrameSet*>(renderer())->userResize(static_cast<MouseEvent*>(evt))) { + evt->setDefaultHandled(); + return; + } + } + HTMLElement::defaultEventHandler(evt); +} + +void HTMLFrameSetElement::recalcStyle(StyleChange ch) +{ + if (changed() && renderer()) { + renderer()->setNeedsLayout(true); +#ifdef FLATTEN_FRAMESET + static_cast<RenderFrameSet*>(renderer())->setGridNeedsLayout(); +#endif + setChanged(NoStyleChange); + } + HTMLElement::recalcStyle(ch); +} + +String HTMLFrameSetElement::cols() const +{ + return getAttribute(colsAttr); +} + +void HTMLFrameSetElement::setCols(const String &value) +{ + setAttribute(colsAttr, value); +} + +String HTMLFrameSetElement::rows() const +{ + return getAttribute(rowsAttr); +} + +void HTMLFrameSetElement::setRows(const String &value) +{ + setAttribute(rowsAttr, value); +} + +} diff --git a/WebCore/html/HTMLFrameSetElement.h b/WebCore/html/HTMLFrameSetElement.h new file mode 100644 index 0000000..ed8acff --- /dev/null +++ b/WebCore/html/HTMLFrameSetElement.h @@ -0,0 +1,91 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ + +#ifndef HTMLFrameSetElement_h +#define HTMLFrameSetElement_h + +#include "HTMLElement.h" +#include "Color.h" + +namespace WebCore { + +class HTMLFrameSetElement : public HTMLElement { +public: + HTMLFrameSetElement(Document*); + ~HTMLFrameSetElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 10; } + virtual bool checkDTD(const Node* newChild); + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void attach(); + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject *createRenderer(RenderArena*, RenderStyle*); + + virtual void defaultEventHandler(Event*); + + bool hasFrameBorder() const { return frameborder; } + bool noResize() const { return noresize; } + + int totalRows() const { return m_totalRows; } + int totalCols() const { return m_totalCols; } + int border() const { return m_border; } + + bool hasBorderColor() const { return m_borderColorSet; } + + virtual void recalcStyle( StyleChange ch ); + + String cols() const; + void setCols(const String&); + + String rows() const; + void setRows(const String&); + + const Length* rowLengths() const { return m_rows; } + const Length* colLengths() const { return m_cols; } + +private: + Length* m_rows; + Length* m_cols; + + int m_totalRows; + int m_totalCols; + + int m_border; + bool m_borderSet; + + bool m_borderColorSet; + + bool frameborder; + bool frameBorderSet; + bool noresize; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLFrameSetElement.idl b/WebCore/html/HTMLFrameSetElement.idl new file mode 100644 index 0000000..060616e --- /dev/null +++ b/WebCore/html/HTMLFrameSetElement.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserve + * 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 html { + + interface [ + GenerateConstructor, + HasOverridingNameGetter, + InterfaceUUID=5038a73d-c0db-4847-acb4-4c6d31f48790, + ImplementationUUID=450f7bf6-fdc0-4a0f-b7e1-baea7f7e5732 + ] HTMLFrameSetElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString cols; + attribute [ConvertNullToNullString] DOMString rows; + + }; + +} diff --git a/WebCore/html/HTMLHRElement.cpp b/WebCore/html/HTMLHRElement.cpp new file mode 100644 index 0000000..743b0d2 --- /dev/null +++ b/WebCore/html/HTMLHRElement.cpp @@ -0,0 +1,142 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLHRElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLHRElement::HTMLHRElement(Document *doc) + : HTMLElement(hrTag, doc) +{ +} + +HTMLHRElement::~HTMLHRElement() +{ +} + +bool HTMLHRElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == alignAttr || + attrName == widthAttr || + attrName == colorAttr || + attrName == sizeAttr || + attrName == noshadeAttr) { + result = eHR; + return false; + } + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLHRElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == alignAttr) { + if (equalIgnoringCase(attr->value(), "left")) { + addCSSProperty(attr, CSSPropertyMarginLeft, "0"); + addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto); + } else if (equalIgnoringCase(attr->value(), "right")) { + addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto); + addCSSProperty(attr, CSSPropertyMarginRight, "0"); + } else { + addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto); + addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto); + } + } else if (attr->name() == widthAttr) { + bool ok; + int v = attr->value().toInt(&ok); + if(ok && !v) + addCSSLength(attr, CSSPropertyWidth, "1"); + else + addCSSLength(attr, CSSPropertyWidth, attr->value()); + } else if (attr->name() == colorAttr) { + addCSSProperty(attr, CSSPropertyBorderTopStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderRightStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderBottomStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderLeftStyle, CSSValueSolid); + addCSSColor(attr, CSSPropertyBorderColor, attr->value()); + addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); + } else if (attr->name() == noshadeAttr) { + addCSSProperty(attr, CSSPropertyBorderTopStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderRightStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderBottomStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderLeftStyle, CSSValueSolid); + addCSSColor(attr, CSSPropertyBorderColor, String("grey")); + addCSSColor(attr, CSSPropertyBackgroundColor, String("grey")); + } else if (attr->name() == sizeAttr) { + StringImpl* si = attr->value().impl(); + int size = si->toInt(); + if (size <= 1) + addCSSProperty(attr, CSSPropertyBorderBottomWidth, String("0")); + else + addCSSLength(attr, CSSPropertyHeight, String::number(size-2)); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLHRElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLHRElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +bool HTMLHRElement::noShade() const +{ + return !getAttribute(noshadeAttr).isNull(); +} + +void HTMLHRElement::setNoShade(bool noShade) +{ + setAttribute(noshadeAttr, noShade ? "" : 0); +} + +String HTMLHRElement::size() const +{ + return getAttribute(sizeAttr); +} + +void HTMLHRElement::setSize(const String &value) +{ + setAttribute(sizeAttr, value); +} + +String HTMLHRElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLHRElement::setWidth(const String &value) +{ + setAttribute(widthAttr, value); +} + +} diff --git a/WebCore/html/HTMLHRElement.h b/WebCore/html/HTMLHRElement.h new file mode 100644 index 0000000..af0783b --- /dev/null +++ b/WebCore/html/HTMLHRElement.h @@ -0,0 +1,57 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLHRElement_h +#define HTMLHRElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLHRElement : public HTMLElement { +public: + HTMLHRElement(Document*); + ~HTMLHRElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + String align() const; + void setAlign(const String&); + + bool noShade() const; + void setNoShade(bool); + + String size() const; + void setSize(const String&); + + String width() const; + void setWidth(const String&); +}; + +} // namespace WebCore + +#endif // HTMLHRElement_h diff --git a/WebCore/html/HTMLHRElement.idl b/WebCore/html/HTMLHRElement.idl new file mode 100644 index 0000000..e49932a --- /dev/null +++ b/WebCore/html/HTMLHRElement.idl @@ -0,0 +1,33 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=20477b34-ab22-47e3-b9aa-80c388d32975, + ImplementationUUID=6cfc8977-172d-48f6-8f08-c7671f02354c + ] HTMLHRElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; + attribute boolean noShade; + attribute [ConvertNullToNullString] DOMString size; + attribute [ConvertNullToNullString] DOMString width; + }; + +} diff --git a/WebCore/html/HTMLHeadElement.cpp b/WebCore/html/HTMLHeadElement.cpp new file mode 100644 index 0000000..349f4ed --- /dev/null +++ b/WebCore/html/HTMLHeadElement.cpp @@ -0,0 +1,71 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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 "HTMLHeadElement.h" + +#include "HTMLNames.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLHeadElement::HTMLHeadElement(Document* doc) + : HTMLElement(headTag, doc) +{ +} + +HTMLHeadElement::~HTMLHeadElement() +{ +} + +String HTMLHeadElement::profile() const +{ + return getAttribute(profileAttr); +} + +void HTMLHeadElement::setProfile(const String &value) +{ + setAttribute(profileAttr, value); +} + +bool HTMLHeadElement::childAllowed(Node* newChild) +{ + // Do not allow non-whitespace text nodes in the head + if (newChild->isTextNode()) + return static_cast<Text*>(newChild)->containsOnlyWhitespace(); + + return HTMLElement::childAllowed(newChild); +} + +bool HTMLHeadElement::checkDTD(const Node* newChild) +{ + return newChild->hasTagName(noscriptTag) || newChild->hasTagName(titleTag) || newChild->hasTagName(isindexTag) || + newChild->hasTagName(baseTag) || newChild->hasTagName(scriptTag) || + newChild->hasTagName(styleTag) || newChild->hasTagName(metaTag) || + newChild->hasTagName(linkTag) || newChild->isTextNode(); +} + +} diff --git a/WebCore/html/HTMLHeadElement.h b/WebCore/html/HTMLHeadElement.h new file mode 100644 index 0000000..3909fa9 --- /dev/null +++ b/WebCore/html/HTMLHeadElement.h @@ -0,0 +1,50 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ + +#ifndef HTMLHeadElement_h +#define HTMLHeadElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLHeadElement : public HTMLElement +{ +public: + HTMLHeadElement(Document*); + ~HTMLHeadElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 10; } + virtual bool childAllowed(Node* newChild); + virtual bool checkDTD(const Node* newChild); + + String profile() const; + void setProfile(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLHeadElement.idl b/WebCore/html/HTMLHeadElement.idl new file mode 100644 index 0000000..82ff796 --- /dev/null +++ b/WebCore/html/HTMLHeadElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=47e0c1a2-39ca-4be8-a4ef-38af06462d2e, + ImplementationUUID=f56408fe-6987-4ece-b925-599f517bde50 + ] HTMLHeadElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString profile; + }; + +} diff --git a/WebCore/html/HTMLHeadingElement.cpp b/WebCore/html/HTMLHeadingElement.cpp new file mode 100644 index 0000000..452f7c3 --- /dev/null +++ b/WebCore/html/HTMLHeadingElement.cpp @@ -0,0 +1,58 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLHeadingElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLHeadingElement::HTMLHeadingElement(const QualifiedName& tagName, Document *doc) + : HTMLElement(tagName, doc) +{ +} + +bool HTMLHeadingElement::checkDTD(const Node* newChild) +{ + if (newChild->hasTagName(h1Tag) || newChild->hasTagName(h2Tag) || + newChild->hasTagName(h3Tag) || newChild->hasTagName(h4Tag) || + newChild->hasTagName(h5Tag) || newChild->hasTagName(h6Tag)) + return false; + + return inEitherTagList(newChild); +} + +String HTMLHeadingElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLHeadingElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +} diff --git a/WebCore/html/HTMLHeadingElement.h b/WebCore/html/HTMLHeadingElement.h new file mode 100644 index 0000000..dac1107 --- /dev/null +++ b/WebCore/html/HTMLHeadingElement.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLHeadingElement_h +#define HTMLHeadingElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLHeadingElement : public HTMLElement { +public: + HTMLHeadingElement(const QualifiedName&, Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + virtual bool checkDTD(const Node* newChild); + + String align() const; + void setAlign(const String&); +}; + +} // namespace WebCore + +#endif // HTMLHeadingElement_h diff --git a/WebCore/html/HTMLHeadingElement.idl b/WebCore/html/HTMLHeadingElement.idl new file mode 100644 index 0000000..7173252 --- /dev/null +++ b/WebCore/html/HTMLHeadingElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=91c029bb-aa3a-4877-8ab5-59f304525fd5, + ImplementationUUID=ab39e189-5d0c-465d-b518-f57bc920038b + ] HTMLHeadingElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; + }; + +} diff --git a/WebCore/html/HTMLHtmlElement.cpp b/WebCore/html/HTMLHtmlElement.cpp new file mode 100644 index 0000000..dd8a609 --- /dev/null +++ b/WebCore/html/HTMLHtmlElement.cpp @@ -0,0 +1,83 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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 "HTMLHtmlElement.h" + +#include "ApplicationCacheGroup.h" +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLHtmlElement::HTMLHtmlElement(Document* doc) + : HTMLElement(htmlTag, doc) +{ +} + +HTMLHtmlElement::~HTMLHtmlElement() +{ +} + +String HTMLHtmlElement::version() const +{ + return getAttribute(versionAttr); +} + +void HTMLHtmlElement::setVersion(const String &value) +{ + setAttribute(versionAttr, value); +} + +bool HTMLHtmlElement::checkDTD(const Node* newChild) +{ + // FIXME: Why is <script> allowed here? + return newChild->hasTagName(headTag) || newChild->hasTagName(bodyTag) || + newChild->hasTagName(framesetTag) || newChild->hasTagName(noframesTag) || + newChild->hasTagName(scriptTag); +} + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +void HTMLHtmlElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + + if (!document()->parsing()) + return; + + if (!document()->frame()) + return; + + // Check the manifest attribute + AtomicString manifest = getAttribute(manifestAttr); + if (manifest.isNull()) + ApplicationCacheGroup::selectCacheWithoutManifestURL(document()->frame()); + else + ApplicationCacheGroup::selectCache(document()->frame(), document()->completeURL(manifest)); +} +#endif + +} diff --git a/WebCore/html/HTMLHtmlElement.h b/WebCore/html/HTMLHtmlElement.h new file mode 100644 index 0000000..2154d95 --- /dev/null +++ b/WebCore/html/HTMLHtmlElement.h @@ -0,0 +1,53 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ + +#ifndef HTMLHtmlElement_h +#define HTMLHtmlElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLHtmlElement : public HTMLElement +{ +public: + HTMLHtmlElement(Document*); + ~HTMLHtmlElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 11; } + virtual bool checkDTD(const Node* newChild); + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + virtual void insertedIntoDocument(); +#endif + + String version() const; + void setVersion(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLHtmlElement.idl b/WebCore/html/HTMLHtmlElement.idl new file mode 100644 index 0000000..e9709bf --- /dev/null +++ b/WebCore/html/HTMLHtmlElement.idl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=162828a5-d4d9-4973-b5ca-00ccbb26ded9, + ImplementationUUID=362f4f5f-99c5-4bbf-91ba-9ae7f9a7b297 + ] HTMLHtmlElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString version; + + }; + +} diff --git a/WebCore/html/HTMLIFrameElement.cpp b/WebCore/html/HTMLIFrameElement.cpp new file mode 100644 index 0000000..4a071bf --- /dev/null +++ b/WebCore/html/HTMLIFrameElement.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann (hausmann@kde.org) + * (C) 2001 Dirk Mueller (mueller@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. + */ + +#include "config.h" +#include "HTMLIFrameElement.h" + +#include "CSSPropertyNames.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLNames.h" +#include "RenderPartObject.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLIFrameElement::HTMLIFrameElement(Document* doc) + : HTMLFrameElementBase(iframeTag, doc) +{ +} + +bool HTMLIFrameElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr || attrName == heightAttr) { + result = eUniversal; + return false; + } + + if (attrName == alignAttr) { + result = eReplaced; // Share with <img> since the alignment behavior is the same. + return false; + } + + if (attrName == frameborderAttr) { + result = eReplaced; + return false; + } + + return HTMLFrameElementBase::mapToEntry(attrName, result); +} + +void HTMLIFrameElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == widthAttr) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + else if (attr->name() == heightAttr) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + else if (attr->name() == alignAttr) + addHTMLAlignment(attr); + else if (attr->name() == nameAttr) { + const AtomicString& newName = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeExtraNamedItem(m_name); + document->addExtraNamedItem(newName); + } + m_name = newName; + } else if (attr->name() == frameborderAttr) { + // Frame border doesn't really match the HTML4 spec definition for iframes. It simply adds + // a presentational hint that the border should be off if set to zero. + if (!attr->isNull() && !attr->value().toInt()) + // Add a rule that nulls out our border width. + addCSSLength(attr, CSSPropertyBorderWidth, "0"); + } else + HTMLFrameElementBase::parseMappedAttribute(attr); +} + +bool HTMLIFrameElement::rendererIsNeeded(RenderStyle* style) +{ + return isURLAllowed(m_URL) && style->display() != NONE; +} + +RenderObject* HTMLIFrameElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + return new (arena) RenderPartObject(this); +} + +void HTMLIFrameElement::insertedIntoDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->addExtraNamedItem(m_name); + + HTMLFrameElementBase::insertedIntoDocument(); +} + +void HTMLIFrameElement::removedFromDocument() +{ + if (document()->isHTMLDocument()) + static_cast<HTMLDocument*>(document())->removeExtraNamedItem(m_name); + + HTMLFrameElementBase::removedFromDocument(); +} + +void HTMLIFrameElement::attach() +{ + HTMLFrameElementBase::attach(); + + if (RenderPartObject* renderPartObject = static_cast<RenderPartObject*>(renderer())) + renderPartObject->updateWidget(false); +} + +bool HTMLIFrameElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == srcAttr; +} + +String HTMLIFrameElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLIFrameElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLIFrameElement::height() const +{ + return getAttribute(heightAttr); +} + +void HTMLIFrameElement::setHeight(const String &value) +{ + setAttribute(heightAttr, value); +} + +String HTMLIFrameElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLIFrameElement::setWidth(const String &value) +{ + setAttribute(widthAttr, value); +} + +} diff --git a/WebCore/html/HTMLIFrameElement.h b/WebCore/html/HTMLIFrameElement.h new file mode 100644 index 0000000..adead51 --- /dev/null +++ b/WebCore/html/HTMLIFrameElement.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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 HTMLIFrameElement_h +#define HTMLIFrameElement_h + +#include "HTMLFrameElementBase.h" + +namespace WebCore { + +class HTMLIFrameElement : public HTMLFrameElementBase { +public: + HTMLIFrameElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + virtual void attach(); + + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + virtual bool isURLAttribute(Attribute*) const; + + String align() const; + void setAlign(const String&); + + String height() const; + void setHeight(const String&); + + String width() const; + void setWidth(const String&); + +private: + AtomicString m_name; +}; + +} // namespace WebCore + +#endif // HTMLIFrameElement_h diff --git a/WebCore/html/HTMLIFrameElement.idl b/WebCore/html/HTMLIFrameElement.idl new file mode 100644 index 0000000..c6a8599 --- /dev/null +++ b/WebCore/html/HTMLIFrameElement.idl @@ -0,0 +1,55 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=32265f2e-79b1-4e4e-b0d1-86b050298883, + ImplementationUUID=370c6318-f804-49f9-bc8a-46b99cd87399 + ] HTMLIFrameElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString frameBorder; + attribute [ConvertNullToNullString] DOMString height; + attribute [ConvertNullToNullString] DOMString longDesc; + attribute [ConvertNullToNullString] DOMString marginHeight; + attribute [ConvertNullToNullString] DOMString marginWidth; + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString scrolling; + attribute [ConvertNullToNullString, CustomSetter] DOMString src; + attribute [ConvertNullToNullString] DOMString width; + + // Introduced in DOM Level 2: + readonly attribute [CheckFrameSecurity] Document contentDocument; + +#if !defined(LANGUAGE_COM) + // Extensions + readonly attribute DOMWindow contentWindow; + +#if ENABLE_SVG + [SVGCheckSecurityDocument] SVGDocument getSVGDocument() + raises(DOMException); +#endif +#endif + + }; + +} diff --git a/WebCore/html/HTMLImageElement.cpp b/WebCore/html/HTMLImageElement.cpp new file mode 100644 index 0000000..ea05689 --- /dev/null +++ b/WebCore/html/HTMLImageElement.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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 "HTMLImageElement.h" + +#include "CSSHelper.h" +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "EventNames.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" +#include "RenderImage.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLImageElement::HTMLImageElement(Document* doc, HTMLFormElement* f) + : HTMLElement(imgTag, doc) + , m_imageLoader(this) + , ismap(false) + , m_form(f) + , m_compositeOperator(CompositeSourceOver) +{ + if (f) + f->registerImgElement(this); +} + +HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) + , m_imageLoader(this) + , ismap(false) + , m_form(0) + , m_compositeOperator(CompositeSourceOver) +{ +} + +HTMLImageElement::~HTMLImageElement() +{ + if (m_form) + m_form->removeImgElement(this); +} + +bool HTMLImageElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr || + attrName == heightAttr || + attrName == vspaceAttr || + attrName == hspaceAttr || + attrName == valignAttr) { + result = eUniversal; + return false; + } + + if (attrName == borderAttr || attrName == alignAttr) { + result = eReplaced; // Shared with embed and iframe elements. + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLImageElement::parseMappedAttribute(MappedAttribute* attr) +{ + const QualifiedName& attrName = attr->name(); + if (attrName == altAttr) { + if (renderer() && renderer()->isImage()) + static_cast<RenderImage*>(renderer())->updateAltText(); + } else if (attrName == srcAttr) + m_imageLoader.updateFromElement(); + else if (attrName == widthAttr) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + else if (attrName == heightAttr) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + else if (attrName == borderAttr) { + // border="noborder" -> border="0" + addCSSLength(attr, CSSPropertyBorderWidth, attr->value().toInt() ? attr->value() : "0"); + addCSSProperty(attr, CSSPropertyBorderTopStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderRightStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderBottomStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderLeftStyle, CSSValueSolid); + } else if (attrName == vspaceAttr) { + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + } else if (attrName == hspaceAttr) { + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + } else if (attrName == alignAttr) + addHTMLAlignment(attr); + else if (attrName == valignAttr) + addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value()); + else if (attrName == usemapAttr) { + if (attr->value().string()[0] == '#') + usemap = attr->value(); + else + usemap = document()->completeURL(parseURL(attr->value())).string(); + setIsLink(!attr->isNull()); + } else if (attrName == ismapAttr) + ismap = true; + else if (attrName == onabortAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().abortEvent, attr); + else if (attrName == onloadAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + else if (attrName == compositeAttr) { + if (!parseCompositeOperator(attr->value(), m_compositeOperator)) + m_compositeOperator = CompositeSourceOver; + } else if (attrName == nameAttr) { + const AtomicString& newName = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(newName); + } + m_name = newName; + } else if (attr->name() == idAttr) { + const AtomicString& newId = attr->value(); + if (inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeExtraNamedItem(m_id); + document->addExtraNamedItem(newId); + } + m_id = newId; + // also call superclass + HTMLElement::parseMappedAttribute(attr); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLImageElement::altText() const +{ + // lets figure out the alt text.. magic stuff + // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen + // also heavily discussed by Hixie on bugzilla + String alt = getAttribute(altAttr); + // fall back to title attribute + if (alt.isNull()) + alt = getAttribute(titleAttr); + return alt; +} + +RenderObject* HTMLImageElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (style->contentData()) + return RenderObject::createObject(this, style); + + return new (arena) RenderImage(this); +} + +void HTMLImageElement::attach() +{ + HTMLElement::attach(); + + if (renderer() && renderer()->isImage()) { + RenderImage* imageObj = static_cast<RenderImage*>(renderer()); + if (imageObj->hasImage()) + return; + imageObj->setCachedImage(m_imageLoader.image()); + + // If we have no image at all because we have no src attribute, set + // image height and width for the alt text instead. + if (!m_imageLoader.image() && !imageObj->cachedImage()) + imageObj->setImageSizeForAltText(); + } +} + +void HTMLImageElement::insertedIntoDocument() +{ + if (document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } + + HTMLElement::insertedIntoDocument(); +} + +void HTMLImageElement::removedFromDocument() +{ + if (document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + + HTMLElement::removedFromDocument(); +} + +int HTMLImageElement::width(bool ignorePendingStylesheets) const +{ + if (!renderer()) { + // check the attribute first for an explicit pixel value + bool ok; + int width = getAttribute(widthAttr).toInt(&ok); + if (ok) + return width; + + // if the image is available, use its width + if (m_imageLoader.image()) { + float zoomFactor = document()->frame() ? document()->frame()->pageZoomFactor() : 1.0f; + return m_imageLoader.image()->imageSize(zoomFactor).width(); + } + } + + if (ignorePendingStylesheets) + document()->updateLayoutIgnorePendingStylesheets(); + else + document()->updateLayout(); + + return renderer() ? renderer()->contentWidth() : 0; +} + +int HTMLImageElement::height(bool ignorePendingStylesheets) const +{ + if (!renderer()) { + // check the attribute first for an explicit pixel value + bool ok; + int height = getAttribute(heightAttr).toInt(&ok); + if (ok) + return height; + + // if the image is available, use its height + if (m_imageLoader.image()) { + float zoomFactor = document()->frame() ? document()->frame()->pageZoomFactor() : 1.0f; + return m_imageLoader.image()->imageSize(zoomFactor).height(); + } + } + + if (ignorePendingStylesheets) + document()->updateLayoutIgnorePendingStylesheets(); + else + document()->updateLayout(); + + return renderer() ? renderer()->contentHeight() : 0; +} + +int HTMLImageElement::naturalWidth() const +{ + if (!m_imageLoader.image()) + return 0; + + return m_imageLoader.image()->imageSize(1.0f).width(); +} + +int HTMLImageElement::naturalHeight() const +{ + if (!m_imageLoader.image()) + return 0; + + return m_imageLoader.image()->imageSize(1.0f).height(); +} + +bool HTMLImageElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == srcAttr + || attr->name() == lowsrcAttr + || attr->name() == longdescAttr + || (attr->name() == usemapAttr && attr->value().string()[0] != '#'); +} + +String HTMLImageElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLImageElement::setName(const String& value) +{ + setAttribute(nameAttr, value); +} + +String HTMLImageElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLImageElement::setAlign(const String& value) +{ + setAttribute(alignAttr, value); +} + +String HTMLImageElement::alt() const +{ + return getAttribute(altAttr); +} + +void HTMLImageElement::setAlt(const String& value) +{ + setAttribute(altAttr, value); +} + +String HTMLImageElement::border() const +{ + return getAttribute(borderAttr); +} + +void HTMLImageElement::setBorder(const String& value) +{ + setAttribute(borderAttr, value); +} + +void HTMLImageElement::setHeight(int value) +{ + setAttribute(heightAttr, String::number(value)); +} + +int HTMLImageElement::hspace() const +{ + // ### return actual value + return getAttribute(hspaceAttr).toInt(); +} + +void HTMLImageElement::setHspace(int value) +{ + setAttribute(hspaceAttr, String::number(value)); +} + +bool HTMLImageElement::isMap() const +{ + return !getAttribute(ismapAttr).isNull(); +} + +void HTMLImageElement::setIsMap(bool isMap) +{ + setAttribute(ismapAttr, isMap ? "" : 0); +} + +KURL HTMLImageElement::longDesc() const +{ + return document()->completeURL(getAttribute(longdescAttr)); +} + +void HTMLImageElement::setLongDesc(const String& value) +{ + setAttribute(longdescAttr, value); +} + +KURL HTMLImageElement::lowsrc() const +{ + return document()->completeURL(getAttribute(lowsrcAttr)); +} + +void HTMLImageElement::setLowsrc(const String& value) +{ + setAttribute(lowsrcAttr, value); +} + +KURL HTMLImageElement::src() const +{ + return document()->completeURL(getAttribute(srcAttr)); +} + +void HTMLImageElement::setSrc(const String& value) +{ + setAttribute(srcAttr, value); +} + +String HTMLImageElement::useMap() const +{ + return getAttribute(usemapAttr); +} + +void HTMLImageElement::setUseMap(const String& value) +{ + setAttribute(usemapAttr, value); +} + +int HTMLImageElement::vspace() const +{ + // ### return actual vspace + return getAttribute(vspaceAttr).toInt(); +} + +void HTMLImageElement::setVspace(int value) +{ + setAttribute(vspaceAttr, String::number(value)); +} + +void HTMLImageElement::setWidth(int value) +{ + setAttribute(widthAttr, String::number(value)); +} + +int HTMLImageElement::x() const +{ + RenderObject* r = renderer(); + if (!r) + return 0; + int x, y; + r->absolutePosition(x, y); + return x; +} + +int HTMLImageElement::y() const +{ + RenderObject* r = renderer(); + if (!r) + return 0; + int x, y; + r->absolutePosition(x, y); + return y; +} + +bool HTMLImageElement::complete() const +{ + return m_imageLoader.imageComplete(); +} + +void HTMLImageElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(src().string()); + urls.append(useMap()); +} + +} diff --git a/WebCore/html/HTMLImageElement.h b/WebCore/html/HTMLImageElement.h new file mode 100644 index 0000000..a7a6c62 --- /dev/null +++ b/WebCore/html/HTMLImageElement.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 HTMLImageElement_h +#define HTMLImageElement_h + +#include "GraphicsTypes.h" +#include "HTMLElement.h" +#include "HTMLImageLoader.h" + +namespace WebCore { + +class HTMLFormElement; + +class HTMLImageElement : public HTMLElement { + friend class HTMLFormElement; +public: + HTMLImageElement(Document*, HTMLFormElement* = 0); + HTMLImageElement(const QualifiedName&, Document*); + ~HTMLImageElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void attach(); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + virtual bool canStartSelection() const { return false; } + + int width(bool ignorePendingStylesheets = false) const; + int height(bool ignorePendingStylesheets = false) const; + + int naturalWidth() const; + int naturalHeight() const; + + bool isServerMap() const { return ismap && usemap.isEmpty(); } + + String altText() const; + + virtual bool isURLAttribute(Attribute*) const; + + CompositeOperator compositeOperator() const { return m_compositeOperator; } + + CachedImage* cachedImage() const { return m_imageLoader.image(); } + void setCachedImage(CachedImage* i) { m_imageLoader.setImage(i); }; + + void setLoadManually (bool loadManually) { m_imageLoader.setLoadManually(loadManually); } + + String name() const; + void setName(const String&); + + String align() const; + void setAlign(const String&); + + String alt() const; + void setAlt(const String&); + + String border() const; + void setBorder(const String&); + + void setHeight(int); + + int hspace() const; + void setHspace(int); + + bool isMap() const; + void setIsMap(bool); + + KURL longDesc() const; + void setLongDesc(const String&); + + KURL lowsrc() const; + void setLowsrc(const String&); + + KURL src() const; + void setSrc(const String&); + + String useMap() const; + void setUseMap(const String&); + + int vspace() const; + void setVspace(int); + + void setWidth(int); + + int x() const; + int y() const; + + bool complete() const; + + bool haveFiredLoadEvent() const { return m_imageLoader.haveFiredLoadEvent(); } + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +private: + HTMLImageLoader m_imageLoader; + String usemap; + bool ismap; + HTMLFormElement* m_form; + AtomicString m_name; + AtomicString m_id; + CompositeOperator m_compositeOperator; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLImageElement.idl b/WebCore/html/HTMLImageElement.idl new file mode 100644 index 0000000..fe64e6f --- /dev/null +++ b/WebCore/html/HTMLImageElement.idl @@ -0,0 +1,56 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=b21b8125-d00b-4bdf-b0e8-659678db3923, + ImplementationUUID=2121ca21-8118-4f1b-b9fe-4788a9050281 + ] HTMLImageElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString alt; + attribute [ConvertNullToNullString] DOMString border; + attribute long height; + attribute long hspace; + attribute boolean isMap; + attribute [ConvertNullToNullString] DOMString longDesc; + attribute [ConvertNullToNullString] DOMString src; + attribute [ConvertNullToNullString] DOMString useMap; + attribute long vspace; + attribute long width; + + // Extensions + readonly attribute boolean complete; + attribute [ConvertNullToNullString] DOMString lowsrc; + readonly attribute long naturalHeight; + readonly attribute long naturalWidth; + readonly attribute long x; + readonly attribute long y; + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute DOMString altDisplayString; + readonly attribute URL absoluteImageURL; +#endif + }; + +} diff --git a/WebCore/html/HTMLImageLoader.cpp b/WebCore/html/HTMLImageLoader.cpp new file mode 100644 index 0000000..22e3abc --- /dev/null +++ b/WebCore/html/HTMLImageLoader.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 "HTMLImageLoader.h" + +#include "CSSHelper.h" +#include "CachedImage.h" +#include "Element.h" +#include "EventNames.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" + +namespace WebCore { + +HTMLImageLoader::HTMLImageLoader(Element* node) + : ImageLoader(node) +{ +} + +HTMLImageLoader::~HTMLImageLoader() +{ +} + +void HTMLImageLoader::dispatchLoadEvent() +{ + if (!haveFiredLoadEvent() && image()) { + setHaveFiredLoadEvent(true); + element()->dispatchEventForType(image()->errorOccurred() ? eventNames().errorEvent : eventNames().loadEvent, false, false); + } +} + +String HTMLImageLoader::sourceURI(const AtomicString& attr) const +{ + return parseURL(attr); +} + +void HTMLImageLoader::notifyFinished(CachedResource* image) +{ + Element* elem = element(); + ImageLoader::notifyFinished(image); + + if (image->errorOccurred() && elem->hasTagName(HTMLNames::objectTag)) + static_cast<HTMLObjectElement*>(elem)->renderFallbackContent(); +} + +} diff --git a/WebCore/html/HTMLImageLoader.h b/WebCore/html/HTMLImageLoader.h new file mode 100644 index 0000000..9e9564b --- /dev/null +++ b/WebCore/html/HTMLImageLoader.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004 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 HTMLImageLoader_h +#define HTMLImageLoader_h + +#include "ImageLoader.h" + +namespace WebCore { + +class HTMLImageLoader : public ImageLoader { +public: + HTMLImageLoader(Element*); + virtual ~HTMLImageLoader(); + + virtual void dispatchLoadEvent(); + virtual String sourceURI(const AtomicString&) const; + + virtual void notifyFinished(CachedResource*); +}; + +} + +#endif diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp new file mode 100644 index 0000000..c5c55fd --- /dev/null +++ b/WebCore/html/HTMLInputElement.cpp @@ -0,0 +1,1703 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2007 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 "HTMLInputElement.h" + +#include "BeforeTextInsertedEvent.h" +#include "CSSPropertyNames.h" +#include "Document.h" +#include "Editor.h" +#include "Event.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "File.h" +#include "FileList.h" +#include "FocusController.h" +#include "FormDataList.h" +#include "Frame.h" +#include "HTMLFormElement.h" +#include "HTMLImageLoader.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "LocalizedStrings.h" +#include "MouseEvent.h" +#include "Page.h" +#include "RenderButton.h" +#include "RenderFileUploadControl.h" +#include "RenderImage.h" +#include "RenderSlider.h" +#include "RenderText.h" +#include "RenderTextControl.h" +#include "RenderTheme.h" +#include "SelectionController.h" +#include "TextBreakIterator.h" +#include "TextEvent.h" +#if USE(LOW_BANDWIDTH_DISPLAY) +#include "FrameLoader.h" +#endif +#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS +#include "WebViewCore.h" +#endif +#include "TextIterator.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +const int maxSavedResults = 256; + +// FIXME: According to HTML4, the length attribute's value can be arbitrarily +// large. However, due to http://bugs.webkit.org/show_bugs.cgi?id=14536 things +// get rather sluggish when a text field has a larger number of characters than +// this, even when just clicking in the text field. +static const int cMaxLen = 524288; + +static int numGraphemeClusters(StringImpl* s) +{ + if (!s) + return 0; + + TextBreakIterator* it = characterBreakIterator(s->characters(), s->length()); + if (!it) + return 0; + int num = 0; + while (textBreakNext(it) != TextBreakDone) + ++num; + return num; +} + +static int numCharactersInGraphemeClusters(StringImpl* s, int numGraphemeClusters) +{ + if (!s) + return 0; + + TextBreakIterator* it = characterBreakIterator(s->characters(), s->length()); + if (!it) + return 0; + for (int i = 0; i < numGraphemeClusters; ++i) + if (textBreakNext(it) == TextBreakDone) + return s->length(); + return textBreakCurrent(it); +} + +HTMLInputElement::HTMLInputElement(Document* doc, HTMLFormElement* f) + : HTMLFormControlElementWithState(inputTag, doc, f) +{ + init(); +} + +HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) + : HTMLFormControlElementWithState(tagName, doc, f) +{ + init(); +} + +void HTMLInputElement::init() +{ + m_type = TEXT; + m_maxLen = cMaxLen; + m_size = 20; + m_checked = false; + m_defaultChecked = false; + m_useDefaultChecked = true; + m_indeterminate = false; + + m_haveType = false; + m_activeSubmit = false; + m_autocomplete = Uninitialized; + m_inited = false; + m_autofilled = false; + m_placeholderShouldBeVisible = false; + + xPos = 0; + yPos = 0; + + cachedSelStart = -1; + cachedSelEnd = -1; + + m_maxResults = -1; +} + +HTMLInputElement::~HTMLInputElement() +{ + if (needsActivationCallback()) + document()->unregisterForDocumentActivationCallbacks(this); + + document()->checkedRadioButtons().removeButton(this); + + // Need to remove this from the form while it is still an HTMLInputElement, + // so can't wait for the base class's destructor to do it. + removeFromForm(); +} + +const AtomicString& HTMLInputElement::name() const +{ + return m_name.isNull() ? emptyAtom : m_name; +} + +bool HTMLInputElement::autoComplete() const +{ + if (m_autocomplete != Uninitialized) + return m_autocomplete == On; + + // Assuming we're still in a Form, respect the Form's setting + if (HTMLFormElement* form = this->form()) + return form->autoComplete(); + + // The default is true + return true; +} + + +static inline HTMLFormElement::CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element) +{ + if (HTMLFormElement* form = element->form()) + return form->checkedRadioButtons(); + + return element->document()->checkedRadioButtons(); +} + +bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const +{ + // If text fields can be focused, then they should always be keyboard focusable + if (isTextField()) + return HTMLFormControlElementWithState::isFocusable(); + + // If the base class says we can't be focused, then we can stop now. + if (!HTMLFormControlElementWithState::isKeyboardFocusable(event)) + return false; + + if (inputType() == RADIO) { + // Unnamed radio buttons are never focusable (matches WinIE). + if (name().isEmpty()) + return false; + + // Never allow keyboard tabbing to leave you in the same radio group. Always + // skip any other elements in the group. + Node* currentFocusedNode = document()->focusedNode(); + if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) { + HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode); + if (focusedInput->inputType() == RADIO && focusedInput->form() == form() && + focusedInput->name() == name()) + return false; + } + + // Allow keyboard focus if we're checked or if nothing in the group is checked. + return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name()); + } + + return true; +} + +bool HTMLInputElement::isMouseFocusable() const +{ + if (isTextField()) + return HTMLFormControlElementWithState::isFocusable(); + return HTMLFormControlElementWithState::isMouseFocusable(); +} + +void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) +{ + if (isTextField()) { + if (!restorePreviousSelection || cachedSelStart == -1) + select(); + else + // Restore the cached selection. + setSelectionRange(cachedSelStart, cachedSelEnd); + + if (document() && document()->frame()) + document()->frame()->revealSelection(); + } else + HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection); +} + +void HTMLInputElement::aboutToUnload() +{ + if (isTextField() && focused() && document()->frame()) + document()->frame()->textFieldDidEndEditing(this); +} + +bool HTMLInputElement::shouldUseInputMethod() const +{ + return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX; +} + +void HTMLInputElement::dispatchFocusEvent() +{ + if (isTextField()) { + setAutofilled(false); + updatePlaceholderVisibility(); + if (inputType() == PASSWORD && document()->frame()) + document()->setUseSecureKeyboardEntryWhenActive(true); + } + HTMLFormControlElementWithState::dispatchFocusEvent(); +} + +void HTMLInputElement::dispatchBlurEvent() +{ + if (isTextField() && document()->frame()) { + updatePlaceholderVisibility(); + if (inputType() == PASSWORD) + document()->setUseSecureKeyboardEntryWhenActive(false); + document()->frame()->textFieldDidEndEditing(this); + } + HTMLFormControlElementWithState::dispatchBlurEvent(); +} + +void HTMLInputElement::setType(const String& t) +{ + if (t.isEmpty()) { + int exccode; + removeAttribute(typeAttr, exccode); + } else + setAttribute(typeAttr, t); +} + +void HTMLInputElement::setInputType(const String& t) +{ + InputType newType; + + if (equalIgnoringCase(t, "password")) +#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS + { + if (document()->focusedNode() == this) + { + android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String()); + } +#endif + newType = PASSWORD; +#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS + } +#endif + else if (equalIgnoringCase(t, "checkbox")) + newType = CHECKBOX; + else if (equalIgnoringCase(t, "radio")) + newType = RADIO; + else if (equalIgnoringCase(t, "submit")) + newType = SUBMIT; + else if (equalIgnoringCase(t, "reset")) + newType = RESET; + else if (equalIgnoringCase(t, "file")) + newType = FILE; + else if (equalIgnoringCase(t, "hidden")) + newType = HIDDEN; + else if (equalIgnoringCase(t, "image")) + newType = IMAGE; + else if (equalIgnoringCase(t, "button")) + newType = BUTTON; + else if (equalIgnoringCase(t, "khtml_isindex")) + newType = ISINDEX; + else if (equalIgnoringCase(t, "search")) + newType = SEARCH; + else if (equalIgnoringCase(t, "range")) + newType = RANGE; + else + newType = TEXT; + + // IMPORTANT: Don't allow the type to be changed to FILE after the first + // type change, otherwise a JavaScript programmer would be able to set a text + // field's value to something like /etc/passwd and then change it to a file field. + if (inputType() != newType) { + if (newType == FILE && m_haveType) + // Set the attribute back to the old value. + // Useful in case we were called from inside parseMappedAttribute. + setAttribute(typeAttr, type()); + else { + checkedRadioButtons(this).removeButton(this); + + if (newType == FILE && !m_fileList) + m_fileList = FileList::create(); + + bool wasAttached = attached(); + if (wasAttached) + detach(); + + bool didStoreValue = storesValueSeparateFromAttribute(); + bool wasPasswordField = inputType() == PASSWORD; + bool didRespectHeightAndWidth = respectHeightAndWidthAttrs(); + m_type = newType; + bool willStoreValue = storesValueSeparateFromAttribute(); + bool isPasswordField = inputType() == PASSWORD; + bool willRespectHeightAndWidth = respectHeightAndWidthAttrs(); + + if (didStoreValue && !willStoreValue && !m_value.isNull()) { + setAttribute(valueAttr, m_value); + m_value = String(); + } + if (!didStoreValue && willStoreValue) + m_value = constrainValue(getAttribute(valueAttr)); + else + recheckValue(); + + if (wasPasswordField && !isPasswordField) + unregisterForActivationCallbackIfNeeded(); + else if (!wasPasswordField && isPasswordField) + registerForActivationCallbackIfNeeded(); + + if (didRespectHeightAndWidth != willRespectHeightAndWidth) { + NamedMappedAttrMap* map = mappedAttributes(); + if (Attribute* height = map->getAttributeItem(heightAttr)) + attributeChanged(height, false); + if (Attribute* width = map->getAttributeItem(widthAttr)) + attributeChanged(width, false); + if (Attribute* align = map->getAttributeItem(alignAttr)) + attributeChanged(align, false); + } + + if (wasAttached) { + attach(); + if (document()->focusedNode() == this) + updateFocusAppearance(true); + } + + checkedRadioButtons(this).addButton(this); + } + } + m_haveType = true; + + if (inputType() != IMAGE && m_imageLoader) + m_imageLoader.clear(); +} + +const AtomicString& HTMLInputElement::type() const +{ + // needs to be lowercase according to DOM spec + switch (inputType()) { + case BUTTON: { + static const AtomicString button("button"); + return button; + } + case CHECKBOX: { + static const AtomicString checkbox("checkbox"); + return checkbox; + } + case FILE: { + static const AtomicString file("file"); + return file; + } + case HIDDEN: { + static const AtomicString hidden("hidden"); + return hidden; + } + case IMAGE: { + static const AtomicString image("image"); + return image; + } + case ISINDEX: + return emptyAtom; + case PASSWORD: { + static const AtomicString password("password"); + return password; + } + case RADIO: { + static const AtomicString radio("radio"); + return radio; + } + case RANGE: { + static const AtomicString range("range"); + return range; + } + case RESET: { + static const AtomicString reset("reset"); + return reset; + } + case SEARCH: { + static const AtomicString search("search"); + return search; + } + case SUBMIT: { + static const AtomicString submit("submit"); + return submit; + } + case TEXT: { + static const AtomicString text("text"); + return text; + } + } + return emptyAtom; +} + +bool HTMLInputElement::saveState(String& result) const +{ + if (!autoComplete()) + return false; + + switch (inputType()) { + case BUTTON: + case FILE: + case HIDDEN: + case IMAGE: + case ISINDEX: + case RANGE: + case RESET: + case SEARCH: + case SUBMIT: + case TEXT: + result = value(); + return true; + case CHECKBOX: + case RADIO: + result = checked() ? "on" : "off"; + return true; + case PASSWORD: + return false; + } + ASSERT_NOT_REACHED(); + return false; +} + +void HTMLInputElement::restoreState(const String& state) +{ + ASSERT(inputType() != PASSWORD); // should never save/restore password fields + switch (inputType()) { + case BUTTON: + case FILE: + case HIDDEN: + case IMAGE: + case ISINDEX: + case RANGE: + case RESET: + case SEARCH: + case SUBMIT: + case TEXT: + setValue(state); + break; + case CHECKBOX: + case RADIO: + setChecked(state == "on"); + break; + case PASSWORD: + break; + } +} + +bool HTMLInputElement::canStartSelection() const +{ + if (!isTextField()) + return false; + return HTMLFormControlElementWithState::canStartSelection(); +} + +bool HTMLInputElement::canHaveSelection() const +{ + return isTextField(); +} + +int HTMLInputElement::selectionStart() const +{ + if (!isTextField()) + return 0; + if (document()->focusedNode() != this && cachedSelStart != -1) + return cachedSelStart; + if (!renderer()) + return 0; + return static_cast<RenderTextControl*>(renderer())->selectionStart(); +} + +int HTMLInputElement::selectionEnd() const +{ + if (!isTextField()) + return 0; + if (document()->focusedNode() != this && cachedSelEnd != -1) + return cachedSelEnd; + if (!renderer()) + return 0; + return static_cast<RenderTextControl*>(renderer())->selectionEnd(); +} + +void HTMLInputElement::setSelectionStart(int start) +{ + if (!isTextField()) + return; + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionStart(start); +} + +void HTMLInputElement::setSelectionEnd(int end) +{ + if (!isTextField()) + return; + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionEnd(end); +} + +void HTMLInputElement::select() +{ + if (!isTextField()) + return; + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->select(); +} + +void HTMLInputElement::setSelectionRange(int start, int end) +{ + if (!isTextField()) + return; + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionRange(start, end); +} + +void HTMLInputElement::accessKeyAction(bool sendToAnyElement) +{ + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case IMAGE: + case RADIO: + case RANGE: + case RESET: + case SUBMIT: + focus(false); + // send the mouse button events iff the caller specified sendToAnyElement + dispatchSimulatedClick(0, sendToAnyElement); + break; + case HIDDEN: + // a no-op for this type + break; + case ISINDEX: + case PASSWORD: + case SEARCH: + case TEXT: + // should never restore previous selection here + focus(false); + break; + } +} + +bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) || + attrName == vspaceAttr || + attrName == hspaceAttr) { + result = eUniversal; + return false; + } + + if (attrName == alignAttr) { + if (inputType() == IMAGE) { + // Share with <img> since the alignment behavior is the same. + result = eReplaced; + return false; + } + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == nameAttr) { + checkedRadioButtons(this).removeButton(this); + m_name = attr->value(); + checkedRadioButtons(this).addButton(this); + } else if (attr->name() == autocompleteAttr) { + if (equalIgnoringCase(attr->value(), "off")) { + m_autocomplete = Off; + registerForActivationCallbackIfNeeded(); + } else { + if (m_autocomplete == Off) + unregisterForActivationCallbackIfNeeded(); + if (attr->isEmpty()) + m_autocomplete = Uninitialized; + else + m_autocomplete = On; + } + } else if (attr->name() == typeAttr) { + setInputType(attr->value()); + } else if (attr->name() == valueAttr) { + // We only need to setChanged if the form is looking at the default value right now. + if (m_value.isNull()) + setChanged(); + setValueMatchesRenderer(false); + } else if (attr->name() == checkedAttr) { + m_defaultChecked = !attr->isNull(); + if (m_useDefaultChecked) { + setChecked(m_defaultChecked); + m_useDefaultChecked = true; + } + } else if (attr->name() == maxlengthAttr) { + int oldMaxLen = m_maxLen; + m_maxLen = !attr->isNull() ? attr->value().toInt() : cMaxLen; + if (m_maxLen <= 0 || m_maxLen > cMaxLen) + m_maxLen = cMaxLen; + if (oldMaxLen != m_maxLen) + recheckValue(); + setChanged(); + } else if (attr->name() == sizeAttr) { + m_size = !attr->isNull() ? attr->value().toInt() : 20; + } else if (attr->name() == altAttr) { + if (renderer() && inputType() == IMAGE) + static_cast<RenderImage*>(renderer())->updateAltText(); + } else if (attr->name() == srcAttr) { + if (renderer() && inputType() == IMAGE) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + } + } else if (attr->name() == usemapAttr || + attr->name() == accesskeyAttr) { + // FIXME: ignore for the moment + } else if (attr->name() == vspaceAttr) { + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + } else if (attr->name() == hspaceAttr) { + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + } else if (attr->name() == alignAttr) { + if (inputType() == IMAGE) + addHTMLAlignment(attr); + } else if (attr->name() == widthAttr) { + if (respectHeightAndWidthAttrs()) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + } else if (attr->name() == heightAttr) { + if (respectHeightAndWidthAttrs()) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + } else if (attr->name() == onfocusAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + } else if (attr->name() == onblurAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + } else if (attr->name() == onselectAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().selectEvent, attr); + } else if (attr->name() == onchangeAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + } else if (attr->name() == oninputAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().inputEvent, attr); + } + // Search field and slider attributes all just cause updateFromElement to be called through style + // recalcing. + else if (attr->name() == onsearchAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().searchEvent, attr); + } else if (attr->name() == resultsAttr) { + int oldResults = m_maxResults; + m_maxResults = !attr->isNull() ? min(attr->value().toInt(), maxSavedResults) : -1; + // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right + // time to relayout for this change. + if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) { + detach(); + attach(); + } + setChanged(); + } else if (attr->name() == placeholderAttr) + updatePlaceholderVisibility(true); + else if (attr->name() == autosaveAttr || + attr->name() == incrementalAttr || + attr->name() == minAttr || + attr->name() == maxAttr || + attr->name() == multipleAttr || + attr->name() == precisionAttr) + setChanged(); + else + HTMLFormControlElementWithState::parseMappedAttribute(attr); +} + +bool HTMLInputElement::rendererIsNeeded(RenderStyle *style) +{ +#if USE(LOW_BANDWIDTH_DISPLAY) + if (document()->inLowBandwidthDisplay()) { + document()->frame()->loader()->needToSwitchOutLowBandwidthDisplay(); + return false; + } +#endif + + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case IMAGE: + case ISINDEX: + case PASSWORD: + case RADIO: + case RANGE: + case RESET: + case SEARCH: + case SUBMIT: + case TEXT: + return HTMLFormControlElementWithState::rendererIsNeeded(style); + case HIDDEN: + return false; + } + ASSERT(false); + return false; +} + +RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style) +{ + switch (inputType()) { + case BUTTON: + case RESET: + case SUBMIT: + return new (arena) RenderButton(this); + case CHECKBOX: + case RADIO: + return RenderObject::createObject(this, style); + case FILE: + return new (arena) RenderFileUploadControl(this); + case HIDDEN: + break; + case IMAGE: + return new (arena) RenderImage(this); + case RANGE: + return new (arena) RenderSlider(this); + case ISINDEX: + case PASSWORD: + case SEARCH: + case TEXT: + return new (arena) RenderTextControl(this, false); + } + ASSERT(false); + return 0; +} + +void HTMLInputElement::attach() +{ + if (!m_inited) { + if (!m_haveType) + setInputType(getAttribute(typeAttr)); + m_inited = true; + } + + HTMLFormControlElementWithState::attach(); + + if (inputType() == IMAGE) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + if (renderer()) { + RenderImage* imageObj = static_cast<RenderImage*>(renderer()); + imageObj->setCachedImage(m_imageLoader->image()); + + // If we have no image at all because we have no src attribute, set + // image height and width for the alt text instead. + if (!m_imageLoader->image() && !imageObj->cachedImage()) + imageObj->setImageSizeForAltText(); + } + } +} + +void HTMLInputElement::detach() +{ + HTMLFormControlElementWithState::detach(); + setValueMatchesRenderer(false); +} + +String HTMLInputElement::altText() const +{ + // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen + // also heavily discussed by Hixie on bugzilla + // note this is intentionally different to HTMLImageElement::altText() + String alt = getAttribute(altAttr); + // fall back to title attribute + if (alt.isNull()) + alt = getAttribute(titleAttr); + if (alt.isNull()) + alt = getAttribute(valueAttr); + if (alt.isEmpty()) + alt = inputElementAltText(); + return alt; +} + +bool HTMLInputElement::isSuccessfulSubmitButton() const +{ + // HTML spec says that buttons must have names to be considered successful. + // However, other browsers do not impose this constraint. So we do likewise. + return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT); +} + +bool HTMLInputElement::isActivatedSubmit() const +{ + return m_activeSubmit; +} + +void HTMLInputElement::setActivatedSubmit(bool flag) +{ + m_activeSubmit = flag; +} + +bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) +{ + // image generates its own names, but for other types there is no form data unless there's a name + if (name().isEmpty() && inputType() != IMAGE) + return false; + + switch (inputType()) { + case HIDDEN: + case ISINDEX: + case PASSWORD: + case RANGE: + case SEARCH: + case TEXT: + // always successful + encoding.appendData(name(), value()); + return true; + + case CHECKBOX: + case RADIO: + if (checked()) { + encoding.appendData(name(), value()); + return true; + } + break; + + case BUTTON: + case RESET: + // these types of buttons are never successful + return false; + + case IMAGE: + if (m_activeSubmit) { + encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), xPos); + encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), yPos); + if (!name().isEmpty() && !value().isEmpty()) + encoding.appendData(name(), value()); + return true; + } + break; + + case SUBMIT: + if (m_activeSubmit) { + String enc_str = valueWithDefault(); + encoding.appendData(name(), enc_str); + return true; + } + break; + + case FILE: { + // Can't submit file on GET. + if (!multipart) + return false; + + // If no filename at all is entered, return successful but empty. + // Null would be more logical, but Netscape posts an empty file. Argh. + unsigned numFiles = m_fileList->length(); + if (!numFiles) { + encoding.appendFile(name(), File::create("")); + return true; + } + + for (unsigned i = 0; i < numFiles; ++i) + encoding.appendFile(name(), m_fileList->item(i)); + return true; + } + } + return false; +} + +void HTMLInputElement::reset() +{ + if (storesValueSeparateFromAttribute()) + setValue(String()); + + setChecked(m_defaultChecked); + m_useDefaultChecked = true; +} + +void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) +{ + if (checked() == nowChecked) + return; + + checkedRadioButtons(this).removeButton(this); + + m_useDefaultChecked = false; + m_checked = nowChecked; + setChanged(); + + checkedRadioButtons(this).addButton(this); + + if (renderer() && renderer()->style()->hasAppearance()) + theme()->stateChanged(renderer(), CheckedState); + + // Only send a change event for items in the document (avoid firing during + // parsing) and don't send a change event for a radio button that's getting + // unchecked to match other browsers. DOM is not a useful standard for this + // because it says only to fire change events at "lose focus" time, which is + // definitely wrong in practice for these types of elements. + if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked)) + onChange(); +} + +void HTMLInputElement::setIndeterminate(bool _indeterminate) +{ + // Only checkboxes honor indeterminate. + if (inputType() != CHECKBOX || indeterminate() == _indeterminate) + return; + + m_indeterminate = _indeterminate; + + setChanged(); + + if (renderer() && renderer()->style()->hasAppearance()) + theme()->stateChanged(renderer(), CheckedState); +} + +void HTMLInputElement::copyNonAttributeProperties(const Element *source) +{ + const HTMLInputElement *sourceElem = static_cast<const HTMLInputElement *>(source); + + m_value = sourceElem->m_value; + m_checked = sourceElem->m_checked; + m_indeterminate = sourceElem->m_indeterminate; + + HTMLFormControlElementWithState::copyNonAttributeProperties(source); +} + +String HTMLInputElement::value() const +{ + // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control + // but we don't want to break existing websites, who may be relying on being able to get the file name as a value. + if (inputType() == FILE) { + if (!m_fileList->isEmpty()) + return m_fileList->item(0)->fileName(); + return String(); + } + + String value = m_value; + if (value.isNull()) { + value = constrainValue(getAttribute(valueAttr)); + + // If no attribute exists, then just use "on" or "" based off the checked() state of the control. + if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO)) + return checked() ? "on" : ""; + } + + return value; +} + +String HTMLInputElement::valueWithDefault() const +{ + String v = value(); + if (v.isNull()) { + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case HIDDEN: + case IMAGE: + case ISINDEX: + case PASSWORD: + case RADIO: + case RANGE: + case SEARCH: + case TEXT: + break; + case RESET: + v = resetButtonDefaultLabel(); + break; + case SUBMIT: + v = submitButtonDefaultLabel(); + break; + } + } + return v; +} + +void HTMLInputElement::setValue(const String& value) +{ + // For security reasons, we don't allow setting the filename, but we do allow clearing it. + // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control + // but we don't want to break existing websites, who may be relying on this method to clear things. + if (inputType() == FILE && !value.isEmpty()) + return; + + if (isTextField()) + updatePlaceholderVisibility(); + + setValueMatchesRenderer(false); + if (storesValueSeparateFromAttribute()) { + if (inputType() == FILE) + m_fileList->clear(); + else { + m_value = constrainValue(value); + if (isTextField() && inDocument()) + document()->updateRendering(); + } + if (renderer()) + renderer()->updateFromElement(); + setChanged(); + } else + setAttribute(valueAttr, constrainValue(value)); + + if (isTextField()) { + unsigned max = m_value.length(); + if (document()->focusedNode() == this) +#ifndef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS + setSelectionRange(max, max); +#else + { + // Make sure our UI side textfield changes to match the RenderTextControl + android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value); + setSelectionRange(max, max); + } +#endif + else { + cachedSelStart = max; + cachedSelEnd = max; + } + } +} + +void HTMLInputElement::setValueFromRenderer(const String& value) +{ + // Renderer and our event handler are responsible for constraining values. + ASSERT(value == constrainValue(value) || constrainValue(value).isEmpty()); + + // File upload controls will always use setFileListFromRenderer. + ASSERT (inputType() != FILE); + + if (isTextField()) + updatePlaceholderVisibility(); + + // Workaround for bug where trailing \n is included in the result of textContent. + // The assert macro above may also be simplified to: value == constrainValue(value) + // http://bugs.webkit.org/show_bug.cgi?id=9661 + if (value == "\n") + m_value = ""; + else + m_value = value; + + setValueMatchesRenderer(); + + // Fire the "input" DOM event. + dispatchEventForType(eventNames().inputEvent, true, false); +} + +void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) +{ + m_fileList->clear(); + int size = paths.size(); + for (int i = 0; i < size; i++) + m_fileList->append(File::create(paths[i])); + + setValueMatchesRenderer(); +} + +bool HTMLInputElement::storesValueSeparateFromAttribute() const +{ + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case HIDDEN: + case IMAGE: + case RADIO: + case RESET: + case SUBMIT: + return false; + case FILE: + case ISINDEX: + case PASSWORD: + case RANGE: + case SEARCH: + case TEXT: + return true; + } + return false; +} + +void* HTMLInputElement::preDispatchEventHandler(Event *evt) +{ + // preventDefault or "return false" are used to reverse the automatic checking/selection we do here. + // This result gives us enough info to perform the "undo" in postDispatch of the action we take here. + void* result = 0; + if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() + && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + if (inputType() == CHECKBOX) { + // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for + // indeterminate. + if (indeterminate()) { + result = (void*)0x2; + setIndeterminate(false); + } else { + if (checked()) + result = (void*)0x1; + setChecked(!checked(), true); + } + } else { + // For radio buttons, store the current selected radio object. + if (name().isEmpty() || checked()) + return 0; // Match WinIE and don't allow unnamed radio buttons to be checked. + // Checked buttons just stay checked. + // FIXME: Need to learn to work without a form. + + // We really want radio groups to end up in sane states, i.e., to have something checked. + // Therefore if nothing is currently selected, we won't allow this action to be "undone", since + // we want some object in the radio group to actually get selected. + HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name()); + if (currRadio) { + // We have a radio button selected that is not us. Cache it in our result field and ref it so + // that it can't be destroyed. + currRadio->ref(); + result = currRadio; + } + setChecked(true, true); + } + } + return result; +} + +void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data) +{ + if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() + && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + if (inputType() == CHECKBOX) { + // Reverse the checking we did in preDispatch. + if (evt->defaultPrevented() || evt->defaultHandled()) { + if (data == (void*)0x2) + setIndeterminate(true); + else + setChecked(data); + } + } else if (data) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(data); + if (evt->defaultPrevented() || evt->defaultHandled()) { + // Restore the original selected radio button if possible. + // Make sure it is still a radio button and only do the restoration if it still + // belongs to our group. + + // Match WinIE and don't allow unnamed radio buttons to be checked. + if (input->form() == form() && input->inputType() == RADIO && !name().isEmpty() && input->name() == name()) { + // Ok, the old radio button is still in our form and in our group and is still a + // radio button, so it's safe to restore selection to it. + input->setChecked(true); + } + } + input->deref(); + } + + // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler(). + evt->setDefaultHandled(); + } +} + +void HTMLInputElement::defaultEventHandler(Event* evt) +{ + bool clickDefaultFormButton = false; + + if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n") + clickDefaultFormButton = true; + + if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) { + // record the mouse position for when we get the DOMActivate event + MouseEvent* me = static_cast<MouseEvent*>(evt); + // FIXME: We could just call offsetX() and offsetY() on the event, + // but that's currently broken, so for now do the computation here. + if (me->isSimulated() || !renderer()) { + xPos = 0; + yPos = 0; + } else { + int offsetX, offsetY; + renderer()->absolutePosition(offsetX, offsetY); + xPos = me->pageX() - offsetX; + // FIXME: Why is yPos a short? + yPos = me->pageY() - offsetY; + } + } + + if (isTextField() && evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame() + && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) { + evt->setDefaultHandled(); + return; + } + + if (inputType() == RADIO && evt->isMouseEvent() + && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + evt->setDefaultHandled(); + return; + } + + // Let the key handling done in EventTargetNode take precedence over the event handling here for editable text fields + if (!clickDefaultFormButton) { + HTMLFormControlElementWithState::defaultEventHandler(evt); + if (evt->defaultHandled()) + return; + } + + // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means + // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks + // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element + // must dispatch a DOMActivate event - a click event will not do the job. + if (evt->type() == eventNames().DOMActivateEvent && !disabled()) { + if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) { + if (!form()) + return; + if (inputType() == RESET) + form()->reset(); + else { + m_activeSubmit = true; + // FIXME: Would be cleaner to get xPos and yPos out of the underlying mouse + // event (if any) here instead of relying on the variables set above when + // processing the click event. Even better, appendFormData could pass the + // event in, and then we could get rid of xPos and yPos altogether! + if (!form()->prepareSubmit(evt)) { + xPos = 0; + yPos = 0; + } + m_activeSubmit = false; + } + } else if (inputType() == FILE && renderer()) + static_cast<RenderFileUploadControl*>(renderer())->click(); + } + + // Use key press event here since sending simulated mouse events + // on key down blocks the proper sending of the key press event. + if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { + bool clickElement = false; + + int charCode = static_cast<KeyboardEvent*>(evt)->charCode(); + + if (charCode == '\r') { + switch (inputType()) { + case CHECKBOX: + case HIDDEN: + case ISINDEX: + case PASSWORD: + case RANGE: + case SEARCH: + case TEXT: + // Simulate mouse click on the default form button for enter for these types of elements. + clickDefaultFormButton = true; + break; + case BUTTON: + case FILE: + case IMAGE: + case RESET: + case SUBMIT: + // Simulate mouse click for enter for these types of elements. + clickElement = true; + break; + case RADIO: + break; // Don't do anything for enter on a radio button. + } + } else if (charCode == ' ') { + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case IMAGE: + case RESET: + case SUBMIT: + case RADIO: + // Prevent scrolling down the page. + evt->setDefaultHandled(); + return; + default: + break; + } + } + + if (clickElement) { + dispatchSimulatedClick(evt); + evt->setDefaultHandled(); + return; + } + } + + if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) { + String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); + + if (key == "U+0020") { + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case IMAGE: + case RESET: + case SUBMIT: + case RADIO: + setActive(true, true); + // No setDefaultHandled() - IE dispatches a keypress in this case. + return; + default: + break; + } + } + +// allow enter to change state of radio + if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) { + // Left and up mean "previous radio button". + // Right and down mean "next radio button". + // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves + // to the right). Seems strange, but we'll match it. + bool forward = (key == "Down" || key == "Right"); + + // We can only stay within the form's children if the form hasn't been demoted to a leaf because + // of malformed HTML. + Node* n = this; + while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) { + // Once we encounter a form element, we know we're through. + if (n->hasTagName(formTag)) + break; + + // Look for more radio buttons. + if (n->hasTagName(inputTag)) { + HTMLInputElement* elt = static_cast<HTMLInputElement*>(n); + if (elt->form() != form()) + break; + if (n->hasTagName(inputTag)) { + // Match WinIE and don't allow unnamed radio buttons to be checked. + HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); + if (inputElt->inputType() == RADIO && !name().isEmpty() && inputElt->name() == name() && inputElt->isFocusable()) { + inputElt->setChecked(true); + document()->setFocusedNode(inputElt); + inputElt->dispatchSimulatedClick(evt, false, false); + evt->setDefaultHandled(); + break; + } + } + } + } + } + } + + if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) { + bool clickElement = false; + + String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); + + if (key == "U+0020") { + switch (inputType()) { + case BUTTON: + case CHECKBOX: + case FILE: + case IMAGE: + case RESET: + case SUBMIT: + // Simulate mouse click for spacebar for these types of elements. + // The AppKit already does this for some, but not all, of them. + clickElement = true; + break; + case RADIO: + // If an unselected radio is tabbed into (because the entire group has nothing + // checked, or because of some explicit .focus() call), then allow space to check it. + if (!checked()) + clickElement = true; + break; + case HIDDEN: + case ISINDEX: + case PASSWORD: + case RANGE: + case SEARCH: + case TEXT: + break; + } + } + + if (clickElement) { + if (active()) + dispatchSimulatedClick(evt); + evt->setDefaultHandled(); + return; + } + } + + if (clickDefaultFormButton) { + if (isSearchField()) { + addSearchResult(); + onSearch(); + } + // Fire onChange for text fields. + RenderObject* r = renderer(); + if (r && r->isTextField() && r->isEdited()) { + onChange(); + // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it. + r = renderer(); + if (r) + r->setEdited(false); + } + // Form may never have been present, or may have been destroyed by the change event. + if (form()) + form()->submitClick(evt); + evt->setDefaultHandled(); + return; + } + + if (evt->isBeforeTextInsertedEvent()) { + // Make sure that the text to be inserted will not violate the maxLength. + int oldLen = numGraphemeClusters(value().impl()); + ASSERT(oldLen <= maxLength()); + int selectionLen = numGraphemeClusters(plainText(document()->frame()->selection()->selection().toRange().get()).impl()); + ASSERT(oldLen >= selectionLen); + int maxNewLen = maxLength() - (oldLen - selectionLen); + + // Truncate the inserted text to avoid violating the maxLength and other constraints. + BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(evt); + textEvent->setText(constrainValue(textEvent->text(), maxNewLen)); + } + + if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) + static_cast<RenderTextControl*>(renderer())->forwardEvent(evt); + + if (inputType() == RANGE && renderer()) { + RenderSlider* slider = static_cast<RenderSlider*>(renderer()); + if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + MouseEvent* mEvt = static_cast<MouseEvent*>(evt); + if (!slider->mouseEventIsInThumb(mEvt)) { + IntPoint eventOffset(mEvt->offsetX(), mEvt->offsetY()); + if (mEvt->target() != this) { + IntRect rect = renderer()->absoluteBoundingBoxRect(); + eventOffset.setX(mEvt->pageX() - rect.x()); + eventOffset.setY(mEvt->pageY() - rect.y()); + } + slider->setValueForPosition(slider->positionForOffset(eventOffset)); + } + } + if (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()) + slider->forwardEvent(evt); + } +} + +bool HTMLInputElement::isURLAttribute(Attribute *attr) const +{ + return (attr->name() == srcAttr); +} + +String HTMLInputElement::defaultValue() const +{ + return getAttribute(valueAttr); +} + +void HTMLInputElement::setDefaultValue(const String &value) +{ + setAttribute(valueAttr, value); +} + +bool HTMLInputElement::defaultChecked() const +{ + return !getAttribute(checkedAttr).isNull(); +} + +void HTMLInputElement::setDefaultChecked(bool defaultChecked) +{ + setAttribute(checkedAttr, defaultChecked ? "" : 0); +} + +String HTMLInputElement::accept() const +{ + return getAttribute(acceptAttr); +} + +void HTMLInputElement::setAccept(const String &value) +{ + setAttribute(acceptAttr, value); +} + +String HTMLInputElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLInputElement::setAccessKey(const String &value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLInputElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLInputElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLInputElement::alt() const +{ + return getAttribute(altAttr); +} + +void HTMLInputElement::setAlt(const String &value) +{ + setAttribute(altAttr, value); +} + +void HTMLInputElement::setMaxLength(int _maxLength) +{ + setAttribute(maxlengthAttr, String::number(_maxLength)); +} + +void HTMLInputElement::setSize(unsigned _size) +{ + setAttribute(sizeAttr, String::number(_size)); +} + +KURL HTMLInputElement::src() const +{ + return document()->completeURL(getAttribute(srcAttr)); +} + +void HTMLInputElement::setSrc(const String &value) +{ + setAttribute(srcAttr, value); +} + +String HTMLInputElement::useMap() const +{ + return getAttribute(usemapAttr); +} + +void HTMLInputElement::setUseMap(const String &value) +{ + setAttribute(usemapAttr, value); +} + +FileList* HTMLInputElement::files() +{ + if (inputType() != FILE) + return 0; + return m_fileList.get(); +} + +String HTMLInputElement::constrainValue(const String& proposedValue) const +{ + return constrainValue(proposedValue, m_maxLen); +} + +void HTMLInputElement::recheckValue() +{ + String oldValue = value(); + String newValue = constrainValue(oldValue); + if (newValue != oldValue) + setValue(newValue); +} + +bool HTMLInputElement::needsActivationCallback() +{ + return inputType() == PASSWORD || m_autocomplete == Off; +} + +void HTMLInputElement::registerForActivationCallbackIfNeeded() +{ + if (needsActivationCallback()) + document()->registerForDocumentActivationCallbacks(this); +} + +void HTMLInputElement::unregisterForActivationCallbackIfNeeded() +{ + if (!needsActivationCallback()) + document()->unregisterForDocumentActivationCallbacks(this); +} + +void HTMLInputElement::updatePlaceholderVisibility(bool placeholderValueChanged) +{ + ASSERT(isTextField()); + + bool oldPlaceholderShouldBeVisible = m_placeholderShouldBeVisible; + + m_placeholderShouldBeVisible = value().isEmpty() + && document()->focusedNode() != this + && !getAttribute(placeholderAttr).isEmpty(); + + if ((oldPlaceholderShouldBeVisible != m_placeholderShouldBeVisible || placeholderValueChanged) && renderer()) + static_cast<RenderTextControl*>(renderer())->updatePlaceholderVisibility(); +} + +String HTMLInputElement::constrainValue(const String& proposedValue, int maxLen) const +{ + String string = proposedValue; + if (isTextField()) { + string.replace("\r\n", " "); + string.replace('\r', ' '); + string.replace('\n', ' '); + StringImpl* s = string.impl(); + int newLen = numCharactersInGraphemeClusters(s, maxLen); + for (int i = 0; i < newLen; ++i) { + const UChar current = (*s)[i]; + if (current < ' ' && current != '\t') { + newLen = i; + break; + } + } + if (newLen < static_cast<int>(string.length())) + return string.substring(0, newLen); + } + return string; +} + +void HTMLInputElement::addSearchResult() +{ + ASSERT(isSearchField()); + if (renderer()) + static_cast<RenderTextControl*>(renderer())->addSearchResult(); +} + +void HTMLInputElement::onSearch() +{ + ASSERT(isSearchField()); + if (renderer()) + static_cast<RenderTextControl*>(renderer())->stopSearchEventTimer(); + dispatchEventForType(eventNames().searchEvent, true, false); +} + +Selection HTMLInputElement::selection() const +{ + if (!renderer() || !isTextField() || cachedSelStart == -1 || cachedSelEnd == -1) + return Selection(); + return static_cast<RenderTextControl*>(renderer())->selection(cachedSelStart, cachedSelEnd); +} + +void HTMLInputElement::documentDidBecomeActive() +{ + ASSERT(needsActivationCallback()); + reset(); +} + +void HTMLInputElement::willMoveToNewOwnerDocument() +{ + // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered + if (needsActivationCallback()) + document()->unregisterForDocumentActivationCallbacks(this); + + document()->checkedRadioButtons().removeButton(this); + + HTMLFormControlElementWithState::willMoveToNewOwnerDocument(); +} + +void HTMLInputElement::didMoveToNewOwnerDocument() +{ + registerForActivationCallbackIfNeeded(); + + HTMLFormControlElementWithState::didMoveToNewOwnerDocument(); +} + +void HTMLInputElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(src().string()); +} + +bool HTMLInputElement::willValidate() const +{ + // FIXME: This shall check for new WF2 input types too + return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN && + inputType() != BUTTON && inputType() != RESET; +} +} // namespace diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h new file mode 100644 index 0000000..7f090a8 --- /dev/null +++ b/WebCore/html/HTMLInputElement.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLInputElement_h +#define HTMLInputElement_h + +#include "HTMLFormControlElement.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class FileList; +class HTMLImageLoader; +class KURL; +class Selection; + +class HTMLInputElement : public HTMLFormControlElementWithState { +public: + enum InputType { + TEXT, + PASSWORD, + ISINDEX, + CHECKBOX, + RADIO, + SUBMIT, + RESET, + FILE, + HIDDEN, + IMAGE, + BUTTON, + SEARCH, + RANGE + }; + + enum AutoCompleteSetting { + Uninitialized, + On, + Off + }; + + HTMLInputElement(Document*, HTMLFormElement* = 0); + HTMLInputElement(const QualifiedName& tagName, Document*, HTMLFormElement* = 0); + virtual ~HTMLInputElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isMouseFocusable() const; + virtual bool isEnumeratable() const { return inputType() != IMAGE; } + virtual void dispatchFocusEvent(); + virtual void dispatchBlurEvent(); + virtual void updateFocusAppearance(bool restorePreviousSelection); + virtual void aboutToUnload(); + virtual bool shouldUseInputMethod() const; + + virtual const AtomicString& name() const; + + bool autoComplete() const; + + // isChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state + virtual bool isChecked() const { return checked() && (inputType() == CHECKBOX || inputType() == RADIO); } + virtual bool isIndeterminate() const { return indeterminate(); } + + bool readOnly() const { return isReadOnlyControl(); } + + virtual bool isTextControl() const { return isTextField(); } + + bool isTextButton() const { return m_type == SUBMIT || m_type == RESET || m_type == BUTTON; } + virtual bool isRadioButton() const { return m_type == RADIO; } + bool isTextField() const { return m_type == TEXT || m_type == PASSWORD || m_type == SEARCH || m_type == ISINDEX; } + bool isSearchField() const { return m_type == SEARCH; } + virtual bool isInputTypeHidden() const { return m_type == HIDDEN; } + virtual bool isPasswordField() const { return m_type == PASSWORD; } + + bool checked() const { return m_checked; } + void setChecked(bool, bool sendChangeEvent = false); + bool indeterminate() const { return m_indeterminate; } + void setIndeterminate(bool); + int maxLength() const { return m_maxLen; } + int size() const { return m_size; } + virtual const AtomicString& type() const; + void setType(const String&); + + String value() const; + void setValue(const String&); + + String valueWithDefault() const; + + void setValueFromRenderer(const String&); + void setFileListFromRenderer(const Vector<String>&); + + virtual bool saveState(String& value) const; + virtual void restoreState(const String&); + + virtual bool canStartSelection() const; + + bool canHaveSelection() const; + int selectionStart() const; + int selectionEnd() const; + void setSelectionStart(int); + void setSelectionEnd(int); + void select(); + void setSelectionRange(int start, int end); + + virtual void accessKeyAction(bool sendToAnyElement); + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void copyNonAttributeProperties(const Element* source); + + virtual void attach(); + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void detach(); + virtual bool appendFormData(FormDataList&, bool); + + virtual bool isSuccessfulSubmitButton() const; + virtual bool isActivatedSubmit() const; + virtual void setActivatedSubmit(bool flag); + + InputType inputType() const { return static_cast<InputType>(m_type); } + void setInputType(const String&); + + // Report if this input type uses height & width attributes + bool respectHeightAndWidthAttrs() const { return inputType() == IMAGE || inputType() == HIDDEN; } + + virtual void reset(); + + virtual void* preDispatchEventHandler(Event*); + virtual void postDispatchEventHandler(Event*, void* dataFromPreDispatch); + virtual void defaultEventHandler(Event*); + + String altText() const; + + virtual bool isURLAttribute(Attribute*) const; + + int maxResults() const { return m_maxResults; } + + String defaultValue() const; + void setDefaultValue(const String&); + + bool defaultChecked() const; + void setDefaultChecked(bool); + + String accept() const; + void setAccept(const String&); + + String accessKey() const; + void setAccessKey(const String&); + + String align() const; + void setAlign(const String&); + + String alt() const; + void setAlt(const String&); + + void setSize(unsigned); + + KURL src() const; + void setSrc(const String&); + + void setMaxLength(int); + + String useMap() const; + void setUseMap(const String&); + + bool autofilled() const { return m_autofilled; } + void setAutofilled(bool b = true) { m_autofilled = b; } + + FileList* files(); + + void cacheSelection(int s, int e) { cachedSelStart = s; cachedSelEnd = e; }; + void addSearchResult(); + void onSearch(); + + Selection selection() const; + + String constrainValue(const String& proposedValue) const; + + virtual void documentDidBecomeActive(); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + + virtual bool willValidate() const; + + bool placeholderShouldBeVisible() const { return m_placeholderShouldBeVisible; } + +protected: + virtual void willMoveToNewOwnerDocument(); + virtual void didMoveToNewOwnerDocument(); + + AtomicString m_name; + +private: + void init(); + bool storesValueSeparateFromAttribute() const; + String constrainValue(const String& proposedValue, int maxLen) const; + void recheckValue(); + + bool needsActivationCallback(); + void registerForActivationCallbackIfNeeded(); + void unregisterForActivationCallbackIfNeeded(); + + void updatePlaceholderVisibility(bool placeholderValueChanged = false); + + String m_value; + String m_originalValue; + int xPos; + int m_maxLen; + short m_size; + short yPos; + + short m_maxResults; + + OwnPtr<HTMLImageLoader> m_imageLoader; + + RefPtr<FileList> m_fileList; + + unsigned m_type : 4; // InputType + bool m_checked : 1; + bool m_defaultChecked : 1; + bool m_useDefaultChecked : 1; + bool m_indeterminate : 1; + bool m_haveType : 1; + bool m_activeSubmit : 1; + unsigned m_autocomplete : 2; // AutoCompleteSetting + bool m_autofilled : 1; + bool m_inited : 1; + bool m_placeholderShouldBeVisible : 1; + + int cachedSelStart; + int cachedSelEnd; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLInputElement.idl b/WebCore/html/HTMLInputElement.idl new file mode 100644 index 0000000..a9b6d2c --- /dev/null +++ b/WebCore/html/HTMLInputElement.idl @@ -0,0 +1,76 @@ +/* + * 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 html { + + interface [ + CustomGetOwnPropertySlot, + GenerateConstructor, + InterfaceUUID=8f388ea3-1c31-4cca-8edd-449d14e222e1, + ImplementationUUID=aeb56b87-a90e-4d9d-a4d5-7eec3687c338 + ] HTMLInputElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString defaultValue; + attribute boolean defaultChecked; + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString accept; + attribute [ConvertNullToNullString] DOMString accessKey; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString alt; + attribute boolean checked; + attribute boolean disabled; + attribute boolean autofocus; + attribute long maxLength; + attribute [ConvertNullToNullString] DOMString name; + attribute boolean readOnly; +#if defined(LANGUAGE_OBJECTIVE_C) + attribute [ConvertToString] DOMString size; // DOM level 2 changed this to a long, but our existing API is a string +#else + // FIXME: the spec says this should be a long, not an unsigned long + attribute unsigned long size; // Changed string -> long as part of DOM level 2 +#endif + attribute [ConvertNullToNullString] DOMString src; + attribute [ConvertNullToNullString] DOMString type; // readonly dropped as part of DOM level 2 + attribute [ConvertNullToNullString] DOMString useMap; + attribute [ConvertNullToNullString] DOMString value; + readonly attribute boolean willValidate; + void select(); + void click(); + + // WinIE extension: + attribute boolean indeterminate; + + // WinIE & FireFox extension: + + attribute [CustomGetter] long selectionStart; + attribute [CustomGetter] long selectionEnd; + void setSelectionRange(in long start, in long end); + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute DOMString altDisplayString; + readonly attribute URL absoluteImageURL; +#endif + +#if !defined(LANGUAGE_COM) + readonly attribute FileList files; +#endif + }; + +} diff --git a/WebCore/html/HTMLIsIndexElement.cpp b/WebCore/html/HTMLIsIndexElement.cpp new file mode 100644 index 0000000..2abc23f --- /dev/null +++ b/WebCore/html/HTMLIsIndexElement.cpp @@ -0,0 +1,61 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLIsIndexElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLIsIndexElement::HTMLIsIndexElement(Document *doc, HTMLFormElement *f) + : HTMLInputElement(isindexTag, doc, f) +{ + m_name = "isindex"; +} + +void HTMLIsIndexElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == promptAttr) + setValue(attr->value()); + else + // don't call HTMLInputElement::parseMappedAttribute here, as it would + // accept attributes this element does not support + HTMLFormControlElement::parseMappedAttribute(attr); +} + +String HTMLIsIndexElement::prompt() const +{ + return getAttribute(promptAttr); +} + +void HTMLIsIndexElement::setPrompt(const String &value) +{ + setAttribute(promptAttr, value); +} + +} // namespace diff --git a/WebCore/html/HTMLIsIndexElement.h b/WebCore/html/HTMLIsIndexElement.h new file mode 100644 index 0000000..dd640f2 --- /dev/null +++ b/WebCore/html/HTMLIsIndexElement.h @@ -0,0 +1,51 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLIsIndexElement_h +#define HTMLIsIndexElement_h + +#include "HTMLInputElement.h" + +namespace WebCore { + +class HTMLIsIndexElement : public HTMLInputElement +{ +public: + HTMLIsIndexElement(Document *doc, HTMLFormElement *f = 0); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void parseMappedAttribute(MappedAttribute *attr); + + String prompt() const; + void setPrompt(const String &); + +protected: + String m_prompt; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLIsIndexElement.idl b/WebCore/html/HTMLIsIndexElement.idl new file mode 100644 index 0000000..1e978b2 --- /dev/null +++ b/WebCore/html/HTMLIsIndexElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=94fc4e39-4d81-44e3-a37d-364553b23a37, + ImplementationUUID=b31d409b-8f68-495d-a0c2-b81520716974 + ] HTMLIsIndexElement : HTMLInputElement { + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString prompt; + }; + +} diff --git a/WebCore/html/HTMLKeygenElement.cpp b/WebCore/html/HTMLKeygenElement.cpp new file mode 100644 index 0000000..b918d78 --- /dev/null +++ b/WebCore/html/HTMLKeygenElement.cpp @@ -0,0 +1,86 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLKeygenElement.h" + +#include "Document.h" +#include "FormDataList.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "SSLKeyGenerator.h" +#include "Text.h" + +using namespace WebCore; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLKeygenElement::HTMLKeygenElement(Document* doc, HTMLFormElement* f) + : HTMLSelectElement(keygenTag, doc, f) +{ + Vector<String> keys; + getSupportedKeySizes(keys); + + Vector<String>::const_iterator end = keys.end(); + for (Vector<String>::const_iterator it = keys.begin(); it != end; ++it) { + HTMLOptionElement* o = new HTMLOptionElement(doc, form()); + addChild(o); + o->addChild(new Text(doc, *it)); + } +} + +const AtomicString& HTMLKeygenElement::type() const +{ + static const AtomicString keygen("keygen"); + return keygen; +} + +void HTMLKeygenElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == challengeAttr) + m_challenge = attr->value(); + else if (attr->name() == keytypeAttr) + m_keyType = attr->value(); + else + // skip HTMLSelectElement parsing! + HTMLFormControlElement::parseMappedAttribute(attr); +} + +bool HTMLKeygenElement::appendFormData(FormDataList& encoded_values, bool) +{ + // Only RSA is supported at this time. + if (!m_keyType.isNull() && !equalIgnoringCase(m_keyType, "rsa")) + return false; + String value = signedPublicKeyAndChallengeString(selectedIndex(), m_challenge, document()->baseURL()); + if (value.isNull()) + return false; + encoded_values.appendData(name(), value.utf8()); + return true; +} + +} // namespace diff --git a/WebCore/html/HTMLKeygenElement.h b/WebCore/html/HTMLKeygenElement.h new file mode 100644 index 0000000..800d217 --- /dev/null +++ b/WebCore/html/HTMLKeygenElement.h @@ -0,0 +1,50 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLKeygenElement_h +#define HTMLKeygenElement_h + +#include "HTMLSelectElement.h" + +namespace WebCore { + +class HTMLKeygenElement : public HTMLSelectElement { +public: + HTMLKeygenElement(Document*, HTMLFormElement* = 0); + + virtual int tagPriority() const { return 0; } + virtual const AtomicString& type() const; + virtual bool isEnumeratable() const { return false; } + virtual void parseMappedAttribute(MappedAttribute*); + virtual bool appendFormData(FormDataList&, bool); + +private: + AtomicString m_challenge; + AtomicString m_keyType; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLLIElement.cpp b/WebCore/html/HTMLLIElement.cpp new file mode 100644 index 0000000..6cb9304 --- /dev/null +++ b/WebCore/html/HTMLLIElement.cpp @@ -0,0 +1,127 @@ +/** + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * 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. + * + */ + +#include "config.h" +#include "HTMLLIElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" +#include "RenderListItem.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLLIElement::HTMLLIElement(Document* doc) + : HTMLElement(HTMLNames::liTag, doc) + , m_requestedValue(0) +{ +} + +bool HTMLLIElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == typeAttr) { + result = eListItem; // Share with <ol> since all the values are the same + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLLIElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == valueAttr) { + m_requestedValue = attr->value().toInt(); + if (renderer() && renderer()->isListItem()) { + if (m_requestedValue > 0) + static_cast<RenderListItem*>(renderer())->setExplicitValue(m_requestedValue); + else + static_cast<RenderListItem*>(renderer())->clearExplicitValue(); + } + } else if (attr->name() == typeAttr) { + if (attr->value() == "a") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueLowerAlpha); + else if (attr->value() == "A") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueUpperAlpha); + else if (attr->value() == "i") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueLowerRoman); + else if (attr->value() == "I") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueUpperRoman); + else if (attr->value() == "1") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueDecimal); + else + addCSSProperty(attr, CSSPropertyListStyleType, attr->value()); + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLLIElement::attach() +{ + ASSERT(!attached()); + + HTMLElement::attach(); + + if (renderer() && renderer()->isListItem()) { + RenderListItem* render = static_cast<RenderListItem*>(renderer()); + + // Find the enclosing list node. + Node* listNode = 0; + Node* n = this; + while (!listNode && (n = n->parentNode())) { + if (n->hasTagName(ulTag) || n->hasTagName(olTag)) + listNode = n; + } + + // If we are not in a list, tell the renderer so it can position us inside. + // We don't want to change our style to say "inside" since that would affect nested nodes. + if (!listNode) + render->setNotInList(true); + + if (m_requestedValue > 0) + render->setExplicitValue(m_requestedValue); + else + render->clearExplicitValue(); + } +} + +String HTMLLIElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLLIElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} + +int HTMLLIElement::value() const +{ + return getAttribute(valueAttr).toInt(); +} + +void HTMLLIElement::setValue(int value) +{ + setAttribute(valueAttr, String::number(value)); +} + +} diff --git a/WebCore/html/HTMLLIElement.h b/WebCore/html/HTMLLIElement.h new file mode 100644 index 0000000..4edd771 --- /dev/null +++ b/WebCore/html/HTMLLIElement.h @@ -0,0 +1,55 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLLIElement_h +#define HTMLLIElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLLIElement : public HTMLElement { +public: + HTMLLIElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 3; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void attach(); + + String type() const; + void setType(const String&); + + int value() const; + void setValue(int); + +private: + int m_requestedValue; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLLIElement.idl b/WebCore/html/HTMLLIElement.idl new file mode 100644 index 0000000..015454e --- /dev/null +++ b/WebCore/html/HTMLLIElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=83a4a75c-4427-4f53-b974-8107fedb4c2b, + ImplementationUUID=5747808d-8cbd-49c9-b89b-3fdc315c55fe + ] HTMLLIElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString type; + attribute long value; + }; + +} diff --git a/WebCore/html/HTMLLabelElement.cpp b/WebCore/html/HTMLLabelElement.cpp new file mode 100644 index 0000000..6d97bc1 --- /dev/null +++ b/WebCore/html/HTMLLabelElement.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. ALl rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLLabelElement.h" + +#include "Document.h" +#include "Event.h" +#include "EventNames.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLLabelElement::HTMLLabelElement(Document *doc) + : HTMLElement(labelTag, doc) +{ +} + +HTMLLabelElement::~HTMLLabelElement() +{ +} + +bool HTMLLabelElement::isFocusable() const +{ + return false; +} + +HTMLElement* HTMLLabelElement::correspondingControl() +{ + const AtomicString& controlId = getAttribute(forAttr); + if (controlId.isNull()) { + // Search children of the label element for a form element. + Node* node = this; + while ((node = node->traverseNextNode(this))) { + if (node->isHTMLElement()) { + HTMLElement* element = static_cast<HTMLElement*>(node); + if (element->isGenericFormElement()) + return element; + } + } + return 0; + } + + // Only return HTML elements. + Element* elt = document()->getElementById(controlId); + if (elt && elt->isHTMLElement()) + return static_cast<HTMLElement*>(elt); + return 0; +} + +void HTMLLabelElement::setActive(bool down, bool pause) +{ + if (down == active()) + return; + + // Update our status first. + HTMLElement::setActive(down, pause); + + // Also update our corresponding control. + if (HTMLElement* element = correspondingControl()) + element->setActive(down, pause); +} + +void HTMLLabelElement::setHovered(bool over) +{ + if (over == hovered()) + return; + + // Update our status first. + HTMLElement::setHovered(over); + + // Also update our corresponding control. + if (HTMLElement* element = correspondingControl()) + element->setHovered(over); +} + +void HTMLLabelElement::defaultEventHandler(Event* evt) +{ + static bool processingClick = false; + + if (evt->type() == eventNames().clickEvent && !processingClick) { + RefPtr<HTMLElement> control = correspondingControl(); + + // If we can't find a control or if the control received the click + // event, then there's no need for us to do anything. + if (!control || (evt->target() && control->contains(evt->target()->toNode()))) + return; + + processingClick = true; + + // Click the corresponding control. + control->dispatchSimulatedClick(evt); + + // If the control can be focused via the mouse, then do that too. + if (control->isMouseFocusable()) + control->focus(); + + processingClick = false; + + evt->setDefaultHandled(); + } + + HTMLElement::defaultEventHandler(evt); +} + +void HTMLLabelElement::focus(bool) +{ + // to match other browsers, always restore previous selection + if (HTMLElement* element = correspondingControl()) + element->focus(); +} + +void HTMLLabelElement::accessKeyAction(bool sendToAnyElement) +{ + if (HTMLElement* element = correspondingControl()) + element->accessKeyAction(sendToAnyElement); +} + +String HTMLLabelElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLLabelElement::setAccessKey(const String &value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLLabelElement::htmlFor() const +{ + return getAttribute(forAttr); +} + +void HTMLLabelElement::setHtmlFor(const String &value) +{ + setAttribute(forAttr, value); +} + +} // namespace diff --git a/WebCore/html/HTMLLabelElement.h b/WebCore/html/HTMLLabelElement.h new file mode 100644 index 0000000..570bdaf --- /dev/null +++ b/WebCore/html/HTMLLabelElement.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLLabelElement_h +#define HTMLLabelElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLLabelElement : public HTMLElement { +public: + HTMLLabelElement(Document*); + virtual ~HTMLLabelElement(); + + virtual int tagPriority() const { return 5; } + + virtual bool isFocusable() const; + + virtual void accessKeyAction(bool sendToAnyElement); + + // Overridden to update the hover/active state of the corresponding control. + virtual void setActive(bool = true, bool pause = false); + virtual void setHovered(bool = true); + + // Overridden to either click() or focus() the corresponding control. + virtual void defaultEventHandler(Event*); + + HTMLElement* correspondingControl(); + + String accessKey() const; + void setAccessKey(const String&); + + String htmlFor() const; + void setHtmlFor(const String&); + + void focus(bool restorePreviousSelection = true); + + private: + String m_formElementID; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLLabelElement.idl b/WebCore/html/HTMLLabelElement.idl new file mode 100644 index 0000000..85b7ef3 --- /dev/null +++ b/WebCore/html/HTMLLabelElement.idl @@ -0,0 +1,33 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=9978d8e6-1d27-4390-bd2f-56f0e72f16e3, + ImplementationUUID=165b7633-0377-4853-a647-2b9005f5aaec + ] HTMLLabelElement : HTMLElement { + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString accessKey; + attribute [ConvertNullToNullString] DOMString htmlFor; + }; + +} diff --git a/WebCore/html/HTMLLegendElement.cpp b/WebCore/html/HTMLLegendElement.cpp new file mode 100644 index 0000000..573f06f --- /dev/null +++ b/WebCore/html/HTMLLegendElement.cpp @@ -0,0 +1,124 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLLegendElement.h" + +#include "HTMLNames.h" +#include "RenderLegend.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLLegendElement::HTMLLegendElement(Document *doc, HTMLFormElement *f) + : HTMLFormControlElement(legendTag, doc, f) +{ +} + +HTMLLegendElement::~HTMLLegendElement() +{ +} + +bool HTMLLegendElement::isFocusable() const +{ + return HTMLElement::isFocusable(); +} + +RenderObject* HTMLLegendElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (style->contentData()) + return RenderObject::createObject(this, style); + + return new (arena) RenderLegend(this); +} + +const AtomicString& HTMLLegendElement::type() const +{ + static const AtomicString legend("legend"); + return legend; +} + +String HTMLLegendElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLLegendElement::setAccessKey(const String &value) +{ + setAttribute(accesskeyAttr, value); +} + +String HTMLLegendElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLLegendElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +Element *HTMLLegendElement::formElement() +{ + // Check if there's a fieldset belonging to this legend. + Node *fieldset = parentNode(); + while (fieldset && !fieldset->hasTagName(fieldsetTag)) + fieldset = fieldset->parentNode(); + if (!fieldset) + return 0; + + // Find first form element inside the fieldset. + // FIXME: Should we care about tabindex? + Node *node = fieldset; + while ((node = node->traverseNextNode(fieldset))) { + if (node->isHTMLElement()) { + HTMLElement *element = static_cast<HTMLElement *>(node); + if (!element->hasLocalName(legendTag) && element->isGenericFormElement()) + return element; + } + } + + return 0; +} + +void HTMLLegendElement::focus(bool) +{ + if (isFocusable()) + Element::focus(); + + // to match other browsers, never restore previous selection + if (Element *element = formElement()) + element->focus(false); +} + +void HTMLLegendElement::accessKeyAction(bool sendToAnyElement) +{ + if (Element *element = formElement()) + element->accessKeyAction(sendToAnyElement); +} + +} // namespace diff --git a/WebCore/html/HTMLLegendElement.h b/WebCore/html/HTMLLegendElement.h new file mode 100644 index 0000000..0873f34 --- /dev/null +++ b/WebCore/html/HTMLLegendElement.h @@ -0,0 +1,59 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLLegendElement_h +#define HTMLLegendElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class HTMLLegendElement : public HTMLFormControlElement { +public: + HTMLLegendElement(Document*, HTMLFormElement* = 0); + virtual ~HTMLLegendElement(); + + virtual bool isFocusable() const; + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual const AtomicString& type() const; + virtual void accessKeyAction(bool sendToAnyElement); + + /** + * The first form element in the legend's fieldset + */ + Element* formElement(); + + String accessKey() const; + void setAccessKey(const String &); + + String align() const; + void setAlign(const String &); + + void focus(bool restorePreviousSelection = true); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLLegendElement.idl b/WebCore/html/HTMLLegendElement.idl new file mode 100644 index 0000000..da00cc1 --- /dev/null +++ b/WebCore/html/HTMLLegendElement.idl @@ -0,0 +1,33 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=a6eb4254-6066-465a-a1c0-b4732281c255, + ImplementationUUID=323e883c-edf8-4b13-a165-8604f4f06ae2 + ] HTMLLegendElement : HTMLElement { + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString accessKey; + attribute [ConvertNullToNullString] DOMString align; + }; + +} diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp new file mode 100644 index 0000000..6cbcd80 --- /dev/null +++ b/WebCore/html/HTMLLinkElement.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 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 "HTMLLinkElement.h" + +#include "CSSHelper.h" +#include "CachedCSSStyleSheet.h" +#include "DNS.h" +#include "DocLoader.h" +#include "Document.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "FrameTree.h" +#include "HTMLNames.h" +#include "MediaList.h" +#include "MediaQueryEvaluator.h" +#include "Page.h" +#include "Settings.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLLinkElement::HTMLLinkElement(Document *doc) + : HTMLElement(linkTag, doc) + , m_cachedSheet(0) + , m_disabledState(0) + , m_loading(false) + , m_alternate(false) + , m_isStyleSheet(false) + , m_isIcon(false) + , m_isDNSPrefetch(false) + , m_createdByParser(false) +{ +} + +HTMLLinkElement::~HTMLLinkElement() +{ + if (m_cachedSheet) { + m_cachedSheet->removeClient(this); + if (m_loading && !isDisabled() && !isAlternate()) + document()->removePendingSheet(); + } +} + +void HTMLLinkElement::setDisabledState(bool _disabled) +{ + int oldDisabledState = m_disabledState; + m_disabledState = _disabled ? 2 : 1; + if (oldDisabledState != m_disabledState) { + // If we change the disabled state while the sheet is still loading, then we have to + // perform three checks: + if (isLoading()) { + // Check #1: If the sheet becomes disabled while it was loading, and if it was either + // a main sheet or a sheet that was previously enabled via script, then we need + // to remove it from the list of pending sheets. + if (m_disabledState == 2 && (!m_alternate || oldDisabledState == 1)) + document()->removePendingSheet(); + + // Check #2: An alternate sheet becomes enabled while it is still loading. + if (m_alternate && m_disabledState == 1) + document()->addPendingSheet(); + + // Check #3: A main sheet becomes enabled while it was still loading and + // after it was disabled via script. It takes really terrible code to make this + // happen (a double toggle for no reason essentially). This happens on + // virtualplastic.net, which manages to do about 12 enable/disables on only 3 + // sheets. :) + if (!m_alternate && m_disabledState == 1 && oldDisabledState == 2) + document()->addPendingSheet(); + + // If the sheet is already loading just bail. + return; + } + + // Load the sheet, since it's never been loaded before. + if (!m_sheet && m_disabledState == 1) + process(); + else + document()->updateStyleSelector(); // Update the style selector. + } +} + +StyleSheet* HTMLLinkElement::sheet() const +{ + return m_sheet.get(); +} + +void HTMLLinkElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == relAttr) { + tokenizeRelAttribute(attr->value(), m_isStyleSheet, m_alternate, m_isIcon, m_isDNSPrefetch); + process(); + } else if (attr->name() == hrefAttr) { + m_url = document()->completeURL(parseURL(attr->value())).string(); + process(); + } else if (attr->name() == typeAttr) { + m_type = attr->value(); + process(); + } else if (attr->name() == mediaAttr) { + m_media = attr->value().string().lower(); + process(); + } else if (attr->name() == disabledAttr) { + setDisabledState(!attr->isNull()); + } else { + if (attr->name() == titleAttr && m_sheet) + m_sheet->setTitle(attr->value()); + HTMLElement::parseMappedAttribute(attr); + } +} + +void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& rel, bool& styleSheet, bool& alternate, bool& icon, bool& dnsPrefetch) +{ + styleSheet = false; + icon = false; + alternate = false; + dnsPrefetch = false; + if (equalIgnoringCase(rel, "stylesheet")) + styleSheet = true; + else if (equalIgnoringCase(rel, "icon") || equalIgnoringCase(rel, "shortcut icon")) + icon = true; + else if (equalIgnoringCase(rel, "dns-prefetch")) + dnsPrefetch = true; + else if (equalIgnoringCase(rel, "alternate stylesheet") || equalIgnoringCase(rel, "stylesheet alternate")) { + styleSheet = true; + alternate = true; + } else { + // Tokenize the rel attribute and set bits based on specific keywords that we find. + String relString = rel.string(); + relString.replace('\n', ' '); + Vector<String> list; + relString.split(' ', list); + Vector<String>::const_iterator end = list.end(); + for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) { + if (equalIgnoringCase(*it, "stylesheet")) + styleSheet = true; + else if (equalIgnoringCase(*it, "alternate")) + alternate = true; + else if (equalIgnoringCase(*it, "icon")) + icon = true; + } + } +} + +void HTMLLinkElement::process() +{ + if (!inDocument()) + return; + + String type = m_type.lower(); + + // IE extension: location of small icon for locationbar / bookmarks + // We'll record this URL per document, even if we later only use it in top level frames + if (m_isIcon && !m_url.isEmpty()) + document()->setIconURL(m_url, type); + + if (m_isDNSPrefetch && !m_url.isEmpty()) + prefetchDNS(KURL(m_url).host()); + + // Stylesheet + // This was buggy and would incorrectly match <link rel="alternate">, which has a different specified meaning. -dwh + if (m_disabledState != 2 && m_isStyleSheet && document()->frame()) { + // no need to load style sheets which aren't for the screen output + // ### there may be in some situations e.g. for an editor or script to manipulate + // also, don't load style sheets for standalone documents + MediaQueryEvaluator allEval(true); + MediaQueryEvaluator screenEval("screen", true); + MediaQueryEvaluator printEval("print", true); + RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(m_media); + if (allEval.eval(media.get()) || screenEval.eval(media.get()) || printEval.eval(media.get())) { + + // Add ourselves as a pending sheet, but only if we aren't an alternate + // stylesheet. Alternate stylesheets don't hold up render tree construction. + if (!isAlternate()) + document()->addPendingSheet(); + + String chset = getAttribute(charsetAttr); + if (chset.isEmpty() && document()->frame()) + chset = document()->frame()->loader()->encoding(); + + if (m_cachedSheet) { + if (m_loading) + document()->removePendingSheet(); + m_cachedSheet->removeClient(this); + } + m_loading = true; + m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(m_url, chset); + if (m_cachedSheet) + m_cachedSheet->addClient(this); + else if (!isAlternate()) { // request may have been denied if stylesheet is local and document is remote. + m_loading = false; + document()->removePendingSheet(); + } + } + } else if (m_sheet) { + // we no longer contain a stylesheet, e.g. perhaps rel or type was changed + m_sheet = 0; + document()->updateStyleSelector(); + } +} + +void HTMLLinkElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + document()->addStyleSheetCandidateNode(this, m_createdByParser); + process(); +} + +void HTMLLinkElement::removedFromDocument() +{ + HTMLElement::removedFromDocument(); + + // FIXME: It's terrible to do a synchronous update of the style selector just because a <style> or <link> element got removed. + if (document()->renderer()) { + document()->removeStyleSheetCandidateNode(this); + document()->updateStyleSelector(); + } +} + +void HTMLLinkElement::finishParsingChildren() +{ + m_createdByParser = false; + HTMLElement::finishParsingChildren(); +} + +void HTMLLinkElement::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet) +{ + m_sheet = CSSStyleSheet::create(this, url, charset); + + bool strictParsing = !document()->inCompatMode(); + bool enforceMIMEType = strictParsing; + + // Check to see if we should enforce the MIME type of the CSS resource in strict mode. + // Running in iWeb 2 is one example of where we don't want to - <rdar://problem/6099748> + if (enforceMIMEType && document()->page() && !document()->page()->settings()->enforceCSSMIMETypeInStrictMode()) + enforceMIMEType = false; + + m_sheet->parseString(sheet->sheetText(enforceMIMEType), strictParsing); + m_sheet->setTitle(title()); + + RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(m_media); + m_sheet->setMedia(media.get()); + + m_loading = false; + m_sheet->checkLoaded(); +} + +bool HTMLLinkElement::isLoading() const +{ + if (m_loading) + return true; + if (!m_sheet) + return false; + return static_cast<CSSStyleSheet *>(m_sheet.get())->isLoading(); +} + +bool HTMLLinkElement::sheetLoaded() +{ + if (!isLoading() && !isDisabled() && !isAlternate()) { + document()->removePendingSheet(); + return true; + } + return false; +} + +bool HTMLLinkElement::isURLAttribute(Attribute *attr) const +{ + return attr->name() == hrefAttr; +} + +bool HTMLLinkElement::disabled() const +{ + return !getAttribute(disabledAttr).isNull(); +} + +void HTMLLinkElement::setDisabled(bool disabled) +{ + setAttribute(disabledAttr, disabled ? "" : 0); +} + +String HTMLLinkElement::charset() const +{ + return getAttribute(charsetAttr); +} + +void HTMLLinkElement::setCharset(const String& value) +{ + setAttribute(charsetAttr, value); +} + +KURL HTMLLinkElement::href() const +{ + return document()->completeURL(getAttribute(hrefAttr)); +} + +void HTMLLinkElement::setHref(const String& value) +{ + setAttribute(hrefAttr, value); +} + +String HTMLLinkElement::hreflang() const +{ + return getAttribute(hreflangAttr); +} + +void HTMLLinkElement::setHreflang(const String& value) +{ + setAttribute(hreflangAttr, value); +} + +String HTMLLinkElement::media() const +{ + return getAttribute(mediaAttr); +} + +void HTMLLinkElement::setMedia(const String& value) +{ + setAttribute(mediaAttr, value); +} + +String HTMLLinkElement::rel() const +{ + return getAttribute(relAttr); +} + +void HTMLLinkElement::setRel(const String& value) +{ + setAttribute(relAttr, value); +} + +String HTMLLinkElement::rev() const +{ + return getAttribute(revAttr); +} + +void HTMLLinkElement::setRev(const String& value) +{ + setAttribute(revAttr, value); +} + +String HTMLLinkElement::target() const +{ + return getAttribute(targetAttr); +} + +void HTMLLinkElement::setTarget(const String& value) +{ + setAttribute(targetAttr, value); +} + +String HTMLLinkElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLLinkElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} + +void HTMLLinkElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + if (m_isIcon) { + urls.append(href().string()); + return; + } + + if (!m_isStyleSheet) + return; + + // Append the URL of this link element. + urls.append(href().string()); + + // Walk the URLs linked by the linked-to stylesheet. + HashSet<String> styleURLs; + StyleSheet* styleSheet = const_cast<HTMLLinkElement*>(this)->sheet(); + if (styleSheet) + styleSheet->addSubresourceURLStrings(styleURLs, href()); + + HashSet<String>::iterator end = styleURLs.end(); + for (HashSet<String>::iterator i = styleURLs.begin(); i != end; ++i) + urls.append(*i); +} + +} diff --git a/WebCore/html/HTMLLinkElement.h b/WebCore/html/HTMLLinkElement.h new file mode 100644 index 0000000..2fcaaa8 --- /dev/null +++ b/WebCore/html/HTMLLinkElement.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLLinkElement_h +#define HTMLLinkElement_h + +#include "CSSStyleSheet.h" +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include "HTMLElement.h" + +namespace WebCore { + +class CachedCSSStyleSheet; +class KURL; + +class HTMLLinkElement : public HTMLElement, public CachedResourceClient { +public: + HTMLLinkElement(Document*); + ~HTMLLinkElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + bool disabled() const; + void setDisabled(bool); + + String charset() const; + void setCharset(const String&); + + KURL href() const; + void setHref(const String&); + + String hreflang() const; + void setHreflang(const String&); + + String media() const; + void setMedia(const String&); + + String rel() const; + void setRel(const String&); + + String rev() const; + void setRev(const String&); + + virtual String target() const; + void setTarget(const String&); + + String type() const; + void setType(const String&); + + StyleSheet* sheet() const; + + // overload from HTMLElement + virtual void parseMappedAttribute(MappedAttribute*); + + void process(); + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + // from CachedResourceClient + virtual void setCSSStyleSheet(const String &url, const String& charset, const CachedCSSStyleSheet* sheet); + bool isLoading() const; + virtual bool sheetLoaded(); + + bool isAlternate() const { return m_disabledState == 0 && m_alternate; } + bool isDisabled() const { return m_disabledState == 2; } + bool isEnabledViaScript() const { return m_disabledState == 1; } + bool isIcon() const { return m_isIcon; } + + int disabledState() { return m_disabledState; } + void setDisabledState(bool _disabled); + + virtual bool isURLAttribute(Attribute*) const; + + static void tokenizeRelAttribute(const AtomicString& value, bool& stylesheet, bool& alternate, bool& icon, bool& dnsPrefetch); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + + void setCreatedByParser(bool createdByParser) { m_createdByParser = createdByParser; } + virtual void finishParsingChildren(); + +protected: + CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet; + RefPtr<CSSStyleSheet> m_sheet; + String m_url; + String m_type; + String m_media; + int m_disabledState; // 0=unset(default), 1=enabled via script, 2=disabled + bool m_loading; + bool m_alternate; + bool m_isStyleSheet; + bool m_isIcon; + bool m_isDNSPrefetch; + bool m_createdByParser; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLLinkElement.idl b/WebCore/html/HTMLLinkElement.idl new file mode 100644 index 0000000..532ac31 --- /dev/null +++ b/WebCore/html/HTMLLinkElement.idl @@ -0,0 +1,49 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=a9e9ef29-f20b-429d-848e-e5dadd32694a, + ImplementationUUID=2d9b944e-88e3-451a-8640-06c593c339a8 + ] HTMLLinkElement : HTMLElement { + attribute boolean disabled; + attribute [ConvertNullToNullString] DOMString charset; + attribute [ConvertNullToNullString] DOMString href; + attribute [ConvertNullToNullString] DOMString hreflang; + attribute [ConvertNullToNullString] DOMString media; + attribute [ConvertNullToNullString] DOMString rel; + attribute [ConvertNullToNullString] DOMString rev; + attribute [ConvertNullToNullString] DOMString target; + attribute [ConvertNullToNullString] DOMString type; + +#if !defined(LANGUAGE_COM) + // DOM Level 2 Style + readonly attribute StyleSheet sheet; +#endif + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute URL absoluteLinkURL; +#endif + }; + +} diff --git a/WebCore/html/HTMLMapElement.cpp b/WebCore/html/HTMLMapElement.cpp new file mode 100644 index 0000000..891f560 --- /dev/null +++ b/WebCore/html/HTMLMapElement.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 "HTMLMapElement.h" + +#include "Document.h" +#include "HTMLAreaElement.h" +#include "HTMLCollection.h" +#include "HTMLNames.h" +#include "IntSize.h" +#include "HitTestResult.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLMapElement::HTMLMapElement(Document *doc) + : HTMLElement(mapTag, doc) +{ +} + +HTMLMapElement::~HTMLMapElement() +{ + document()->removeImageMap(this); +} + +bool HTMLMapElement::checkDTD(const Node* newChild) +{ + return inEitherTagList(newChild) || newChild->hasTagName(areaTag) // HTML 4 DTD + || newChild->hasTagName(scriptTag); // extensions +} + +bool HTMLMapElement::mapMouseEvent(int x, int y, const IntSize& size, HitTestResult& result) +{ + HTMLAreaElement* defaultArea = 0; + Node *node = this; + while ((node = node->traverseNextNode(this))) { + if (node->hasTagName(areaTag)) { + HTMLAreaElement* areaElt = static_cast<HTMLAreaElement*>(node); + if (areaElt->isDefault()) { + if (!defaultArea) + defaultArea = areaElt; + } else if (areaElt->mapMouseEvent(x, y, size, result)) + return true; + } + } + + if (defaultArea) { + result.setInnerNode(defaultArea); + result.setURLElement(defaultArea); + } + return defaultArea; +} + +void HTMLMapElement::parseMappedAttribute(MappedAttribute* attr) +{ + const QualifiedName& attrName = attr->name(); + if (attrName == idAttr || attrName == nameAttr) { + Document* doc = document(); + if (attrName == idAttr) { + // Call base class so that hasID bit gets set. + HTMLElement::parseMappedAttribute(attr); + if (doc->isHTMLDocument()) + return; + } + doc->removeImageMap(this); + String mapName = attr->value(); + if (mapName[0] == '#') + mapName = mapName.substring(1); + m_name = doc->isHTMLDocument() ? mapName.lower() : mapName; + doc->addImageMap(this); + } else + HTMLElement::parseMappedAttribute(attr); +} + +PassRefPtr<HTMLCollection> HTMLMapElement::areas() +{ + return HTMLCollection::create(this, HTMLCollection::MapAreas); +} + +String HTMLMapElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLMapElement::setName(const String& value) +{ + setAttribute(nameAttr, value); +} + +} diff --git a/WebCore/html/HTMLMapElement.h b/WebCore/html/HTMLMapElement.h new file mode 100644 index 0000000..35e6c28 --- /dev/null +++ b/WebCore/html/HTMLMapElement.h @@ -0,0 +1,61 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004 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 HTMLMapElement_h +#define HTMLMapElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class IntSize; +class HitTestResult; + +class HTMLMapElement : public HTMLElement { +public: + HTMLMapElement(Document*); + ~HTMLMapElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + virtual bool checkDTD(const Node*); + + const AtomicString& getName() const { return m_name; } + + virtual void parseMappedAttribute(MappedAttribute*); + + bool mapMouseEvent(int x, int y, const IntSize&, HitTestResult&); + + PassRefPtr<HTMLCollection> areas(); + + String name() const; + void setName(const String&); + +private: + AtomicString m_name; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLMapElement.idl b/WebCore/html/HTMLMapElement.idl new file mode 100644 index 0000000..9d5db47 --- /dev/null +++ b/WebCore/html/HTMLMapElement.idl @@ -0,0 +1,32 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=8a660b48-4beb-4f9e-855b-e04131eb2519, + ImplementationUUID=7ad57e02-91e5-4761-a1ca-e967188e5e0d + ] HTMLMapElement : HTMLElement { + readonly attribute HTMLCollection areas; + attribute [ConvertNullToNullString] DOMString name; + }; + +} diff --git a/WebCore/html/HTMLMarqueeElement.cpp b/WebCore/html/HTMLMarqueeElement.cpp new file mode 100644 index 0000000..0fd8805 --- /dev/null +++ b/WebCore/html/HTMLMarqueeElement.cpp @@ -0,0 +1,123 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLMarqueeElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" +#include "RenderLayer.h" +#include "RenderMarquee.h" + +namespace WebCore { + +using namespace HTMLNames; + + // WinIE uses 60ms as the minimum delay by default. +const int defaultMinimumDelay = 60; + +HTMLMarqueeElement::HTMLMarqueeElement(Document* doc) + : HTMLElement(marqueeTag, doc) + , m_minimumDelay(defaultMinimumDelay) +{ +} + +bool HTMLMarqueeElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr || + attrName == heightAttr || + attrName == bgcolorAttr || + attrName == vspaceAttr || + attrName == hspaceAttr || + attrName == scrollamountAttr || + attrName == scrolldelayAttr || + attrName == loopAttr || + attrName == behaviorAttr || + attrName == directionAttr) { + result = eUniversal; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLMarqueeElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == widthAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + } else if (attr->name() == heightAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + } else if (attr->name() == bgcolorAttr) { + if (!attr->value().isEmpty()) + addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); + } else if (attr->name() == vspaceAttr) { + if (!attr->value().isEmpty()) { + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + } + } else if (attr->name() == hspaceAttr) { + if (!attr->value().isEmpty()) { + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + } + } else if (attr->name() == scrollamountAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyWebkitMarqueeIncrement, attr->value()); + } else if (attr->name() == scrolldelayAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyWebkitMarqueeSpeed, attr->value()); + } else if (attr->name() == loopAttr) { + if (!attr->value().isEmpty()) { + if (attr->value() == "-1" || equalIgnoringCase(attr->value(), "infinite")) + addCSSProperty(attr, CSSPropertyWebkitMarqueeRepetition, CSSValueInfinite); + else + addCSSLength(attr, CSSPropertyWebkitMarqueeRepetition, attr->value()); + } + } else if (attr->name() == behaviorAttr) { + if (!attr->value().isEmpty()) + addCSSProperty(attr, CSSPropertyWebkitMarqueeStyle, attr->value()); + } else if (attr->name() == directionAttr) { + if (!attr->value().isEmpty()) + addCSSProperty(attr, CSSPropertyWebkitMarqueeDirection, attr->value()); + } else if (attr->name() == truespeedAttr) + m_minimumDelay = !attr->isEmpty() ? 0 : defaultMinimumDelay; + else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLMarqueeElement::start() +{ + if (renderer() && renderer()->hasLayer() && renderer()->layer()->marquee()) + renderer()->layer()->marquee()->start(); +} + +void HTMLMarqueeElement::stop() +{ + if (renderer() && renderer()->hasLayer() && renderer()->layer()->marquee()) + renderer()->layer()->marquee()->stop(); +} + +} // namespace WebCore diff --git a/WebCore/html/HTMLMarqueeElement.h b/WebCore/html/HTMLMarqueeElement.h new file mode 100644 index 0000000..14c0571 --- /dev/null +++ b/WebCore/html/HTMLMarqueeElement.h @@ -0,0 +1,55 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 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 HTMLMarqueeElement_h +#define HTMLMarqueeElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLMarqueeElement : public HTMLElement { +public: + HTMLMarqueeElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 3; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + int minimumDelay() const { return m_minimumDelay; } + + // DOM Functions + + void start(); + void stop(); + +private: + int m_minimumDelay; +}; + +} // namespace WebCore + +#endif // HTMLMarqueeElement_h diff --git a/WebCore/html/HTMLMarqueeElement.idl b/WebCore/html/HTMLMarqueeElement.idl new file mode 100644 index 0000000..eca53db --- /dev/null +++ b/WebCore/html/HTMLMarqueeElement.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=100ca673-eb1e-40b6-8cba-a15abc4cd590, + ImplementationUUID=b9427505-1f10-4299-8b85-4e2891428988 + ] HTMLMarqueeElement : HTMLElement { + void start(); + void stop(); + + // FIXME: Find out what WinIE exposes as attributes. + }; + +} diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp new file mode 100644 index 0000000..f86c44d --- /dev/null +++ b/WebCore/html/HTMLMediaElement.cpp @@ -0,0 +1,1062 @@ +/* + * 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" + +#if ENABLE(VIDEO) +#include "HTMLMediaElement.h" + +#include "CSSHelper.h" +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "Event.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "HTMLDocument.h" +#include "HTMLNames.h" +#include "HTMLSourceElement.h" +#include "HTMLVideoElement.h" +#include <limits> +#include "MediaError.h" +#include "MediaList.h" +#include "MediaQueryEvaluator.h" +#include "MIMETypeRegistry.h" +#include "MediaPlayer.h" +#include "RenderVideo.h" +#include "SystemTime.h" +#include "TimeRanges.h" +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) + , m_loadTimer(this, &HTMLMediaElement::loadTimerFired) + , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired) + , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired) + , m_defaultPlaybackRate(1.0f) + , m_networkState(EMPTY) + , m_readyState(DATA_UNAVAILABLE) + , m_begun(false) + , m_loadedFirstFrame(false) + , m_autoplaying(true) + , m_currentLoop(0) + , m_volume(1.0f) + , m_muted(false) + , m_paused(true) + , m_seeking(false) + , m_currentTimeDuringSeek(0) + , m_previousProgress(0) + , m_previousProgressTime(numeric_limits<double>::max()) + , m_sentStalledEvent(false) + , m_bufferingRate(0) + , m_loadNestingLevel(0) + , m_terminateLoadBelowNestingLevel(0) + , m_pausedInternal(false) + , m_inActiveDocument(true) + , m_player(0) +{ + document()->registerForDocumentActivationCallbacks(this); +} + +HTMLMediaElement::~HTMLMediaElement() +{ + document()->unregisterForDocumentActivationCallbacks(this); +} + +bool HTMLMediaElement::checkDTD(const Node* newChild) +{ + return newChild->hasTagName(sourceTag) || HTMLElement::checkDTD(newChild); +} + +void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls) +{ + HTMLElement::attributeChanged(attr, preserveDecls); + + const QualifiedName& attrName = attr->name(); + if (attrName == srcAttr) { + // 3.14.9.2. + // change to src attribute triggers load() + if (inDocument() && m_networkState == EMPTY) + scheduleLoad(); + } if (attrName == controlsAttr) { + if (!isVideo() && attached() && (controls() != (renderer() != 0))) { + detach(); + attach(); + } + if (renderer()) + renderer()->updateFromElement(); + } +} + +bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style) +{ + return controls() ? HTMLElement::rendererIsNeeded(style) : false; +} + +RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + return new (arena) RenderMedia(this); +} + +void HTMLMediaElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + if (!src().isEmpty()) + scheduleLoad(); +} + +void HTMLMediaElement::removedFromDocument() +{ + // FIXME: pause() may invoke load() which seem like a strange thing to do as a side effect + // of removing an element. This might need to be fixed in the spec. + ExceptionCode ec; + pause(ec); + HTMLElement::removedFromDocument(); +} + +void HTMLMediaElement::attach() +{ + ASSERT(!attached()); + + HTMLElement::attach(); + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::recalcStyle(StyleChange change) +{ + HTMLElement::recalcStyle(change); + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::scheduleLoad() +{ + m_loadTimer.startOneShot(0); +} + +void HTMLMediaElement::initAndDispatchProgressEvent(const AtomicString& eventName) +{ + bool totalKnown = m_player && m_player->totalBytesKnown(); + unsigned loaded = m_player ? m_player->bytesLoaded() : 0; + unsigned total = m_player ? m_player->totalBytes() : 0; + dispatchProgressEvent(eventName, totalKnown, loaded, total); + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::dispatchEventAsync(const AtomicString& eventName) +{ + m_asyncEventsToDispatch.append(eventName); + if (!m_asyncEventTimer.isActive()) + m_asyncEventTimer.startOneShot(0); +} + +void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*) +{ + ExceptionCode ec; + load(ec); +} + +void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*) +{ + Vector<AtomicString> asyncEventsToDispatch; + m_asyncEventsToDispatch.swap(asyncEventsToDispatch); + unsigned count = asyncEventsToDispatch.size(); + for (unsigned n = 0; n < count; ++n) + dispatchEventForType(asyncEventsToDispatch[n], false, true); +} + +String serializeTimeOffset(float time) +{ + String timeString = String::number(time); + // FIXME serialize time offset values properly (format not specified yet) + timeString.append("s"); + return timeString; +} + +float parseTimeOffset(const String& timeString, bool* ok = 0) +{ + const UChar* characters = timeString.characters(); + unsigned length = timeString.length(); + + if (length && characters[length - 1] == 's') + length--; + + // FIXME parse time offset values (format not specified yet) + float val = charactersToFloat(characters, length, ok); + return val; +} + +float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const +{ + bool ok; + String timeString = getAttribute(name); + float result = parseTimeOffset(timeString, &ok); + if (ok) + return result; + return valueOnError; +} + +void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value) +{ + setAttribute(name, serializeTimeOffset(value)); +} + +PassRefPtr<MediaError> HTMLMediaElement::error() const +{ + return m_error; +} + +KURL HTMLMediaElement::src() const +{ + return document()->completeURL(getAttribute(srcAttr)); +} + +void HTMLMediaElement::setSrc(const String& url) +{ + setAttribute(srcAttr, url); +} + +String HTMLMediaElement::currentSrc() const +{ + return m_currentSrc; +} + +HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const +{ + return m_networkState; +} + +float HTMLMediaElement::bufferingRate() +{ + if (!m_player) + return 0; + return m_bufferingRate; + //return m_player->dataRate(); +} + +void HTMLMediaElement::load(ExceptionCode& ec) +{ + String mediaSrc; + + // 3.14.9.4. Loading the media resource + // 1 + // if an event generated during load() ends up re-entering load(), terminate previous instances + m_loadNestingLevel++; + m_terminateLoadBelowNestingLevel = m_loadNestingLevel; + + m_progressEventTimer.stop(); + m_sentStalledEvent = false; + m_bufferingRate = 0; + + m_loadTimer.stop(); + + // 2 + if (m_begun) { + m_begun = false; + m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED); + initAndDispatchProgressEvent(eventNames().abortEvent); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + goto end; + } + + // 3 + m_error = 0; + m_loadedFirstFrame = false; + m_autoplaying = true; + + // 4 + setPlaybackRate(defaultPlaybackRate(), ec); + + // 5 + if (networkState() != EMPTY) { + m_networkState = EMPTY; + m_readyState = DATA_UNAVAILABLE; + m_paused = true; + m_seeking = false; + if (m_player) { + m_player->pause(); + m_player->seek(0); + } + m_currentLoop = 0; + dispatchEventForType(eventNames().emptiedEvent, false, true); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + goto end; + } + + // 6 + mediaSrc = pickMedia(); + if (mediaSrc.isEmpty()) { + ec = INVALID_STATE_ERR; + goto end; + } + + // 7 + m_networkState = LOADING; + + // 8 + m_currentSrc = mediaSrc; + + // 9 + m_begun = true; + dispatchProgressEvent(eventNames().loadstartEvent, false, 0, 0); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + goto end; + + // 10, 11, 12, 13 + m_player.clear(); + m_player.set(new MediaPlayer(this)); + updateVolume(); + m_player->load(m_currentSrc); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + goto end; + + if (renderer()) + renderer()->updateFromElement(); + + // 14 + m_previousProgressTime = WebCore::currentTime(); + m_previousProgress = 0; + if (m_begun) + // 350ms is not magic, it is in the spec! + m_progressEventTimer.startRepeating(0.350); +end: + ASSERT(m_loadNestingLevel); + m_loadNestingLevel--; +} + +void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*) +{ + if (!m_begun || m_networkState == EMPTY) + return; + + m_terminateLoadBelowNestingLevel = m_loadNestingLevel; + + MediaPlayer::NetworkState state = m_player->networkState(); + + // 3.14.9.4. Loading the media resource + // 14 + if (state == MediaPlayer::LoadFailed) { + //delete m_player; + //m_player = 0; + // FIXME better error handling + m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK); + m_begun = false; + m_progressEventTimer.stop(); + m_bufferingRate = 0; + + initAndDispatchProgressEvent(eventNames().errorEvent); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + + m_networkState = EMPTY; + + if (isVideo()) + static_cast<HTMLVideoElement*>(this)->updatePosterImage(); + + dispatchEventForType(eventNames().emptiedEvent, false, true); + return; + } + + if (state >= MediaPlayer::Loading && m_networkState < LOADING) + m_networkState = LOADING; + + if (state >= MediaPlayer::LoadedMetaData && m_networkState < LOADED_METADATA) { + m_player->seek(effectiveStart()); + m_networkState = LOADED_METADATA; + + dispatchEventForType(eventNames().durationchangeEvent, false, true); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + + dispatchEventForType(eventNames().loadedmetadataEvent, false, true); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + } + + if (state >= MediaPlayer::LoadedFirstFrame && m_networkState < LOADED_FIRST_FRAME) { + m_networkState = LOADED_FIRST_FRAME; + + setReadyState(CAN_SHOW_CURRENT_FRAME); + + if (isVideo()) + static_cast<HTMLVideoElement*>(this)->updatePosterImage(); + + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + + m_loadedFirstFrame = true; + if (renderer()) { + ASSERT(!renderer()->isImage()); + static_cast<RenderVideo*>(renderer())->videoSizeChanged(); + } + + dispatchEventForType(eventNames().loadedfirstframeEvent, false, true); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + + dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true); + if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) + return; + } + + // 15 + if (state == MediaPlayer::Loaded && m_networkState < LOADED) { + m_begun = false; + m_networkState = LOADED; + m_progressEventTimer.stop(); + m_bufferingRate = 0; + initAndDispatchProgressEvent(eventNames().loadEvent); + } +} + +void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*) +{ + MediaPlayer::ReadyState state = m_player->readyState(); + setReadyState((ReadyState)state); +} + +void HTMLMediaElement::setReadyState(ReadyState state) +{ + // 3.14.9.6. The ready states + if (m_readyState == state) + return; + + bool wasActivelyPlaying = activelyPlaying(); + m_readyState = state; + + if (state >= CAN_PLAY) + m_seeking = false; + + if (networkState() == EMPTY) + return; + + if (state == DATA_UNAVAILABLE) { + dispatchEventForType(eventNames().dataunavailableEvent, false, true); + if (wasActivelyPlaying) { + dispatchEventForType(eventNames().timeupdateEvent, false, true); + dispatchEventForType(eventNames().waitingEvent, false, true); + } + } else if (state == CAN_SHOW_CURRENT_FRAME) { + if (m_loadedFirstFrame) + dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true); + if (wasActivelyPlaying) { + dispatchEventForType(eventNames().timeupdateEvent, false, true); + dispatchEventForType(eventNames().waitingEvent, false, true); + } + } else if (state == CAN_PLAY) { + dispatchEventForType(eventNames().canplayEvent, false, true); + } else if (state == CAN_PLAY_THROUGH) { + dispatchEventForType(eventNames().canplaythroughEvent, false, true); + if (m_autoplaying && m_paused && autoplay()) { + m_paused = false; + dispatchEventForType(eventNames().playEvent, false, true); + } + } + updatePlayState(); +} + +void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*) +{ + ASSERT(m_player); + unsigned progress = m_player->bytesLoaded(); + double time = WebCore::currentTime(); + double timedelta = time - m_previousProgressTime; + if (timedelta) + m_bufferingRate = (float)(0.8 * m_bufferingRate + 0.2 * ((float)(progress - m_previousProgress)) / timedelta); + + if (progress == m_previousProgress) { + if (timedelta > 3.0 && !m_sentStalledEvent) { + m_bufferingRate = 0; + initAndDispatchProgressEvent(eventNames().stalledEvent); + m_sentStalledEvent = true; + } + } else { + initAndDispatchProgressEvent(eventNames().progressEvent); + m_previousProgress = progress; + m_previousProgressTime = time; + m_sentStalledEvent = false; + } +} + +void HTMLMediaElement::seek(float time, ExceptionCode& ec) +{ + // 3.14.9.8. Seeking + // 1 + if (networkState() < LOADED_METADATA) { + ec = INVALID_STATE_ERR; + return; + } + + // 2 + float minTime; + if (currentLoop() == 0) + minTime = effectiveStart(); + else + minTime = effectiveLoopStart(); + + // 3 + float maxTime = currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd(); + + // 4 + time = min(time, maxTime); + + // 5 + time = max(time, minTime); + + // 6 + RefPtr<TimeRanges> seekableRanges = seekable(); + if (!seekableRanges->contain(time)) { + ec = INDEX_SIZE_ERR; + return; + } + + // 7 + m_currentTimeDuringSeek = time; + + // 8 + m_seeking = true; + + // 9 + dispatchEventForType(eventNames().timeupdateEvent, false, true); + + // 10 + // As soon as the user agent has established whether or not the media data for the new playback position is available, + // and, if it is, decoded enough data to play back that position, the seeking DOM attribute must be set to false. + if (m_player) { + m_player->setEndTime(maxTime); + m_player->seek(time); + } +} + +HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const +{ + return m_readyState; +} + +bool HTMLMediaElement::seeking() const +{ + return m_seeking; +} + +// playback state +float HTMLMediaElement::currentTime() const +{ + if (!m_player) + return 0; + if (m_seeking) + return m_currentTimeDuringSeek; + return m_player->currentTime(); +} + +void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec) +{ + seek(time, ec); +} + +float HTMLMediaElement::duration() const +{ + return m_player ? m_player->duration() : 0; +} + +bool HTMLMediaElement::paused() const +{ + return m_paused; +} + +float HTMLMediaElement::defaultPlaybackRate() const +{ + return m_defaultPlaybackRate; +} + +void HTMLMediaElement::setDefaultPlaybackRate(float rate, ExceptionCode& ec) +{ + if (rate == 0.0f) { + ec = NOT_SUPPORTED_ERR; + return; + } + if (m_defaultPlaybackRate != rate) { + m_defaultPlaybackRate = rate; + dispatchEventAsync(eventNames().ratechangeEvent); + } +} + +float HTMLMediaElement::playbackRate() const +{ + return m_player ? m_player->rate() : 0; +} + +void HTMLMediaElement::setPlaybackRate(float rate, ExceptionCode& ec) +{ + if (rate == 0.0f) { + ec = NOT_SUPPORTED_ERR; + return; + } + if (m_player && m_player->rate() != rate) { + m_player->setRate(rate); + dispatchEventAsync(eventNames().ratechangeEvent); + } +} + +bool HTMLMediaElement::ended() const +{ + return endedPlayback(); +} + +bool HTMLMediaElement::autoplay() const +{ + return hasAttribute(autoplayAttr); +} + +void HTMLMediaElement::setAutoplay(bool b) +{ + setBooleanAttribute(autoplayAttr, b); +} + +void HTMLMediaElement::play(ExceptionCode& ec) +{ + // 3.14.9.7. Playing the media resource + if (!m_player || networkState() == EMPTY) { + ec = 0; + load(ec); + if (ec) + return; + } + ExceptionCode unused; + if (endedPlayback()) { + m_currentLoop = 0; + seek(effectiveStart(), unused); + } + setPlaybackRate(defaultPlaybackRate(), unused); + + if (m_paused) { + m_paused = false; + dispatchEventAsync(eventNames().playEvent); + } + + m_autoplaying = false; + + updatePlayState(); +} + +void HTMLMediaElement::pause(ExceptionCode& ec) +{ + // 3.14.9.7. Playing the media resource + if (!m_player || networkState() == EMPTY) { + ec = 0; + load(ec); + if (ec) + return; + } + + if (!m_paused) { + m_paused = true; + dispatchEventAsync(eventNames().timeupdateEvent); + dispatchEventAsync(eventNames().pauseEvent); + } + + m_autoplaying = false; + + updatePlayState(); +} + +unsigned HTMLMediaElement::playCount() const +{ + bool ok; + unsigned count = getAttribute(playcountAttr).string().toUInt(&ok); + return (count > 0 && ok) ? count : 1; +} + +void HTMLMediaElement::setPlayCount(unsigned count, ExceptionCode& ec) +{ + if (!count) { + ec = INDEX_SIZE_ERR; + return; + } + setAttribute(playcountAttr, String::number(count)); + checkIfSeekNeeded(); +} + +float HTMLMediaElement::start() const +{ + return getTimeOffsetAttribute(startAttr, 0); +} + +void HTMLMediaElement::setStart(float time) +{ + setTimeOffsetAttribute(startAttr, time); + checkIfSeekNeeded(); +} + +float HTMLMediaElement::end() const +{ + return getTimeOffsetAttribute(endAttr, std::numeric_limits<float>::infinity()); +} + +void HTMLMediaElement::setEnd(float time) +{ + setTimeOffsetAttribute(endAttr, time); + checkIfSeekNeeded(); +} + +float HTMLMediaElement::loopStart() const +{ + return getTimeOffsetAttribute(loopstartAttr, start()); +} + +void HTMLMediaElement::setLoopStart(float time) +{ + setTimeOffsetAttribute(loopstartAttr, time); + checkIfSeekNeeded(); +} + +float HTMLMediaElement::loopEnd() const +{ + return getTimeOffsetAttribute(loopendAttr, end()); +} + +void HTMLMediaElement::setLoopEnd(float time) +{ + setTimeOffsetAttribute(loopendAttr, time); + checkIfSeekNeeded(); +} + +unsigned HTMLMediaElement::currentLoop() const +{ + return m_currentLoop; +} + +void HTMLMediaElement::setCurrentLoop(unsigned currentLoop) +{ + m_currentLoop = currentLoop; +} + +bool HTMLMediaElement::controls() const +{ + return hasAttribute(controlsAttr); +} + +void HTMLMediaElement::setControls(bool b) +{ + setBooleanAttribute(controlsAttr, b); +} + +float HTMLMediaElement::volume() const +{ + return m_volume; +} + +void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec) +{ + if (vol < 0.0f || vol > 1.0f) { + ec = INDEX_SIZE_ERR; + return; + } + + if (m_volume != vol) { + m_volume = vol; + updateVolume(); + dispatchEventAsync(eventNames().volumechangeEvent); + } +} + +bool HTMLMediaElement::muted() const +{ + return m_muted; +} + +void HTMLMediaElement::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + updateVolume(); + dispatchEventAsync(eventNames().volumechangeEvent); + } +} + +bool HTMLMediaElement::canPlay() const +{ + return paused() || ended() || networkState() < LOADED_METADATA; +} + +String HTMLMediaElement::pickMedia() +{ + // 3.14.9.2. Location of the media resource + String mediaSrc = getAttribute(srcAttr); + if (mediaSrc.isEmpty()) { + for (Node* n = firstChild(); n; n = n->nextSibling()) { + if (n->hasTagName(sourceTag)) { + HTMLSourceElement* source = static_cast<HTMLSourceElement*>(n); + if (!source->hasAttribute(srcAttr)) + continue; + if (source->hasAttribute(mediaAttr)) { + MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0); + RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media()); + if (!screenEval.eval(media.get())) + continue; + } + if (source->hasAttribute(typeAttr)) { + String type = source->type().stripWhiteSpace(); + + // "type" can have parameters after a semi-colon, strip them before checking with the type registry + int semi = type.find(';'); + if (semi != -1) + type = type.left(semi).stripWhiteSpace(); + + if (!MIMETypeRegistry::isSupportedMediaMIMEType(type)) + continue; + } + mediaSrc = source->src().string(); + break; + } + } + } + if (!mediaSrc.isEmpty()) + mediaSrc = document()->completeURL(mediaSrc).string(); + return mediaSrc; +} + +void HTMLMediaElement::checkIfSeekNeeded() +{ + // 3.14.9.5. Offsets into the media resource + // 1 + if (playCount() <= m_currentLoop) + m_currentLoop = playCount() - 1; + + // 2 + if (networkState() <= LOADING) + return; + + // 3 + ExceptionCode ec; + float time = currentTime(); + if (!m_currentLoop && time < effectiveStart()) + seek(effectiveStart(), ec); + + // 4 + if (m_currentLoop && time < effectiveLoopStart()) + seek(effectiveLoopStart(), ec); + + // 5 + if (m_currentLoop < playCount() - 1 && time > effectiveLoopEnd()) { + seek(effectiveLoopStart(), ec); + m_currentLoop++; + } + + // 6 + if (m_currentLoop == playCount() - 1 && time > effectiveEnd()) + seek(effectiveEnd(), ec); + + updatePlayState(); +} + +void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) +{ + if (readyState() >= CAN_PLAY) + m_seeking = false; + + if (m_currentLoop < playCount() - 1 && currentTime() >= effectiveLoopEnd()) { + ExceptionCode ec; + seek(effectiveLoopStart(), ec); + m_currentLoop++; + dispatchEventForType(eventNames().timeupdateEvent, false, true); + } + + if (m_currentLoop == playCount() - 1 && currentTime() >= effectiveEnd()) { + dispatchEventForType(eventNames().timeupdateEvent, false, true); + dispatchEventForType(eventNames().endedEvent, false, true); + } + + updatePlayState(); +} + +void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*) +{ + if (renderer()) + renderer()->repaint(); +} + +PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const +{ + // FIXME real ranges support + if (!m_player || !m_player->maxTimeBuffered()) + return TimeRanges::create(); + return TimeRanges::create(0, m_player->maxTimeBuffered()); +} + +PassRefPtr<TimeRanges> HTMLMediaElement::played() const +{ + // FIXME track played + return TimeRanges::create(); +} + +PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const +{ + // FIXME real ranges support + if (!m_player || !m_player->maxTimeSeekable()) + return TimeRanges::create(); + return TimeRanges::create(0, m_player->maxTimeSeekable()); +} + +float HTMLMediaElement::effectiveStart() const +{ + if (!m_player) + return 0; + return min(start(), m_player->duration()); +} + +float HTMLMediaElement::effectiveEnd() const +{ + if (!m_player) + return 0; + return min(max(end(), max(start(), loopStart())), m_player->duration()); +} + +float HTMLMediaElement::effectiveLoopStart() const +{ + if (!m_player) + return 0; + return min(loopStart(), m_player->duration()); +} + +float HTMLMediaElement::effectiveLoopEnd() const +{ + if (!m_player) + return 0; + return min(max(start(), max(loopStart(), loopEnd())), m_player->duration()); +} + +bool HTMLMediaElement::activelyPlaying() const +{ + return !paused() && readyState() >= CAN_PLAY && !endedPlayback(); // && !stoppedDueToErrors() && !pausedForUserInteraction(); +} + +bool HTMLMediaElement::endedPlayback() const +{ + return networkState() >= LOADED_METADATA && currentTime() >= effectiveEnd() && currentLoop() == playCount() - 1; +} + +void HTMLMediaElement::updateVolume() +{ + if (!m_player) + return; + + m_player->setVolume(m_muted ? 0 : m_volume); + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::updatePlayState() +{ + if (!m_player) + return; + + if (m_pausedInternal) { + if (!m_player->paused()) + m_player->pause(); + return; + } + + m_player->setEndTime(currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd()); + + bool shouldBePlaying = activelyPlaying() && currentTime() < effectiveEnd(); + if (shouldBePlaying && m_player->paused()) + m_player->play(); + else if (!shouldBePlaying && !m_player->paused()) + m_player->pause(); + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::setPausedInternal(bool b) +{ + m_pausedInternal = b; + updatePlayState(); +} + +void HTMLMediaElement::documentWillBecomeInactive() +{ + // 3.14.9.4. Loading the media resource + // 14 + if (m_begun) { + // For simplicity cancel the incomplete load by deleting the player + m_player.clear(); + m_progressEventTimer.stop(); + + m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED); + m_begun = false; + initAndDispatchProgressEvent(eventNames().abortEvent); + if (m_networkState >= LOADING) { + m_networkState = EMPTY; + m_readyState = DATA_UNAVAILABLE; + dispatchEventForType(eventNames().emptiedEvent, false, true); + } + } + m_inActiveDocument = false; + // Stop the playback without generating events + setPausedInternal(true); + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::documentDidBecomeActive() +{ + m_inActiveDocument = true; + setPausedInternal(false); + + if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) { + // Restart the load if it was aborted in the middle by moving the document to the page cache. + // This behavior is not specified but it seems like a sensible thing to do. + ExceptionCode ec; + load(ec); + } + + if (renderer()) + renderer()->updateFromElement(); +} + +void HTMLMediaElement::defaultEventHandler(Event* event) +{ + if (renderer() && renderer()->isMedia()) + static_cast<RenderMedia*>(renderer())->forwardEvent(event); + if (event->defaultHandled()) + return; + HTMLElement::defaultEventHandler(event); +} + +} + +#endif diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h new file mode 100644 index 0000000..27fac2f --- /dev/null +++ b/WebCore/html/HTMLMediaElement.h @@ -0,0 +1,211 @@ +/* + * 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 HTMLMediaElement_h +#define HTMLMediaElement_h + +#if ENABLE(VIDEO) + +#include "HTMLElement.h" +#include "MediaPlayer.h" +#include "Timer.h" +#include "VoidCallback.h" + +namespace WebCore { + +class MediaError; +class TimeRanges; +class KURL; + +class HTMLMediaElement : public HTMLElement, public MediaPlayerClient { +public: + HTMLMediaElement(const QualifiedName&, Document*); + virtual ~HTMLMediaElement(); + + bool checkDTD(const Node* newChild); + + void attributeChanged(Attribute*, bool preserveDecls); + + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void attach(); + virtual void recalcStyle(StyleChange); + + MediaPlayer* player() const { return m_player.get(); } + + virtual bool isVideo() const { return false; } + + void scheduleLoad(); + + virtual void defaultEventHandler(Event*); + + // Pauses playback without changing any states or generating events + void setPausedInternal(bool); + + bool inActiveDocument() const { return m_inActiveDocument; } + +// DOM API +// error state + PassRefPtr<MediaError> error() const; + +// network state + KURL src() const; + void setSrc(const String&); + String currentSrc() const; + + enum NetworkState { EMPTY, LOADING, LOADED_METADATA, LOADED_FIRST_FRAME, LOADED }; + NetworkState networkState() const; + float bufferingRate(); + PassRefPtr<TimeRanges> buffered() const; + void load(ExceptionCode&); + +// ready state + enum ReadyState { DATA_UNAVAILABLE, CAN_SHOW_CURRENT_FRAME, CAN_PLAY, CAN_PLAY_THROUGH }; + ReadyState readyState() const; + bool seeking() const; + +// playback state + float currentTime() const; + void setCurrentTime(float, ExceptionCode&); + float duration() const; + bool paused() const; + float defaultPlaybackRate() const; + void setDefaultPlaybackRate(float, ExceptionCode&); + float playbackRate() const; + void setPlaybackRate(float, ExceptionCode&); + PassRefPtr<TimeRanges> played() const; + PassRefPtr<TimeRanges> seekable() const; + bool ended() const; + bool autoplay() const; + void setAutoplay(bool b); + void play(ExceptionCode&); + void pause(ExceptionCode&); + +// looping + float start() const; + void setStart(float time); + float end() const; + void setEnd(float time); + float loopStart() const; + void setLoopStart(float time); + float loopEnd() const; + void setLoopEnd(float time); + unsigned playCount() const; + void setPlayCount(unsigned, ExceptionCode&); + unsigned currentLoop() const; + void setCurrentLoop(unsigned); + +// controls + bool controls() const; + void setControls(bool); + float volume() const; + void setVolume(float, ExceptionCode&); + bool muted() const; + void setMuted(bool); + + bool canPlay() const; + +protected: + float getTimeOffsetAttribute(const QualifiedName&, float valueOnError) const; + void setTimeOffsetAttribute(const QualifiedName&, float value); + + virtual void documentWillBecomeInactive(); + virtual void documentDidBecomeActive(); + + void initAndDispatchProgressEvent(const AtomicString& eventName); + void dispatchEventAsync(const AtomicString& eventName); + + void setReadyState(ReadyState); + +private: // MediaPlayerObserver + virtual void mediaPlayerNetworkStateChanged(MediaPlayer*); + virtual void mediaPlayerReadyStateChanged(MediaPlayer*); + virtual void mediaPlayerTimeChanged(MediaPlayer*); + virtual void mediaPlayerRepaint(MediaPlayer*); + +private: + void loadTimerFired(Timer<HTMLMediaElement>*); + void asyncEventTimerFired(Timer<HTMLMediaElement>*); + void progressEventTimerFired(Timer<HTMLMediaElement>*); + void seek(float time, ExceptionCode& ec); + void checkIfSeekNeeded(); + + String pickMedia(); + void updateVolume(); + void updatePlayState(); + float effectiveStart() const; + float effectiveEnd() const; + float effectiveLoopStart() const; + float effectiveLoopEnd() const; + bool activelyPlaying() const; + bool endedPlayback() const; + +protected: + Timer<HTMLMediaElement> m_loadTimer; + Timer<HTMLMediaElement> m_asyncEventTimer; + Timer<HTMLMediaElement> m_progressEventTimer; + Vector<AtomicString> m_asyncEventsToDispatch; + + float m_defaultPlaybackRate; + NetworkState m_networkState; + ReadyState m_readyState; + String m_currentSrc; + + RefPtr<MediaError> m_error; + + bool m_begun; + bool m_loadedFirstFrame; + bool m_autoplaying; + + unsigned m_currentLoop; + float m_volume; + bool m_muted; + + bool m_paused; + bool m_seeking; + + float m_currentTimeDuringSeek; + + unsigned m_previousProgress; + double m_previousProgressTime; + bool m_sentStalledEvent; + + float m_bufferingRate; + + unsigned m_loadNestingLevel; + unsigned m_terminateLoadBelowNestingLevel; + + bool m_pausedInternal; + bool m_inActiveDocument; + + OwnPtr<MediaPlayer> m_player; +}; + +} //namespace + +#endif +#endif diff --git a/WebCore/html/HTMLMediaElement.idl b/WebCore/html/HTMLMediaElement.idl new file mode 100644 index 0000000..1e3eb90 --- /dev/null +++ b/WebCore/html/HTMLMediaElement.idl @@ -0,0 +1,88 @@ +/* + * Copyright (C) 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 html { +interface [GenerateConstructor, Conditional=VIDEO] HTMLMediaElement : HTMLElement { + + // error state + readonly attribute MediaError error; + + // network state + attribute DOMString src; + readonly attribute DOMString currentSrc; + + const unsigned short EMPTY = 0; + const unsigned short LOADING = 1; + const unsigned short LOADED_METADATA = 2; + const unsigned short LOADED_FIRST_FRAME = 3; + const unsigned short LOADED = 4; + readonly attribute unsigned short networkState; + readonly attribute float bufferingRate; + readonly attribute TimeRanges buffered; + void load() + raises (DOMException); + + // ready state + const unsigned short DATA_UNAVAILABLE = 0; + const unsigned short CAN_SHOW_CURRENT_FRAME = 1; + const unsigned short CAN_PLAY = 2; + const unsigned short CAN_PLAY_THROUGH = 3; + readonly attribute unsigned short readyState; + readonly attribute boolean seeking; + + // playback state + attribute float currentTime + setter raises (DOMException); + readonly attribute float duration; + readonly attribute boolean paused; + attribute float defaultPlaybackRate + setter raises (DOMException); + attribute float playbackRate + setter raises (DOMException); + readonly attribute TimeRanges played; + readonly attribute TimeRanges seekable; + readonly attribute boolean ended; + attribute boolean autoplay; + void play() + raises (DOMException); + void pause() + raises (DOMException); + + // looping + attribute float start; + attribute float end; + attribute float loopStart; + attribute float loopEnd; + attribute unsigned long playCount + setter raises (DOMException); + attribute unsigned long currentLoop; + + // controls + attribute boolean controls; + attribute float volume + setter raises (DOMException); + attribute boolean muted; +}; +} diff --git a/WebCore/html/HTMLMenuElement.cpp b/WebCore/html/HTMLMenuElement.cpp new file mode 100644 index 0000000..78e2109 --- /dev/null +++ b/WebCore/html/HTMLMenuElement.cpp @@ -0,0 +1,47 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ +#include "config.h" +#include "HTMLMenuElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLMenuElement::HTMLMenuElement(Document* doc) + : HTMLElement(HTMLNames::menuTag, doc) +{ +} + +bool HTMLMenuElement::compact() const +{ + return !getAttribute(compactAttr).isNull(); +} + +void HTMLMenuElement::setCompact(bool b) +{ + setAttribute(compactAttr, b ? "" : 0); +} + +} diff --git a/WebCore/html/HTMLMenuElement.h b/WebCore/html/HTMLMenuElement.h new file mode 100644 index 0000000..4032cf2 --- /dev/null +++ b/WebCore/html/HTMLMenuElement.h @@ -0,0 +1,45 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLMenuElement_h +#define HTMLMenuElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLMenuElement : public HTMLElement +{ +public: + HTMLMenuElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + bool compact() const; + void setCompact(bool); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLMenuElement.idl b/WebCore/html/HTMLMenuElement.idl new file mode 100644 index 0000000..4c2701a --- /dev/null +++ b/WebCore/html/HTMLMenuElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=fb353af6-4927-4512-ad43-4ad8191b5615, + ImplementationUUID=ec26257c-a2a4-43dc-b234-cf644d22b1fb + ] HTMLMenuElement : HTMLElement { + attribute boolean compact; + }; + +} diff --git a/WebCore/html/HTMLMetaElement.cpp b/WebCore/html/HTMLMetaElement.cpp new file mode 100644 index 0000000..f2b5c4a --- /dev/null +++ b/WebCore/html/HTMLMetaElement.cpp @@ -0,0 +1,117 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003 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 "HTMLMetaElement.h" + +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLMetaElement::HTMLMetaElement(Document* doc) + : HTMLElement(metaTag, doc) +{ +} + +HTMLMetaElement::~HTMLMetaElement() +{ +} + +void HTMLMetaElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == http_equivAttr) { + m_equiv = attr->value(); + process(); + } else if (attr->name() == contentAttr) { + m_content = attr->value(); + process(); + } else if (attr->name() == nameAttr) { + // Do nothing. + } else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLMetaElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + process(); +} + +void HTMLMetaElement::process() +{ +#ifdef ANDROID_META_SUPPORT + if (!inDocument() || m_content.isNull()) + return; + if (equalIgnoringCase(name(), "viewport") || equalIgnoringCase(name(), "format-detection")) + document()->processMetadataSettings(m_content); +#endif + // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while + // it's not in the tree shouldn't have any effect on the document) + if (inDocument() && !m_equiv.isNull() && !m_content.isNull()) + document()->processHttpEquiv(m_equiv, m_content); +} + +String HTMLMetaElement::content() const +{ + return getAttribute(contentAttr); +} + +void HTMLMetaElement::setContent(const String& value) +{ + setAttribute(contentAttr, value); +} + +String HTMLMetaElement::httpEquiv() const +{ + return getAttribute(http_equivAttr); +} + +void HTMLMetaElement::setHttpEquiv(const String& value) +{ + setAttribute(http_equivAttr, value); +} + +String HTMLMetaElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLMetaElement::setName(const String& value) +{ + setAttribute(nameAttr, value); +} + +String HTMLMetaElement::scheme() const +{ + return getAttribute(schemeAttr); +} + +void HTMLMetaElement::setScheme(const String &value) +{ + setAttribute(schemeAttr, value); +} + +} diff --git a/WebCore/html/HTMLMetaElement.h b/WebCore/html/HTMLMetaElement.h new file mode 100644 index 0000000..e55cd9f --- /dev/null +++ b/WebCore/html/HTMLMetaElement.h @@ -0,0 +1,64 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 HTMLMetaElement_h +#define HTMLMetaElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLMetaElement : public HTMLElement +{ +public: + HTMLMetaElement(Document*); + ~HTMLMetaElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void parseMappedAttribute(MappedAttribute*); + virtual void insertedIntoDocument(); + + void process(); + + String content() const; + void setContent(const String&); + + String httpEquiv() const; + void setHttpEquiv(const String&); + + String name() const; + void setName(const String&); + + String scheme() const; + void setScheme(const String&); + +protected: + String m_equiv; + String m_content; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLMetaElement.idl b/WebCore/html/HTMLMetaElement.idl new file mode 100644 index 0000000..2c350c9 --- /dev/null +++ b/WebCore/html/HTMLMetaElement.idl @@ -0,0 +1,33 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=65e3374d-4789-4c81-983b-1b5a29d2c075, + ImplementationUUID=a9ac9c73-055d-4c00-bd02-1fa215ae32f1 + ] HTMLMetaElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString content; + attribute [ConvertNullToNullString] DOMString httpEquiv; + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString scheme; + }; + +} diff --git a/WebCore/html/HTMLModElement.cpp b/WebCore/html/HTMLModElement.cpp new file mode 100644 index 0000000..b48182a --- /dev/null +++ b/WebCore/html/HTMLModElement.cpp @@ -0,0 +1,58 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 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 "HTMLModElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLModElement::HTMLModElement(const QualifiedName& tagName, Document *doc) + : HTMLElement(tagName, doc) +{ +} + +String HTMLModElement::cite() const +{ + return getAttribute(citeAttr); +} + +void HTMLModElement::setCite(const String& value) +{ + setAttribute(citeAttr, value); +} + +String HTMLModElement::dateTime() const +{ + return getAttribute(datetimeAttr); +} + +void HTMLModElement::setDateTime(const String& value) +{ + setAttribute(datetimeAttr, value); +} + +} diff --git a/WebCore/html/HTMLModElement.h b/WebCore/html/HTMLModElement.h new file mode 100644 index 0000000..399053c --- /dev/null +++ b/WebCore/html/HTMLModElement.h @@ -0,0 +1,50 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ +#ifndef HTMLModElement_h +#define HTMLModElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class String; + +class HTMLModElement : public HTMLElement +{ +public: + HTMLModElement(const QualifiedName&, Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + String cite() const; + void setCite(const String&); + + String dateTime() const; + void setDateTime(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLModElement.idl b/WebCore/html/HTMLModElement.idl new file mode 100644 index 0000000..a22b7b4 --- /dev/null +++ b/WebCore/html/HTMLModElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=78c2bf89-c6e7-4d81-97df-429d07b91ff8, + ImplementationUUID=39e7c659-40be-4620-949b-15ec6a25bb90 + ] HTMLModElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString cite; + attribute [ConvertNullToNullString] DOMString dateTime; + }; + +} diff --git a/WebCore/html/HTMLNameCollection.cpp b/WebCore/html/HTMLNameCollection.cpp new file mode 100644 index 0000000..fdebe78 --- /dev/null +++ b/WebCore/html/HTMLNameCollection.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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 "HTMLNameCollection.h" + +#include "Element.h" +#include "HTMLDocument.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLNameCollection::HTMLNameCollection(PassRefPtr<Document> document, Type type, const String& name) + : HTMLCollection(document.get(), type, document->nameCollectionInfo(type, name)) + , m_name(name) +{ +} + +Element* HTMLNameCollection::itemAfter(Element* previous) const +{ + ASSERT(previous != base()); + + Node* current; + if (!previous) + current = base()->firstChild(); + else + current = previous->traverseNextNode(base()); + + for (; current; current = current->traverseNextNode(base())) { + if (!current->isElementNode()) + continue; + Element* e = static_cast<Element*>(current); + switch (type()) { + case WindowNamedItems: + // find only images, forms, applets, embeds and objects by name, + // but anything by id + if (e->hasTagName(imgTag) || + e->hasTagName(formTag) || + e->hasTagName(appletTag) || + e->hasTagName(embedTag) || + e->hasTagName(objectTag)) + if (e->getAttribute(nameAttr) == m_name) + return e; + if (e->getAttribute(idAttr) == m_name) + return e; + break; + case DocumentNamedItems: + // find images, forms, applets, embeds, objects and iframes by name, + // applets and object by id, and images by id but only if they have + // a name attribute (this very strange rule matches IE) + if (e->hasTagName(formTag) || e->hasTagName(embedTag) || e->hasTagName(iframeTag)) { + if (e->getAttribute(nameAttr) == m_name) + return e; + } else if (e->hasTagName(appletTag)) { + if (e->getAttribute(nameAttr) == m_name || e->getAttribute(idAttr) == m_name) + return e; + } else if (e->hasTagName(objectTag)) { + if ((e->getAttribute(nameAttr) == m_name || e->getAttribute(idAttr) == m_name) + && static_cast<HTMLObjectElement*>(e)->isDocNamedItem()) + return e; + } else if (e->hasTagName(imgTag)) { + if (e->getAttribute(nameAttr) == m_name || (e->getAttribute(idAttr) == m_name && e->hasAttribute(nameAttr))) + return e; + } + break; + default: + ASSERT_NOT_REACHED(); + } + } + + return 0; +} + +} diff --git a/WebCore/html/HTMLNameCollection.h b/WebCore/html/HTMLNameCollection.h new file mode 100644 index 0000000..9add926 --- /dev/null +++ b/WebCore/html/HTMLNameCollection.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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. + * + */ + +#ifndef HTMLNameCollection_h +#define HTMLNameCollection_h + +#include "HTMLCollection.h" +#include "PlatformString.h" + +namespace WebCore { + +class Document; + +class HTMLNameCollection : public HTMLCollection { +public: + static PassRefPtr<HTMLNameCollection> create(PassRefPtr<Document> document, Type type, const String& name) + { + return adoptRef(new HTMLNameCollection(document, type, name)); + } + +private: + HTMLNameCollection(PassRefPtr<Document>, Type, const String& name); + + virtual Element* itemAfter(Element*) const; + + String m_name; +}; + +} + +#endif diff --git a/WebCore/html/HTMLOListElement.cpp b/WebCore/html/HTMLOListElement.cpp new file mode 100644 index 0000000..a37d4ef --- /dev/null +++ b/WebCore/html/HTMLOListElement.cpp @@ -0,0 +1,100 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ +#include "config.h" +#include "HTMLOListElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" +#include "RenderListItem.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLOListElement::HTMLOListElement(Document* doc) + : HTMLElement(HTMLNames::olTag, doc) + , m_start(1) +{ +} + +bool HTMLOListElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == typeAttr) { + result = eListItem; // Share with <li> + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLOListElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == typeAttr) { + if (attr->value() == "a") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueLowerAlpha); + else if (attr->value() == "A") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueUpperAlpha); + else if (attr->value() == "i") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueLowerRoman); + else if (attr->value() == "I") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueUpperRoman); + else if (attr->value() == "1") + addCSSProperty(attr, CSSPropertyListStyleType, CSSValueDecimal); + } else if (attr->name() == startAttr) { + int s = !attr->isNull() ? attr->value().toInt() : 1; + if (s != m_start) { + m_start = s; + for (RenderObject* r = renderer(); r; r = r->nextInPreOrder(renderer())) + if (r->isListItem()) + static_cast<RenderListItem*>(r)->updateValue(); + } + } else + HTMLElement::parseMappedAttribute(attr); +} + +bool HTMLOListElement::compact() const +{ + return !getAttribute(compactAttr).isNull(); +} + +void HTMLOListElement::setCompact(bool b) +{ + setAttribute(compactAttr, b ? "" : 0); +} + +void HTMLOListElement::setStart(int start) +{ + setAttribute(startAttr, String::number(start)); +} + +String HTMLOListElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLOListElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} +} diff --git a/WebCore/html/HTMLOListElement.h b/WebCore/html/HTMLOListElement.h new file mode 100644 index 0000000..fcf78a4 --- /dev/null +++ b/WebCore/html/HTMLOListElement.h @@ -0,0 +1,58 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLOListElement_h +#define HTMLOListElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLOListElement : public HTMLElement +{ +public: + HTMLOListElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + bool compact() const; + void setCompact(bool); + + int start() const { return m_start; } + void setStart(int); + + String type() const; + void setType(const String&); + +private: + int m_start; +}; + + +} //namespace + +#endif diff --git a/WebCore/html/HTMLOListElement.idl b/WebCore/html/HTMLOListElement.idl new file mode 100644 index 0000000..d787ee7 --- /dev/null +++ b/WebCore/html/HTMLOListElement.idl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=64165a4c-8889-4725-a149-abd13d5b4b61, + ImplementationUUID=a20e9b6a-e3a5-4276-aa43-0097e57df8d8 + ] HTMLOListElement : HTMLElement { + attribute boolean compact; + attribute long start; + attribute [ConvertNullToNullString] DOMString type; + }; + +} diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp new file mode 100644 index 0000000..940d0b4 --- /dev/null +++ b/WebCore/html/HTMLObjectElement.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * 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. + */ + +#include "config.h" +#include "HTMLObjectElement.h" + +#include "CSSHelper.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLFormElement.h" +#include "HTMLImageLoader.h" +#include "HTMLNames.h" +#include "MIMETypeRegistry.h" +#include "RenderImage.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "ScriptController.h" +#include "Text.h" + + +namespace WebCore { + +using namespace HTMLNames; + +HTMLObjectElement::HTMLObjectElement(Document* doc, bool createdByParser) + : HTMLPlugInImageElement(objectTag, doc) + , m_docNamedItem(true) + , m_needWidgetUpdate(!createdByParser) + , m_useFallbackContent(false) +{ +} + +HTMLObjectElement::~HTMLObjectElement() +{ +} + +RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const +{ + RenderWidget* renderWidget = (renderer() && renderer()->isWidget()) ? static_cast<RenderWidget*>(renderer()) : 0; + if (renderWidget && !renderWidget->widget()) { + document()->updateLayoutIgnorePendingStylesheets(); + renderWidget = (renderer() && renderer()->isWidget()) ? static_cast<RenderWidget*>(renderer()) : 0; + } + return renderWidget; +} + +void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr) +{ + String val = attr->value(); + int pos; + if (attr->name() == typeAttr) { + m_serviceType = val.lower(); + pos = m_serviceType.find(";"); + if (pos != -1) + m_serviceType = m_serviceType.left(pos); + if (renderer()) + m_needWidgetUpdate = true; + if (!isImageType() && m_imageLoader) + m_imageLoader.clear(); + } else if (attr->name() == dataAttr) { + m_url = parseURL(val); + if (renderer()) + m_needWidgetUpdate = true; + if (renderer() && isImageType()) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + } + } else if (attr->name() == classidAttr) { + m_classId = val; + if (renderer()) + m_needWidgetUpdate = true; + } else if (attr->name() == onloadAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + } else if (attr->name() == nameAttr) { + const AtomicString& newName = attr->value(); + if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(newName); + } + m_name = newName; + } else if (attr->name() == idAttr) { + const AtomicString& newId = attr->value(); + if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeExtraNamedItem(m_id); + document->addExtraNamedItem(newId); + } + m_id = newId; + // also call superclass + HTMLPlugInElement::parseMappedAttribute(attr); + } else + HTMLPlugInElement::parseMappedAttribute(attr); +} + +bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style) +{ + if (m_useFallbackContent || isImageType()) + return HTMLPlugInElement::rendererIsNeeded(style); + + Frame* frame = document()->frame(); + if (!frame) + return false; + + return true; +} + +RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (m_useFallbackContent) + return RenderObject::createObject(this, style); + if (isImageType()) + return new (arena) RenderImage(this); + return new (arena) RenderPartObject(this); +} + +void HTMLObjectElement::attach() +{ + bool isImage = isImageType(); + + if (!isImage) + queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this); + + HTMLPlugInElement::attach(); + + if (isImage && renderer() && !m_useFallbackContent) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + // updateForElement() may have changed us to use fallback content and called detach() and attach(). + if (m_useFallbackContent) + return; + + if (renderer()) + static_cast<RenderImage*>(renderer())->setCachedImage(m_imageLoader->image()); + } +} + +void HTMLObjectElement::updateWidget() +{ + document()->updateRendering(); + if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType()) + static_cast<RenderPartObject*>(renderer())->updateWidget(true); +} + +void HTMLObjectElement::finishParsingChildren() +{ + HTMLPlugInElement::finishParsingChildren(); + if (!m_useFallbackContent) { + m_needWidgetUpdate = true; + if (inDocument()) + setChanged(); + } +} + +void HTMLObjectElement::detach() +{ + if (attached() && renderer() && !m_useFallbackContent) + // Update the widget the next time we attach (detaching destroys the plugin). + m_needWidgetUpdate = true; + HTMLPlugInElement::detach(); +} + +void HTMLObjectElement::insertedIntoDocument() +{ + if (isDocNamedItem() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } + + HTMLPlugInElement::insertedIntoDocument(); +} + +void HTMLObjectElement::removedFromDocument() +{ + if (isDocNamedItem() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + + HTMLPlugInElement::removedFromDocument(); +} + +void HTMLObjectElement::recalcStyle(StyleChange ch) +{ + if (!m_useFallbackContent && m_needWidgetUpdate && renderer() && !isImageType()) { + detach(); + attach(); + } + HTMLPlugInElement::recalcStyle(ch); +} + +void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + updateDocNamedItem(); + if (inDocument() && !m_useFallbackContent) { + m_needWidgetUpdate = true; + setChanged(); + } + HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +bool HTMLObjectElement::isURLAttribute(Attribute *attr) const +{ + return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#')); +} + +const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const +{ + return dataAttr; +} + +void HTMLObjectElement::renderFallbackContent() +{ + if (m_useFallbackContent) + return; + + // Before we give up and use fallback content, check to see if this is a MIME type issue. + if (m_imageLoader && m_imageLoader->image()) { + m_serviceType = m_imageLoader->image()->response().mimeType(); + if (!isImageType()) { + // If we don't think we have an image type anymore, then ditch the image loader. + m_imageLoader.clear(); + detach(); + attach(); + return; + } + } + + // Mark ourselves as using the fallback content. + m_useFallbackContent = true; + + // Now do a detach and reattach. + // FIXME: Style gets recalculated which is suboptimal. + detach(); + attach(); +} + +void HTMLObjectElement::updateDocNamedItem() +{ + // The rule is "<object> elements with no children other than + // <param> elements, unknown elements and whitespace can be + // found by name in a document, and other <object> elements cannot." + bool wasNamedItem = m_docNamedItem; + bool isNamedItem = true; + Node* child = firstChild(); + while (child && isNamedItem) { + if (child->isElementNode()) { + Element* element = static_cast<Element*>(child); + if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag)) + isNamedItem = false; + } else if (child->isTextNode()) { + if (!static_cast<Text*>(child)->containsOnlyWhitespace()) + isNamedItem = false; + } else + isNamedItem = false; + child = child->nextSibling(); + } + if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); + if (isNamedItem) { + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } else { + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + } + m_docNamedItem = isNamedItem; +} + +String HTMLObjectElement::code() const +{ + return getAttribute(codeAttr); +} + +void HTMLObjectElement::setCode(const String& value) +{ + setAttribute(codeAttr, value); +} + +String HTMLObjectElement::archive() const +{ + return getAttribute(archiveAttr); +} + +void HTMLObjectElement::setArchive(const String& value) +{ + setAttribute(archiveAttr, value); +} + +String HTMLObjectElement::border() const +{ + return getAttribute(borderAttr); +} + +void HTMLObjectElement::setBorder(const String& value) +{ + setAttribute(borderAttr, value); +} + +String HTMLObjectElement::codeBase() const +{ + return getAttribute(codebaseAttr); +} + +void HTMLObjectElement::setCodeBase(const String& value) +{ + setAttribute(codebaseAttr, value); +} + +String HTMLObjectElement::codeType() const +{ + return getAttribute(codetypeAttr); +} + +void HTMLObjectElement::setCodeType(const String& value) +{ + setAttribute(codetypeAttr, value); +} + +KURL HTMLObjectElement::data() const +{ + return document()->completeURL(getAttribute(dataAttr)); +} + +void HTMLObjectElement::setData(const String& value) +{ + setAttribute(dataAttr, value); +} + +bool HTMLObjectElement::declare() const +{ + return !getAttribute(declareAttr).isNull(); +} + +void HTMLObjectElement::setDeclare(bool declare) +{ + setAttribute(declareAttr, declare ? "" : 0); +} + +int HTMLObjectElement::hspace() const +{ + return getAttribute(hspaceAttr).toInt(); +} + +void HTMLObjectElement::setHspace(int value) +{ + setAttribute(hspaceAttr, String::number(value)); +} + +String HTMLObjectElement::standby() const +{ + return getAttribute(standbyAttr); +} + +void HTMLObjectElement::setStandby(const String& value) +{ + setAttribute(standbyAttr, value); +} + +String HTMLObjectElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLObjectElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} + +String HTMLObjectElement::useMap() const +{ + return getAttribute(usemapAttr); +} + +void HTMLObjectElement::setUseMap(const String& value) +{ + setAttribute(usemapAttr, value); +} + +int HTMLObjectElement::vspace() const +{ + return getAttribute(vspaceAttr).toInt(); +} + +void HTMLObjectElement::setVspace(int value) +{ + setAttribute(vspaceAttr, String::number(value)); +} + +bool HTMLObjectElement::containsJavaApplet() const +{ + if (MIMETypeRegistry::isJavaAppletMIMEType(type())) + return true; + + Node* child = firstChild(); + while (child) { + if (child->isElementNode()) { + Element* e = static_cast<Element*>(child); + if (e->hasTagName(paramTag) && equalIgnoringCase(e->getAttribute(nameAttr), "type") && MIMETypeRegistry::isJavaAppletMIMEType(e->getAttribute(valueAttr).string())) + return true; + else if (e->hasTagName(objectTag) && static_cast<HTMLObjectElement*>(e)->containsJavaApplet()) + return true; + else if (e->hasTagName(appletTag)) + return true; + } + child = child->nextSibling(); + } + + return false; +} + +void HTMLObjectElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(data().string()); + if (useMap().startsWith("#")) + urls.append(useMap()); +} + +} diff --git a/WebCore/html/HTMLObjectElement.h b/WebCore/html/HTMLObjectElement.h new file mode 100644 index 0000000..859c73f --- /dev/null +++ b/WebCore/html/HTMLObjectElement.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 HTMLObjectElement_h +#define HTMLObjectElement_h + +#include "HTMLPlugInImageElement.h" + +namespace WebCore { + +class KURL; + +class HTMLObjectElement : public HTMLPlugInImageElement { +public: + HTMLObjectElement(Document*, bool createdByParser); + ~HTMLObjectElement(); + + virtual int tagPriority() const { return 5; } + + virtual void parseMappedAttribute(MappedAttribute*); + + virtual void attach(); + virtual bool canLazyAttach() { return false; } + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void finishParsingChildren(); + virtual void detach(); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + + virtual void recalcStyle(StyleChange); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + virtual bool isURLAttribute(Attribute*) const; + virtual const QualifiedName& imageSourceAttributeName() const; + + virtual void updateWidget(); + void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; } + + void renderFallbackContent(); + + virtual RenderWidget* renderWidgetForJSBindings() const; + + String archive() const; + void setArchive(const String&); + + String border() const; + void setBorder(const String&); + + String code() const; + void setCode(const String&); + + String codeBase() const; + void setCodeBase(const String&); + + String codeType() const; + void setCodeType(const String&); + + KURL data() const; + void setData(const String&); + + bool declare() const; + void setDeclare(bool); + + int hspace() const; + void setHspace(int); + + String standby() const; + void setStandby(const String&); + + String type() const; + void setType(const String&); + + String useMap() const; + void setUseMap(const String&); + + int vspace() const; + void setVspace(int); + + bool isDocNamedItem() const { return m_docNamedItem; } + + const String& classId() const { return m_classId; } + + bool containsJavaApplet() const; + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +private: + void updateDocNamedItem(); + + AtomicString m_id; + String m_classId; + bool m_docNamedItem : 1; + bool m_needWidgetUpdate : 1; + bool m_useFallbackContent : 1; +}; + +} + +#endif diff --git a/WebCore/html/HTMLObjectElement.idl b/WebCore/html/HTMLObjectElement.idl new file mode 100644 index 0000000..c225238 --- /dev/null +++ b/WebCore/html/HTMLObjectElement.idl @@ -0,0 +1,66 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + CustomPutFunction, + CustomGetOwnPropertySlot, + CustomCall, + HasOverridingNameGetter, + InterfaceUUID=9d04a3b8-9016-4b64-913a-3b00d548aca7, + ImplementationUUID=2dd24554-6784-4ef9-9713-179f3d37b2f9 + ] HTMLObjectElement : HTMLElement { + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString code; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString archive; + attribute [ConvertNullToNullString] DOMString border; + attribute [ConvertNullToNullString] DOMString codeBase; + attribute [ConvertNullToNullString] DOMString codeType; + attribute [ConvertNullToNullString] DOMString data; + attribute boolean declare; + attribute [ConvertNullToNullString] DOMString height; + attribute long hspace; + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString standby; + attribute [ConvertNullToNullString] DOMString type; + attribute [ConvertNullToNullString] DOMString useMap; + attribute long vspace; + attribute [ConvertNullToNullString] DOMString width; + + // Introduced in DOM Level 2: + readonly attribute [CheckFrameSecurity] Document contentDocument; + +#if !defined(LANGUAGE_COM) +#if ENABLE_SVG + [SVGCheckSecurityDocument] SVGDocument getSVGDocument() + raises(DOMException); +#endif +#endif + +#if defined(LANGUAGE_OBJECTIVE_C) + // Objective-C extension: + readonly attribute URL absoluteImageURL; +#endif + }; + +} diff --git a/WebCore/html/HTMLOptGroupElement.cpp b/WebCore/html/HTMLOptGroupElement.cpp new file mode 100644 index 0000000..0465fb4 --- /dev/null +++ b/WebCore/html/HTMLOptGroupElement.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLOptGroupElement.h" + +#include "CSSStyleSelector.h" +#include "Document.h" +#include "HTMLNames.h" +#include "HTMLSelectElement.h" +#include "RenderMenuList.h" +#include "NodeRenderStyle.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLOptGroupElement::HTMLOptGroupElement(Document* doc, HTMLFormElement* f) + : HTMLFormControlElement(optgroupTag, doc, f) + , m_style(0) +{ +} + +bool HTMLOptGroupElement::isFocusable() const +{ + return HTMLElement::isFocusable(); +} + +const AtomicString& HTMLOptGroupElement::type() const +{ + static const AtomicString optgroup("optgroup"); + return optgroup; +} + +bool HTMLOptGroupElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElement::insertBefore(newChild, refChild, ec, shouldLazyAttach); + if (result) + recalcSelectOptions(); + return result; +} + +bool HTMLOptGroupElement::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElement::replaceChild(newChild, oldChild, ec, shouldLazyAttach); + if (result) + recalcSelectOptions(); + return result; +} + +bool HTMLOptGroupElement::removeChild(Node* oldChild, ExceptionCode& ec) +{ + bool result = HTMLFormControlElement::removeChild(oldChild, ec); + if (result) + recalcSelectOptions(); + return result; +} + +bool HTMLOptGroupElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElement::appendChild(newChild, ec, shouldLazyAttach); + if (result) + recalcSelectOptions(); + return result; +} + +bool HTMLOptGroupElement::removeChildren() +{ + bool result = HTMLFormControlElement::removeChildren(); + if (result) + recalcSelectOptions(); + return result; +} + +void HTMLOptGroupElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + recalcSelectOptions(); + HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +void HTMLOptGroupElement::parseMappedAttribute(MappedAttribute* attr) +{ + HTMLFormControlElement::parseMappedAttribute(attr); + recalcSelectOptions(); +} + +void HTMLOptGroupElement::recalcSelectOptions() +{ + Node* select = parentNode(); + while (select && !select->hasTagName(selectTag)) + select = select->parentNode(); + if (select) + static_cast<HTMLSelectElement*>(select)->setRecalcListItems(); +} + +String HTMLOptGroupElement::label() const +{ + return getAttribute(labelAttr); +} + +void HTMLOptGroupElement::setLabel(const String &value) +{ + setAttribute(labelAttr, value); +} + +bool HTMLOptGroupElement::checkDTD(const Node* newChild) +{ + // Make sure to keep this in sync with <select> (other than not allowing an optgroup). + return newChild->isTextNode() || newChild->hasTagName(HTMLNames::optionTag) || newChild->hasTagName(HTMLNames::hrTag) || newChild->hasTagName(HTMLNames::scriptTag); +} + +void HTMLOptGroupElement::attach() +{ + if (parentNode()->renderStyle()) + setRenderStyle(styleForRenderer()); + HTMLFormControlElement::attach(); +} + +void HTMLOptGroupElement::detach() +{ + m_style.clear(); + HTMLFormControlElement::detach(); +} + +void HTMLOptGroupElement::setRenderStyle(PassRefPtr<RenderStyle> newStyle) +{ + m_style = newStyle; +} + +RenderStyle* HTMLOptGroupElement::nonRendererRenderStyle() const +{ + return m_style.get(); +} + +String HTMLOptGroupElement::groupLabelText() const +{ + String itemText = getAttribute(labelAttr); + + itemText.replace('\\', document()->backslashAsCurrencySymbol()); + // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior. + itemText = itemText.stripWhiteSpace(); + // We want to collapse our whitespace too. This will match other browsers. + itemText = itemText.simplifyWhiteSpace(); + + return itemText; +} + +HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const +{ + Node* select = parentNode(); + while (select && !select->hasTagName(selectTag)) + select = select->parentNode(); + + if (!select) + return 0; + + return static_cast<HTMLSelectElement*>(select); +} + +void HTMLOptGroupElement::accessKeyAction(bool sendToAnyElement) +{ + HTMLSelectElement* select = ownerSelectElement(); + // send to the parent to bring focus to the list box + if (select && !select->focused()) + select->accessKeyAction(false); +} + +} // namespace diff --git a/WebCore/html/HTMLOptGroupElement.h b/WebCore/html/HTMLOptGroupElement.h new file mode 100644 index 0000000..85e789b --- /dev/null +++ b/WebCore/html/HTMLOptGroupElement.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLOptGroupElement_h +#define HTMLOptGroupElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class HTMLSelectElement; + +class HTMLOptGroupElement : public HTMLFormControlElement { +public: + HTMLOptGroupElement(Document*, HTMLFormElement* = 0); + + virtual bool checkDTD(const Node*); + virtual const AtomicString& type() const; + virtual bool isFocusable() const; + virtual void parseMappedAttribute(MappedAttribute*); + virtual bool rendererIsNeeded(RenderStyle*) { return false; } + virtual void attach(); + virtual void detach(); + virtual void setRenderStyle(PassRefPtr<RenderStyle>); + + virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool removeChild(Node* child, ExceptionCode&); + virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool removeChildren(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + String label() const; + void setLabel(const String&); + + String groupLabelText() const; + HTMLSelectElement* ownerSelectElement() const; + virtual void accessKeyAction(bool sendToAnyElement); + +private: + virtual RenderStyle* nonRendererRenderStyle() const; + + void recalcSelectOptions(); + + RefPtr<RenderStyle> m_style; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLOptGroupElement.idl b/WebCore/html/HTMLOptGroupElement.idl new file mode 100644 index 0000000..9f07c38 --- /dev/null +++ b/WebCore/html/HTMLOptGroupElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=18b0ea8c-d3ea-4b14-abd8-8e1d4269fffc, + ImplementationUUID=e26d8c4b-5181-4858-8231-f68ccbf819df + ] HTMLOptGroupElement : HTMLElement { + attribute boolean disabled; + attribute [ConvertNullToNullString] DOMString label; + }; + +} diff --git a/WebCore/html/HTMLOptionElement.cpp b/WebCore/html/HTMLOptionElement.cpp new file mode 100644 index 0000000..887a4e5 --- /dev/null +++ b/WebCore/html/HTMLOptionElement.cpp @@ -0,0 +1,262 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLOptionElement.h" + +#include "CSSStyleSelector.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "HTMLNames.h" +#include "HTMLSelectElement.h" +#include "RenderMenuList.h" +#include "Text.h" +#include "NodeRenderStyle.h" +#include <wtf/Vector.h> + +namespace WebCore { + +using namespace HTMLNames; + +HTMLOptionElement::HTMLOptionElement(Document* doc, HTMLFormElement* f) + : HTMLFormControlElement(optionTag, doc, f) + , m_selected(false) + , m_style(0) +{ +} + +bool HTMLOptionElement::checkDTD(const Node* newChild) +{ + return newChild->isTextNode() || newChild->hasTagName(scriptTag); +} + +void HTMLOptionElement::attach() +{ + if (parentNode()->renderStyle()) + setRenderStyle(styleForRenderer()); + HTMLFormControlElement::attach(); +} + +void HTMLOptionElement::detach() +{ + m_style.clear(); + HTMLFormControlElement::detach(); +} + +bool HTMLOptionElement::isFocusable() const +{ + return HTMLElement::isFocusable(); +} + +const AtomicString& HTMLOptionElement::type() const +{ + static const AtomicString option("option"); + return option; +} + +String HTMLOptionElement::text() const +{ + String text; + + // WinIE does not use the label attribute, so as a quirk, we ignore it. + if (!document()->inCompatMode()) + text = getAttribute(labelAttr); + + if (text.isEmpty()) { + const Node* n = firstChild(); + while (n) { + if (n->nodeType() == TEXT_NODE || n->nodeType() == CDATA_SECTION_NODE) + text += n->nodeValue(); + // skip script content + if (n->isElementNode() && n->hasTagName(HTMLNames::scriptTag)) + n = n->traverseNextSibling(this); + else + n = n->traverseNextNode(this); + } + } + + text.replace('\\', document()->backslashAsCurrencySymbol()); + // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior. + text = text.stripWhiteSpace(); + // We want to collapse our whitespace too. This will match other browsers. + text = text.simplifyWhiteSpace(); + + return text; +} + +void HTMLOptionElement::setText(const String &text, ExceptionCode& ec) +{ + // Handle the common special case where there's exactly 1 child node, and it's a text node. + Node* child = firstChild(); + if (child && child->isTextNode() && !child->nextSibling()) { + static_cast<Text *>(child)->setData(text, ec); + return; + } + + removeChildren(); + appendChild(new Text(document(), text), ec); +} + +void HTMLOptionElement::accessKeyAction(bool sendToAnyElement) +{ + HTMLSelectElement* select = ownerSelectElement(); + if (select) + select->accessKeySetSelectedIndex(index()); +} + +int HTMLOptionElement::index() const +{ + // Let's do this dynamically. Might be a bit slow, but we're sure + // we won't forget to update a member variable in some cases... + HTMLSelectElement* select = ownerSelectElement(); + if (select) { + const Vector<HTMLElement*>& items = select->listItems(); + int l = items.size(); + int optionIndex = 0; + for(int i = 0; i < l; i++) { + if (items[i]->hasLocalName(optionTag)) { + if (static_cast<HTMLOptionElement*>(items[i]) == this) + return optionIndex; + optionIndex++; + } + } + } + return 0; +} + +void HTMLOptionElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == selectedAttr) + m_selected = (!attr->isNull()); + else if (attr->name() == valueAttr) + m_value = attr->value(); + else + HTMLFormControlElement::parseMappedAttribute(attr); +} + +String HTMLOptionElement::value() const +{ + if ( !m_value.isNull() ) + return m_value; + // Use the text if the value wasn't set. + return text().stripWhiteSpace(); +} + +void HTMLOptionElement::setValue(const String& value) +{ + setAttribute(valueAttr, value); +} + +void HTMLOptionElement::setSelected(bool selected) +{ + if (m_selected == selected) + return; + if (HTMLSelectElement* select = ownerSelectElement()) + select->setSelectedIndex(selected ? index() : -1, false); + m_selected = selected; +} + +void HTMLOptionElement::setSelectedState(bool selected) +{ + if (m_selected == selected) + return; + m_selected = selected; + setChanged(); +} + +void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + HTMLSelectElement* select = ownerSelectElement(); + if (select) + select->childrenChanged(changedByParser); + HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const +{ + Node* select = parentNode(); + while (select && !select->hasTagName(selectTag)) + select = select->parentNode(); + + if (!select) + return 0; + + return static_cast<HTMLSelectElement*>(select); +} + +bool HTMLOptionElement::defaultSelected() const +{ + return !getAttribute(selectedAttr).isNull(); +} + +void HTMLOptionElement::setDefaultSelected(bool b) +{ + setAttribute(selectedAttr, b ? "" : 0); +} + +String HTMLOptionElement::label() const +{ + return getAttribute(labelAttr); +} + +void HTMLOptionElement::setLabel(const String& value) +{ + setAttribute(labelAttr, value); +} + +void HTMLOptionElement::setRenderStyle(PassRefPtr<RenderStyle> newStyle) +{ + m_style = newStyle; +} + +RenderStyle* HTMLOptionElement::nonRendererRenderStyle() const +{ + return m_style.get(); +} + +String HTMLOptionElement::optionText() +{ + if (parentNode() && parentNode()->hasTagName(optgroupTag)) + return " " + text(); + + return text(); +} + +bool HTMLOptionElement::disabled() const +{ + return HTMLFormControlElement::disabled() || (parentNode() && static_cast<HTMLFormControlElement*>(parentNode())->disabled()); +} + +void HTMLOptionElement::insertedIntoDocument() +{ + HTMLSelectElement* select; + if (selected() && (select = ownerSelectElement())) + select->scrollToSelection(); + + HTMLFormControlElement::insertedIntoDocument(); +} + +} // namespace diff --git a/WebCore/html/HTMLOptionElement.h b/WebCore/html/HTMLOptionElement.h new file mode 100644 index 0000000..58426eb --- /dev/null +++ b/WebCore/html/HTMLOptionElement.h @@ -0,0 +1,94 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLOptionElement_h +#define HTMLOptionElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class HTMLSelectElement; +class HTMLFormElement; +class MappedAttribute; + +class HTMLOptionElement : public HTMLFormControlElement { + friend class HTMLSelectElement; + friend class RenderMenuList; + +public: + HTMLOptionElement(Document*, HTMLFormElement* = 0); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 2; } + virtual bool checkDTD(const Node* newChild); + virtual bool isFocusable() const; + virtual bool rendererIsNeeded(RenderStyle*) { return false; } + virtual void attach(); + virtual void detach(); + virtual void setRenderStyle(PassRefPtr<RenderStyle>); + + virtual const AtomicString& type() const; + + String text() const; + void setText(const String&, ExceptionCode&); + + int index() const; + virtual void parseMappedAttribute(MappedAttribute*); + + String value() const; + void setValue(const String&); + + bool selected() const { return m_selected; } + void setSelected(bool); + void setSelectedState(bool); + + HTMLSelectElement* ownerSelectElement() const; + + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + bool defaultSelected() const; + void setDefaultSelected(bool); + + String label() const; + void setLabel(const String&); + + String optionText(); + + virtual bool disabled() const; + + virtual void insertedIntoDocument(); + virtual void accessKeyAction(bool); + +private: + virtual RenderStyle* nonRendererRenderStyle() const; + + String m_value; + bool m_selected; + RefPtr<RenderStyle> m_style; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLOptionElement.idl b/WebCore/html/HTMLOptionElement.idl new file mode 100644 index 0000000..34fa999 --- /dev/null +++ b/WebCore/html/HTMLOptionElement.idl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006, 2007 Apple, 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 html { + + interface [ + GenerateConstructor, + GenerateNativeConverter, + InterfaceUUID=74a7b64a-cf18-4da9-b3aa-e1f4d245d607, + ImplementationUUID=166915d5-2c93-404b-b076-af3fa5ccbd83 + ] HTMLOptionElement : HTMLElement { + readonly attribute HTMLFormElement form; + attribute boolean defaultSelected; +#if defined(LANGUAGE_JAVASCRIPT) + attribute [ConvertNullToNullString] DOMString text + setter raises(DOMException); +#else + readonly attribute DOMString text; +#endif + readonly attribute long index; + attribute boolean disabled; + attribute [ConvertNullToNullString] DOMString label; + attribute boolean selected; + attribute [ConvertNullToNullString] DOMString value; + }; + +} diff --git a/WebCore/html/HTMLOptionsCollection.cpp b/WebCore/html/HTMLOptionsCollection.cpp new file mode 100644 index 0000000..0b88183 --- /dev/null +++ b/WebCore/html/HTMLOptionsCollection.cpp @@ -0,0 +1,92 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * 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. + * + */ + +#include "config.h" +#include "HTMLOptionsCollection.h" + +#include "ExceptionCode.h" +#include "HTMLOptionElement.h" +#include "HTMLSelectElement.h" + +namespace WebCore { + +HTMLOptionsCollection::HTMLOptionsCollection(PassRefPtr<HTMLSelectElement> select) + : HTMLCollection(select.get(), SelectOptions, select->collectionInfo()) +{ +} + +PassRefPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(PassRefPtr<HTMLSelectElement> select) +{ + return adoptRef(new HTMLOptionsCollection(select)); +} + +void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, ExceptionCode &ec) +{ + add(element, length(), ec); +} + +void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index, ExceptionCode &ec) +{ + HTMLOptionElement* newOption = element.get(); + + if (!newOption) { + ec = TYPE_MISMATCH_ERR; + return; + } + + if (index < -1) { + ec = INDEX_SIZE_ERR; + return; + } + + ec = 0; + HTMLSelectElement* select = static_cast<HTMLSelectElement*>(base()); + + if (index == -1 || unsigned(index) >= length()) + select->add(newOption, 0, ec); + else + select->add(newOption, static_cast<HTMLOptionElement*>(item(index)), ec); + + ASSERT(ec == 0); +} + +void HTMLOptionsCollection::remove(int index) +{ + static_cast<HTMLSelectElement*>(base())->remove(index); +} + +int HTMLOptionsCollection::selectedIndex() const +{ + return static_cast<HTMLSelectElement*>(base())->selectedIndex(); +} + +void HTMLOptionsCollection::setSelectedIndex(int index) +{ + static_cast<HTMLSelectElement*>(base())->setSelectedIndex(index); +} + +void HTMLOptionsCollection::setLength(unsigned length, ExceptionCode& ec) +{ + static_cast<HTMLSelectElement*>(base())->setLength(length, ec); +} + +} //namespace diff --git a/WebCore/html/HTMLOptionsCollection.h b/WebCore/html/HTMLOptionsCollection.h new file mode 100644 index 0000000..a82749b --- /dev/null +++ b/WebCore/html/HTMLOptionsCollection.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@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 HTMLOptionsCollection_h +#define HTMLOptionsCollection_h + +#include "HTMLCollection.h" + +namespace WebCore { + +class HTMLOptionElement; +class HTMLSelectElement; + +typedef int ExceptionCode; + +class HTMLOptionsCollection : public HTMLCollection { +public: + static PassRefPtr<HTMLOptionsCollection> create(PassRefPtr<HTMLSelectElement>); + + void add(PassRefPtr<HTMLOptionElement>, ExceptionCode&); + void add(PassRefPtr<HTMLOptionElement>, int index, ExceptionCode&); + void remove(int index); + + int selectedIndex() const; + void setSelectedIndex(int); + + void setLength(unsigned, ExceptionCode&); + +private: + HTMLOptionsCollection(PassRefPtr<HTMLSelectElement>); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLOptionsCollection.idl b/WebCore/html/HTMLOptionsCollection.idl new file mode 100644 index 0000000..226f3d7 --- /dev/null +++ b/WebCore/html/HTMLOptionsCollection.idl @@ -0,0 +1,45 @@ +/* + * 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 html { + + // FIXME: The W3C spec says that HTMLOptionsCollection should not have a parent class. + + interface [ + GenerateNativeConverter, + HasCustomIndexSetter, + InterfaceUUID=a03aaeac-e47d-4bb3-acb4-f1897ae74237, + ImplementationUUID=99c11fde-6f9f-44a4-a041-49a894c52e70 + ] HTMLOptionsCollection : HTMLCollection { + attribute long selectedIndex; + attribute [Custom] unsigned long length + setter raises (DOMException); + + [Custom] void add(in HTMLOptionElement option, in [Optional] unsigned long index) + raises (DOMException); + [Custom] void remove(in unsigned long index); + +#if !defined(LANGUAGE_JAVASCRIPT) + Node item(in unsigned long index); + Node namedItem(in DOMString name); +#endif + }; + +} diff --git a/WebCore/html/HTMLParagraphElement.cpp b/WebCore/html/HTMLParagraphElement.cpp new file mode 100644 index 0000000..1b5f054 --- /dev/null +++ b/WebCore/html/HTMLParagraphElement.cpp @@ -0,0 +1,81 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLParagraphElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLParagraphElement::HTMLParagraphElement(Document *doc) + : HTMLElement(pTag, doc) +{ +} + +bool HTMLParagraphElement::checkDTD(const Node* newChild) +{ + return inInlineTagList(newChild) || (document()->inCompatMode() && newChild->hasTagName(tableTag)); +} + +bool HTMLParagraphElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == alignAttr) { + result = eBlock; // We can share with DIV here. + return false; + } + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLParagraphElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == alignAttr) { + String v = attr->value(); + if (equalIgnoringCase(attr->value(), "middle") || equalIgnoringCase(attr->value(), "center")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitCenter); + else if (equalIgnoringCase(attr->value(), "left")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitLeft); + else if (equalIgnoringCase(attr->value(), "right")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitRight); + else + addCSSProperty(attr, CSSPropertyTextAlign, v); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLParagraphElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLParagraphElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +} diff --git a/WebCore/html/HTMLParagraphElement.h b/WebCore/html/HTMLParagraphElement.h new file mode 100644 index 0000000..9b5b4fa --- /dev/null +++ b/WebCore/html/HTMLParagraphElement.h @@ -0,0 +1,48 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLParagraphElement_h +#define HTMLParagraphElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLParagraphElement : public HTMLElement { +public: + HTMLParagraphElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 3; } + virtual bool checkDTD(const Node* newChild); + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + String align() const; + void setAlign(const String&); +}; + +} // namespace WebCore + +#endif // HTMLParagraphElement_h diff --git a/WebCore/html/HTMLParagraphElement.idl b/WebCore/html/HTMLParagraphElement.idl new file mode 100644 index 0000000..b974ec2 --- /dev/null +++ b/WebCore/html/HTMLParagraphElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=dffe0809-f3f8-499d-8d5c-7d9893f23337, + ImplementationUUID=21d60b62-4ecb-4849-8729-0a40c64d12aa + ] HTMLParagraphElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString align; + }; + +} diff --git a/WebCore/html/HTMLParamElement.cpp b/WebCore/html/HTMLParamElement.cpp new file mode 100644 index 0000000..0c9d593 --- /dev/null +++ b/WebCore/html/HTMLParamElement.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * 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 "HTMLParamElement.h" + +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLParamElement::HTMLParamElement(Document* doc) + : HTMLElement(paramTag, doc) +{ +} + +HTMLParamElement::~HTMLParamElement() +{ +} + +void HTMLParamElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == idAttr) { + // Must call base class so that hasID bit gets set. + HTMLElement::parseMappedAttribute(attr); + if (document()->isHTMLDocument()) + return; + m_name = attr->value(); + } else if (attr->name() == nameAttr) { + m_name = attr->value(); + } else if (attr->name() == valueAttr) { + m_value = attr->value(); + } else + HTMLElement::parseMappedAttribute(attr); +} + +bool HTMLParamElement::isURLAttribute(Attribute* attr) const +{ + if (attr->name() == valueAttr) { + Attribute* attr = attributes()->getAttributeItem(nameAttr); + if (attr) { + const AtomicString& value = attr->value(); + if (equalIgnoringCase(value, "data") || equalIgnoringCase(value, "movie") || equalIgnoringCase(value, "src")) + return true; + } + } + return false; +} + +void HTMLParamElement::setName(const String& value) +{ + setAttribute(nameAttr, value); +} + +String HTMLParamElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLParamElement::setType(const String& value) +{ + setAttribute(typeAttr, value); +} + +void HTMLParamElement::setValue(const String& value) +{ + setAttribute(valueAttr, value); +} + +String HTMLParamElement::valueType() const +{ + return getAttribute(valuetypeAttr); +} + +void HTMLParamElement::setValueType(const String& value) +{ + setAttribute(valuetypeAttr, value); +} + +void HTMLParamElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + if (!equalIgnoringCase(name(), "data") && + !equalIgnoringCase(name(), "movie") && + !equalIgnoringCase(name(), "src")) + return; + + urls.append(value()); +} + +} diff --git a/WebCore/html/HTMLParamElement.h b/WebCore/html/HTMLParamElement.h new file mode 100644 index 0000000..5e31aed --- /dev/null +++ b/WebCore/html/HTMLParamElement.h @@ -0,0 +1,68 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLParamElement_h +#define HTMLParamElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLParamElement : public HTMLElement +{ + friend class HTMLAppletElement; +public: + HTMLParamElement(Document*); + ~HTMLParamElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void parseMappedAttribute(MappedAttribute*); + + virtual bool isURLAttribute(Attribute*) const; + + String name() const { return m_name; } + void setName(const String&); + + String type() const; + void setType(const String&); + + String value() const { return m_value; } + void setValue(const String&); + + String valueType() const; + void setValueType(const String&); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + + protected: + AtomicString m_name; + AtomicString m_value; +}; + + +} + +#endif diff --git a/WebCore/html/HTMLParamElement.idl b/WebCore/html/HTMLParamElement.idl new file mode 100644 index 0000000..805d170 --- /dev/null +++ b/WebCore/html/HTMLParamElement.idl @@ -0,0 +1,33 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=76e05eee-c30d-4d52-a356-271f17b31dbf, + ImplementationUUID=418d8a82-0a99-4c6f-a630-1e6071a74350 + ] HTMLParamElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString name; + attribute [ConvertNullToNullString] DOMString type; + attribute [ConvertNullToNullString] DOMString value; + attribute [ConvertNullToNullString] DOMString valueType; + }; + +} diff --git a/WebCore/html/HTMLParser.cpp b/WebCore/html/HTMLParser.cpp new file mode 100644 index 0000000..ba2220c --- /dev/null +++ b/WebCore/html/HTMLParser.cpp @@ -0,0 +1,1602 @@ +/* + Copyright (C) 1997 Martin Jones (mjones@kde.org) + (C) 1997 Torben Weis (weis@kde.org) + (C) 1999,2001 Lars Knoll (knoll@kde.org) + (C) 2000,2001 Dirk Mueller (mueller@kde.org) + Copyright (C) 2004, 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 "HTMLParser.h" + +#include "CharacterNames.h" +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "Comment.h" +#include "Console.h" +#include "DOMWindow.h" +#include "DocumentFragment.h" +#include "DocumentType.h" +#include "Frame.h" +#include "HTMLBodyElement.h" +#include "HTMLDocument.h" +#include "HTMLDivElement.h" +#include "HTMLDListElement.h" +#include "HTMLElementFactory.h" +#include "HTMLFormElement.h" +#include "HTMLHeadElement.h" +#include "HTMLHRElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLIsIndexElement.h" +#include "HTMLMapElement.h" +#include "HTMLNames.h" +#include "HTMLTableCellElement.h" +#include "HTMLTableRowElement.h" +#include "HTMLTableSectionElement.h" +#include "HTMLTokenizer.h" +#include "LocalizedStrings.h" +#include "Settings.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +static const unsigned cMaxRedundantTagDepth = 20; +static const unsigned cResidualStyleMaxDepth = 200; + +struct HTMLStackElem : Noncopyable { + HTMLStackElem(const AtomicString& t, int lvl, Node* n, bool r, HTMLStackElem* nx) + : tagName(t) + , level(lvl) + , strayTableContent(false) + , node(n) + , didRefNode(r) + , next(nx) + { + } + + void derefNode() + { + if (didRefNode) + node->deref(); + } + + AtomicString tagName; + int level; + bool strayTableContent; + Node* node; + bool didRefNode; + HTMLStackElem* next; +}; + +/** + * The parser parses tokenized input into the document, building up the + * document tree. If the document is well-formed, parsing it is straightforward. + * + * Unfortunately, we have to handle many HTML documents that are not well-formed, + * so the parser has to be tolerant about errors. + * + * We have to take care of at least the following error conditions: + * + * 1. The element being added is explicitly forbidden inside some outer tag. + * In this case we should close all tags up to the one, which forbids + * the element, and add it afterwards. + * + * 2. We are not allowed to add the element directly. It could be that + * the person writing the document forgot some tag in between (or that the + * tag in between is optional). This could be the case with the following + * tags: HTML HEAD BODY TBODY TR TD LI (did I forget any?). + * + * 3. We want to add a block element inside to an inline element. Close all + * inline elements up to the next higher block element. + * + * 4. If this doesn't help, close elements until we are allowed to add the + * element or ignore the tag. + * + */ + +HTMLParser::HTMLParser(HTMLDocument* doc, bool reportErrors) + : document(doc) + , current(doc) + , didRefCurrent(false) + , blockStack(0) + , m_hasPElementInScope(NotInScope) + , head(0) + , inBody(false) + , haveContent(false) + , haveFrameSet(false) + , m_isParsingFragment(false) + , m_reportErrors(reportErrors) + , m_handlingResidualStyleAcrossBlocks(false) + , inStrayTableContent(0) +{ +} + +HTMLParser::HTMLParser(DocumentFragment* frag) + : document(frag->document()) + , current(frag) + , didRefCurrent(true) + , blockStack(0) + , m_hasPElementInScope(NotInScope) + , head(0) + , inBody(true) + , haveContent(false) + , haveFrameSet(false) + , m_isParsingFragment(true) + , m_reportErrors(false) + , m_handlingResidualStyleAcrossBlocks(false) + , inStrayTableContent(0) +{ + if (frag) + frag->ref(); +} + +HTMLParser::~HTMLParser() +{ + freeBlock(); + if (didRefCurrent) + current->deref(); +} + +void HTMLParser::reset() +{ + ASSERT(!m_isParsingFragment); + + setCurrent(document); + + freeBlock(); + + inBody = false; + haveFrameSet = false; + haveContent = false; + inStrayTableContent = 0; + + m_currentFormElement = 0; + m_currentMapElement = 0; + head = 0; + m_isindexElement = 0; + + m_skipModeTag = nullAtom; +} + +void HTMLParser::setCurrent(Node* newCurrent) +{ + bool didRefNewCurrent = newCurrent && newCurrent != document; + if (didRefNewCurrent) + newCurrent->ref(); + if (didRefCurrent) + current->deref(); + current = newCurrent; + didRefCurrent = didRefNewCurrent; +} + +PassRefPtr<Node> HTMLParser::parseToken(Token* t) +{ + if (!m_skipModeTag.isNull()) { + if (!t->beginTag && t->tagName == m_skipModeTag) + // Found the end tag for the current skip mode, so we're done skipping. + m_skipModeTag = nullAtom; + else if (current->localName() == t->tagName) + // Do not skip </iframe>. + // FIXME: What does that comment mean? How can it be right to parse a token without clearing m_skipModeTag? + ; + else + return 0; + } + + // Apparently some sites use </br> instead of <br>. Be compatible with IE and Firefox and treat this like <br>. + if (t->isCloseTag(brTag) && document->inCompatMode()) { + reportError(MalformedBRError); + t->beginTag = true; + } + + if (!t->beginTag) { + processCloseTag(t); + return 0; + } + + // Ignore spaces, if we're not inside a paragraph or other inline code. + // Do not alter the text if it is part of a scriptTag. + if (t->tagName == textAtom && t->text && current->localName() != scriptTag) { + if (inBody && !skipMode() && current->localName() != styleTag && + current->localName() != titleTag && !t->text->containsOnlyWhitespace()) + haveContent = true; + + RefPtr<Node> n; + String text = t->text.get(); + unsigned charsLeft = text.length(); + while (charsLeft) { + // split large blocks of text to nodes of manageable size + n = Text::createWithLengthLimit(document, text, charsLeft); + if (!insertNode(n.get(), t->flat)) + return 0; + } + return n; + } + + RefPtr<Node> n = getNode(t); + // just to be sure, and to catch currently unimplemented stuff + if (!n) + return 0; + + // set attributes + if (n->isHTMLElement()) { + HTMLElement* e = static_cast<HTMLElement*>(n.get()); + e->setAttributeMap(t->attrs.get()); + + // take care of optional close tags + if (e->endTagRequirement() == TagStatusOptional) + popBlock(t->tagName); + + // If the node does not have a forbidden end tag requirement, and if the broken XML self-closing + // syntax was used, report an error. + if (t->brokenXMLStyle && e->endTagRequirement() != TagStatusForbidden) { + if (t->tagName == scriptTag) + reportError(IncorrectXMLCloseScriptWarning); + else + reportError(IncorrectXMLSelfCloseError, &t->tagName); + } + } + + if (!insertNode(n.get(), t->flat)) { + // we couldn't insert the node + + if (n->isElementNode()) { + Element* e = static_cast<Element*>(n.get()); + e->setAttributeMap(0); + } + + if (m_currentMapElement == n) + m_currentMapElement = 0; + + if (m_currentFormElement == n) + m_currentFormElement = 0; + + if (head == n) + head = 0; + + return 0; + } + return n; +} + +void HTMLParser::parseDoctypeToken(DoctypeToken* t) +{ + // Ignore any doctype after the first. Ignore doctypes in fragments. + if (document->doctype() || m_isParsingFragment || current != document) + return; + + // Make a new doctype node and set it as our doctype. + document->addChild(DocumentType::create(document, String::adopt(t->m_name), String::adopt(t->m_publicID), String::adopt(t->m_systemID))); +} + +static bool isTableSection(Node* n) +{ + return n->hasTagName(tbodyTag) || n->hasTagName(tfootTag) || n->hasTagName(theadTag); +} + +static bool isTablePart(Node* n) +{ + return n->hasTagName(trTag) || n->hasTagName(tdTag) || n->hasTagName(thTag) || + isTableSection(n); +} + +static bool isTableRelated(Node* n) +{ + return n->hasTagName(tableTag) || isTablePart(n); +} + +static bool isScopingTag(const AtomicString& tagName) +{ + return tagName == appletTag || tagName == captionTag || tagName == tdTag || tagName == thTag || tagName == buttonTag || tagName == marqueeTag || tagName == objectTag || tagName == tableTag || tagName == htmlTag; +} + +bool HTMLParser::insertNode(Node* n, bool flat) +{ + RefPtr<Node> protectNode(n); + + const AtomicString& localName = n->localName(); + int tagPriority = n->isHTMLElement() ? static_cast<HTMLElement*>(n)->tagPriority() : 0; + + // <table> is never allowed inside stray table content. Always pop out of the stray table content + // and close up the first table, and then start the second table as a sibling. + if (inStrayTableContent && localName == tableTag) + popBlock(tableTag); + + // let's be stupid and just try to insert it. + // this should work if the document is well-formed + Node* newNode = current->addChild(n); + if (!newNode) + return handleError(n, flat, localName, tagPriority); // Try to handle the error. + + // don't push elements without end tags (e.g., <img>) on the stack + bool parentAttached = current->attached(); + if (tagPriority > 0 && !flat) { + if (newNode == current) { + // This case should only be hit when a demoted <form> is placed inside a table. + ASSERT(localName == formTag); + reportError(FormInsideTablePartError, ¤t->localName()); + } else { + // The pushBlock function transfers ownership of current to the block stack + // so we're guaranteed that didRefCurrent is false. The code below is an + // optimized version of setCurrent that takes advantage of that fact and also + // assumes that newNode is neither 0 nor a pointer to the document. + pushBlock(localName, tagPriority); + newNode->beginParsingChildren(); + ASSERT(!didRefCurrent); + newNode->ref(); + current = newNode; + didRefCurrent = true; + } + if (parentAttached && !n->attached() && !m_isParsingFragment) + n->attach(); + } else { + if (parentAttached && !n->attached() && !m_isParsingFragment) + n->attach(); + n->finishParsingChildren(); + } + + return true; +} + +bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, int tagPriority) +{ + // Error handling code. This is just ad hoc handling of specific parent/child combinations. + HTMLElement* e; + bool handled = false; + + // 1. Check out the element's tag name to decide how to deal with errors. + if (n->isHTMLElement()) { + HTMLElement* h = static_cast<HTMLElement*>(n); + if (h->hasLocalName(trTag) || h->hasLocalName(thTag) || h->hasLocalName(tdTag)) { + if (inStrayTableContent && !isTableRelated(current)) { + reportError(MisplacedTablePartError, &localName, ¤t->localName()); + // pop out to the nearest enclosing table-related tag. + while (blockStack && !isTableRelated(current)) + popOneBlock(); + return insertNode(n); + } + } else if (h->hasLocalName(headTag)) { + if (!current->isDocumentNode() && !current->hasTagName(htmlTag)) { + reportError(MisplacedHeadError); + return false; + } + } else if (h->hasLocalName(metaTag) || h->hasLocalName(linkTag) || h->hasLocalName(baseTag)) { + bool createdHead = false; + if (!head) { + createHead(); + createdHead = true; + } + if (head) { + if (!createdHead) + reportError(MisplacedHeadContentError, &localName, ¤t->localName()); + if (head->addChild(n)) { + if (!n->attached() && !m_isParsingFragment) + n->attach(); + return true; + } else + return false; + } + } else if (h->hasLocalName(htmlTag)) { + if (!current->isDocumentNode() ) { + if (document->documentElement() && document->documentElement()->hasTagName(htmlTag)) { + reportError(RedundantHTMLBodyError, &localName); + // we have another <HTML> element.... apply attributes to existing one + // make sure we don't overwrite already existing attributes + NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); + Element* existingHTML = static_cast<Element*>(document->documentElement()); + NamedAttrMap* bmap = existingHTML->attributes(false); + for (unsigned l = 0; map && l < map->length(); ++l) { + Attribute* it = map->attributeItem(l); + if (!bmap->getAttributeItem(it->name())) + existingHTML->setAttribute(it->name(), it->value()); + } + } + return false; + } + } else if (h->hasLocalName(titleTag) || h->hasLocalName(styleTag)) { + bool createdHead = false; + if (!head) { + createHead(); + createdHead = true; + } + if (head) { + Node* newNode = head->addChild(n); + if (!newNode) { + setSkipMode(h->tagQName()); + return false; + } + + if (!createdHead) + reportError(MisplacedHeadContentError, &localName, ¤t->localName()); + + pushBlock(localName, tagPriority); + newNode->beginParsingChildren(); + setCurrent(newNode); + if (!n->attached() && !m_isParsingFragment) + n->attach(); + return true; + } + if (inBody) { + setSkipMode(h->tagQName()); + return false; + } + } else if (h->hasLocalName(bodyTag)) { + if (inBody && document->body()) { + // we have another <BODY> element.... apply attributes to existing one + // make sure we don't overwrite already existing attributes + // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor> + reportError(RedundantHTMLBodyError, &localName); + NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); + Element* existingBody = document->body(); + NamedAttrMap* bmap = existingBody->attributes(false); + for (unsigned l = 0; map && l < map->length(); ++l) { + Attribute* it = map->attributeItem(l); + if (!bmap->getAttributeItem(it->name())) + existingBody->setAttribute(it->name(), it->value()); + } + return false; + } + else if (!current->isDocumentNode()) + return false; + } else if (h->hasLocalName(areaTag)) { + if (m_currentMapElement) { + reportError(MisplacedAreaError, ¤t->localName()); + m_currentMapElement->addChild(n); + if (!n->attached() && !m_isParsingFragment) + n->attach(); + handled = true; + return true; + } + return false; + } else if (h->hasLocalName(colgroupTag) || h->hasLocalName(captionTag)) { + if (isTableRelated(current)) { + while (blockStack && isTablePart(current)) + popOneBlock(); + return insertNode(n); + } + } + } else if (n->isCommentNode() && !head) + return false; + + // 2. Next we examine our currently active element to do some further error handling. + if (current->isHTMLElement()) { + HTMLElement* h = static_cast<HTMLElement*>(current); + const AtomicString& currentTagName = h->localName(); + if (h->hasLocalName(htmlTag)) { + HTMLElement* elt = n->isHTMLElement() ? static_cast<HTMLElement*>(n) : 0; + if (elt && (elt->hasLocalName(scriptTag) || elt->hasLocalName(styleTag) || + elt->hasLocalName(metaTag) || elt->hasLocalName(linkTag) || + elt->hasLocalName(objectTag) || elt->hasLocalName(embedTag) || + elt->hasLocalName(titleTag) || elt->hasLocalName(isindexTag) || + elt->hasLocalName(baseTag))) { + if (!head) { + head = new HTMLHeadElement(document); + e = head; + insertNode(e); + handled = true; + } + } else { + if (n->isTextNode()) { + Text* t = static_cast<Text*>(n); + if (t->containsOnlyWhitespace()) + return false; + } + if (!haveFrameSet) { + e = new HTMLBodyElement(document); + startBody(); + insertNode(e); + handled = true; + } else + reportError(MisplacedFramesetContentError, &localName); + } + } else if (h->hasLocalName(headTag)) { + if (n->hasTagName(htmlTag)) + return false; + else { + // This means the body starts here... + if (!haveFrameSet) { + popBlock(currentTagName); + e = new HTMLBodyElement(document); + startBody(); + insertNode(e); + handled = true; + } else + reportError(MisplacedFramesetContentError, &localName); + } + } else if (h->hasLocalName(addressTag) || h->hasLocalName(fontTag) + || h->hasLocalName(styleTag) || h->hasLocalName(titleTag)) { + reportError(MisplacedContentRetryError, &localName, ¤tTagName); + popBlock(currentTagName); + handled = true; + } else if (h->hasLocalName(captionTag)) { + // Illegal content in a caption. Close the caption and try again. + reportError(MisplacedCaptionContentError, &localName); + popBlock(currentTagName); + if (isTablePart(n)) + return insertNode(n, flat); + } else if (h->hasLocalName(tableTag) || h->hasLocalName(trTag) || isTableSection(h)) { + if (n->hasTagName(tableTag)) { + reportError(MisplacedTableError, ¤tTagName); + if (m_isParsingFragment && !h->hasLocalName(tableTag)) + // fragment may contain table parts without <table> ancestor, pop them one by one + popBlock(h->localName()); + popBlock(localName); // end the table + handled = true; // ...and start a new one + } else { + ExceptionCode ec = 0; + Node* node = current; + Node* parent = node->parentNode(); + // A script may have removed the current node's parent from the DOM + // http://bugs.webkit.org/show_bug.cgi?id=7137 + // FIXME: we should do real recovery here and re-parent with the correct node. + if (!parent) + return false; + Node* grandparent = parent->parentNode(); + + if (n->isTextNode() || + (h->hasLocalName(trTag) && + isTableSection(parent) && grandparent && grandparent->hasTagName(tableTag)) || + ((!n->hasTagName(tdTag) && !n->hasTagName(thTag) && + !n->hasTagName(formTag) && !n->hasTagName(scriptTag)) && isTableSection(node) && + parent->hasTagName(tableTag))) { + node = (node->hasTagName(tableTag)) ? node : + ((node->hasTagName(trTag)) ? grandparent : parent); + // This can happen with fragments + if (!node) + return false; + Node* parent = node->parentNode(); + if (!parent) + return false; + parent->insertBefore(n, node, ec); + if (!ec) { + reportError(StrayTableContentError, &localName, ¤tTagName); + if (n->isHTMLElement() && tagPriority > 0 && + !flat && static_cast<HTMLElement*>(n)->endTagRequirement() != TagStatusForbidden) + { + pushBlock(localName, tagPriority); + n->beginParsingChildren(); + setCurrent(n); + inStrayTableContent++; + blockStack->strayTableContent = true; + } + return true; + } + } + + if (!ec) { + if (current->hasTagName(trTag)) { + reportError(TablePartRequiredError, &localName, &tdTag.localName()); + e = new HTMLTableCellElement(tdTag, document); + } else if (current->hasTagName(tableTag)) { + // Don't report an error in this case, since making a <tbody> happens all the time when you have <table><tr>, + // and it isn't really a parse error per se. + e = new HTMLTableSectionElement(tbodyTag, document); + } else { + reportError(TablePartRequiredError, &localName, &trTag.localName()); + e = new HTMLTableRowElement(document); + } + + insertNode(e); + handled = true; + } + } + } else if (h->hasLocalName(objectTag)) { + reportError(MisplacedContentRetryError, &localName, ¤tTagName); + popBlock(objectTag); + handled = true; + } else if (h->hasLocalName(pTag) || isHeaderTag(currentTagName)) { + if (!isInline(n)) { + popBlock(currentTagName); + handled = true; + } + } else if (h->hasLocalName(optionTag) || h->hasLocalName(optgroupTag)) { + if (localName == optgroupTag) { + popBlock(currentTagName); + handled = true; + } else if (localName == selectTag) { + // IE treats a nested select as </select>. Let's do the same + popBlock(localName); + } + } else if (h->hasLocalName(selectTag)) { + if (localName == inputTag || localName == textareaTag) { + reportError(MisplacedContentRetryError, &localName, ¤tTagName); + popBlock(currentTagName); + handled = true; + } + } else if (h->hasLocalName(colgroupTag)) { + popBlock(currentTagName); + handled = true; + } else if (!h->hasLocalName(bodyTag)) { + if (isInline(current)) { + popInlineBlocks(); + handled = true; + } + } + } else if (current->isDocumentNode()) { + if (n->isTextNode()) { + Text* t = static_cast<Text*>(n); + if (t->containsOnlyWhitespace()) + return false; + } + + if (!document->documentElement()) { + e = new HTMLHtmlElement(document); + insertNode(e); + handled = true; + } + } + + // 3. If we couldn't handle the error, just return false and attempt to error-correct again. + if (!handled) { + reportError(IgnoredContentError, &localName, ¤t->localName()); + return false; + } + return insertNode(n); +} + +typedef bool (HTMLParser::*CreateErrorCheckFunc)(Token* t, RefPtr<Node>&); +typedef HashMap<AtomicStringImpl*, CreateErrorCheckFunc> FunctionMap; + +bool HTMLParser::textCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + result = new Text(document, t->text.get()); + return false; +} + +bool HTMLParser::commentCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + result = new Comment(document, t->text.get()); + return false; +} + +bool HTMLParser::headCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + if (!head || current->localName() == htmlTag) { + head = new HTMLHeadElement(document); + result = head; + } else + reportError(MisplacedHeadError); + return false; +} + +bool HTMLParser::bodyCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + // body no longer allowed if we have a frameset + if (haveFrameSet) + return false; + popBlock(headTag); + startBody(); + return true; +} + +bool HTMLParser::framesetCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + popBlock(headTag); + if (inBody && !haveFrameSet && !haveContent) { + popBlock(bodyTag); + // ### actually for IE document.body returns the now hidden "body" element + // we can't implement that behaviour now because it could cause too many + // regressions and the headaches are not worth the work as long as there is + // no site actually relying on that detail (Dirk) + if (document->body()) + document->body()->setAttribute(styleAttr, "display:none"); + inBody = false; + } + if ((haveContent || haveFrameSet) && current->localName() == htmlTag) + return false; + haveFrameSet = true; + startBody(); + return true; +} + +bool HTMLParser::formCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + // Only create a new form if we're not already inside one. + // This is consistent with other browsers' behavior. + if (!m_currentFormElement) { + m_currentFormElement = new HTMLFormElement(document); + result = m_currentFormElement; + pCloserCreateErrorCheck(t, result); + } + return false; +} + +bool HTMLParser::isindexCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + RefPtr<Node> n = handleIsindex(t); + if (!inBody) { + m_isindexElement = n.release(); + } else { + t->flat = true; + result = n.release(); + } + return false; +} + +bool HTMLParser::selectCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + return true; +} + +bool HTMLParser::ddCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + pCloserCreateErrorCheck(t, result); + popBlock(dtTag); + popBlock(ddTag); + return true; +} + +bool HTMLParser::dtCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + pCloserCreateErrorCheck(t, result); + popBlock(ddTag); + popBlock(dtTag); + return true; +} + +bool HTMLParser::nestedCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + popBlock(t->tagName); + return true; +} + +bool HTMLParser::nestedPCloserCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + pCloserCreateErrorCheck(t, result); + popBlock(t->tagName); + return true; +} + +bool HTMLParser::nestedStyleCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + return allowNestedRedundantTag(t->tagName); +} + +bool HTMLParser::tableCellCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + popBlock(tdTag); + popBlock(thTag); + return true; +} + +bool HTMLParser::tableSectionCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + popBlock(theadTag); + popBlock(tbodyTag); + popBlock(tfootTag); + return true; +} + +bool HTMLParser::noembedCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + setSkipMode(noembedTag); + return true; +} + +bool HTMLParser::noframesCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + setSkipMode(noframesTag); + return true; +} + +bool HTMLParser::noscriptCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + if (!m_isParsingFragment) { + Settings* settings = document->settings(); + if (settings && settings->isJavaScriptEnabled()) + setSkipMode(noscriptTag); + } + return true; +} + +bool HTMLParser::pCloserCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + if (hasPElementInScope()) + popBlock(pTag); + return true; +} + +bool HTMLParser::pCloserStrictCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + if (document->inCompatMode()) + return true; + if (hasPElementInScope()) + popBlock(pTag); + return true; +} + +bool HTMLParser::mapCreateErrorCheck(Token* t, RefPtr<Node>& result) +{ + m_currentMapElement = new HTMLMapElement(document); + result = m_currentMapElement; + return false; +} + +PassRefPtr<Node> HTMLParser::getNode(Token* t) +{ + // Init our error handling table. + static FunctionMap gFunctionMap; + if (gFunctionMap.isEmpty()) { + gFunctionMap.set(aTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck); + gFunctionMap.set(addressTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(bTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(bigTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(blockquoteTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(bodyTag.localName().impl(), &HTMLParser::bodyCreateErrorCheck); + gFunctionMap.set(buttonTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck); + gFunctionMap.set(centerTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(commentAtom.impl(), &HTMLParser::commentCreateErrorCheck); + gFunctionMap.set(ddTag.localName().impl(), &HTMLParser::ddCreateErrorCheck); + gFunctionMap.set(dirTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(divTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(dlTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(dtTag.localName().impl(), &HTMLParser::dtCreateErrorCheck); + gFunctionMap.set(formTag.localName().impl(), &HTMLParser::formCreateErrorCheck); + gFunctionMap.set(fieldsetTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(framesetTag.localName().impl(), &HTMLParser::framesetCreateErrorCheck); + gFunctionMap.set(h1Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(h2Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(h3Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(h4Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(h5Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(h6Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(headTag.localName().impl(), &HTMLParser::headCreateErrorCheck); + gFunctionMap.set(hrTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(iTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(isindexTag.localName().impl(), &HTMLParser::isindexCreateErrorCheck); + gFunctionMap.set(liTag.localName().impl(), &HTMLParser::nestedPCloserCreateErrorCheck); + gFunctionMap.set(listingTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(mapTag.localName().impl(), &HTMLParser::mapCreateErrorCheck); + gFunctionMap.set(menuTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(nobrTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck); + gFunctionMap.set(noembedTag.localName().impl(), &HTMLParser::noembedCreateErrorCheck); + gFunctionMap.set(noframesTag.localName().impl(), &HTMLParser::noframesCreateErrorCheck); + gFunctionMap.set(noscriptTag.localName().impl(), &HTMLParser::noscriptCreateErrorCheck); + gFunctionMap.set(olTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(pTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(plaintextTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(preTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(sTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(selectTag.localName().impl(), &HTMLParser::selectCreateErrorCheck); + gFunctionMap.set(smallTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(strikeTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(tableTag.localName().impl(), &HTMLParser::pCloserStrictCreateErrorCheck); + gFunctionMap.set(tbodyTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck); + gFunctionMap.set(tdTag.localName().impl(), &HTMLParser::tableCellCreateErrorCheck); + gFunctionMap.set(textAtom.impl(), &HTMLParser::textCreateErrorCheck); + gFunctionMap.set(tfootTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck); + gFunctionMap.set(thTag.localName().impl(), &HTMLParser::tableCellCreateErrorCheck); + gFunctionMap.set(theadTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck); + gFunctionMap.set(trTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck); + gFunctionMap.set(ttTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(uTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); + gFunctionMap.set(ulTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + } + + bool proceed = true; + RefPtr<Node> result; + if (CreateErrorCheckFunc errorCheckFunc = gFunctionMap.get(t->tagName.impl())) + proceed = (this->*errorCheckFunc)(t, result); + if (proceed) + result = HTMLElementFactory::createHTMLElement(t->tagName, document, m_currentFormElement.get()); + return result.release(); +} + +bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName) +{ + // www.liceo.edu.mx is an example of a site that achieves a level of nesting of + // about 1500 tags, all from a bunch of <b>s. We will only allow at most 20 + // nested tags of the same type before just ignoring them all together. + unsigned i = 0; + for (HTMLStackElem* curr = blockStack; + i < cMaxRedundantTagDepth && curr && curr->tagName == tagName; + curr = curr->next, i++) { } + return i != cMaxRedundantTagDepth; +} + +void HTMLParser::processCloseTag(Token* t) +{ + // Support for really broken html. + // we never close the body tag, since some stupid web pages close it before the actual end of the doc. + // let's rely on the end() call to close things. + if (t->tagName == htmlTag || t->tagName == bodyTag || t->tagName == commentAtom) + return; + + bool checkForCloseTagErrors = true; + if (t->tagName == formTag && m_currentFormElement) { + m_currentFormElement = 0; + checkForCloseTagErrors = false; + } else if (t->tagName == mapTag) + m_currentMapElement = 0; + else if (t->tagName == pTag) + checkForCloseTagErrors = false; + + HTMLStackElem* oldElem = blockStack; + popBlock(t->tagName, checkForCloseTagErrors); + if (oldElem == blockStack && t->tagName == pTag) { + // We encountered a stray </p>. Amazingly Gecko, WinIE, and MacIE all treat + // this as a valid break, i.e., <p></p>. So go ahead and make the empty + // paragraph. + t->beginTag = true; + parseToken(t); + popBlock(t->tagName); + reportError(StrayParagraphCloseError); + } +} + +bool HTMLParser::isHeaderTag(const AtomicString& tagName) +{ + static HashSet<AtomicStringImpl*> headerTags; + if (headerTags.isEmpty()) { + headerTags.add(h1Tag.localName().impl()); + headerTags.add(h2Tag.localName().impl()); + headerTags.add(h3Tag.localName().impl()); + headerTags.add(h4Tag.localName().impl()); + headerTags.add(h5Tag.localName().impl()); + headerTags.add(h6Tag.localName().impl()); + } + + return headerTags.contains(tagName.impl()); +} + +bool HTMLParser::isInline(Node* node) const +{ + if (node->isTextNode()) + return true; + + if (node->isHTMLElement()) { + HTMLElement* e = static_cast<HTMLElement*>(node); + if (e->hasLocalName(aTag) || e->hasLocalName(fontTag) || e->hasLocalName(ttTag) || + e->hasLocalName(uTag) || e->hasLocalName(bTag) || e->hasLocalName(iTag) || + e->hasLocalName(sTag) || e->hasLocalName(strikeTag) || e->hasLocalName(bigTag) || + e->hasLocalName(smallTag) || e->hasLocalName(emTag) || e->hasLocalName(strongTag) || + e->hasLocalName(dfnTag) || e->hasLocalName(codeTag) || e->hasLocalName(sampTag) || + e->hasLocalName(kbdTag) || e->hasLocalName(varTag) || e->hasLocalName(citeTag) || + e->hasLocalName(abbrTag) || e->hasLocalName(acronymTag) || e->hasLocalName(subTag) || + e->hasLocalName(supTag) || e->hasLocalName(spanTag) || e->hasLocalName(nobrTag) || + e->hasLocalName(noframesTag) || e->hasLocalName(nolayerTag) || + e->hasLocalName(noembedTag)) + return true; + if (e->hasLocalName(noscriptTag) && !m_isParsingFragment) { + Settings* settings = document->settings(); + if (settings && settings->isJavaScriptEnabled()) + return true; + } + } + + return false; +} + +bool HTMLParser::isResidualStyleTag(const AtomicString& tagName) +{ + static HashSet<AtomicStringImpl*> residualStyleTags; + if (residualStyleTags.isEmpty()) { + residualStyleTags.add(aTag.localName().impl()); + residualStyleTags.add(fontTag.localName().impl()); + residualStyleTags.add(ttTag.localName().impl()); + residualStyleTags.add(uTag.localName().impl()); + residualStyleTags.add(bTag.localName().impl()); + residualStyleTags.add(iTag.localName().impl()); + residualStyleTags.add(sTag.localName().impl()); + residualStyleTags.add(strikeTag.localName().impl()); + residualStyleTags.add(bigTag.localName().impl()); + residualStyleTags.add(smallTag.localName().impl()); + residualStyleTags.add(emTag.localName().impl()); + residualStyleTags.add(strongTag.localName().impl()); + residualStyleTags.add(dfnTag.localName().impl()); + residualStyleTags.add(codeTag.localName().impl()); + residualStyleTags.add(sampTag.localName().impl()); + residualStyleTags.add(kbdTag.localName().impl()); + residualStyleTags.add(varTag.localName().impl()); + residualStyleTags.add(nobrTag.localName().impl()); + } + + return residualStyleTags.contains(tagName.impl()); +} + +bool HTMLParser::isAffectedByResidualStyle(const AtomicString& tagName) +{ + static HashSet<AtomicStringImpl*> unaffectedTags; + if (unaffectedTags.isEmpty()) { + unaffectedTags.add(bodyTag.localName().impl()); + unaffectedTags.add(tableTag.localName().impl()); + unaffectedTags.add(theadTag.localName().impl()); + unaffectedTags.add(tbodyTag.localName().impl()); + unaffectedTags.add(tfootTag.localName().impl()); + unaffectedTags.add(trTag.localName().impl()); + unaffectedTags.add(thTag.localName().impl()); + unaffectedTags.add(tdTag.localName().impl()); + unaffectedTags.add(captionTag.localName().impl()); + unaffectedTags.add(colgroupTag.localName().impl()); + unaffectedTags.add(colTag.localName().impl()); + unaffectedTags.add(optionTag.localName().impl()); + unaffectedTags.add(optgroupTag.localName().impl()); + unaffectedTags.add(selectTag.localName().impl()); + unaffectedTags.add(objectTag.localName().impl()); + } + + return !unaffectedTags.contains(tagName.impl()); +} + +void HTMLParser::handleResidualStyleCloseTagAcrossBlocks(HTMLStackElem* elem) +{ + HTMLStackElem* maxElem = 0; + bool finished = false; + bool strayTableContent = elem->strayTableContent; + + m_handlingResidualStyleAcrossBlocks = true; + while (!finished) { + // Find the outermost element that crosses over to a higher level. If there exists another higher-level + // element, we will do another pass, until we have corrected the innermost one. + ExceptionCode ec = 0; + HTMLStackElem* curr = blockStack; + HTMLStackElem* prev = 0; + HTMLStackElem* prevMaxElem = 0; + maxElem = 0; + finished = true; + while (curr && curr != elem) { + if (curr->level > elem->level) { + if (!isAffectedByResidualStyle(curr->tagName)) + return; + if (maxElem) + // We will need another pass. + finished = false; + maxElem = curr; + prevMaxElem = prev; + } + + prev = curr; + curr = curr->next; + } + + if (!curr || !maxElem) + return; + + Node* residualElem = prev->node; + Node* blockElem = prevMaxElem ? prevMaxElem->node : current; + Node* parentElem = elem->node; + + // Check to see if the reparenting that is going to occur is allowed according to the DOM. + // FIXME: We should either always allow it or perform an additional fixup instead of + // just bailing here. + // Example: <p><font><center>blah</font></center></p> isn't doing a fixup right now. + if (!parentElem->childAllowed(blockElem)) + return; + + m_hasPElementInScope = Unknown; + + if (maxElem->node->parentNode() != elem->node) { + // Walk the stack and remove any elements that aren't residual style tags. These + // are basically just being closed up. Example: + // <font><span>Moo<p>Goo</font></p>. + // In the above example, the <span> doesn't need to be reopened. It can just close. + HTMLStackElem* currElem = maxElem->next; + HTMLStackElem* prevElem = maxElem; + while (currElem != elem) { + HTMLStackElem* nextElem = currElem->next; + if (!isResidualStyleTag(currElem->tagName)) { + prevElem->next = nextElem; + prevElem->derefNode(); + prevElem->node = currElem->node; + prevElem->didRefNode = currElem->didRefNode; + delete currElem; + } + else + prevElem = currElem; + currElem = nextElem; + } + + // We have to reopen residual tags in between maxElem and elem. An example of this case is: + // <font><i>Moo<p>Foo</font>. + // In this case, we need to transform the part before the <p> into: + // <font><i>Moo</i></font><i> + // so that the <i> will remain open. This involves the modification of elements + // in the block stack. + // This will also affect how we ultimately reparent the block, since we want it to end up + // under the reopened residual tags (e.g., the <i> in the above example.) + RefPtr<Node> prevNode = 0; + currElem = maxElem; + while (currElem->node != residualElem) { + if (isResidualStyleTag(currElem->node->localName())) { + // Create a clone of this element. + // We call releaseRef to get a raw pointer since we plan to hand over ownership to currElem. + Node* currNode = currElem->node->cloneNode(false).releaseRef(); + reportError(ResidualStyleError, &currNode->localName()); + + // Change the stack element's node to point to the clone. + // The stack element adopts the reference we obtained above by calling release(). + currElem->derefNode(); + currElem->node = currNode; + currElem->didRefNode = true; + + // Attach the previous node as a child of this new node. + if (prevNode) + currNode->appendChild(prevNode, ec); + else // The new parent for the block element is going to be the innermost clone. + parentElem = currNode; // FIXME: We shifted parentElem to be a residual inline. We never checked to see if blockElem could be legally placed inside the inline though. + + prevNode = currNode; + } + + currElem = currElem->next; + } + + // Now append the chain of new residual style elements if one exists. + if (prevNode) + elem->node->appendChild(prevNode, ec); // FIXME: This append can result in weird stuff happening, like an inline chain being put into a table section. + } + + // Check if the block is still in the tree. If it isn't, then we don't + // want to remove it from its parent (that would crash) or insert it into + // a new parent later. See http://bugs.webkit.org/show_bug.cgi?id=6778 + bool isBlockStillInTree = blockElem->parentNode(); + + // We need to make a clone of |residualElem| and place it just inside |blockElem|. + // All content of |blockElem| is reparented to be under this clone. We then + // reparent |blockElem| using real DOM calls so that attachment/detachment will + // be performed to fix up the rendering tree. + // So for this example: <b>...<p>Foo</b>Goo</p> + // The end result will be: <b>...</b><p><b>Foo</b>Goo</p> + // + // Step 1: Remove |blockElem| from its parent, doing a batch detach of all the kids. + if (isBlockStillInTree) + blockElem->parentNode()->removeChild(blockElem, ec); + + Node* newNodePtr = 0; + if (blockElem->firstChild()) { + // Step 2: Clone |residualElem|. + RefPtr<Node> newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids. + newNodePtr = newNode.get(); + reportError(ResidualStyleError, &newNode->localName()); + + // Step 3: Place |blockElem|'s children under |newNode|. Remove all of the children of |blockElem| + // before we've put |newElem| into the document. That way we'll only do one attachment of all + // the new content (instead of a bunch of individual attachments). + Node* currNode = blockElem->firstChild(); + while (currNode) { + Node* nextNode = currNode->nextSibling(); + newNode->appendChild(currNode, ec); + currNode = nextNode; + } + + // Step 4: Place |newNode| under |blockElem|. |blockElem| is still out of the document, so no + // attachment can occur yet. + blockElem->appendChild(newNode.release(), ec); + } else + finished = true; + + // Step 5: Reparent |blockElem|. Now the full attachment of the fixed up tree takes place. + if (isBlockStillInTree) + parentElem->appendChild(blockElem, ec); + + // Step 6: Pull |elem| out of the stack, since it is no longer enclosing us. Also update + // the node associated with the previous stack element so that when it gets popped, + // it doesn't make the residual element the next current node. + HTMLStackElem* currElem = maxElem; + HTMLStackElem* prevElem = 0; + while (currElem != elem) { + prevElem = currElem; + currElem = currElem->next; + } + prevElem->next = elem->next; + prevElem->derefNode(); + prevElem->node = elem->node; + prevElem->didRefNode = elem->didRefNode; + if (!finished) { + // Repurpose |elem| to represent |newNode| and insert it at the appropriate position + // in the stack. We do not do this for the innermost block, because in that case the new + // node is effectively no longer open. + elem->next = maxElem; + elem->node = prevMaxElem->node; + elem->didRefNode = prevMaxElem->didRefNode; + elem->strayTableContent = false; + prevMaxElem->next = elem; + ASSERT(newNodePtr); + prevMaxElem->node = newNodePtr; + prevMaxElem->didRefNode = false; + } else + delete elem; + } + + // FIXME: If we ever make a case like this work: + // <table><b><i><form></b></form></i></table> + // Then this check will be too simplistic. Right now the <i><form> chain will end up inside the <tbody>, which is pretty crazy. + if (strayTableContent) + inStrayTableContent--; + + // Step 7: Reopen intermediate inlines, e.g., <b><p><i>Foo</b>Goo</p>. + // In the above example, Goo should stay italic. + // We cap the number of tags we're willing to reopen based off cResidualStyleMaxDepth. + + HTMLStackElem* curr = blockStack; + HTMLStackElem* residualStyleStack = 0; + unsigned stackDepth = 1; + unsigned redundantStyleCount = 0; + while (curr && curr != maxElem) { + // We will actually schedule this tag for reopening + // after we complete the close of this entire block. + if (isResidualStyleTag(curr->tagName) && stackDepth++ < cResidualStyleMaxDepth) { + // We've overloaded the use of stack elements and are just reusing the + // struct with a slightly different meaning to the variables. Instead of chaining + // from innermost to outermost, we build up a list of all the tags we need to reopen + // from the outermost to the innermost, i.e., residualStyleStack will end up pointing + // to the outermost tag we need to reopen. + // We also set curr->node to be the actual element that corresponds to the ID stored in + // curr->id rather than the node that you should pop to when the element gets pulled off + // the stack. + if (residualStyleStack && curr->tagName == residualStyleStack->tagName && curr->node->attributes()->mapsEquivalent(residualStyleStack->node->attributes())) + redundantStyleCount++; + else + redundantStyleCount = 0; + + if (redundantStyleCount < cMaxRedundantTagDepth) + moveOneBlockToStack(residualStyleStack); + else + popOneBlock(); + } else + popOneBlock(); + + curr = blockStack; + } + + reopenResidualStyleTags(residualStyleStack, 0); // Stray table content can't be an issue here, since some element above will always become the root of new stray table content. + + m_handlingResidualStyleAcrossBlocks = false; +} + +void HTMLParser::reopenResidualStyleTags(HTMLStackElem* elem, Node* malformedTableParent) +{ + // Loop for each tag that needs to be reopened. + while (elem) { + // Create a shallow clone of the DOM node for this element. + RefPtr<Node> newNode = elem->node->cloneNode(false); + reportError(ResidualStyleError, &newNode->localName()); + + // Append the new node. In the malformed table case, we need to insert before the table, + // which will be the last child. + ExceptionCode ec = 0; + if (malformedTableParent) + malformedTableParent->insertBefore(newNode, malformedTableParent->lastChild(), ec); + else + current->appendChild(newNode, ec); + // FIXME: Is it really OK to ignore the exceptions here? + + // Now push a new stack element for this node we just created. + pushBlock(elem->tagName, elem->level); + newNode->beginParsingChildren(); + + // Set our strayTableContent boolean if needed, so that the reopened tag also knows + // that it is inside a malformed table. + blockStack->strayTableContent = malformedTableParent != 0; + if (blockStack->strayTableContent) + inStrayTableContent++; + + // Clear our malformed table parent variable. + malformedTableParent = 0; + + // Update |current| manually to point to the new node. + setCurrent(newNode.get()); + + // Advance to the next tag that needs to be reopened. + HTMLStackElem* next = elem->next; + elem->derefNode(); + delete elem; + elem = next; + } +} + +void HTMLParser::pushBlock(const AtomicString& tagName, int level) +{ + blockStack = new HTMLStackElem(tagName, level, current, didRefCurrent, blockStack); + didRefCurrent = false; + if (tagName == pTag) + m_hasPElementInScope = InScope; + else if (isScopingTag(tagName)) + m_hasPElementInScope = NotInScope; +} + +void HTMLParser::popBlock(const AtomicString& tagName, bool reportErrors) +{ + HTMLStackElem* elem = blockStack; + + int maxLevel = 0; + + while (elem && (elem->tagName != tagName)) { + if (maxLevel < elem->level) + maxLevel = elem->level; + elem = elem->next; + } + + if (!elem) { + if (reportErrors) + reportError(StrayCloseTagError, &tagName, 0, true); + return; + } + + if (maxLevel > elem->level) { + // We didn't match because the tag is in a different scope, e.g., + // <b><p>Foo</b>. Try to correct the problem. + if (!isResidualStyleTag(tagName)) + return; + return handleResidualStyleCloseTagAcrossBlocks(elem); + } + + bool isAffectedByStyle = isAffectedByResidualStyle(elem->tagName); + HTMLStackElem* residualStyleStack = 0; + Node* malformedTableParent = 0; + + elem = blockStack; + unsigned stackDepth = 1; + unsigned redundantStyleCount = 0; + while (elem) { + if (elem->tagName == tagName) { + int strayTable = inStrayTableContent; + popOneBlock(); + elem = 0; + + // This element was the root of some malformed content just inside an implicit or + // explicit <tbody> or <tr>. + // If we end up needing to reopen residual style tags, the root of the reopened chain + // must also know that it is the root of malformed content inside a <tbody>/<tr>. + if (strayTable && (inStrayTableContent < strayTable) && residualStyleStack) { + Node* curr = current; + while (curr && !curr->hasTagName(tableTag)) + curr = curr->parentNode(); + malformedTableParent = curr ? curr->parentNode() : 0; + } + } + else { + if (m_currentFormElement && elem->tagName == formTag) + // A <form> is being closed prematurely (and this is + // malformed HTML). Set an attribute on the form to clear out its + // bottom margin. + m_currentFormElement->setMalformed(true); + + // Schedule this tag for reopening + // after we complete the close of this entire block. + if (isAffectedByStyle && isResidualStyleTag(elem->tagName) && stackDepth++ < cResidualStyleMaxDepth) { + // We've overloaded the use of stack elements and are just reusing the + // struct with a slightly different meaning to the variables. Instead of chaining + // from innermost to outermost, we build up a list of all the tags we need to reopen + // from the outermost to the innermost, i.e., residualStyleStack will end up pointing + // to the outermost tag we need to reopen. + // We also set elem->node to be the actual element that corresponds to the ID stored in + // elem->id rather than the node that you should pop to when the element gets pulled off + // the stack. + if (residualStyleStack && elem->tagName == residualStyleStack->tagName && elem->node->attributes()->mapsEquivalent(residualStyleStack->node->attributes())) + redundantStyleCount++; + else + redundantStyleCount = 0; + + if (redundantStyleCount < cMaxRedundantTagDepth) + moveOneBlockToStack(residualStyleStack); + else + popOneBlock(); + } else + popOneBlock(); + elem = blockStack; + } + } + + reopenResidualStyleTags(residualStyleStack, malformedTableParent); +} + +inline HTMLStackElem* HTMLParser::popOneBlockCommon() +{ + HTMLStackElem* elem = blockStack; + + // Form elements restore their state during the parsing process. + // Also, a few elements (<applet>, <object>) need to know when all child elements (<param>s) are available. + if (current && elem->node != current) + current->finishParsingChildren(); + + blockStack = elem->next; + current = elem->node; + didRefCurrent = elem->didRefNode; + + if (elem->strayTableContent) + inStrayTableContent--; + + if (elem->tagName == pTag) + m_hasPElementInScope = NotInScope; + else if (isScopingTag(elem->tagName)) + m_hasPElementInScope = Unknown; + + return elem; +} + +void HTMLParser::popOneBlock() +{ + // Store the current node before popOneBlockCommon overwrites it. + Node* lastCurrent = current; + bool didRefLastCurrent = didRefCurrent; + + delete popOneBlockCommon(); + + if (didRefLastCurrent) + lastCurrent->deref(); +} + +void HTMLParser::moveOneBlockToStack(HTMLStackElem*& head) +{ + // We'll be using the stack element we're popping, but for the current node. + // See the two callers for details. + + // Store the current node before popOneBlockCommon overwrites it. + Node* lastCurrent = current; + bool didRefLastCurrent = didRefCurrent; + + // Pop the block, but don't deref the current node as popOneBlock does because + // we'll be using the pointer in the new stack element. + HTMLStackElem* elem = popOneBlockCommon(); + + // Transfer the current node into the stack element. + // No need to deref the old elem->node because popOneBlockCommon transferred + // it into the current/didRefCurrent fields. + elem->node = lastCurrent; + elem->didRefNode = didRefLastCurrent; + elem->next = head; + head = elem; +} + +void HTMLParser::checkIfHasPElementInScope() +{ + m_hasPElementInScope = NotInScope; + HTMLStackElem* elem = blockStack; + while (elem) { + const AtomicString& tagName = elem->tagName; + if (tagName == pTag) { + m_hasPElementInScope = InScope; + return; + } else if (isScopingTag(tagName)) + return; + elem = elem->next; + } +} + +void HTMLParser::popInlineBlocks() +{ + while (blockStack && isInline(current)) + popOneBlock(); +} + +void HTMLParser::freeBlock() +{ + while (blockStack) + popOneBlock(); +} + +void HTMLParser::createHead() +{ + if (head || !document->documentElement()) + return; + + head = new HTMLHeadElement(document); + HTMLElement* body = document->body(); + ExceptionCode ec = 0; + document->documentElement()->insertBefore(head, body, ec); + if (ec) + head = 0; + + // If the body does not exist yet, then the <head> should be pushed as the current block. + if (head && !body) { + pushBlock(head->localName(), head->tagPriority()); + setCurrent(head); + } +} + +PassRefPtr<Node> HTMLParser::handleIsindex(Token* t) +{ + RefPtr<Node> n = new HTMLDivElement(document); + + NamedMappedAttrMap* attrs = t->attrs.get(); + + RefPtr<HTMLIsIndexElement> isIndex = new HTMLIsIndexElement(document, m_currentFormElement.get()); + isIndex->setAttributeMap(attrs); + isIndex->setAttribute(typeAttr, "khtml_isindex"); + + String text = searchableIndexIntroduction(); + if (attrs) { + if (Attribute* a = attrs->getAttributeItem(promptAttr)) + text = a->value().string() + " "; + t->attrs = 0; + } + + n->addChild(new HTMLHRElement(document)); + n->addChild(new Text(document, text)); + n->addChild(isIndex.release()); + n->addChild(new HTMLHRElement(document)); + + return n.release(); +} + +void HTMLParser::startBody() +{ + if (inBody) + return; + + inBody = true; + + if (m_isindexElement) { + insertNode(m_isindexElement.get(), true /* don't descend into this node */); + m_isindexElement = 0; + } +} + +void HTMLParser::finished() +{ + // In the case of a completely empty document, here's the place to create the HTML element. + if (current && current->isDocumentNode() && !document->documentElement()) + insertNode(new HTMLHtmlElement(document)); + + // This ensures that "current" is not left pointing to a node when the document is destroyed. + freeBlock(); + setCurrent(0); + + // Warning, this may delete the tokenizer and parser, so don't try to do anything else after this. + if (!m_isParsingFragment) + document->finishedParsing(); +} + +void HTMLParser::reportErrorToConsole(HTMLParserErrorCode errorCode, const AtomicString* tagName1, const AtomicString* tagName2, bool closeTags) +{ + Frame* frame = document->frame(); + if (!frame) + return; + + HTMLTokenizer* htmlTokenizer = static_cast<HTMLTokenizer*>(document->tokenizer()); + int lineNumber = htmlTokenizer->lineNumber() + 1; + + AtomicString tag1; + AtomicString tag2; + if (tagName1) { + if (*tagName1 == "#text") + tag1 = "Text"; + else if (*tagName1 == "#comment") + tag1 = "<!-- comment -->"; + else + tag1 = (closeTags ? "</" : "<") + *tagName1 + ">"; + } + if (tagName2) { + if (*tagName2 == "#text") + tag2 = "Text"; + else if (*tagName2 == "#comment") + tag2 = "<!-- comment -->"; + else + tag2 = (closeTags ? "</" : "<") + *tagName2 + ">"; + } + + const char* errorMsg = htmlParserErrorMessageTemplate(errorCode); + if (!errorMsg) + return; + + String message; + if (htmlTokenizer->processingContentWrittenByScript()) + message += htmlParserDocumentWriteMessage(); + message += errorMsg; + message.replace("%tag1", tag1); + message.replace("%tag2", tag2); + + frame->domWindow()->console()->addMessage(HTMLMessageSource, + isWarning(errorCode) ? WarningMessageLevel : ErrorMessageLevel, + message, lineNumber, document->url().string()); +} + +} diff --git a/WebCore/html/HTMLParser.h b/WebCore/html/HTMLParser.h new file mode 100644 index 0000000..3a5b437 --- /dev/null +++ b/WebCore/html/HTMLParser.h @@ -0,0 +1,184 @@ +/* + Copyright (C) 1997 Martin Jones (mjones@kde.org) + (C) 1997 Torben Weis (weis@kde.org) + (C) 1998 Waldo Bastian (bastian@kde.org) + (C) 1999 Lars Knoll (knoll@kde.org) + Copyright (C) 2004, 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. +*/ + +#ifndef HTMLParser_h +#define HTMLParser_h + +#include "QualifiedName.h" +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> +#include "HTMLParserErrorCodes.h" + +namespace WebCore { + +class DoctypeToken; +class Document; +class DocumentFragment; +class HTMLDocument; +class HTMLFormElement; +class HTMLHeadElement; +class HTMLMapElement; +class Node; +class Token; + +struct HTMLStackElem; + +/** + * The parser for HTML. It receives a stream of tokens from the HTMLTokenizer, and + * builds up the Document structure from it. + */ +class HTMLParser : Noncopyable { +public: + HTMLParser(HTMLDocument*, bool reportErrors); + HTMLParser(DocumentFragment*); + virtual ~HTMLParser(); + + /** + * parses one token delivered by the tokenizer + */ + PassRefPtr<Node> parseToken(Token*); + + // Parses a doctype token. + void parseDoctypeToken(DoctypeToken*); + + /** + * tokenizer says it's not going to be sending us any more tokens + */ + void finished(); + + /** + * resets the parser + */ + void reset(); + + bool skipMode() const { return !m_skipModeTag.isNull(); } + bool isHandlingResidualStyleAcrossBlocks() const { return m_handlingResidualStyleAcrossBlocks; } + +private: + void setCurrent(Node*); + void derefCurrent(); + void setSkipMode(const QualifiedName& qName) { m_skipModeTag = qName.localName(); } + + PassRefPtr<Node> getNode(Token*); + bool bodyCreateErrorCheck(Token*, RefPtr<Node>&); + bool canvasCreateErrorCheck(Token*, RefPtr<Node>&); + bool commentCreateErrorCheck(Token*, RefPtr<Node>&); + bool ddCreateErrorCheck(Token*, RefPtr<Node>&); + bool dtCreateErrorCheck(Token*, RefPtr<Node>&); + bool formCreateErrorCheck(Token*, RefPtr<Node>&); + bool framesetCreateErrorCheck(Token*, RefPtr<Node>&); + bool headCreateErrorCheck(Token*, RefPtr<Node>&); + bool iframeCreateErrorCheck(Token*, RefPtr<Node>&); + bool isindexCreateErrorCheck(Token*, RefPtr<Node>&); + bool mapCreateErrorCheck(Token*, RefPtr<Node>&); + bool nestedCreateErrorCheck(Token*, RefPtr<Node>&); + bool nestedPCloserCreateErrorCheck(Token*, RefPtr<Node>&); + bool nestedStyleCreateErrorCheck(Token*, RefPtr<Node>&); + bool noembedCreateErrorCheck(Token*, RefPtr<Node>&); + bool noframesCreateErrorCheck(Token*, RefPtr<Node>&); + bool nolayerCreateErrorCheck(Token*, RefPtr<Node>&); + bool noscriptCreateErrorCheck(Token*, RefPtr<Node>&); + bool pCloserCreateErrorCheck(Token*, RefPtr<Node>&); + bool pCloserStrictCreateErrorCheck(Token*, RefPtr<Node>&); + bool selectCreateErrorCheck(Token*, RefPtr<Node>&); + bool tableCellCreateErrorCheck(Token*, RefPtr<Node>&); + bool tableSectionCreateErrorCheck(Token*, RefPtr<Node>&); + bool textCreateErrorCheck(Token*, RefPtr<Node>&); + + void processCloseTag(Token*); + + bool insertNode(Node*, bool flat = false); + bool handleError(Node*, bool flat, const AtomicString& localName, int tagPriority); + + void pushBlock(const AtomicString& tagName, int level); + void popBlock(const AtomicString& tagName, bool reportErrors = false); + void popBlock(const QualifiedName& qName, bool reportErrors = false) { return popBlock(qName.localName(), reportErrors); } // Convenience function for readability. + void popOneBlock(); + void moveOneBlockToStack(HTMLStackElem*& head); + inline HTMLStackElem* popOneBlockCommon(); + void popInlineBlocks(); + + void freeBlock(); + + void createHead(); + + static bool isResidualStyleTag(const AtomicString& tagName); + static bool isAffectedByResidualStyle(const AtomicString& tagName); + void handleResidualStyleCloseTagAcrossBlocks(HTMLStackElem*); + void reopenResidualStyleTags(HTMLStackElem*, Node* malformedTableParent); + + bool allowNestedRedundantTag(const AtomicString& tagName); + + static bool isHeaderTag(const AtomicString& tagName); + void popNestedHeaderTag(); + + bool isInline(Node*) const; + + void startBody(); // inserts the isindex element + PassRefPtr<Node> handleIsindex(Token*); + + void checkIfHasPElementInScope(); + bool hasPElementInScope() + { + if (m_hasPElementInScope == Unknown) + checkIfHasPElementInScope(); + return m_hasPElementInScope == InScope; + } + + void reportError(HTMLParserErrorCode errorCode, const AtomicString* tagName1 = 0, const AtomicString* tagName2 = 0, bool closeTags = false) + { if (!m_reportErrors) return; reportErrorToConsole(errorCode, tagName1, tagName2, closeTags); } + + void reportErrorToConsole(HTMLParserErrorCode, const AtomicString* tagName1, const AtomicString* tagName2, bool closeTags); + + Document* document; + + // The currently active element (the one new elements will be added to). Can be a document fragment, a document or an element. + Node* current; + // We can't ref a document, but we don't want to constantly check if a node is a document just to decide whether to deref. + bool didRefCurrent; + + HTMLStackElem* blockStack; + + enum ElementInScopeState { NotInScope, InScope, Unknown }; + ElementInScopeState m_hasPElementInScope; + + RefPtr<HTMLFormElement> m_currentFormElement; // currently active form + RefPtr<HTMLMapElement> m_currentMapElement; // current map + HTMLHeadElement* head; // head element; needed for HTML which defines <base> after </head> + RefPtr<Node> m_isindexElement; // a possible <isindex> element in the head + + bool inBody; + bool haveContent; + bool haveFrameSet; + + AtomicString m_skipModeTag; // tells the parser to discard all tags until it reaches the one specified + + bool m_isParsingFragment; + bool m_reportErrors; + bool m_handlingResidualStyleAcrossBlocks; + int inStrayTableContent; +}; + +} + +#endif // HTMLParser_h diff --git a/WebCore/html/HTMLParserErrorCodes.cpp b/WebCore/html/HTMLParserErrorCodes.cpp new file mode 100644 index 0000000..6f973df --- /dev/null +++ b/WebCore/html/HTMLParserErrorCodes.cpp @@ -0,0 +1,70 @@ +/* + * 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 "HTMLParserErrorCodes.h" + +namespace WebCore { + +const char* htmlParserErrorMessageTemplate(HTMLParserErrorCode errorCode) +{ + static const char* const errors[] = { + "%tag1 is not allowed inside %tag2. Moving %tag1 into the nearest enclosing <table>.", + "<head> must be a child of <html>. Content ignored.", + "%tag1 is not allowed inside %tag2. Moving %tag1 into the <head>.", + "Extra %tag1 encountered. Migrating attributes back to the original %tag1 element and ignoring the tag.", + "<area> is not allowed inside %tag1. Moving the <area> into the nearest enclosing <map>.", + "%tag1 is not allowed inside %tag2. Content ignored.", + "%tag1 is not allowed in a <frameset> page. Content ignored.", + "%tag1 is not allowed inside %tag2. Closing %tag2 and trying the insertion again.", + "%tag1 is not allowed inside <caption>. Closing the <caption> and trying the insertion again.", + "<table> is not allowed inside %tag1. Closing the current <table> and inserting the new <table> as a sibling.", + "%tag1 is not allowed inside %tag2. Inserting %tag1 before the <table> instead.", + "%tag1 misplaced in <table>. Creating %tag2 and putting %tag1 inside it.", + "</br> encountered. Converting </br> into <br>.", + "XML self-closing tag syntax used on %tag1. The tag will not be closed.", + "Unmatched </p> encountered. Converting </p> into <p></p>.", + "Unmatched %tag1 encountered. Ignoring tag.", + "%tag1 misnested or not properly closed. Cloning %tag1 in order to preserve the styles applied by it.", + "<form> cannot act as a container inside %tag1 without disrupting the table. The children of the <form> will be placed inside the %tag1 instead.", + "XML self-closing tag syntax used on <script>. The tag will be closed by WebKit, but not all browsers do this. Change to <script></script> instead for best cross-browser compatibility." + }; + + if (errorCode >= MisplacedTablePartError && errorCode <= IncorrectXMLCloseScriptWarning) + return errors[errorCode]; + return 0; +} + +const char* htmlParserDocumentWriteMessage() +{ + return "[The HTML that caused this error was generated by a script.] "; +} + +bool isWarning(HTMLParserErrorCode code) +{ + return code >= IncorrectXMLCloseScriptWarning; +} + +} diff --git a/WebCore/html/HTMLParserErrorCodes.h b/WebCore/html/HTMLParserErrorCodes.h new file mode 100644 index 0000000..4da6b90 --- /dev/null +++ b/WebCore/html/HTMLParserErrorCodes.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef HTMLParserErrorCodes_h +#define HTMLParserErrorCodes_h + +namespace WebCore { + +enum HTMLParserErrorCode { + MisplacedTablePartError, + MisplacedHeadError, + MisplacedHeadContentError, + RedundantHTMLBodyError, + MisplacedAreaError, + IgnoredContentError, + MisplacedFramesetContentError, + MisplacedContentRetryError, + MisplacedCaptionContentError, + MisplacedTableError, + StrayTableContentError, + TablePartRequiredError, + MalformedBRError, + IncorrectXMLSelfCloseError, + StrayParagraphCloseError, + StrayCloseTagError, + ResidualStyleError, + FormInsideTablePartError, + IncorrectXMLCloseScriptWarning +}; + +const char* htmlParserErrorMessageTemplate(HTMLParserErrorCode); +const char* htmlParserDocumentWriteMessage(); + +bool isWarning(HTMLParserErrorCode); + +} + +#endif diff --git a/WebCore/html/HTMLPlugInElement.cpp b/WebCore/html/HTMLPlugInElement.cpp new file mode 100644 index 0000000..7334132 --- /dev/null +++ b/WebCore/html/HTMLPlugInElement.cpp @@ -0,0 +1,210 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * 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 "HTMLPlugInElement.h" + +#include "CSSPropertyNames.h" +#include "Document.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "HTMLNames.h" +#include "Page.h" +#include "RenderWidget.h" +#include "Settings.h" +#include "Widget.h" +#include "ScriptController.h" + +#if USE(JSC) +#include "runtime.h" +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) +#include "JSNode.h" +#include "NP_jsobject.h" +#include "npruntime_impl.h" +#include "runtime_root.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc) + : HTMLFrameOwnerElement(tagName, doc) +#if ENABLE(NETSCAPE_PLUGIN_API) + , m_NPObject(0) +#endif +{ +} + +HTMLPlugInElement::~HTMLPlugInElement() +{ +#if USE(JSC) + ASSERT(!m_instance); // cleared in detach() +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) + if (m_NPObject) { + _NPN_ReleaseObject(m_NPObject); + m_NPObject = 0; + } +#endif +} + +#if USE(JSC) +void HTMLPlugInElement::detach() +{ + m_instance.clear(); + HTMLFrameOwnerElement::detach(); +} + +JSC::Bindings::Instance* HTMLPlugInElement::getInstance() const +{ + Frame* frame = document()->frame(); + if (!frame) + return 0; + + // If the host dynamically turns off JavaScript (or Java) we will still return + // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. + if (m_instance) + return m_instance.get(); + + RenderWidget* renderWidget = renderWidgetForJSBindings(); + if (renderWidget && renderWidget->widget()) + m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); + + return m_instance.get(); +} +#endif + +String HTMLPlugInElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLPlugInElement::setAlign(const String& value) +{ + setAttribute(alignAttr, value); +} + +String HTMLPlugInElement::height() const +{ + return getAttribute(heightAttr); +} + +void HTMLPlugInElement::setHeight(const String& value) +{ + setAttribute(heightAttr, value); +} + +String HTMLPlugInElement::name() const +{ + return getAttribute(nameAttr); +} + +void HTMLPlugInElement::setName(const String& value) +{ + setAttribute(nameAttr, value); +} + +String HTMLPlugInElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLPlugInElement::setWidth(const String& value) +{ + setAttribute(widthAttr, value); +} + +bool HTMLPlugInElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr || + attrName == heightAttr || + attrName == vspaceAttr || + attrName == hspaceAttr) { + result = eUniversal; + return false; + } + + if (attrName == alignAttr) { + result = eReplaced; // Share with <img> since the alignment behavior is the same. + return false; + } + + return HTMLFrameOwnerElement::mapToEntry(attrName, result); +} + +void HTMLPlugInElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == widthAttr) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + else if (attr->name() == heightAttr) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + else if (attr->name() == vspaceAttr) { + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + } else if (attr->name() == hspaceAttr) { + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + } else if (attr->name() == alignAttr) + addHTMLAlignment(attr); + else + HTMLFrameOwnerElement::parseMappedAttribute(attr); +} + +bool HTMLPlugInElement::checkDTD(const Node* newChild) +{ + return newChild->hasTagName(paramTag) || HTMLFrameOwnerElement::checkDTD(newChild); +} + +void HTMLPlugInElement::defaultEventHandler(Event* event) +{ + RenderObject* r = renderer(); + if (!r || !r->isWidget()) + return; + + if (Widget* widget = static_cast<RenderWidget*>(r)->widget()) + widget->handleEvent(event); +} + +#if ENABLE(NETSCAPE_PLUGIN_API) + +NPObject* HTMLPlugInElement::getNPObject() +{ + ASSERT(document()->frame()); + if (!m_NPObject) + m_NPObject = document()->frame()->script()->createScriptObjectForPluginElement(this); + return m_NPObject; +} + +#endif /* ENABLE(NETSCAPE_PLUGIN_API) */ + +void HTMLPlugInElement::updateWidgetCallback(Node* n) +{ + static_cast<HTMLPlugInElement*>(n)->updateWidget(); +} + +} diff --git a/WebCore/html/HTMLPlugInElement.h b/WebCore/html/HTMLPlugInElement.h new file mode 100644 index 0000000..1b3d911 --- /dev/null +++ b/WebCore/html/HTMLPlugInElement.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 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 HTMLPlugInElement_h +#define HTMLPlugInElement_h + +#include "HTMLFrameOwnerElement.h" + +#if USE(JSC) +namespace JSC { + namespace Bindings { + class Instance; + } +} +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) +struct NPObject; +#endif + +namespace WebCore { + +class RenderWidget; + +class HTMLPlugInElement : public HTMLFrameOwnerElement { +public: + HTMLPlugInElement(const QualifiedName& tagName, Document*); + virtual ~HTMLPlugInElement(); + + virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; + virtual void parseMappedAttribute(MappedAttribute*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual bool checkDTD(const Node* newChild); + + virtual void updateWidget() { } + + String align() const; + void setAlign(const String&); + + String height() const; + void setHeight(const String&); + + String name() const; + void setName(const String&); + + String width() const; + void setWidth(const String&); + + virtual void defaultEventHandler(Event*); + + virtual RenderWidget* renderWidgetForJSBindings() const = 0; +#if USE(JSC) + virtual void detach(); + JSC::Bindings::Instance* getInstance() const; +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) + virtual NPObject* getNPObject(); +#endif + +protected: + static void updateWidgetCallback(Node*); + + AtomicString m_name; +#if USE(JSC) + mutable RefPtr<JSC::Bindings::Instance> m_instance; +#endif +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* m_NPObject; +#endif +}; + +} // namespace WebCore + +#endif // HTMLPlugInElement_h diff --git a/WebCore/html/HTMLPlugInImageElement.cpp b/WebCore/html/HTMLPlugInImageElement.cpp new file mode 100644 index 0000000..6dcd5fb --- /dev/null +++ b/WebCore/html/HTMLPlugInImageElement.cpp @@ -0,0 +1,54 @@ +/* + * 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 "HTMLPlugInImageElement.h" + +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "HTMLImageLoader.h" +#include "Image.h" + +namespace WebCore { + +HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Document* document) + : HTMLPlugInElement(tagName, document) +{ +} + +HTMLPlugInImageElement::~HTMLPlugInImageElement() +{ +} + +bool HTMLPlugInImageElement::isImageType() +{ + if (m_serviceType.isEmpty() && protocolIs(m_url, "data")) + m_serviceType = mimeTypeFromDataURL(m_url); + + if (Frame* frame = document()->frame()) { + KURL completedURL = frame->loader()->completeURL(m_url); + return frame->loader()->client()->objectContentType(completedURL, m_serviceType) == ObjectContentImage; + } + + return Image::supportsType(m_serviceType); +} + +} // namespace WebCore diff --git a/WebCore/html/HTMLPlugInImageElement.h b/WebCore/html/HTMLPlugInImageElement.h new file mode 100644 index 0000000..ec3b258 --- /dev/null +++ b/WebCore/html/HTMLPlugInImageElement.h @@ -0,0 +1,49 @@ +/* + * 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. + * + */ + +#ifndef HTMLPlugInImageElement_h +#define HTMLPlugInImageElement_h + +#include "HTMLPlugInElement.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class HTMLImageLoader; + +class HTMLPlugInImageElement : public HTMLPlugInElement { +public: + HTMLPlugInImageElement(const QualifiedName& tagName, Document*); + virtual ~HTMLPlugInImageElement(); + + bool isImageType(); + + const String& serviceType() const { return m_serviceType; } + const String& url() const { return m_url; } + +protected: + OwnPtr<HTMLImageLoader> m_imageLoader; + String m_serviceType; + String m_url; +}; + +} // namespace WebCore + +#endif // HTMLPlugInImageElement_h diff --git a/WebCore/html/HTMLPreElement.cpp b/WebCore/html/HTMLPreElement.cpp new file mode 100644 index 0000000..23ecaaa --- /dev/null +++ b/WebCore/html/HTMLPreElement.cpp @@ -0,0 +1,83 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 "HTMLPreElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLPreElement::HTMLPreElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) +{ +} + +bool HTMLPreElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr || attrName == wrapAttr) { + result = ePre; + return false; + } + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLPreElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == widthAttr) { + // FIXME: Implement this some day. Width on a <pre> is the # of characters that + // we should size the pre to. We basically need to take the width of a space, + // multiply by the value of the attribute and then set that as the width CSS + // property. + } else if (attr->name() == wrapAttr) { + if (!attr->value().isNull()) + addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValuePreWrap); + } else + return HTMLElement::parseMappedAttribute(attr); +} + +int HTMLPreElement::width() const +{ + return getAttribute(widthAttr).toInt(); +} + +void HTMLPreElement::setWidth(int width) +{ + setAttribute(widthAttr, String::number(width)); +} + +bool HTMLPreElement::wrap() const +{ + return !getAttribute(wrapAttr).isNull(); +} + +void HTMLPreElement::setWrap(bool wrap) +{ + setAttribute(wrapAttr, wrap ? "" : 0); +} + +} diff --git a/WebCore/html/HTMLPreElement.h b/WebCore/html/HTMLPreElement.h new file mode 100644 index 0000000..691daf8 --- /dev/null +++ b/WebCore/html/HTMLPreElement.h @@ -0,0 +1,50 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLPreElement_h +#define HTMLPreElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLPreElement : public HTMLElement { +public: + HTMLPreElement(const QualifiedName&, Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + void parseMappedAttribute(MappedAttribute*); + + int width() const; + void setWidth(int w); + + bool wrap() const; + void setWrap(bool b); +}; + +} // namespace WebCore + +#endif // HTMLPreElement_h diff --git a/WebCore/html/HTMLPreElement.idl b/WebCore/html/HTMLPreElement.idl new file mode 100644 index 0000000..5597d95 --- /dev/null +++ b/WebCore/html/HTMLPreElement.idl @@ -0,0 +1,36 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=84050abc-45e6-4fd8-bdc3-29c7b4efb5cb, + ImplementationUUID=e6de0d19-883e-4e87-9569-fd068e5ee17d + ] HTMLPreElement : HTMLElement { + // FIXME: DOM spec says that width should be of type DOMString + // see http://bugs.webkit.org/show_bug.cgi?id=8992 + attribute long width; + + // Extensions + attribute boolean wrap; + }; + +} diff --git a/WebCore/html/HTMLQuoteElement.cpp b/WebCore/html/HTMLQuoteElement.cpp new file mode 100644 index 0000000..c8f6d1a --- /dev/null +++ b/WebCore/html/HTMLQuoteElement.cpp @@ -0,0 +1,48 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2003, 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 "HTMLQuoteElement.h" + +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLQuoteElement::HTMLQuoteElement(Document *doc) + : HTMLElement(qTag, doc) +{ +} + +String HTMLQuoteElement::cite() const +{ + return getAttribute(citeAttr); +} + +void HTMLQuoteElement::setCite(const String &value) +{ + setAttribute(citeAttr, value); +} + +} diff --git a/WebCore/html/HTMLQuoteElement.h b/WebCore/html/HTMLQuoteElement.h new file mode 100644 index 0000000..b078f70 --- /dev/null +++ b/WebCore/html/HTMLQuoteElement.h @@ -0,0 +1,47 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Simon Hausmann <hausmann@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. + * + */ +#ifndef HTMLQuoteElement_h +#define HTMLQuoteElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class String; + +class HTMLQuoteElement : public HTMLElement +{ +public: + HTMLQuoteElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + + String cite() const; + void setCite(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLQuoteElement.idl b/WebCore/html/HTMLQuoteElement.idl new file mode 100644 index 0000000..99047c4 --- /dev/null +++ b/WebCore/html/HTMLQuoteElement.idl @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=a011e1a3-19ec-4999-a225-79ebdc64abdd, + ImplementationUUID=85c885ee-cc47-4d98-852c-fb907d573024 + ] HTMLQuoteElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString cite; + }; +} diff --git a/WebCore/html/HTMLScriptElement.cpp b/WebCore/html/HTMLScriptElement.cpp new file mode 100644 index 0000000..ce334d7 --- /dev/null +++ b/WebCore/html/HTMLScriptElement.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "HTMLScriptElement.h" + +#include "Document.h" +#include "EventNames.h" +#include "HTMLNames.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLScriptElement::HTMLScriptElement(Document* doc) + : HTMLElement(scriptTag, doc) + , m_data(this, this) +{ +} + +HTMLScriptElement::~HTMLScriptElement() +{ +} + +bool HTMLScriptElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == sourceAttributeValue(); +} + +void HTMLScriptElement::setCreatedByParser(bool createdByParser) +{ + m_data.setCreatedByParser(createdByParser); +} + +bool HTMLScriptElement::shouldExecuteAsJavaScript() const +{ + return m_data.shouldExecuteAsJavaScript(); +} + +void HTMLScriptElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + ScriptElement::childrenChanged(m_data); + HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +void HTMLScriptElement::parseMappedAttribute(MappedAttribute* attr) +{ + const QualifiedName& attrName = attr->name(); + + if (attrName == srcAttr) + handleSourceAttribute(m_data, attr->value()); + else if (attrName == onloadAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLScriptElement::finishParsingChildren() +{ + ScriptElement::finishParsingChildren(m_data, sourceAttributeValue()); + HTMLElement::finishParsingChildren(); +} + +void HTMLScriptElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + ScriptElement::insertedIntoDocument(m_data, sourceAttributeValue()); +} + +void HTMLScriptElement::removedFromDocument() +{ + HTMLElement::removedFromDocument(); + ScriptElement::removedFromDocument(m_data); +} + +String HTMLScriptElement::text() const +{ + return m_data.scriptContent(); +} + +void HTMLScriptElement::setText(const String &value) +{ + ExceptionCode ec = 0; + int numChildren = childNodeCount(); + + if (numChildren == 1 && firstChild()->isTextNode()) { + static_cast<Text*>(firstChild())->setData(value, ec); + return; + } + + if (numChildren > 0) + removeChildren(); + + appendChild(document()->createTextNode(value.impl()), ec); +} + +String HTMLScriptElement::htmlFor() const +{ + // DOM Level 1 says: reserved for future use. + return String(); +} + +void HTMLScriptElement::setHtmlFor(const String&) +{ + // DOM Level 1 says: reserved for future use. +} + +String HTMLScriptElement::event() const +{ + // DOM Level 1 says: reserved for future use. + return String(); +} + +void HTMLScriptElement::setEvent(const String&) +{ + // DOM Level 1 says: reserved for future use. +} + +String HTMLScriptElement::charset() const +{ + return charsetAttributeValue(); +} + +void HTMLScriptElement::setCharset(const String &value) +{ + setAttribute(charsetAttr, value); +} + +bool HTMLScriptElement::defer() const +{ + return !getAttribute(deferAttr).isNull(); +} + +void HTMLScriptElement::setDefer(bool defer) +{ + setAttribute(deferAttr, defer ? "" : 0); +} + +KURL HTMLScriptElement::src() const +{ + return document()->completeURL(sourceAttributeValue()); +} + +void HTMLScriptElement::setSrc(const String &value) +{ + setAttribute(srcAttr, value); +} + +String HTMLScriptElement::type() const +{ + return typeAttributeValue(); +} + +void HTMLScriptElement::setType(const String &value) +{ + setAttribute(typeAttr, value); +} + +String HTMLScriptElement::scriptCharset() const +{ + return m_data.scriptCharset(); +} + +String HTMLScriptElement::scriptContent() const +{ + return m_data.scriptContent(); +} + +void HTMLScriptElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(src().string()); +} + +String HTMLScriptElement::sourceAttributeValue() const +{ + return getAttribute(srcAttr).string(); +} + +String HTMLScriptElement::charsetAttributeValue() const +{ + return getAttribute(charsetAttr).string(); +} + +String HTMLScriptElement::typeAttributeValue() const +{ + return getAttribute(typeAttr).string(); +} + +String HTMLScriptElement::languageAttributeValue() const +{ + return getAttribute(languageAttr).string(); +} + +void HTMLScriptElement::dispatchLoadEvent() +{ + ASSERT(!m_data.haveFiredLoadEvent()); + m_data.setHaveFiredLoadEvent(true); + + dispatchEventForType(eventNames().loadEvent, false, false); +} + +void HTMLScriptElement::dispatchErrorEvent() +{ + dispatchEventForType(eventNames().errorEvent, true, false); +} + +} diff --git a/WebCore/html/HTMLScriptElement.h b/WebCore/html/HTMLScriptElement.h new file mode 100644 index 0000000..aa5b7d9 --- /dev/null +++ b/WebCore/html/HTMLScriptElement.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@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. + * + */ + +#ifndef HTMLScriptElement_h +#define HTMLScriptElement_h + +#include "ScriptElement.h" +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLScriptElement : public HTMLElement + , public ScriptElement { +public: + HTMLScriptElement(Document*); + ~HTMLScriptElement(); + + void setCreatedByParser(bool); + bool shouldExecuteAsJavaScript() const; + virtual String scriptContent() const; + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + virtual bool checkDTD(const Node* newChild) { return newChild->isTextNode(); } + + virtual void parseMappedAttribute(MappedAttribute*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + virtual bool isURLAttribute(Attribute*) const; + virtual void finishParsingChildren(); + + String text() const; + void setText(const String&); + + String htmlFor() const; + void setHtmlFor(const String&); + + String event() const; + void setEvent(const String&); + + String charset() const; + void setCharset(const String&); + + bool defer() const; + void setDefer(bool); + + KURL src() const; + void setSrc(const String&); + + String type() const; + void setType(const String&); + + virtual String scriptCharset() const; + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +protected: + virtual String sourceAttributeValue() const; + virtual String charsetAttributeValue() const; + virtual String typeAttributeValue() const; + virtual String languageAttributeValue() const; + + virtual void dispatchLoadEvent(); + virtual void dispatchErrorEvent(); + +private: + ScriptElementData m_data; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLScriptElement.idl b/WebCore/html/HTMLScriptElement.idl new file mode 100644 index 0000000..4a19b8c --- /dev/null +++ b/WebCore/html/HTMLScriptElement.idl @@ -0,0 +1,35 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=57ddf4da-1c9b-4005-87d7-eb9b2ed78e95, + ImplementationUUID=2edb1093-08f1-4e76-9728-df5dedb879fe + ] HTMLScriptElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString text; + attribute [ConvertNullToNullString] DOMString htmlFor; + attribute [ConvertNullToNullString] DOMString event; + attribute [ConvertNullToNullString] DOMString charset; + attribute boolean defer; + attribute [ConvertNullToNullString] DOMString src; + attribute [ConvertNullToNullString] DOMString type; + }; +} diff --git a/WebCore/html/HTMLSelectElement.cpp b/WebCore/html/HTMLSelectElement.cpp new file mode 100644 index 0000000..e95bfd3 --- /dev/null +++ b/WebCore/html/HTMLSelectElement.cpp @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLSelectElement.h" + +#include "AXObjectCache.h" +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "CharacterNames.h" +#include "Document.h" +#include "Event.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "FormDataList.h" +#include "Frame.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLOptionsCollection.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "RenderListBox.h" +#include "RenderMenuList.h" +#include <math.h> +#include <wtf/Vector.h> + +#if PLATFORM(MAC) +#define ARROW_KEYS_POP_MENU 1 +#else +#define ARROW_KEYS_POP_MENU 0 +#endif + +using namespace std; +using namespace WTF; +using namespace Unicode; + +namespace WebCore { + +using namespace HTMLNames; + +static const DOMTimeStamp typeAheadTimeout = 1000; + +HTMLSelectElement::HTMLSelectElement(Document* doc, HTMLFormElement* f) + : HTMLFormControlElementWithState(selectTag, doc, f) + , m_minwidth(0) + , m_size(0) + , m_multiple(false) + , m_recalcListItems(false) + , m_lastOnChangeIndex(-1) + , m_activeSelectionAnchorIndex(-1) + , m_activeSelectionEndIndex(-1) + , m_activeSelectionState(false) + , m_repeatingChar(0) + , m_lastCharTime(0) +{ +} + +HTMLSelectElement::HTMLSelectElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) + : HTMLFormControlElementWithState(tagName, doc, f) + , m_minwidth(0) + , m_size(0) + , m_multiple(false) + , m_recalcListItems(false) + , m_lastOnChangeIndex(-1) + , m_activeSelectionAnchorIndex(-1) + , m_activeSelectionEndIndex(-1) + , m_activeSelectionState(false) + , m_repeatingChar(0) + , m_lastCharTime(0) +{ +} + +bool HTMLSelectElement::checkDTD(const Node* newChild) +{ + // Make sure to keep <optgroup> in sync with this. + return newChild->isTextNode() || newChild->hasTagName(optionTag) || newChild->hasTagName(optgroupTag) || newChild->hasTagName(hrTag) || + newChild->hasTagName(scriptTag); +} + +void HTMLSelectElement::recalcStyle( StyleChange ch ) +{ + if (hasChangedChild() && renderer()) { + if (usesMenuList()) + static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true); + else + static_cast<RenderListBox*>(renderer())->setOptionsChanged(true); + } else if (m_recalcListItems) + recalcListItems(); + + HTMLFormControlElementWithState::recalcStyle(ch); +} + +const AtomicString& HTMLSelectElement::type() const +{ + static const AtomicString selectMultiple("select-multiple"); + static const AtomicString selectOne("select-one"); + return m_multiple ? selectMultiple : selectOne; +} + +int HTMLSelectElement::selectedIndex() const +{ + // return the number of the first option selected + unsigned index = 0; + const Vector<HTMLElement*>& items = listItems(); + for (unsigned int i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + if (static_cast<HTMLOptionElement*>(items[i])->selected()) + return index; + index++; + } + } + return -1; +} + +int HTMLSelectElement::lastSelectedListIndex() const +{ + // return the number of the last option selected + unsigned index = 0; + bool found = false; + const Vector<HTMLElement*>& items = listItems(); + for (unsigned int i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + if (static_cast<HTMLOptionElement*>(items[i])->selected()) { + index = i; + found = true; + } + } + } + return found ? (int) index : -1; +} + +void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement) +{ + const Vector<HTMLElement*>& items = listItems(); + unsigned i; + for (i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) { + HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]); + element->setSelectedState(false); + } + } +} + +void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange) +{ + const Vector<HTMLElement*>& items = listItems(); + int listIndex = optionToListIndex(optionIndex); + HTMLOptionElement* element = 0; + + if (!multiple()) + deselect = true; + + if (listIndex >= 0) { + if (m_activeSelectionAnchorIndex < 0 || deselect) + setActiveSelectionAnchorIndex(listIndex); + if (m_activeSelectionEndIndex < 0 || deselect) + setActiveSelectionEndIndex(listIndex); + element = static_cast<HTMLOptionElement*>(items[listIndex]); + element->setSelectedState(true); + } + + if (deselect) + deselectItems(element); + + scrollToSelection(); + + // This only gets called with fireOnChange for menu lists. + if (fireOnChange && usesMenuList()) + menuListOnChange(); +} + +int HTMLSelectElement::activeSelectionStartListIndex() const +{ + if (m_activeSelectionAnchorIndex >= 0) + return m_activeSelectionAnchorIndex; + return optionToListIndex(selectedIndex()); +} + +int HTMLSelectElement::activeSelectionEndListIndex() const +{ + if (m_activeSelectionEndIndex >= 0) + return m_activeSelectionEndIndex; + return lastSelectedListIndex(); +} + +unsigned HTMLSelectElement::length() const +{ + unsigned len = 0; + const Vector<HTMLElement*>& items = listItems(); + for (unsigned i = 0; i < items.size(); ++i) { + if (items[i]->hasLocalName(optionTag)) + ++len; + } + return len; +} + +void HTMLSelectElement::add(HTMLElement *element, HTMLElement *before, ExceptionCode& ec) +{ + RefPtr<HTMLElement> protectNewChild(element); // make sure the element is ref'd and deref'd so we don't leak it + + if (!element || !(element->hasLocalName(optionTag) || element->hasLocalName(hrTag))) + return; + + ec = 0; + insertBefore(element, before, ec); + if (!ec) + setRecalcListItems(); +} + +void HTMLSelectElement::remove(int index) +{ + ExceptionCode ec = 0; + int listIndex = optionToListIndex(index); + + const Vector<HTMLElement*>& items = listItems(); + if (listIndex < 0 || index >= int(items.size())) + return; // ### what should we do ? remove the last item? + + Element *item = items[listIndex]; + ASSERT(item->parentNode()); + item->parentNode()->removeChild(item, ec); + if (!ec) + setRecalcListItems(); +} + +String HTMLSelectElement::value() +{ + unsigned i; + const Vector<HTMLElement*>& items = listItems(); + for (i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(items[i])->selected()) + return static_cast<HTMLOptionElement*>(items[i])->value(); + } + return String(""); +} + +void HTMLSelectElement::setValue(const String &value) +{ + if (value.isNull()) + return; + // find the option with value() matching the given parameter + // and make it the current selection. + const Vector<HTMLElement*>& items = listItems(); + unsigned optionIndex = 0; + for (unsigned i = 0; i < items.size(); i++) + if (items[i]->hasLocalName(optionTag)) { + if (static_cast<HTMLOptionElement*>(items[i])->value() == value) { + setSelectedIndex(optionIndex, true); + return; + } + optionIndex++; + } +} + +bool HTMLSelectElement::saveState(String& value) const +{ + const Vector<HTMLElement*>& items = listItems(); + int l = items.size(); + Vector<char, 1024> characters(l); + for (int i = 0; i < l; ++i) { + HTMLElement* e = items[i]; + bool selected = e->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(e)->selected(); + characters[i] = selected ? 'X' : '.'; + } + value = String(characters.data(), l); + return true; +} + +void HTMLSelectElement::restoreState(const String& state) +{ + recalcListItems(); + + const Vector<HTMLElement*>& items = listItems(); + int l = items.size(); + for (int i = 0; i < l; i++) + if (items[i]->hasLocalName(optionTag)) + static_cast<HTMLOptionElement*>(items[i])->setSelectedState(state[i] == 'X'); + + setChanged(); +} + +bool HTMLSelectElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElementWithState::insertBefore(newChild, refChild, ec, shouldLazyAttach); + if (result) + setRecalcListItems(); + return result; +} + +bool HTMLSelectElement::replaceChild(PassRefPtr<Node> newChild, Node *oldChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElementWithState::replaceChild(newChild, oldChild, ec, shouldLazyAttach); + if (result) + setRecalcListItems(); + return result; +} + +bool HTMLSelectElement::removeChild(Node* oldChild, ExceptionCode& ec) +{ + bool result = HTMLFormControlElementWithState::removeChild(oldChild, ec); + if (result) + setRecalcListItems(); + return result; +} + +bool HTMLSelectElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach) +{ + bool result = HTMLFormControlElementWithState::appendChild(newChild, ec, shouldLazyAttach); + if (result) + setRecalcListItems(); + return result; +} + +bool HTMLSelectElement::removeChildren() +{ + bool result = HTMLFormControlElementWithState::removeChildren(); + if (result) + setRecalcListItems(); + return result; +} + +void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr) +{ + bool oldUsesMenuList = usesMenuList(); + if (attr->name() == sizeAttr) { + int oldSize = m_size; + // Set the attribute value to a number. + // This is important since the style rules for this attribute can determine the appearance property. + int size = attr->value().toInt(); + String attrSize = String::number(size); + if (attrSize != attr->value()) + attr->setValue(attrSize); + + m_size = max(size, 1); + if ((oldUsesMenuList != usesMenuList() || !oldUsesMenuList && m_size != oldSize) && attached()) { + detach(); + attach(); + setRecalcListItems(); + } + } else if (attr->name() == widthAttr) { + m_minwidth = max(attr->value().toInt(), 0); + } else if (attr->name() == multipleAttr) { + m_multiple = (!attr->isNull()); + if (oldUsesMenuList != usesMenuList() && attached()) { + detach(); + attach(); + } + } else if (attr->name() == accesskeyAttr) { + // FIXME: ignore for the moment + } else if (attr->name() == alignAttr) { + // Don't map 'align' attribute. This matches what Firefox, Opera and IE do. + // See http://bugs.webkit.org/show_bug.cgi?id=12072 + } else if (attr->name() == onfocusAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + } else if (attr->name() == onblurAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + } else if (attr->name() == onchangeAttr) { + setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + } else + HTMLFormControlElementWithState::parseMappedAttribute(attr); +} + +bool HTMLSelectElement::isKeyboardFocusable(KeyboardEvent* event) const +{ + if (renderer()) + return isFocusable(); + return HTMLFormControlElementWithState::isKeyboardFocusable(event); +} + +bool HTMLSelectElement::isMouseFocusable() const +{ + if (renderer()) + return isFocusable(); + return HTMLFormControlElementWithState::isMouseFocusable(); +} + +bool HTMLSelectElement::canSelectAll() const +{ + return !usesMenuList(); +} + +void HTMLSelectElement::selectAll() +{ + ASSERT(!usesMenuList()); + if (!renderer() || !multiple()) + return; + + // Save the selection so it can be compared to the new selectAll selection when we call onChange + saveLastSelection(); + + m_activeSelectionState = true; + setActiveSelectionAnchorIndex(nextSelectableListIndex(-1)); + setActiveSelectionEndIndex(previousSelectableListIndex(-1)); + + updateListBoxSelection(false); + listBoxOnChange(); +} + +RenderObject *HTMLSelectElement::createRenderer(RenderArena *arena, RenderStyle *style) +{ + if (usesMenuList()) + return new (arena) RenderMenuList(this); + return new (arena) RenderListBox(this); +} + +bool HTMLSelectElement::appendFormData(FormDataList& list, bool) +{ + bool successful = false; + const Vector<HTMLElement*>& items = listItems(); + + unsigned i; + for (i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]); + if (option->selected()) { + list.appendData(name(), option->value()); + successful = true; + } + } + } + + // ### this case should not happen. make sure that we select the first option + // in any case. otherwise we have no consistency with the DOM interface. FIXME! + // we return the first one if it was a combobox select + if (!successful && !m_multiple && m_size <= 1 && items.size() && + (items[0]->hasLocalName(optionTag))) { + HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[0]); + if (option->value().isNull()) + list.appendData(name(), option->text().stripWhiteSpace()); + else + list.appendData(name(), option->value()); + successful = true; + } + + return successful; +} + +int HTMLSelectElement::optionToListIndex(int optionIndex) const +{ + const Vector<HTMLElement*>& items = listItems(); + int listSize = (int)items.size(); + if (optionIndex < 0 || optionIndex >= listSize) + return -1; + + int optionIndex2 = -1; + for (int listIndex = 0; listIndex < listSize; listIndex++) { + if (items[listIndex]->hasLocalName(optionTag)) { + optionIndex2++; + if (optionIndex2 == optionIndex) + return listIndex; + } + } + return -1; +} + +int HTMLSelectElement::listToOptionIndex(int listIndex) const +{ + const Vector<HTMLElement*>& items = listItems(); + if (listIndex < 0 || listIndex >= int(items.size()) || + !items[listIndex]->hasLocalName(optionTag)) + return -1; + + int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list + for (int i = 0; i < listIndex; i++) + if (items[i]->hasLocalName(optionTag)) + optionIndex++; + return optionIndex; +} + +PassRefPtr<HTMLOptionsCollection> HTMLSelectElement::options() +{ + return HTMLOptionsCollection::create(this); +} + +void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const +{ + m_listItems.clear(); + HTMLOptionElement* foundSelected = 0; + for (Node* current = firstChild(); current; current = current->traverseNextSibling(this)) { + if (current->hasTagName(optgroupTag) && current->firstChild()) { + // FIXME: It doesn't make sense to add an optgroup to the list items, + // when it has children, but not to add it if it happens to have, + // children (say some comment nodes or text nodes), yet that's what + // this code does! + m_listItems.append(static_cast<HTMLElement*>(current)); + current = current->firstChild(); + // FIXME: It doesn't make sense to handle an <optgroup> inside another <optgroup> + // if it's not the first child, but not handle it if it happens to be the first + // child, yet that's what this code does! + } + + if (current->hasTagName(optionTag)) { + m_listItems.append(static_cast<HTMLElement*>(current)); + if (updateSelectedStates) { + if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) { + foundSelected = static_cast<HTMLOptionElement*>(current); + foundSelected->setSelectedState(true); + } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) { + foundSelected->setSelectedState(false); + foundSelected = static_cast<HTMLOptionElement*>(current); + } + } + } + if (current->hasTagName(hrTag)) + m_listItems.append(static_cast<HTMLElement*>(current)); + } + m_recalcListItems = false; +} + +void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + setRecalcListItems(); + HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); + + if (AXObjectCache::accessibilityEnabled() && renderer()) + renderer()->document()->axObjectCache()->childrenChanged(renderer()); +} + +void HTMLSelectElement::setRecalcListItems() +{ + m_recalcListItems = true; + if (renderer()) { + if (usesMenuList()) + static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true); + else + static_cast<RenderListBox*>(renderer())->setOptionsChanged(true); + } + if (!inDocument()) + m_collectionInfo.reset(); + setChanged(); +} + +void HTMLSelectElement::reset() +{ + bool optionSelected = false; + HTMLOptionElement* firstOption = 0; + const Vector<HTMLElement*>& items = listItems(); + unsigned i; + for (i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]); + if (!option->getAttribute(selectedAttr).isNull()) { + option->setSelectedState(true); + optionSelected = true; + } else + option->setSelectedState(false); + if (!firstOption) + firstOption = option; + } + } + if (!optionSelected && firstOption && usesMenuList()) + firstOption->setSelectedState(true); + + setChanged(); +} + +void HTMLSelectElement::dispatchFocusEvent() +{ + if (usesMenuList()) + // Save the selection so it can be compared to the new selection when we call onChange during dispatchBlurEvent. + saveLastSelection(); + HTMLFormControlElementWithState::dispatchFocusEvent(); +} + +void HTMLSelectElement::dispatchBlurEvent() +{ + // We only need to fire onChange here for menu lists, because we fire onChange for list boxes whenever the selection change is actually made. + // This matches other browsers' behavior. + if (usesMenuList()) + menuListOnChange(); + HTMLFormControlElementWithState::dispatchBlurEvent(); +} + +void HTMLSelectElement::defaultEventHandler(Event* evt) +{ + if (!renderer()) + return; + + if (usesMenuList()) + menuListDefaultEventHandler(evt); + else + listBoxDefaultEventHandler(evt); + + if (evt->defaultHandled()) + return; + + if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { + KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(evt); + + if (!keyboardEvent->ctrlKey() && !keyboardEvent->altKey() && !keyboardEvent->metaKey() && + isPrintableChar(keyboardEvent->charCode())) { + typeAheadFind(keyboardEvent); + evt->setDefaultHandled(); + return; + } + } + + HTMLFormControlElementWithState::defaultEventHandler(evt); +} + +void HTMLSelectElement::menuListDefaultEventHandler(Event* evt) +{ + RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer()); + + if (evt->type() == eventNames().keydownEvent) { + if (!renderer() || !evt->isKeyboardEvent()) + return; + String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); + bool handled = false; +#if ARROW_KEYS_POP_MENU + if (keyIdentifier == "Down" || keyIdentifier == "Up") { + focus(); + // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, + // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. + saveLastSelection(); + menuList->showPopup(); + handled = true; + } +#elif defined ANDROID_KEYBOARD_NAVIGATION + if ("Enter" == keyIdentifier && usesMenuList()) { + menuList->showPopup(); + handled = true; + } +#else + int listIndex = optionToListIndex(selectedIndex()); + if (keyIdentifier == "Down" || keyIdentifier == "Right") { + int size = listItems().size(); + for (listIndex += 1; + listIndex >= 0 && listIndex < size && (listItems()[listIndex]->disabled() || !listItems()[listIndex]->hasTagName(optionTag)); + ++listIndex) { } + + if (listIndex >= 0 && listIndex < size) + setSelectedIndex(listToOptionIndex(listIndex)); + handled = true; + } else if (keyIdentifier == "Up" || keyIdentifier == "Left") { + int size = listItems().size(); + for (listIndex -= 1; + listIndex >= 0 && listIndex < size && (listItems()[listIndex]->disabled() || !listItems()[listIndex]->hasTagName(optionTag)); + --listIndex) { } + + if (listIndex >= 0 && listIndex < size) + setSelectedIndex(listToOptionIndex(listIndex)); + handled = true; + } +#endif + if (handled) + evt->setDefaultHandled(); + } + + // Use key press event here since sending simulated mouse events + // on key down blocks the proper sending of the key press event. + if (evt->type() == eventNames().keypressEvent) { + if (!renderer() || !evt->isKeyboardEvent()) + return; + int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode(); + bool handled = false; +#if ARROW_KEYS_POP_MENU + if (keyCode == ' ') { + focus(); + // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, + // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. + saveLastSelection(); + menuList->showPopup(); + handled = true; + } + if (keyCode == '\r') { + menuListOnChange(); + if (form()) + form()->submitClick(evt); + handled = true; + } +#else + int listIndex = optionToListIndex(selectedIndex()); + if (keyCode == '\r') { + // listIndex should already be selected, but this will fire the onchange handler. + setSelectedIndex(listToOptionIndex(listIndex), true, true); + handled = true; + } +#endif + if (handled) + evt->setDefaultHandled(); + } + + if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + focus(); + if (menuList->popupIsVisible()) + menuList->hidePopup(); + else { + // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, + // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. + saveLastSelection(); + menuList->showPopup(); + } + evt->setDefaultHandled(); + } +} + +void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt) +{ + if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + focus(); + + MouseEvent* mEvt = static_cast<MouseEvent*>(evt); + int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(mEvt->offsetX(), mEvt->offsetY()); + if (listIndex >= 0) { + // Save the selection so it can be compared to the new selection when we call onChange during mouseup, or after autoscroll finishes. + saveLastSelection(); + + m_activeSelectionState = true; + + bool multiSelectKeyPressed = false; +#if PLATFORM(MAC) + multiSelectKeyPressed = mEvt->metaKey(); +#else + multiSelectKeyPressed = mEvt->ctrlKey(); +#endif + + bool shiftSelect = multiple() && mEvt->shiftKey(); + bool multiSelect = multiple() && multiSelectKeyPressed && !mEvt->shiftKey(); + + HTMLElement* clickedElement = listItems()[listIndex]; + HTMLOptionElement* option = 0; + if (clickedElement->hasLocalName(optionTag)) { + option = static_cast<HTMLOptionElement*>(clickedElement); + + // Keep track of whether an active selection (like during drag selection), should select or deselect + if (option->selected() && multiSelectKeyPressed) + m_activeSelectionState = false; + + if (!m_activeSelectionState) + option->setSelectedState(false); + } + + // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option. + // If no option was clicked, then this will deselect all items in the list. + if (!shiftSelect && !multiSelect) + deselectItems(option); + + // If the anchor hasn't been set, and we're doing a single selection or a shift selection, then initialize the anchor to the first selected index. + if (m_activeSelectionAnchorIndex < 0 && !multiSelect) + setActiveSelectionAnchorIndex(selectedIndex()); + + // Set the selection state of the clicked option + if (option && !option->disabled()) + option->setSelectedState(true); + + // If there was no selectedIndex() for the previous initialization, or + // If we're doing a single selection, or a multiple selection (using cmd or ctrl), then initialize the anchor index to the listIndex that just got clicked. + if (listIndex >= 0 && (m_activeSelectionAnchorIndex < 0 || !shiftSelect)) + setActiveSelectionAnchorIndex(listIndex); + + setActiveSelectionEndIndex(listIndex); + updateListBoxSelection(!multiSelect); + + if (Frame* frame = document()->frame()) + frame->eventHandler()->setMouseDownMayStartAutoscroll(); + + evt->setDefaultHandled(); + } + } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer()) + // This makes sure we fire onChange for a single click. For drag selection, onChange will fire when the autoscroll timer stops. + listBoxOnChange(); + else if (evt->type() == eventNames().keydownEvent) { + if (!evt->isKeyboardEvent()) + return; + String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); + + int endIndex = 0; + if (m_activeSelectionEndIndex < 0) { + // Initialize the end index + if (keyIdentifier == "Down") + endIndex = nextSelectableListIndex(lastSelectedListIndex()); + else if (keyIdentifier == "Up") + endIndex = previousSelectableListIndex(optionToListIndex(selectedIndex())); + } else { + // Set the end index based on the current end index + if (keyIdentifier == "Down") + endIndex = nextSelectableListIndex(m_activeSelectionEndIndex); + else if (keyIdentifier == "Up") + endIndex = previousSelectableListIndex(m_activeSelectionEndIndex); + } + + if (keyIdentifier == "Down" || keyIdentifier == "Up") { + // Save the selection so it can be compared to the new selection when we call onChange immediately after making the new selection. + saveLastSelection(); + + ASSERT(endIndex >= 0 && (unsigned)endIndex < listItems().size()); + setActiveSelectionEndIndex(endIndex); + + // If the anchor is unitialized, or if we're going to deselect all other options, then set the anchor index equal to the end index. + bool deselectOthers = !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey(); + if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { + m_activeSelectionState = true; + if (deselectOthers) + deselectItems(); + setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); + } + + static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(endIndex); + updateListBoxSelection(deselectOthers); + listBoxOnChange(); + evt->setDefaultHandled(); + } + } else if (evt->type() == eventNames().keypressEvent) { + if (!evt->isKeyboardEvent()) + return; + int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode(); + + if (keyCode == '\r') { + if (form()) + form()->submitClick(evt); + evt->setDefaultHandled(); + return; + } + } +} + +void HTMLSelectElement::setActiveSelectionAnchorIndex(int index) +{ + m_activeSelectionAnchorIndex = index; + + // Cache the selection state so we can restore the old selection as the new selection pivots around this anchor index + const Vector<HTMLElement*>& items = listItems(); + m_cachedStateForActiveSelection.clear(); + for (unsigned i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); + m_cachedStateForActiveSelection.append(option->selected()); + } else + m_cachedStateForActiveSelection.append(false); + } +} + +void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions) +{ + ASSERT(renderer() && renderer()->isListBox()); + + unsigned start; + unsigned end; + ASSERT(m_activeSelectionAnchorIndex >= 0); + start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); + end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); + + const Vector<HTMLElement*>& items = listItems(); + for (unsigned i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); + if (!option->disabled()) { + if (i >= start && i <= end) + option->setSelectedState(m_activeSelectionState); + else if (deselectOtherOptions) + option->setSelectedState(false); + else + option->setSelectedState(m_cachedStateForActiveSelection[i]); + } + } + } + + scrollToSelection(); +} + +void HTMLSelectElement::menuListOnChange() +{ + ASSERT(usesMenuList()); + int selected = selectedIndex(); + if (m_lastOnChangeIndex != selected) { + m_lastOnChangeIndex = selected; + onChange(); + } +} + +void HTMLSelectElement::listBoxOnChange() +{ + ASSERT(!usesMenuList()); + + const Vector<HTMLElement*>& items = listItems(); + + // If the cached selection list is empty, or the size has changed, then fire onChange, and return early. + if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != items.size()) { + onChange(); + return; + } + + // Update m_lastOnChangeSelection and fire onChange + bool fireOnChange = false; + for (unsigned i = 0; i < items.size(); i++) { + bool selected = false; + if (items[i]->hasLocalName(optionTag)) + selected = static_cast<HTMLOptionElement*>(items[i])->selected(); + if (selected != m_lastOnChangeSelection[i]) + fireOnChange = true; + m_lastOnChangeSelection[i] = selected; + } + if (fireOnChange) + onChange(); +} + +void HTMLSelectElement::saveLastSelection() +{ + const Vector<HTMLElement*>& items = listItems(); + + if (usesMenuList()) { + m_lastOnChangeIndex = selectedIndex(); + return; + } + + m_lastOnChangeSelection.clear(); + for (unsigned i = 0; i < items.size(); i++) { + if (items[i]->hasLocalName(optionTag)) { + HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); + m_lastOnChangeSelection.append(option->selected()); + } else + m_lastOnChangeSelection.append(false); + } +} + +static String stripLeadingWhiteSpace(const String& string) +{ + int length = string.length(); + int i; + for (i = 0; i < length; ++i) + if (string[i] != noBreakSpace && + (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral))) + break; + + return string.substring(i, length - i); +} + +void HTMLSelectElement::typeAheadFind(KeyboardEvent* event) +{ + if (event->timeStamp() < m_lastCharTime) + return; + + DOMTimeStamp delta = event->timeStamp() - m_lastCharTime; + + m_lastCharTime = event->timeStamp(); + + UChar c = event->charCode(); + + String prefix; + int searchStartOffset = 1; + if (delta > typeAheadTimeout) { + m_typedString = prefix = String(&c, 1); + m_repeatingChar = c; + } else { + m_typedString.append(c); + + if (c == m_repeatingChar) + // The user is likely trying to cycle through all the items starting with this character, so just search on the character + prefix = String(&c, 1); + else { + m_repeatingChar = 0; + prefix = m_typedString; + searchStartOffset = 0; + } + } + + const Vector<HTMLElement*>& items = listItems(); + int itemCount = items.size(); + if (itemCount < 1) + return; + + int selected = selectedIndex(); + int index = (optionToListIndex(selected >= 0 ? selected : 0) + searchStartOffset) % itemCount; + ASSERT(index >= 0); + for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { + if (!items[index]->hasTagName(optionTag) || items[index]->disabled()) + continue; + + if (stripLeadingWhiteSpace(static_cast<HTMLOptionElement*>(items[index])->optionText()).startsWith(prefix, false)) { + setSelectedIndex(listToOptionIndex(index)); + if(!usesMenuList()) + listBoxOnChange(); + setChanged(); + return; + } + } +} + +int HTMLSelectElement::nextSelectableListIndex(int startIndex) +{ + const Vector<HTMLElement*>& items = listItems(); + int index = startIndex + 1; + while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled())) + index++; + if ((unsigned) index == items.size()) + return startIndex; + return index; +} + +int HTMLSelectElement::previousSelectableListIndex(int startIndex) +{ + const Vector<HTMLElement*>& items = listItems(); + if (startIndex == -1) + startIndex = items.size(); + int index = startIndex - 1; + while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled())) + index--; + if (index == -1) + return startIndex; + return index; +} + +void HTMLSelectElement::accessKeyAction(bool sendToAnyElement) +{ + focus(); + dispatchSimulatedClick(0, sendToAnyElement); +} + +void HTMLSelectElement::accessKeySetSelectedIndex(int index) +{ + // first bring into focus the list box + if (!focused()) + accessKeyAction(false); + + // if this index is already selected, unselect. otherwise update the selected index + Node* listNode = item(index); + if (listNode && listNode->hasTagName(optionTag)) { + HTMLOptionElement* listElement = static_cast<HTMLOptionElement*>(listNode); + if (listElement->selected()) + listElement->setSelectedState(false); + else + setSelectedIndex(index, false, true); + } + + listBoxOnChange(); + scrollToSelection(); +} + +void HTMLSelectElement::setMultiple(bool multiple) +{ + setAttribute(multipleAttr, multiple ? "" : 0); +} + +void HTMLSelectElement::setSize(int size) +{ + setAttribute(sizeAttr, String::number(size)); +} + +Node* HTMLSelectElement::namedItem(const String &name, bool caseSensitive) +{ + return options()->namedItem(name, caseSensitive); +} + +Node* HTMLSelectElement::item(unsigned index) +{ + return options()->item(index); +} + +void HTMLSelectElement::setOption(unsigned index, HTMLOptionElement* option, ExceptionCode& ec) +{ + ec = 0; + if (index > INT_MAX) + index = INT_MAX; + int diff = index - length(); + HTMLElement* before = 0; + // out of array bounds ? first insert empty dummies + if (diff > 0) { + setLength(index, ec); + // replace an existing entry ? + } else if (diff < 0) { + before = static_cast<HTMLElement*>(options()->item(index+1)); + remove(index); + } + // finally add the new element + if (!ec) { + add(option, before, ec); + if (diff >= 0 && option->selected()) + setSelectedIndex(index, !m_multiple); + } +} + +void HTMLSelectElement::setLength(unsigned newLen, ExceptionCode& ec) +{ + ec = 0; + if (newLen > INT_MAX) + newLen = INT_MAX; + int diff = length() - newLen; + + if (diff < 0) { // add dummy elements + do { + RefPtr<Element> option = document()->createElement("option", ec); + if (!option) + break; + add(static_cast<HTMLElement*>(option.get()), 0, ec); + if (ec) + break; + } while (++diff); + } + else // remove elements + while (diff-- > 0) + remove(newLen); +} + +void HTMLSelectElement::scrollToSelection() +{ + if (renderer() && !usesMenuList()) + static_cast<RenderListBox*>(renderer())->selectionChanged(); +} + +#ifndef NDEBUG + +void HTMLSelectElement::checkListItems() const +{ + Vector<HTMLElement*> items = m_listItems; + recalcListItems(false); + ASSERT(items == m_listItems); +} + +#endif + +} // namespace diff --git a/WebCore/html/HTMLSelectElement.h b/WebCore/html/HTMLSelectElement.h new file mode 100644 index 0000000..0b438ab --- /dev/null +++ b/WebCore/html/HTMLSelectElement.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLSelectElement_h +#define HTMLSelectElement_h + +#include "Event.h" +#include "HTMLCollection.h" +#include "HTMLFormControlElement.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class HTMLOptionElement; +class HTMLOptionsCollection; +class KeyboardEvent; + +class HTMLSelectElement : public HTMLFormControlElementWithState { +public: + HTMLSelectElement(Document*, HTMLFormElement* = 0); + HTMLSelectElement(const QualifiedName& tagName, Document*, HTMLFormElement* = 0); + + virtual int tagPriority() const { return 6; } + virtual bool checkDTD(const Node* newChild); + + virtual const AtomicString& type() const; + + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isMouseFocusable() const; + virtual bool canSelectAll() const; + virtual void selectAll(); + + virtual void recalcStyle(StyleChange); + + virtual void dispatchFocusEvent(); + virtual void dispatchBlurEvent(); + + virtual bool canStartSelection() const { return false; } + + int selectedIndex() const; + void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false); + int lastSelectedListIndex() const; + + virtual bool isEnumeratable() const { return true; } + + unsigned length() const; + + int minWidth() const { return m_minwidth; } + + int size() const { return m_size; } + + bool multiple() const { return m_multiple; } + + void add(HTMLElement* element, HTMLElement* before, ExceptionCode&); + void remove(int index); + + String value(); + void setValue(const String&); + + PassRefPtr<HTMLOptionsCollection> options(); + + virtual bool saveState(String& value) const; + virtual void restoreState(const String&); + + virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool removeChild(Node* child, ExceptionCode&); + virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false); + virtual bool removeChildren(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + virtual void parseMappedAttribute(MappedAttribute*); + + virtual RenderObject* createRenderer(RenderArena*, RenderStyle *); + virtual bool appendFormData(FormDataList&, bool); + + // get the actual listbox index of the optionIndexth option + int optionToListIndex(int optionIndex) const; + // reverse of optionToListIndex - get optionIndex from listboxIndex + int listToOptionIndex(int listIndex) const; + + void setRecalcListItems(); + + const Vector<HTMLElement*>& listItems() const + { + if (m_recalcListItems) + recalcListItems(); + else + checkListItems(); + return m_listItems; + } + virtual void reset(); + + virtual void defaultEventHandler(Event*); + virtual void accessKeyAction(bool sendToAnyElement); + void accessKeySetSelectedIndex(int); + + void setMultiple(bool); + + void setSize(int); + + void setOption(unsigned index, HTMLOptionElement*, ExceptionCode&); + void setLength(unsigned, ExceptionCode&); + + Node* namedItem(const String& name, bool caseSensitive = true); + Node* item(unsigned index); + + HTMLCollection::CollectionInfo* collectionInfo() { return &m_collectionInfo; } + + void setActiveSelectionAnchorIndex(int index); + void setActiveSelectionEndIndex(int index) { m_activeSelectionEndIndex = index; } + void updateListBoxSelection(bool deselectOtherOptions); + void listBoxOnChange(); + void menuListOnChange(); + + int activeSelectionStartListIndex() const; + int activeSelectionEndListIndex() const; + + void scrollToSelection(); + +private: + void recalcListItems(bool updateSelectedStates = true) const; + void checkListItems() const; + +#ifdef ANDROID_DESELECT_SELECT +public: +#endif + void deselectItems(HTMLOptionElement* excludeElement = 0); +#ifdef ANDROID_DESELECT_SELECT +private: +#endif +#ifdef ANDROID_LISTBOX_USES_MENU_LIST + bool usesMenuList() const { return true; } +#else + bool usesMenuList() const { return !m_multiple && m_size <= 1; } +#endif + int nextSelectableListIndex(int startIndex); + int previousSelectableListIndex(int startIndex); + void menuListDefaultEventHandler(Event*); + void listBoxDefaultEventHandler(Event*); + void typeAheadFind(KeyboardEvent*); + void saveLastSelection(); + + mutable Vector<HTMLElement*> m_listItems; + Vector<bool> m_cachedStateForActiveSelection; + Vector<bool> m_lastOnChangeSelection; + int m_minwidth; + int m_size; + bool m_multiple; + mutable bool m_recalcListItems; + mutable int m_lastOnChangeIndex; + + int m_activeSelectionAnchorIndex; + int m_activeSelectionEndIndex; + bool m_activeSelectionState; + + // Instance variables for type-ahead find + UChar m_repeatingChar; + DOMTimeStamp m_lastCharTime; + String m_typedString; + + HTMLCollection::CollectionInfo m_collectionInfo; +}; + +#ifdef NDEBUG + +inline void HTMLSelectElement::checkListItems() const +{ +} + +#endif + +} // namespace + +#endif diff --git a/WebCore/html/HTMLSelectElement.idl b/WebCore/html/HTMLSelectElement.idl new file mode 100644 index 0000000..d3e85a8 --- /dev/null +++ b/WebCore/html/HTMLSelectElement.idl @@ -0,0 +1,72 @@ +/* + * 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 html { + + interface [ + HasIndexGetter, + HasCustomIndexSetter, + GenerateConstructor, + InterfaceUUID=99013cd3-d644-4bb5-86a3-2e743821383b, + ImplementationUUID=afe20462-588d-469a-9b4c-8879c4a461d5 + ] HTMLSelectElement : HTMLElement { + + readonly attribute DOMString type; + attribute long selectedIndex; + attribute [ConvertNullToNullString] DOMString value; + + // Modified in DOM Level 2: +#if defined(LANGUAGE_OBJECTIVE_C) + readonly attribute long length; +#else + attribute unsigned long length + setter raises (DOMException); +#endif + + readonly attribute HTMLFormElement form; + readonly attribute boolean willValidate; + + // Modified in DOM Level 2: + readonly attribute HTMLOptionsCollection options; + + attribute boolean disabled; + attribute boolean autofocus; + attribute boolean multiple; + attribute [ConvertNullToNullString] DOMString name; + attribute long size; + + [OldStyleObjC] void add(in HTMLElement element, + in HTMLElement before) + raises(DOMException); + +#if defined(LANGUAGE_JAVASCRIPT) + // In JS, we support both options index and options object parameters - this cannot be autogenerated now. + [Custom] void remove(/* 1 */); +#else + void remove(in long index); +#endif + + // These methods are not in DOM Level 2 IDL, but are mentioned in the standard: + // "The contained options can be directly accessed through the select element as a collection." + Node item(in [IsIndex] unsigned long index); + Node namedItem(in DOMString name); + }; + +} diff --git a/WebCore/html/HTMLSourceElement.cpp b/WebCore/html/HTMLSourceElement.cpp new file mode 100644 index 0000000..86af4e4 --- /dev/null +++ b/WebCore/html/HTMLSourceElement.cpp @@ -0,0 +1,91 @@ +/* + * 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" + +#if ENABLE(VIDEO) +#include "HTMLSourceElement.h" + +#include "HTMLDocument.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +HTMLSourceElement::HTMLSourceElement(Document* doc) + : HTMLElement(sourceTag, doc) +{ +} + +HTMLSourceElement::~HTMLSourceElement() +{ +} + +void HTMLSourceElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + if (parentNode() && (parentNode()->hasTagName(audioTag) || parentNode()->hasTagName(videoTag))) { + HTMLMediaElement* media = static_cast<HTMLMediaElement*>(parentNode()); + if (media->networkState() == HTMLMediaElement::EMPTY) + media->scheduleLoad(); + } +} + +KURL HTMLSourceElement::src() const +{ + return document()->completeURL(getAttribute(srcAttr)); +} + +void HTMLSourceElement::setSrc(const String& url) +{ + setAttribute(srcAttr, url); +} + +String HTMLSourceElement::media() const +{ + return getAttribute(mediaAttr); +} + +void HTMLSourceElement::setMedia(const String& media) +{ + setAttribute(mediaAttr, media); +} + +String HTMLSourceElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLSourceElement::setType(const String& type) +{ + setAttribute(typeAttr, type); +} + +} +#endif diff --git a/WebCore/html/HTMLSourceElement.h b/WebCore/html/HTMLSourceElement.h new file mode 100644 index 0000000..8187877 --- /dev/null +++ b/WebCore/html/HTMLSourceElement.h @@ -0,0 +1,59 @@ +/* + * 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 HTMLSourceElement_h +#define HTMLSourceElement_h + +#if ENABLE(VIDEO) + +#include "HTMLElement.h" +#include <limits> + +namespace WebCore { + +class KURL; + +class HTMLSourceElement : public HTMLElement { +public: + HTMLSourceElement(Document*); + virtual ~HTMLSourceElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } + virtual int tagPriority() const { return 0; } + + virtual void insertedIntoDocument(); + + KURL src() const; + String media() const; + String type() const; + void setSrc(const String&); + void setMedia(const String&); + void setType(const String&); +}; + +} //namespace + +#endif +#endif diff --git a/WebCore/html/HTMLSourceElement.idl b/WebCore/html/HTMLSourceElement.idl new file mode 100644 index 0000000..5a25c23 --- /dev/null +++ b/WebCore/html/HTMLSourceElement.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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 html { +interface [GenerateConstructor, Conditional=VIDEO] HTMLSourceElement : HTMLElement { + attribute DOMString src; + attribute DOMString type; + attribute DOMString media; +}; +} diff --git a/WebCore/html/HTMLStyleElement.cpp b/WebCore/html/HTMLStyleElement.cpp new file mode 100644 index 0000000..dd00db6 --- /dev/null +++ b/WebCore/html/HTMLStyleElement.cpp @@ -0,0 +1,150 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * (C) 2007 Rob Buis (buis@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. + */ +#include "config.h" +#include "HTMLStyleElement.h" + +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLStyleElement::HTMLStyleElement(Document* doc) + : HTMLElement(styleTag, doc) + , m_loading(false) + , m_createdByParser(false) +{ +} + +// other stuff... +void HTMLStyleElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == mediaAttr) + m_media = attr->value().string().lower(); + else if (attr->name() == titleAttr && m_sheet) + m_sheet->setTitle(attr->value()); + else + HTMLElement::parseMappedAttribute(attr); +} + +void HTMLStyleElement::finishParsingChildren() +{ + StyleElement::process(this); + StyleElement::sheet(this); + m_createdByParser = false; + HTMLElement::finishParsingChildren(); +} + +void HTMLStyleElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + + document()->addStyleSheetCandidateNode(this, m_createdByParser); + if (!m_createdByParser) + StyleElement::insertedIntoDocument(document(), this); +} + +void HTMLStyleElement::removedFromDocument() +{ + HTMLElement::removedFromDocument(); + if (document()->renderer()) + document()->removeStyleSheetCandidateNode(this); + StyleElement::removedFromDocument(document()); +} + +void HTMLStyleElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + if (!changedByParser) + StyleElement::process(this); + HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +StyleSheet* HTMLStyleElement::sheet() +{ + return StyleElement::sheet(this); +} + +bool HTMLStyleElement::isLoading() const +{ + if (m_loading) + return true; + if (!m_sheet) + return false; + return static_cast<CSSStyleSheet *>(m_sheet.get())->isLoading(); +} + +bool HTMLStyleElement::sheetLoaded() +{ + if (!isLoading()) { + document()->removePendingSheet(); + return true; + } + return false; +} + +bool HTMLStyleElement::disabled() const +{ + return !getAttribute(disabledAttr).isNull(); +} + +void HTMLStyleElement::setDisabled(bool disabled) +{ + setAttribute(disabledAttr, disabled ? "" : 0); +} + +const AtomicString& HTMLStyleElement::media() const +{ + return getAttribute(mediaAttr); +} + +void HTMLStyleElement::setMedia(const AtomicString &value) +{ + setAttribute(mediaAttr, value); +} + +const AtomicString& HTMLStyleElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLStyleElement::setType(const AtomicString &value) +{ + setAttribute(typeAttr, value); +} + +void HTMLStyleElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + HashSet<String> styleURLs; + StyleSheet* styleSheet = const_cast<HTMLStyleElement*>(this)->sheet(); + if (styleSheet) + styleSheet->addSubresourceURLStrings(styleURLs, ownerDocument()->baseURL()); + + HashSet<String>::iterator end = styleURLs.end(); + for (HashSet<String>::iterator i = styleURLs.begin(); i != end; ++i) + urls.append(*i); +} + +} diff --git a/WebCore/html/HTMLStyleElement.h b/WebCore/html/HTMLStyleElement.h new file mode 100644 index 0000000..a85916f --- /dev/null +++ b/WebCore/html/HTMLStyleElement.h @@ -0,0 +1,77 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 HTMLStyleElement_h +#define HTMLStyleElement_h + +#include "CSSStyleSheet.h" +#include "HTMLElement.h" +#include "StyleElement.h" + +namespace WebCore { + +class HTMLStyleElement : public HTMLElement, public StyleElement +{ +public: + HTMLStyleElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 1; } + virtual bool checkDTD(const Node* newChild) { return newChild->isTextNode(); } + + // overload from HTMLElement + virtual void parseMappedAttribute(MappedAttribute*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + void setCreatedByParser(bool createdByParser) { m_createdByParser = createdByParser; } + virtual void finishParsingChildren(); + + virtual bool isLoading() const; + virtual bool sheetLoaded(); + + bool disabled() const; + void setDisabled(bool); + + virtual const AtomicString& media() const; + void setMedia(const AtomicString&); + + virtual const AtomicString& type() const; + void setType(const AtomicString&); + + StyleSheet* sheet(); + + virtual void setLoading(bool loading) { m_loading = loading; } + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +protected: + String m_media; + bool m_loading; + bool m_createdByParser; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLStyleElement.idl b/WebCore/html/HTMLStyleElement.idl new file mode 100644 index 0000000..e6238b7 --- /dev/null +++ b/WebCore/html/HTMLStyleElement.idl @@ -0,0 +1,38 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=3aaa334c-9660-48cf-b8e2-6d2b4ac0a1da, + ImplementationUUID=73024a55-b8a1-461b-ad85-befa4089f80d + ] HTMLStyleElement : HTMLElement { + attribute boolean disabled; + attribute [ConvertNullToNullString] DOMString media; + attribute [ConvertNullToNullString] DOMString type; + +#if !defined(LANGUAGE_COM) + // DOM Level 2 Style + readonly attribute StyleSheet sheet; +#endif + }; + +} diff --git a/WebCore/html/HTMLTableCaptionElement.cpp b/WebCore/html/HTMLTableCaptionElement.cpp new file mode 100644 index 0000000..b6c9c73 --- /dev/null +++ b/WebCore/html/HTMLTableCaptionElement.cpp @@ -0,0 +1,70 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTableCaptionElement.h" + +#include "CSSPropertyNames.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTableCaptionElement::HTMLTableCaptionElement(Document *doc) + : HTMLTablePartElement(captionTag, doc) +{ +} + +bool HTMLTableCaptionElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == alignAttr) { + result = eCaption; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLTableCaptionElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == alignAttr) { + if (!attr->value().isEmpty()) + addCSSProperty(attr, CSSPropertyCaptionSide, attr->value()); + } else + HTMLElement::parseMappedAttribute(attr); +} + +String HTMLTableCaptionElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableCaptionElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +} diff --git a/WebCore/html/HTMLTableCaptionElement.h b/WebCore/html/HTMLTableCaptionElement.h new file mode 100644 index 0000000..6ed52c9 --- /dev/null +++ b/WebCore/html/HTMLTableCaptionElement.h @@ -0,0 +1,52 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLTableCaptionElement_h +#define HTMLTableCaptionElement_h + +#include "HTMLTablePartElement.h" + +namespace WebCore { + +class HTMLTableCaptionElement : public HTMLTablePartElement +{ +public: + HTMLTableCaptionElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + String align() const; + void setAlign(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableCaptionElement.idl b/WebCore/html/HTMLTableCaptionElement.idl new file mode 100644 index 0000000..9424cd5 --- /dev/null +++ b/WebCore/html/HTMLTableCaptionElement.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateNativeConverter, + GenerateConstructor, + InterfaceUUID=cd92752d-2f0e-44af-b68e-12c178e1f087, + ImplementationUUID=7c0e3749-0f81-4063-9760-8cec314a5b72 + ] HTMLTableCaptionElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString align; + + }; + +} diff --git a/WebCore/html/HTMLTableCellElement.cpp b/WebCore/html/HTMLTableCellElement.cpp new file mode 100644 index 0000000..3395d23 --- /dev/null +++ b/WebCore/html/HTMLTableCellElement.cpp @@ -0,0 +1,277 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTableCellElement.h" + +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "HTMLNames.h" +#include "HTMLTableElement.h" +#include "RenderTableCell.h" +#ifdef ANDROID_LAYOUT +#include "Document.h" +#include "Frame.h" +#include "Settings.h" +#endif + +using std::max; +using std::min; + +namespace WebCore { + +// Clamp rowspan at 8k to match Firefox. +static const int maxRowspan = 8190; + +using namespace HTMLNames; + +HTMLTableCellElement::HTMLTableCellElement(const QualifiedName& tagName, Document *doc) + : HTMLTablePartElement(tagName, doc) + , _row(-1) + , _col(-1) + , rSpan(1) + , cSpan(1) + , rowHeight(0) + , m_solid(false) +{ +} + +HTMLTableCellElement::~HTMLTableCellElement() +{ +} + +int HTMLTableCellElement::cellIndex() const +{ + int index = 0; + for (const Node * node = previousSibling(); node; node = node->previousSibling()) { + if (node->hasTagName(tdTag) || node->hasTagName(thTag)) + index++; + } + + return index; +} + +bool HTMLTableCellElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == nowrapAttr) { + result = eUniversal; + return false; + } + + if (attrName == widthAttr || + attrName == heightAttr) { + result = eCell; // Because of the quirky behavior of ignoring 0 values, cells are special. + return false; + } + + return HTMLTablePartElement::mapToEntry(attrName, result); +} + +void HTMLTableCellElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == rowspanAttr) { + rSpan = !attr->isNull() ? attr->value().toInt() : 1; + rSpan = max(1, min(rSpan, maxRowspan)); + if (renderer() && renderer()->isTableCell()) + static_cast<RenderTableCell*>(renderer())->updateFromElement(); + } else if (attr->name() == colspanAttr) { + cSpan = !attr->isNull() ? attr->value().toInt() : 1; + cSpan = max(1, cSpan); + if (renderer() && renderer()->isTableCell()) + static_cast<RenderTableCell*>(renderer())->updateFromElement(); + } else if (attr->name() == nowrapAttr) { +#ifdef ANDROID_LAYOUT + if (!(document()->frame()) || document()->frame()->settings()->layoutAlgorithm() != Settings::kLayoutSSR) +#endif + if (!attr->isNull()) + addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValueWebkitNowrap); + } else if (attr->name() == widthAttr) { + if (!attr->value().isEmpty()) { + int widthInt = attr->value().toInt(); + if (widthInt > 0) // width="0" is ignored for compatibility with WinIE. + addCSSLength(attr, CSSPropertyWidth, attr->value()); + } + } else if (attr->name() == heightAttr) { + if (!attr->value().isEmpty()) { + int heightInt = attr->value().toInt(); + if (heightInt > 0) // height="0" is ignored for compatibility with WinIE. + addCSSLength(attr, CSSPropertyHeight, attr->value()); + } + } else + HTMLTablePartElement::parseMappedAttribute(attr); +} + +// used by table cells to share style decls created by the enclosing table. +void HTMLTableCellElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) +{ + Node* p = parentNode(); + while (p && !p->hasTagName(tableTag)) + p = p->parentNode(); + if (!p) + return; + static_cast<HTMLTableElement*>(p)->addSharedCellDecls(results); +} + +bool HTMLTableCellElement::isURLAttribute(Attribute *attr) const +{ + return attr->name() == backgroundAttr; +} + +String HTMLTableCellElement::abbr() const +{ + return getAttribute(abbrAttr); +} + +void HTMLTableCellElement::setAbbr(const String &value) +{ + setAttribute(abbrAttr, value); +} + +String HTMLTableCellElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableCellElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLTableCellElement::axis() const +{ + return getAttribute(axisAttr); +} + +void HTMLTableCellElement::setAxis(const String &value) +{ + setAttribute(axisAttr, value); +} + +String HTMLTableCellElement::bgColor() const +{ + return getAttribute(bgcolorAttr); +} + +void HTMLTableCellElement::setBgColor(const String &value) +{ + setAttribute(bgcolorAttr, value); +} + +String HTMLTableCellElement::ch() const +{ + return getAttribute(charAttr); +} + +void HTMLTableCellElement::setCh(const String &value) +{ + setAttribute(charAttr, value); +} + +String HTMLTableCellElement::chOff() const +{ + return getAttribute(charoffAttr); +} + +void HTMLTableCellElement::setChOff(const String &value) +{ + setAttribute(charoffAttr, value); +} + +void HTMLTableCellElement::setColSpan(int n) +{ + setAttribute(colspanAttr, String::number(n)); +} + +String HTMLTableCellElement::headers() const +{ + return getAttribute(headersAttr); +} + +void HTMLTableCellElement::setHeaders(const String &value) +{ + setAttribute(headersAttr, value); +} + +String HTMLTableCellElement::height() const +{ + return getAttribute(heightAttr); +} + +void HTMLTableCellElement::setHeight(const String &value) +{ + setAttribute(heightAttr, value); +} + +bool HTMLTableCellElement::noWrap() const +{ + return !getAttribute(nowrapAttr).isNull(); +} + +void HTMLTableCellElement::setNoWrap(bool b) +{ + setAttribute(nowrapAttr, b ? "" : 0); +} + +void HTMLTableCellElement::setRowSpan(int n) +{ + setAttribute(rowspanAttr, String::number(n)); +} + +String HTMLTableCellElement::scope() const +{ + return getAttribute(scopeAttr); +} + +void HTMLTableCellElement::setScope(const String &value) +{ + setAttribute(scopeAttr, value); +} + +String HTMLTableCellElement::vAlign() const +{ + return getAttribute(valignAttr); +} + +void HTMLTableCellElement::setVAlign(const String &value) +{ + setAttribute(valignAttr, value); +} + +String HTMLTableCellElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLTableCellElement::setWidth(const String &value) +{ + setAttribute(widthAttr, value); +} + +void HTMLTableCellElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(getAttribute(HTMLNames::backgroundAttr).string()); +} + +} diff --git a/WebCore/html/HTMLTableCellElement.h b/WebCore/html/HTMLTableCellElement.h new file mode 100644 index 0000000..6ac4b29 --- /dev/null +++ b/WebCore/html/HTMLTableCellElement.h @@ -0,0 +1,118 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLTableCellElement_h +#define HTMLTableCellElement_h + +#include "HTMLTablePartElement.h" + +namespace WebCore { + +class HTMLTableCellElement : public HTMLTablePartElement +{ +public: + HTMLTableCellElement(const QualifiedName&, Document*); + ~HTMLTableCellElement(); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 6; } + + int cellIndex() const; + + int col() const { return _col; } + void setCol(int col) { _col = col; } + int row() const { return _row; } + void setRow(int r) { _row = r; } + + int colSpan() const { return cSpan; } + int rowSpan() const { return rSpan; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + // used by table cells to share style decls created by the enclosing table. + virtual bool canHaveAdditionalAttributeStyleDecls() const { return true; } + virtual void additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>&); + + virtual bool isURLAttribute(Attribute*) const; + + void setCellIndex(int); + + String abbr() const; + void setAbbr(const String&); + + String align() const; + void setAlign(const String&); + + String axis() const; + void setAxis(const String&); + + String bgColor() const; + void setBgColor(const String&); + + String ch() const; + void setCh(const String&); + + String chOff() const; + void setChOff(const String&); + + void setColSpan(int); + + String headers() const; + void setHeaders(const String&); + + String height() const; + void setHeight(const String&); + + bool noWrap() const; + void setNoWrap(bool); + + void setRowSpan(int); + + String scope() const; + void setScope(const String&); + + String vAlign() const; + void setVAlign(const String&); + + String width() const; + void setWidth(const String&); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +protected: + int _row; + int _col; + int rSpan; + int cSpan; + int rowHeight; + bool m_solid; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableCellElement.idl b/WebCore/html/HTMLTableCellElement.idl new file mode 100644 index 0000000..c0d22ca --- /dev/null +++ b/WebCore/html/HTMLTableCellElement.idl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=3ad21d30-ce64-4a6f-9296-c07a16170783, + ImplementationUUID=36fe6075-c9c1-4f22-bbc2-dd440f21f7cf + ] HTMLTableCellElement : HTMLElement { + + readonly attribute long cellIndex; + attribute [ConvertNullToNullString] DOMString abbr; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString axis; + attribute [ConvertNullToNullString] DOMString bgColor; + attribute [ConvertNullToNullString] DOMString ch; + attribute [ConvertNullToNullString] DOMString chOff; + attribute long colSpan; + attribute [ConvertNullToNullString] DOMString headers; + attribute [ConvertNullToNullString] DOMString height; + attribute boolean noWrap; + attribute long rowSpan; + attribute [ConvertNullToNullString] DOMString scope; + attribute [ConvertNullToNullString] DOMString vAlign; + attribute [ConvertNullToNullString] DOMString width; + + }; + +} diff --git a/WebCore/html/HTMLTableColElement.cpp b/WebCore/html/HTMLTableColElement.cpp new file mode 100644 index 0000000..11f6df6 --- /dev/null +++ b/WebCore/html/HTMLTableColElement.cpp @@ -0,0 +1,156 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTableColElement.h" + +#include "CSSPropertyNames.h" +#include "HTMLNames.h" +#include "RenderTableCol.h" +#include "HTMLTableElement.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTableColElement::HTMLTableColElement(const QualifiedName& tagName, Document *doc) + : HTMLTablePartElement(tagName, doc) +{ + _span = 1; +} + +HTMLTagStatus HTMLTableColElement::endTagRequirement() const +{ + return hasLocalName(colTag) ? TagStatusForbidden : TagStatusOptional; +} + +int HTMLTableColElement::tagPriority() const +{ + return hasLocalName(colTag) ? 0 : 1; +} + +bool HTMLTableColElement::checkDTD(const Node* newChild) +{ + if (hasLocalName(colTag)) + return false; + + if (newChild->isTextNode()) + return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); + return newChild->hasTagName(colTag); +} + +bool HTMLTableColElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == widthAttr) { + result = eUniversal; + return false; + } + + return HTMLTablePartElement::mapToEntry(attrName, result); +} + +void HTMLTableColElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == spanAttr) { + _span = !attr->isNull() ? attr->value().toInt() : 1; + if (renderer() && renderer()->isTableCol()) + static_cast<RenderTableCol*>(renderer())->updateFromElement(); + } else if (attr->name() == widthAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + } else + HTMLTablePartElement::parseMappedAttribute(attr); +} + +// used by table columns and column groups to share style decls created by the enclosing table. +void HTMLTableColElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) +{ + if (!hasLocalName(colgroupTag)) + return; + Node* p = parentNode(); + while (p && !p->hasTagName(tableTag)) + p = p->parentNode(); + if (!p) + return; + static_cast<HTMLTableElement*>(p)->addSharedGroupDecls(false, results); +} + +String HTMLTableColElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableColElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLTableColElement::ch() const +{ + return getAttribute(charAttr); +} + +void HTMLTableColElement::setCh(const String &value) +{ + setAttribute(charAttr, value); +} + +String HTMLTableColElement::chOff() const +{ + return getAttribute(charoffAttr); +} + +void HTMLTableColElement::setChOff(const String &value) +{ + setAttribute(charoffAttr, value); +} + +void HTMLTableColElement::setSpan(int n) +{ + setAttribute(spanAttr, String::number(n)); +} + +String HTMLTableColElement::vAlign() const +{ + return getAttribute(valignAttr); +} + +void HTMLTableColElement::setVAlign(const String &value) +{ + setAttribute(valignAttr, value); +} + +String HTMLTableColElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLTableColElement::setWidth(const String &value) +{ + setAttribute(widthAttr, value); +} + +} diff --git a/WebCore/html/HTMLTableColElement.h b/WebCore/html/HTMLTableColElement.h new file mode 100644 index 0000000..0bed401 --- /dev/null +++ b/WebCore/html/HTMLTableColElement.h @@ -0,0 +1,77 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLTableColElement_h +#define HTMLTableColElement_h + +#include "HTMLTablePartElement.h" + +namespace WebCore { + +class HTMLTableElement; + +class HTMLTableColElement : public HTMLTablePartElement +{ +public: + HTMLTableColElement(const QualifiedName& tagName, Document*); + + virtual HTMLTagStatus endTagRequirement() const; + virtual int tagPriority() const; + virtual bool checkDTD(const Node*); + + // overrides + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + virtual bool canHaveAdditionalAttributeStyleDecls() const { return true; } + virtual void additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>&); + + int span() const { return _span; } + + String align() const; + void setAlign(const String&); + + String ch() const; + void setCh(const String&); + + String chOff() const; + void setChOff(const String&); + + void setSpan(int); + + String vAlign() const; + void setVAlign(const String&); + + String width() const; + void setWidth(const String&); + +protected: + int _span; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableColElement.idl b/WebCore/html/HTMLTableColElement.idl new file mode 100644 index 0000000..083e4a6 --- /dev/null +++ b/WebCore/html/HTMLTableColElement.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=4e886641-910e-424a-995c-e525c09dcfd3, + ImplementationUUID=5f4cdf17-44f1-4b1d-9c68-206737085892 + ] HTMLTableColElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString ch; + attribute [ConvertNullToNullString] DOMString chOff; + attribute long span; + attribute [ConvertNullToNullString] DOMString vAlign; + attribute [ConvertNullToNullString] DOMString width; + + }; + +} diff --git a/WebCore/html/HTMLTableElement.cpp b/WebCore/html/HTMLTableElement.cpp new file mode 100644 index 0000000..ed5c577 --- /dev/null +++ b/WebCore/html/HTMLTableElement.cpp @@ -0,0 +1,755 @@ +/* + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTableElement.h" + +#include "CSSPropertyNames.h" +#include "CSSStyleSheet.h" +#include "CSSValueKeywords.h" +#include "ExceptionCode.h" +#include "HTMLNames.h" +#include "HTMLTableCaptionElement.h" +#include "HTMLTableRowsCollection.h" +#include "HTMLTableRowElement.h" +#include "HTMLTableSectionElement.h" +#include "RenderTable.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTableElement::HTMLTableElement(Document *doc) + : HTMLElement(tableTag, doc) + , m_borderAttr(false) + , m_borderColorAttr(false) + , m_frameAttr(false) + , m_rulesAttr(UnsetRules) + , m_padding(1) +{ +} + +bool HTMLTableElement::checkDTD(const Node* newChild) +{ + if (newChild->isTextNode()) + return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); + return newChild->hasTagName(captionTag) || + newChild->hasTagName(colTag) || newChild->hasTagName(colgroupTag) || + newChild->hasTagName(theadTag) || newChild->hasTagName(tfootTag) || + newChild->hasTagName(tbodyTag) || newChild->hasTagName(formTag) || + newChild->hasTagName(scriptTag); +} + +HTMLTableCaptionElement* HTMLTableElement::caption() const +{ + for (Node* child = firstChild(); child; child = child->nextSibling()) { + if (child->hasTagName(captionTag)) + return static_cast<HTMLTableCaptionElement*>(child); + } + return 0; +} + +void HTMLTableElement::setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption, ExceptionCode& ec) +{ + deleteCaption(); + insertBefore(newCaption, firstChild(), ec); +} + +HTMLTableSectionElement* HTMLTableElement::tHead() const +{ + for (Node* child = firstChild(); child; child = child->nextSibling()) { + if (child->hasTagName(theadTag)) + return static_cast<HTMLTableSectionElement*>(child); + } + return 0; +} + +void HTMLTableElement::setTHead(PassRefPtr<HTMLTableSectionElement> newHead, ExceptionCode& ec) +{ + deleteTHead(); + + Node* child; + for (child = firstChild(); child; child = child->nextSibling()) + if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag)) + break; + + insertBefore(newHead, child, ec); +} + +HTMLTableSectionElement* HTMLTableElement::tFoot() const +{ + for (Node* child = firstChild(); child; child = child->nextSibling()) { + if (child->hasTagName(tfootTag)) + return static_cast<HTMLTableSectionElement*>(child); + } + return 0; +} + +void HTMLTableElement::setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot, ExceptionCode& ec) +{ + deleteTFoot(); + + Node* child; + for (child = firstChild(); child; child = child->nextSibling()) + if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag) && !child->hasTagName(theadTag)) + break; + + insertBefore(newFoot, child, ec); +} + +PassRefPtr<HTMLElement> HTMLTableElement::createTHead() +{ + if (HTMLTableSectionElement* existingHead = tHead()) + return existingHead; + RefPtr<HTMLTableSectionElement> head = new HTMLTableSectionElement(theadTag, document()); + ExceptionCode ec; + setTHead(head, ec); + return head.release(); +} + +void HTMLTableElement::deleteTHead() +{ + ExceptionCode ec; + removeChild(tHead(), ec); +} + +PassRefPtr<HTMLElement> HTMLTableElement::createTFoot() +{ + if (HTMLTableSectionElement* existingFoot = tFoot()) + return existingFoot; + RefPtr<HTMLTableSectionElement> foot = new HTMLTableSectionElement(tfootTag, document()); + ExceptionCode ec; + setTFoot(foot, ec); + return foot.release(); +} + +void HTMLTableElement::deleteTFoot() +{ + ExceptionCode ec; + removeChild(tFoot(), ec); +} + +PassRefPtr<HTMLElement> HTMLTableElement::createCaption() +{ + if (HTMLTableCaptionElement* existingCaption = caption()) + return existingCaption; + RefPtr<HTMLTableCaptionElement> caption = new HTMLTableCaptionElement(document()); + ExceptionCode ec; + setCaption(caption, ec); + return caption.release(); +} + +void HTMLTableElement::deleteCaption() +{ + ExceptionCode ec; + removeChild(caption(), ec); +} + +HTMLTableSectionElement* HTMLTableElement::lastBody() const +{ + for (Node* child = lastChild(); child; child = child->previousSibling()) { + if (child->hasTagName(tbodyTag)) + return static_cast<HTMLTableSectionElement*>(child); + } + return 0; +} + +PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec) +{ + if (index < -1) { + ec = INDEX_SIZE_ERR; + return 0; + } + + HTMLTableRowElement* lastRow = 0; + HTMLTableRowElement* row = 0; + if (index == -1) + lastRow = HTMLTableRowsCollection::lastRow(this); + else { + for (int i = 0; i <= index; ++i) { + row = HTMLTableRowsCollection::rowAfter(this, lastRow); + if (!row) { + if (i != index) { + ec = INDEX_SIZE_ERR; + return 0; + } + break; + } + lastRow = row; + } + } + + Node* parent; + if (lastRow) + parent = row ? row->parent() : lastRow->parent(); + else { + parent = lastBody(); + if (!parent) { + RefPtr<HTMLTableSectionElement> newBody = new HTMLTableSectionElement(tbodyTag, document()); + RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(document()); + newBody->appendChild(newRow, ec); + appendChild(newBody.release(), ec); + return newRow.release(); + } + } + + RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(document()); + parent->insertBefore(newRow, row, ec); + return newRow.release(); +} + +void HTMLTableElement::deleteRow(int index, ExceptionCode& ec) +{ + HTMLTableRowElement* row = 0; + if (index == -1) + row = HTMLTableRowsCollection::lastRow(this); + else { + for (int i = 0; i <= index; ++i) { + row = HTMLTableRowsCollection::rowAfter(this, row); + if (!row) + break; + } + } + if (!row) { + ec = INDEX_SIZE_ERR; + return; + } + row->remove(ec); +} + +ContainerNode* HTMLTableElement::addChild(PassRefPtr<Node> child) +{ + if (child->hasTagName(formTag)) { + // First add the child. + HTMLElement::addChild(child); + + // Now simply return ourselves as the container to insert into. + // This has the effect of demoting the form to a leaf and moving it safely out of the way. + return this; + } + + return HTMLElement::addChild(child.get()); +} + +bool HTMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == backgroundAttr) { + result = (MappedAttributeEntry)(eLastEntry + document()->docID()); + return false; + } + + if (attrName == widthAttr || + attrName == heightAttr || + attrName == bgcolorAttr || + attrName == cellspacingAttr || + attrName == vspaceAttr || + attrName == hspaceAttr || + attrName == valignAttr) { + result = eUniversal; + return false; + } + + if (attrName == bordercolorAttr || attrName == frameAttr || attrName == rulesAttr) { + result = eUniversal; + return true; + } + + if (attrName == borderAttr) { + result = eTable; + return true; + } + + if (attrName == alignAttr) { + result = eTable; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +static inline bool isTableCellAncestor(Node* n) +{ + return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) || + n->hasTagName(tfootTag) || n->hasTagName(trTag) || + n->hasTagName(thTag); +} + +static bool setTableCellsChanged(Node* n) +{ + ASSERT(n); + bool cellChanged = false; + + if (n->hasTagName(tdTag)) + cellChanged = true; + else if (isTableCellAncestor(n)) { + for (Node* child = n->firstChild(); child; child = child->nextSibling()) + cellChanged |= setTableCellsChanged(child); + } + + if (cellChanged) + n->setChanged(); + + return cellChanged; +} + +void HTMLTableElement::parseMappedAttribute(MappedAttribute* attr) +{ + CellBorders bordersBefore = cellBorders(); + unsigned short oldPadding = m_padding; + + if (attr->name() == widthAttr) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + else if (attr->name() == heightAttr) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + else if (attr->name() == borderAttr) { + m_borderAttr = true; + if (attr->decl()) { + RefPtr<CSSValue> val = attr->decl()->getPropertyCSSValue(CSSPropertyBorderLeftWidth); + if (val && val->isPrimitiveValue()) { + CSSPrimitiveValue* primVal = static_cast<CSSPrimitiveValue*>(val.get()); + m_borderAttr = primVal->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); + } + } else if (!attr->isNull()) { + int border = 0; + if (attr->isEmpty()) + border = 1; + else + border = attr->value().toInt(); + m_borderAttr = border; + addCSSLength(attr, CSSPropertyBorderWidth, String::number(border)); + } + } else if (attr->name() == bgcolorAttr) + addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); + else if (attr->name() == bordercolorAttr) { + m_borderColorAttr = attr->decl(); + if (!attr->decl() && !attr->isEmpty()) { + addCSSColor(attr, CSSPropertyBorderColor, attr->value()); + m_borderColorAttr = true; + } + } else if (attr->name() == backgroundAttr) { + String url = parseURL(attr->value()); + if (!url.isEmpty()) + addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); + } else if (attr->name() == frameAttr) { + // Cache the value of "frame" so that the table can examine it later. + m_frameAttr = false; + + // Whether or not to hide the top/right/bottom/left borders. + const int cTop = 0; + const int cRight = 1; + const int cBottom = 2; + const int cLeft = 3; + bool borders[4] = { false, false, false, false }; + + // void, above, below, hsides, vsides, lhs, rhs, box, border + if (equalIgnoringCase(attr->value(), "void")) + m_frameAttr = true; + else if (equalIgnoringCase(attr->value(), "above")) { + m_frameAttr = true; + borders[cTop] = true; + } else if (equalIgnoringCase(attr->value(), "below")) { + m_frameAttr = true; + borders[cBottom] = true; + } else if (equalIgnoringCase(attr->value(), "hsides")) { + m_frameAttr = true; + borders[cTop] = borders[cBottom] = true; + } else if (equalIgnoringCase(attr->value(), "vsides")) { + m_frameAttr = true; + borders[cLeft] = borders[cRight] = true; + } else if (equalIgnoringCase(attr->value(), "lhs")) { + m_frameAttr = true; + borders[cLeft] = true; + } else if (equalIgnoringCase(attr->value(), "rhs")) { + m_frameAttr = true; + borders[cRight] = true; + } else if (equalIgnoringCase(attr->value(), "box") || + equalIgnoringCase(attr->value(), "border")) { + m_frameAttr = true; + borders[cTop] = borders[cBottom] = borders[cLeft] = borders[cRight] = true; + } + + // Now map in the border styles of solid and hidden respectively. + if (m_frameAttr) { + addCSSProperty(attr, CSSPropertyBorderTopWidth, CSSValueThin); + addCSSProperty(attr, CSSPropertyBorderBottomWidth, CSSValueThin); + addCSSProperty(attr, CSSPropertyBorderLeftWidth, CSSValueThin); + addCSSProperty(attr, CSSPropertyBorderRightWidth, CSSValueThin); + addCSSProperty(attr, CSSPropertyBorderTopStyle, borders[cTop] ? CSSValueSolid : CSSValueHidden); + addCSSProperty(attr, CSSPropertyBorderBottomStyle, borders[cBottom] ? CSSValueSolid : CSSValueHidden); + addCSSProperty(attr, CSSPropertyBorderLeftStyle, borders[cLeft] ? CSSValueSolid : CSSValueHidden); + addCSSProperty(attr, CSSPropertyBorderRightStyle, borders[cRight] ? CSSValueSolid : CSSValueHidden); + } + } else if (attr->name() == rulesAttr) { + m_rulesAttr = UnsetRules; + if (equalIgnoringCase(attr->value(), "none")) + m_rulesAttr = NoneRules; + else if (equalIgnoringCase(attr->value(), "groups")) + m_rulesAttr = GroupsRules; + else if (equalIgnoringCase(attr->value(), "rows")) + m_rulesAttr = RowsRules; + if (equalIgnoringCase(attr->value(), "cols")) + m_rulesAttr = ColsRules; + if (equalIgnoringCase(attr->value(), "all")) + m_rulesAttr = AllRules; + + // The presence of a valid rules attribute causes border collapsing to be enabled. + if (m_rulesAttr != UnsetRules) + addCSSProperty(attr, CSSPropertyBorderCollapse, CSSValueCollapse); + } else if (attr->name() == cellspacingAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyBorderSpacing, attr->value()); + } else if (attr->name() == cellpaddingAttr) { + if (!attr->value().isEmpty()) + m_padding = max(0, attr->value().toInt()); + else + m_padding = 1; + } else if (attr->name() == colsAttr) { + // ### + } else if (attr->name() == vspaceAttr) { + addCSSLength(attr, CSSPropertyMarginTop, attr->value()); + addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); + } else if (attr->name() == hspaceAttr) { + addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); + addCSSLength(attr, CSSPropertyMarginRight, attr->value()); + } else if (attr->name() == alignAttr) { + if (!attr->value().isEmpty()) { + if (equalIgnoringCase(attr->value(), "center")) { + addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto); + addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto); + } else + addCSSProperty(attr, CSSPropertyFloat, attr->value()); + } + } else if (attr->name() == valignAttr) { + if (!attr->value().isEmpty()) + addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value()); + } else + HTMLElement::parseMappedAttribute(attr); + + if (bordersBefore != cellBorders() || oldPadding != m_padding) { + if (oldPadding != m_padding) + m_paddingDecl = 0; + bool cellChanged = false; + for (Node* child = firstChild(); child; child = child->nextSibling()) + cellChanged |= setTableCellsChanged(child); + if (cellChanged) + setChanged(); + } +} + +void HTMLTableElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) +{ + if ((!m_borderAttr && !m_borderColorAttr) || m_frameAttr) + return; + + AtomicString borderValue = m_borderColorAttr ? "solid" : "outset"; + CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, tableborderAttr, borderValue); + if (!decl) { + decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. + decl->setParent(document()->elementSheet()); + decl->setNode(this); + decl->setStrictParsing(false); // Mapped attributes are just always quirky. + + int v = m_borderColorAttr ? CSSValueSolid : CSSValueOutset; + decl->setProperty(CSSPropertyBorderTopStyle, v, false); + decl->setProperty(CSSPropertyBorderBottomStyle, v, false); + decl->setProperty(CSSPropertyBorderLeftStyle, v, false); + decl->setProperty(CSSPropertyBorderRightStyle, v, false); + + setMappedAttributeDecl(ePersistent, tableborderAttr, borderValue, decl); + decl->setParent(0); + decl->setNode(0); + decl->setMappedState(ePersistent, tableborderAttr, borderValue); + } + + + results.append(decl); +} + +HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const +{ + switch (m_rulesAttr) { + case NoneRules: + case GroupsRules: + return NoBorders; + case AllRules: + return SolidBorders; + case ColsRules: + return SolidBordersColsOnly; + case RowsRules: + return SolidBordersRowsOnly; + case UnsetRules: + if (!m_borderAttr) + return NoBorders; + if (m_borderColorAttr) + return SolidBorders; + return InsetBorders; + } + ASSERT_NOT_REACHED(); + return NoBorders; +} + +void HTMLTableElement::addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>& results) +{ + addSharedCellBordersDecl(results); + addSharedCellPaddingDecl(results); +} + +void HTMLTableElement::addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>& results) +{ + CellBorders borders = cellBorders(); + + static const AtomicString cellBorderNames[] = { "none", "solid", "inset", "solid-cols", "solid-rows" }; + const AtomicString& cellborderValue = cellBorderNames[borders]; + CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, cellborderAttr, cellborderValue); + if (!decl) { + decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. + decl->setParent(document()->elementSheet()); + decl->setNode(this); + decl->setStrictParsing(false); // Mapped attributes are just always quirky. + + switch (borders) { + case SolidBordersColsOnly: + decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderColor, "inherit", false); + break; + case SolidBordersRowsOnly: + decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderColor, "inherit", false); + break; + case SolidBorders: + decl->setProperty(CSSPropertyBorderWidth, "1px", false); + decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderColor, "inherit", false); + break; + case InsetBorders: + decl->setProperty(CSSPropertyBorderWidth, "1px", false); + decl->setProperty(CSSPropertyBorderTopStyle, CSSValueInset, false); + decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueInset, false); + decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueInset, false); + decl->setProperty(CSSPropertyBorderRightStyle, CSSValueInset, false); + decl->setProperty(CSSPropertyBorderColor, "inherit", false); + break; + case NoBorders: + decl->setProperty(CSSPropertyBorderWidth, "0", false); + break; + } + + setMappedAttributeDecl(ePersistent, cellborderAttr, cellBorderNames[borders], decl); + decl->setParent(0); + decl->setNode(0); + decl->setMappedState(ePersistent, cellborderAttr, cellborderValue); + } + + results.append(decl); +} + +void HTMLTableElement::addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>& results) +{ + if (m_padding == 0) + return; + + if (!m_paddingDecl) { + String paddingValue = String::number(m_padding); + m_paddingDecl = getMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue); + if (!m_paddingDecl) { + m_paddingDecl = CSSMappedAttributeDeclaration::create(); + m_paddingDecl->setParent(document()->elementSheet()); + m_paddingDecl->setNode(this); + m_paddingDecl->setStrictParsing(false); // Mapped attributes are just always quirky. + + m_paddingDecl->setProperty(CSSPropertyPaddingTop, paddingValue, false); + m_paddingDecl->setProperty(CSSPropertyPaddingRight, paddingValue, false); + m_paddingDecl->setProperty(CSSPropertyPaddingBottom, paddingValue, false); + m_paddingDecl->setProperty(CSSPropertyPaddingLeft, paddingValue, false); + } + setMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue, m_paddingDecl.get()); + m_paddingDecl->setParent(0); + m_paddingDecl->setNode(0); + m_paddingDecl->setMappedState(eUniversal, cellpaddingAttr, paddingValue); + } + + results.append(m_paddingDecl.get()); +} + +void HTMLTableElement::addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>& results) +{ + if (m_rulesAttr != GroupsRules) + return; + + AtomicString rulesValue = rows ? "rowgroups" : "colgroups"; + CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, rulesAttr, rulesValue); + if (!decl) { + decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. + decl->setParent(document()->elementSheet()); + decl->setNode(this); + decl->setStrictParsing(false); // Mapped attributes are just always quirky. + + if (rows) { + decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); + } else { + decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false); + decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); + decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); + } + + setMappedAttributeDecl(ePersistent, rulesAttr, rulesValue, decl); + decl->setParent(0); + decl->setNode(0); + decl->setMappedState(ePersistent, rulesAttr, rulesValue); + } + + results.append(decl); +} + +void HTMLTableElement::attach() +{ + ASSERT(!attached()); + HTMLElement::attach(); +} + +bool HTMLTableElement::isURLAttribute(Attribute *attr) const +{ + return attr->name() == backgroundAttr; +} + +PassRefPtr<HTMLCollection> HTMLTableElement::rows() +{ + return HTMLTableRowsCollection::create(this); +} + +PassRefPtr<HTMLCollection> HTMLTableElement::tBodies() +{ + return HTMLCollection::create(this, HTMLCollection::TableTBodies); +} + +String HTMLTableElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLTableElement::bgColor() const +{ + return getAttribute(bgcolorAttr); +} + +void HTMLTableElement::setBgColor(const String &value) +{ + setAttribute(bgcolorAttr, value); +} + +String HTMLTableElement::border() const +{ + return getAttribute(borderAttr); +} + +void HTMLTableElement::setBorder(const String &value) +{ + setAttribute(borderAttr, value); +} + +String HTMLTableElement::cellPadding() const +{ + return getAttribute(cellpaddingAttr); +} + +void HTMLTableElement::setCellPadding(const String &value) +{ + setAttribute(cellpaddingAttr, value); +} + +String HTMLTableElement::cellSpacing() const +{ + return getAttribute(cellspacingAttr); +} + +void HTMLTableElement::setCellSpacing(const String &value) +{ + setAttribute(cellspacingAttr, value); +} + +String HTMLTableElement::frame() const +{ + return getAttribute(frameAttr); +} + +void HTMLTableElement::setFrame(const String &value) +{ + setAttribute(frameAttr, value); +} + +String HTMLTableElement::rules() const +{ + return getAttribute(rulesAttr); +} + +void HTMLTableElement::setRules(const String &value) +{ + setAttribute(rulesAttr, value); +} + +String HTMLTableElement::summary() const +{ + return getAttribute(summaryAttr); +} + +void HTMLTableElement::setSummary(const String &value) +{ + setAttribute(summaryAttr, value); +} + +String HTMLTableElement::width() const +{ + return getAttribute(widthAttr); +} + +void HTMLTableElement::setWidth(const String &value) +{ + setAttribute(widthAttr, value); +} + +void HTMLTableElement::getSubresourceAttributeStrings(Vector<String>& urls) const +{ + urls.append(getAttribute(HTMLNames::backgroundAttr).string()); +} + +} diff --git a/WebCore/html/HTMLTableElement.h b/WebCore/html/HTMLTableElement.h new file mode 100644 index 0000000..aced79e --- /dev/null +++ b/WebCore/html/HTMLTableElement.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLTableElement_h +#define HTMLTableElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLCollection; +class HTMLTableCaptionElement; +class HTMLTableSectionElement; + +class HTMLTableElement : public HTMLElement { +public: + HTMLTableElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 9; } + virtual bool checkDTD(const Node*); + + HTMLTableCaptionElement* caption() const; + void setCaption(PassRefPtr<HTMLTableCaptionElement>, ExceptionCode&); + + HTMLTableSectionElement* tHead() const; + void setTHead(PassRefPtr<HTMLTableSectionElement>, ExceptionCode&); + + HTMLTableSectionElement* tFoot() const; + void setTFoot(PassRefPtr<HTMLTableSectionElement>, ExceptionCode&); + + PassRefPtr<HTMLElement> createTHead(); + void deleteTHead(); + PassRefPtr<HTMLElement> createTFoot(); + void deleteTFoot(); + PassRefPtr<HTMLElement> createCaption(); + void deleteCaption(); + PassRefPtr<HTMLElement> insertRow(int index, ExceptionCode&); + void deleteRow(int index, ExceptionCode&); + + PassRefPtr<HTMLCollection> rows(); + PassRefPtr<HTMLCollection> tBodies(); + + String align() const; + void setAlign(const String&); + + String bgColor() const; + void setBgColor(const String&); + + String border() const; + void setBorder(const String&); + + String cellPadding() const; + void setCellPadding(const String&); + + String cellSpacing() const; + void setCellSpacing(const String&); + + String frame() const; + void setFrame(const String&); + + String rules() const; + void setRules(const String&); + + String summary() const; + void setSummary(const String&); + + String width() const; + void setWidth(const String&); + + virtual ContainerNode* addChild(PassRefPtr<Node>); + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + virtual void attach(); + virtual bool isURLAttribute(Attribute*) const; + + // Used to obtain either a solid or outset border decl and to deal with the frame + // and rules attributes. + virtual bool canHaveAdditionalAttributeStyleDecls() const { return true; } + virtual void additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>&); + void addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>&); + void addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>&); + + virtual void getSubresourceAttributeStrings(Vector<String>&) const; + +private: + void addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>&); + void addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>&); + + enum TableRules { UnsetRules, NoneRules, GroupsRules, RowsRules, ColsRules, AllRules }; + enum CellBorders { NoBorders, SolidBorders, InsetBorders, SolidBordersColsOnly, SolidBordersRowsOnly }; + + CellBorders cellBorders() const; + + HTMLTableSectionElement* lastBody() const; + + bool m_borderAttr; // Sets a precise border width and creates an outset border for the table and for its cells. + bool m_borderColorAttr; // Overrides the outset border and makes it solid for the table and cells instead. + bool m_frameAttr; // Implies a thin border width if no border is set and then a certain set of solid/hidden borders based off the value. + TableRules m_rulesAttr; // Implies a thin border width, a collapsing border model, and all borders on the table becoming set to hidden (if frame/border + // are present, to none otherwise). + + unsigned short m_padding; + RefPtr<CSSMappedAttributeDeclaration> m_paddingDecl; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableElement.idl b/WebCore/html/HTMLTableElement.idl new file mode 100644 index 0000000..7092be0 --- /dev/null +++ b/WebCore/html/HTMLTableElement.idl @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=3f9c6e17-ee0c-43de-94b0-2a21b19b612c, + ImplementationUUID=159bb8fe-ffee-4ff9-b507-76741118143f + ] HTMLTableElement : HTMLElement { + + // could raise excepetions on setting. + attribute HTMLTableCaptionElement caption + setter raises(DOMException); + attribute HTMLTableSectionElement tHead + setter raises(DOMException); + attribute HTMLTableSectionElement tFoot + setter raises(DOMException); + + readonly attribute HTMLCollection rows; + readonly attribute HTMLCollection tBodies; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString bgColor; + attribute [ConvertNullToNullString] DOMString border; + attribute [ConvertNullToNullString] DOMString cellPadding; + attribute [ConvertNullToNullString] DOMString cellSpacing; + + // FIXME: the obj-c attribute is called frameBorders + attribute [ConvertNullToNullString] DOMString frame; + + attribute [ConvertNullToNullString] DOMString rules; + attribute [ConvertNullToNullString] DOMString summary; + attribute [ConvertNullToNullString] DOMString width; + + HTMLElement createTHead(); + void deleteTHead(); + HTMLElement createTFoot(); + void deleteTFoot(); + HTMLElement createCaption(); + void deleteCaption(); + + HTMLElement insertRow(in long index) + raises(DOMException); + + void deleteRow(in long index) + raises(DOMException); + + }; + +} diff --git a/WebCore/html/HTMLTablePartElement.cpp b/WebCore/html/HTMLTablePartElement.cpp new file mode 100644 index 0000000..6341197 --- /dev/null +++ b/WebCore/html/HTMLTablePartElement.cpp @@ -0,0 +1,100 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTablePartElement.h" + +#include "CSSHelper.h" +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +bool HTMLTablePartElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == backgroundAttr) { + result = (MappedAttributeEntry)(eLastEntry + document()->docID()); + return false; + } + + if (attrName == bgcolorAttr || + attrName == bordercolorAttr || + attrName == valignAttr || + attrName == heightAttr) { + result = eUniversal; + return false; + } + + if (attrName == alignAttr) { + result = eCell; // All table parts will just share in the TD space. + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLTablePartElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == bgcolorAttr) + addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); + else if (attr->name() == backgroundAttr) { + String url = parseURL(attr->value()); + if (!url.isEmpty()) + addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); + } else if (attr->name() == bordercolorAttr) { + if (!attr->value().isEmpty()) { + addCSSColor(attr, CSSPropertyBorderColor, attr->value()); + addCSSProperty(attr, CSSPropertyBorderTopStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderBottomStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderLeftStyle, CSSValueSolid); + addCSSProperty(attr, CSSPropertyBorderRightStyle, CSSValueSolid); + } + } else if (attr->name() == valignAttr) { + if (!attr->value().isEmpty()) + addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value()); + } else if (attr->name() == alignAttr) { + const AtomicString& v = attr->value(); + if (equalIgnoringCase(v, "middle") || equalIgnoringCase(v, "center")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitCenter); + else if (equalIgnoringCase(v, "absmiddle")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueCenter); + else if (equalIgnoringCase(v, "left")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitLeft); + else if (equalIgnoringCase(v, "right")) + addCSSProperty(attr, CSSPropertyTextAlign, CSSValueWebkitRight); + else + addCSSProperty(attr, CSSPropertyTextAlign, v); + } else if (attr->name() == heightAttr) { + if (!attr->value().isEmpty()) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + } else + HTMLElement::parseMappedAttribute(attr); +} + +} diff --git a/WebCore/html/HTMLTablePartElement.h b/WebCore/html/HTMLTablePartElement.h new file mode 100644 index 0000000..adbd63b --- /dev/null +++ b/WebCore/html/HTMLTablePartElement.h @@ -0,0 +1,47 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 HTMLTablePartElement_h +#define HTMLTablePartElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLTablePartElement : public HTMLElement { +public: + HTMLTablePartElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) + { } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableRowElement.cpp b/WebCore/html/HTMLTableRowElement.cpp new file mode 100644 index 0000000..da07594 --- /dev/null +++ b/WebCore/html/HTMLTableRowElement.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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 "HTMLTableRowElement.h" + +#include "ExceptionCode.h" +#include "HTMLCollection.h" +#include "HTMLNames.h" +#include "HTMLTableCellElement.h" +#include "HTMLTableElement.h" +#include "HTMLTableSectionElement.h" +#include "NodeList.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTableRowElement::HTMLTableRowElement(Document* doc) + : HTMLTablePartElement(trTag, doc) +{ +} + +bool HTMLTableRowElement::checkDTD(const Node* newChild) +{ + if (newChild->isTextNode()) + return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); + return newChild->hasTagName(tdTag) || newChild->hasTagName(thTag) || + newChild->hasTagName(formTag) || newChild->hasTagName(scriptTag); +} + +ContainerNode* HTMLTableRowElement::addChild(PassRefPtr<Node> child) +{ + if (child->hasTagName(formTag)) { + // First add the child. + HTMLTablePartElement::addChild(child); + + // Now simply return ourselves as the container to insert into. + // This has the effect of demoting the form to a leaf and moving it safely out of the way. + return this; + } + + return HTMLTablePartElement::addChild(child); +} + +int HTMLTableRowElement::rowIndex() const +{ + Node *table = parentNode(); + if (!table) + return -1; + table = table->parentNode(); + if (!table || !table->hasTagName(tableTag)) + return -1; + + // To match Firefox, the row indices work like this: + // Rows from the first <thead> are numbered before all <tbody> rows. + // Rows from the first <tfoot> are numbered after all <tbody> rows. + // Rows from other <thead> and <tfoot> elements don't get row indices at all. + + int rIndex = 0; + + if (HTMLTableSectionElement* head = static_cast<HTMLTableElement*>(table)->tHead()) { + for (Node *row = head->firstChild(); row; row = row->nextSibling()) { + if (row == this) + return rIndex; + if (row->hasTagName(trTag)) + ++rIndex; + } + } + + for (Node *node = table->firstChild(); node; node = node->nextSibling()) { + if (node->hasTagName(tbodyTag)) { + HTMLTableSectionElement* section = static_cast<HTMLTableSectionElement*>(node); + for (Node* row = section->firstChild(); row; row = row->nextSibling()) { + if (row == this) + return rIndex; + if (row->hasTagName(trTag)) + ++rIndex; + } + } + } + + if (HTMLTableSectionElement* foot = static_cast<HTMLTableElement*>(table)->tFoot()) { + for (Node *row = foot->firstChild(); row; row = row->nextSibling()) { + if (row == this) + return rIndex; + if (row->hasTagName(trTag)) + ++rIndex; + } + } + + // We get here for rows that are in <thead> or <tfoot> sections other than the main header and footer. + return -1; +} + +int HTMLTableRowElement::sectionRowIndex() const +{ + int rIndex = 0; + const Node *n = this; + do { + n = n->previousSibling(); + if (n && n->hasTagName(trTag)) + rIndex++; + } + while (n); + + return rIndex; +} + +PassRefPtr<HTMLElement> HTMLTableRowElement::insertCell(int index, ExceptionCode& ec) +{ + RefPtr<HTMLCollection> children = cells(); + int numCells = children ? children->length() : 0; + if (index < -1 || index > numCells) { + ec = INDEX_SIZE_ERR; + return 0; + } + + RefPtr<HTMLTableCellElement> c = new HTMLTableCellElement(tdTag, document()); + if (index < 0 || index >= numCells) + appendChild(c, ec); + else { + Node* n; + if (index < 1) + n = firstChild(); + else + n = children->item(index); + insertBefore(c, n, ec); + } + return c.release(); +} + +void HTMLTableRowElement::deleteCell(int index, ExceptionCode& ec) +{ + RefPtr<HTMLCollection> children = cells(); + int numCells = children ? children->length() : 0; + if (index == -1) + index = numCells-1; + if (index >= 0 && index < numCells) { + RefPtr<Node> cell = children->item(index); + HTMLElement::removeChild(cell.get(), ec); + } else + ec = INDEX_SIZE_ERR; +} + +PassRefPtr<HTMLCollection> HTMLTableRowElement::cells() +{ + return HTMLCollection::create(this, HTMLCollection::TRCells); +} + +void HTMLTableRowElement::setCells(HTMLCollection *, ExceptionCode& ec) +{ + ec = NO_MODIFICATION_ALLOWED_ERR; +} + +String HTMLTableRowElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableRowElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLTableRowElement::bgColor() const +{ + return getAttribute(bgcolorAttr); +} + +void HTMLTableRowElement::setBgColor(const String &value) +{ + setAttribute(bgcolorAttr, value); +} + +String HTMLTableRowElement::ch() const +{ + return getAttribute(charAttr); +} + +void HTMLTableRowElement::setCh(const String &value) +{ + setAttribute(charAttr, value); +} + +String HTMLTableRowElement::chOff() const +{ + return getAttribute(charoffAttr); +} + +void HTMLTableRowElement::setChOff(const String &value) +{ + setAttribute(charoffAttr, value); +} + +String HTMLTableRowElement::vAlign() const +{ + return getAttribute(valignAttr); +} + +void HTMLTableRowElement::setVAlign(const String &value) +{ + setAttribute(valignAttr, value); +} + +} diff --git a/WebCore/html/HTMLTableRowElement.h b/WebCore/html/HTMLTableRowElement.h new file mode 100644 index 0000000..26ffa1f --- /dev/null +++ b/WebCore/html/HTMLTableRowElement.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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. + * + */ + +#ifndef HTMLTableRowElement_h +#define HTMLTableRowElement_h + +#include "HTMLTablePartElement.h" + +namespace WebCore { + +class HTMLTableRowElement : public HTMLTablePartElement { +public: + HTMLTableRowElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 7; } + virtual bool checkDTD(const Node*); + virtual ContainerNode* addChild(PassRefPtr<Node>); + + int rowIndex() const; + void setRowIndex(int); + + int sectionRowIndex() const; + void setSectionRowIndex(int); + + PassRefPtr<HTMLElement> insertCell(int index, ExceptionCode&); + void deleteCell(int index, ExceptionCode&); + + PassRefPtr<HTMLCollection> cells(); + void setCells(HTMLCollection *, ExceptionCode&); + + String align() const; + void setAlign(const String&); + + String bgColor() const; + void setBgColor(const String&); + + String ch() const; + void setCh(const String&); + + String chOff() const; + void setChOff(const String&); + + String vAlign() const; + void setVAlign(const String&); +}; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLTableRowElement.idl b/WebCore/html/HTMLTableRowElement.idl new file mode 100644 index 0000000..3a76ca3 --- /dev/null +++ b/WebCore/html/HTMLTableRowElement.idl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=f14ea3d9-8643-4cfd-a692-cefe6d5c65ea, + ImplementationUUID=0ce090da-33bb-4163-bb35-3ca8a2f6be47 + ] HTMLTableRowElement : HTMLElement { + + readonly attribute long rowIndex; + readonly attribute long sectionRowIndex; + readonly attribute HTMLCollection cells; + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString bgColor; + attribute [ConvertNullToNullString] DOMString ch; + attribute [ConvertNullToNullString] DOMString chOff; + attribute [ConvertNullToNullString] DOMString vAlign; + + HTMLElement insertCell(in long index) + raises(DOMException); + void deleteCell(in long index) + raises(DOMException); + + }; + +} diff --git a/WebCore/html/HTMLTableRowsCollection.cpp b/WebCore/html/HTMLTableRowsCollection.cpp new file mode 100644 index 0000000..7047576 --- /dev/null +++ b/WebCore/html/HTMLTableRowsCollection.cpp @@ -0,0 +1,167 @@ +/* + * 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. + */ + +#include "config.h" +#include "HTMLTableRowsCollection.h" + +#include "HTMLNames.h" +#include "HTMLTableElement.h" +#include "HTMLTableRowElement.h" + +namespace WebCore { + +using namespace HTMLNames; + +static bool isInHead(Element* row) +{ + return row->parent() && static_cast<Element*>(row->parent())->hasLocalName(theadTag); +} + +static bool isInBody(Element* row) +{ + return row->parent() && static_cast<Element*>(row->parent())->hasLocalName(tbodyTag); +} + +static bool isInFoot(Element* row) +{ + return row->parent() && static_cast<Element*>(row->parent())->hasLocalName(tfootTag); +} + +HTMLTableRowElement* HTMLTableRowsCollection::rowAfter(HTMLTableElement* table, HTMLTableRowElement* previous) +{ + Node* child = 0; + + // Start by looking for the next row in this section. + // Continue only if there is none. + if (previous && previous->parent() != table) { + for (child = previous->nextSibling(); child; child = child->nextSibling()) { + if (child->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(child); + } + } + + // If still looking at head sections, find the first row in the next head section. + if (!previous) + child = table->firstChild(); + else if (isInHead(previous)) + child = previous->parent()->nextSibling(); + for (; child; child = child->nextSibling()) { + if (child->hasTagName(theadTag)) { + for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + // If still looking at top level and bodies, find the next row in top level or the first in the next body section. + if (!previous || isInHead(previous)) + child = table->firstChild(); + else if (previous->parent() == table) + child = previous->nextSibling(); + else if (isInBody(previous)) + child = previous->parent()->nextSibling(); + for (; child; child = child->nextSibling()) { + if (child->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(child); + if (child->hasTagName(tbodyTag)) { + for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + // Find the first row in the next foot section. + if (!previous || !isInFoot(previous)) + child = table->firstChild(); + else + child = previous->parent()->nextSibling(); + for (; child; child = child->nextSibling()) { + if (child->hasTagName(tfootTag)) { + for (Node* grandchild = child->firstChild(); grandchild; grandchild = grandchild->nextSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + return 0; +} + +HTMLTableRowElement* HTMLTableRowsCollection::lastRow(HTMLTableElement* table) +{ + for (Node* child = table->lastChild(); child; child = child->previousSibling()) { + if (child->hasTagName(tfootTag)) { + for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + for (Node* child = table->lastChild(); child; child = child->previousSibling()) { + if (child->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(child); + if (child->hasTagName(tbodyTag)) { + for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + for (Node* child = table->lastChild(); child; child = child->previousSibling()) { + if (child->hasTagName(theadTag)) { + for (Node* grandchild = child->lastChild(); grandchild; grandchild = grandchild->previousSibling()) { + if (grandchild->hasTagName(trTag)) + return static_cast<HTMLTableRowElement*>(grandchild); + } + } + } + + return 0; +} + +HTMLTableRowsCollection::HTMLTableRowsCollection(PassRefPtr<HTMLTableElement> table) + : HTMLCollection(table, Other, 0) +{ +} + +PassRefPtr<HTMLTableRowsCollection> HTMLTableRowsCollection::create(PassRefPtr<HTMLTableElement> table) +{ + return adoptRef(new HTMLTableRowsCollection(table)); +} + +Element* HTMLTableRowsCollection::itemAfter(Element* previous) const +{ + ASSERT(!previous || previous->hasLocalName(trTag)); + return rowAfter(static_cast<HTMLTableElement*>(base()), static_cast<HTMLTableRowElement*>(previous)); +} + +} diff --git a/WebCore/html/HTMLTableRowsCollection.h b/WebCore/html/HTMLTableRowsCollection.h new file mode 100644 index 0000000..f997e3c --- /dev/null +++ b/WebCore/html/HTMLTableRowsCollection.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. + * 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 HTMLTableRowsCollection_h +#define HTMLTableRowsCollection_h + +#include "HTMLCollection.h" + +namespace WebCore { + +class HTMLTableElement; +class HTMLTableRowElement; + +class HTMLTableRowsCollection : public HTMLCollection { +public: + static PassRefPtr<HTMLTableRowsCollection> create(PassRefPtr<HTMLTableElement>); + + static HTMLTableRowElement* rowAfter(HTMLTableElement*, HTMLTableRowElement*); + static HTMLTableRowElement* lastRow(HTMLTableElement*); + +private: + HTMLTableRowsCollection(PassRefPtr<HTMLTableElement>); + + virtual Element* itemAfter(Element*) const; +}; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLTableSectionElement.cpp b/WebCore/html/HTMLTableSectionElement.cpp new file mode 100644 index 0000000..8190d93 --- /dev/null +++ b/WebCore/html/HTMLTableSectionElement.cpp @@ -0,0 +1,175 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 "HTMLTableSectionElement.h" + +#include "ExceptionCode.h" +#include "HTMLCollection.h" +#include "HTMLNames.h" +#include "HTMLTableRowElement.h" +#include "HTMLTableElement.h" +#include "NodeList.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTableSectionElement::HTMLTableSectionElement(const QualifiedName& tagName, Document* document) + : HTMLTablePartElement(tagName, document) +{ +} + +bool HTMLTableSectionElement::checkDTD(const Node* newChild) +{ + if (newChild->isTextNode()) + return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); + return newChild->hasTagName(trTag) || newChild->hasTagName(formTag) || + newChild->hasTagName(scriptTag); +} + +ContainerNode* HTMLTableSectionElement::addChild(PassRefPtr<Node> child) +{ + if (child->hasTagName(formTag)) { + // First add the child. + HTMLTablePartElement::addChild(child); + + // Now simply return ourselves as the container to insert into. + // This has the effect of demoting the form to a leaf and moving it safely out of the way. + return this; + } + + return HTMLTablePartElement::addChild(child); +} + +// used by table row groups to share style decls created by the enclosing table. +void HTMLTableSectionElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) +{ + Node* p = parentNode(); + while (p && !p->hasTagName(tableTag)) + p = p->parentNode(); + if (!p) + return; + static_cast<HTMLTableElement*>(p)->addSharedGroupDecls(true, results); +} + +// these functions are rather slow, since we need to get the row at +// the index... but they aren't used during usual HTML parsing anyway +PassRefPtr<HTMLElement> HTMLTableSectionElement::insertRow(int index, ExceptionCode& ec) +{ + RefPtr<HTMLTableRowElement> r; + RefPtr<HTMLCollection> children = rows(); + int numRows = children ? (int)children->length() : 0; + if (index < -1 || index > numRows) + ec = INDEX_SIZE_ERR; // per the DOM + else { + r = new HTMLTableRowElement(document()); + if (numRows == index || index == -1) + appendChild(r, ec); + else { + Node* n; + if (index < 1) + n = firstChild(); + else + n = children->item(index); + insertBefore(r, n, ec); + } + } + return r.release(); +} + +void HTMLTableSectionElement::deleteRow( int index, ExceptionCode& ec) +{ + RefPtr<HTMLCollection> children = rows(); + int numRows = children ? (int)children->length() : 0; + if (index == -1) + index = numRows - 1; + if (index >= 0 && index < numRows) { + RefPtr<Node> row = children->item(index); + HTMLElement::removeChild(row.get(), ec); + } else + ec = INDEX_SIZE_ERR; +} + +int HTMLTableSectionElement::numRows() const +{ + int rows = 0; + const Node *n = firstChild(); + while (n) { + if (n->hasTagName(trTag)) + rows++; + n = n->nextSibling(); + } + + return rows; +} + +String HTMLTableSectionElement::align() const +{ + return getAttribute(alignAttr); +} + +void HTMLTableSectionElement::setAlign(const String &value) +{ + setAttribute(alignAttr, value); +} + +String HTMLTableSectionElement::ch() const +{ + return getAttribute(charAttr); +} + +void HTMLTableSectionElement::setCh(const String &value) +{ + setAttribute(charAttr, value); +} + +String HTMLTableSectionElement::chOff() const +{ + return getAttribute(charoffAttr); +} + +void HTMLTableSectionElement::setChOff(const String &value) +{ + setAttribute(charoffAttr, value); +} + +String HTMLTableSectionElement::vAlign() const +{ + return getAttribute(valignAttr); +} + +void HTMLTableSectionElement::setVAlign(const String &value) +{ + setAttribute(valignAttr, value); +} + +PassRefPtr<HTMLCollection> HTMLTableSectionElement::rows() +{ + return HTMLCollection::create(this, HTMLCollection::TSectionRows); +} + +} diff --git a/WebCore/html/HTMLTableSectionElement.h b/WebCore/html/HTMLTableSectionElement.h new file mode 100644 index 0000000..819b369 --- /dev/null +++ b/WebCore/html/HTMLTableSectionElement.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1997 Martin Jones (mjones@kde.org) + * (C) 1997 Torben Weis (weis@kde.org) + * (C) 1998 Waldo Bastian (bastian@kde.org) + * (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 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. + * + */ + +#ifndef HTMLTableSectionElement_h +#define HTMLTableSectionElement_h + +#include "HTMLTablePartElement.h" + +namespace WebCore { + +class HTMLTableSectionElement : public HTMLTablePartElement { +public: + HTMLTableSectionElement(const QualifiedName& tagName, Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusOptional; } + virtual int tagPriority() const { return 8; } + virtual bool checkDTD(const Node*); + virtual ContainerNode* addChild(PassRefPtr<Node>); + virtual bool canHaveAdditionalAttributeStyleDecls() const { return true; } + virtual void additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>&); + + PassRefPtr<HTMLElement> insertRow(int index, ExceptionCode&); + void deleteRow(int index, ExceptionCode&); + + int numRows() const; + + String align() const; + void setAlign(const String&); + + String ch() const; + void setCh(const String&); + + String chOff() const; + void setChOff(const String&); + + String vAlign() const; + void setVAlign(const String&); + + PassRefPtr<HTMLCollection> rows(); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTableSectionElement.idl b/WebCore/html/HTMLTableSectionElement.idl new file mode 100644 index 0000000..7078e33 --- /dev/null +++ b/WebCore/html/HTMLTableSectionElement.idl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 html { + + interface [ + GenerateNativeConverter, + GenerateConstructor, + InterfaceUUID=e0cf6b6a-9ba1-400f-b523-dbb22819dfb6, + ImplementationUUID=85329cf4-1eae-4245-a971-1bddb212a9c5 + ] HTMLTableSectionElement : HTMLElement { + + attribute [ConvertNullToNullString] DOMString align; + attribute [ConvertNullToNullString] DOMString ch; + attribute [ConvertNullToNullString] DOMString chOff; + attribute [ConvertNullToNullString] DOMString vAlign; + readonly attribute HTMLCollection rows; + + HTMLElement insertRow(in long index) + raises(DOMException); + void deleteRow(in long index) + raises(DOMException); + + }; + +} diff --git a/WebCore/html/HTMLTagNames.in b/WebCore/html/HTMLTagNames.in new file mode 100644 index 0000000..6493c39 --- /dev/null +++ b/WebCore/html/HTMLTagNames.in @@ -0,0 +1,117 @@ +namespace="HTML" +namespacePrefix="xhtml" +namespaceURI="http://www.w3.org/1999/xhtml" + +a interfaceName=AnchorElement +abbr +acronym +address +applet +area +#if ENABLE_VIDEO +audio applyAudioHack=1 +#endif +b +base +basefont interfaceName=BaseFontElement +bdo +big +blockquote +body +br interfaceName=BRElement +button +canvas +caption interfaceName=TableCaptionElement +center +cite +code +col interfaceName=TableColElement +colgroup +dd +del interfaceName=ModElement +dfn +dir interfaceName=DirectoryElement +div +dl interfaceName=DListElement +dt +em +embed +fieldset interfaceName=FieldSetElement +font +form +frame +frameset interfaceName=FrameSetElement +head +h1 interfaceName=HeadingElement +h2 +h3 +h4 +h5 +h6 +hr interfaceName=HRElement +html +i +iframe interfaceName=IFrameElement +image +img interfaceName=ImageElement +input +ins +isindex interfaceName=IsIndexElement +kbd +keygen +label +layer +legend +li interfaceName=LIElement +link +listing +map +marquee +menu +meta +nobr +noembed +noframes +nolayer +noscript +object +ol interfaceName=OListElement +optgroup interfaceName=OptGroupElement +option +p interfaceName=ParagraphElement +param +plaintext +pre +q interfaceName=QuoteElement +s +samp +script +select +small +#if ENABLE_VIDEO +source applyAudioHack=1 +#endif +span +strike +strong +style +sub +sup +table +tbody interfaceName=TableSectionElement +td interfaceName=TableCellElement +textarea interfaceName=TextAreaElement +tfoot +th +thead +title +tr interfaceName=TableRowElement +tt +u +ul interfaceName=UListElement +var +#if ENABLE_VIDEO +video applyAudioHack=1 +#endif +wbr +xmp diff --git a/WebCore/html/HTMLTextAreaElement.cpp b/WebCore/html/HTMLTextAreaElement.cpp new file mode 100644 index 0000000..1882fe5 --- /dev/null +++ b/WebCore/html/HTMLTextAreaElement.cpp @@ -0,0 +1,381 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2007 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 "HTMLTextAreaElement.h" + +#include "Document.h" +#include "Event.h" +#include "EventNames.h" +#include "FocusController.h" +#include "FormDataList.h" +#include "Frame.h" +#include "HTMLNames.h" +#include "Page.h" +#include "RenderStyle.h" +#include "RenderTextControl.h" +#include "Selection.h" +#include "Text.h" + +#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS +#include "WebViewCore.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +static const int defaultRows = 2; +static const int defaultCols = 20; + +HTMLTextAreaElement::HTMLTextAreaElement(Document* document, HTMLFormElement* form) + : HTMLFormControlElementWithState(textareaTag, document, form) + , m_rows(defaultRows) + , m_cols(defaultCols) + , m_wrap(SoftWrap) + , m_cachedSelectionStart(-1) + , m_cachedSelectionEnd(-1) +{ + setValueMatchesRenderer(); +} + +const AtomicString& HTMLTextAreaElement::type() const +{ + static const AtomicString textarea("textarea"); + return textarea; +} + +bool HTMLTextAreaElement::saveState(String& result) const +{ + result = value(); + return true; +} + +void HTMLTextAreaElement::restoreState(const String& state) +{ + setDefaultValue(state); +} + +int HTMLTextAreaElement::selectionStart() +{ + if (!renderer()) + return 0; + if (document()->focusedNode() != this && m_cachedSelectionStart >= 0) + return m_cachedSelectionStart; + return static_cast<RenderTextControl*>(renderer())->selectionStart(); +} + +int HTMLTextAreaElement::selectionEnd() +{ + if (!renderer()) + return 0; + if (document()->focusedNode() != this && m_cachedSelectionEnd >= 0) + return m_cachedSelectionEnd; + return static_cast<RenderTextControl*>(renderer())->selectionEnd(); +} + +void HTMLTextAreaElement::setSelectionStart(int start) +{ + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionStart(start); +} + +void HTMLTextAreaElement::setSelectionEnd(int end) +{ + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionEnd(end); +} + +void HTMLTextAreaElement::select() +{ + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->select(); +} + +void HTMLTextAreaElement::setSelectionRange(int start, int end) +{ + if (!renderer()) + return; + static_cast<RenderTextControl*>(renderer())->setSelectionRange(start, end); +} + +void HTMLTextAreaElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + setValue(defaultValue()); + HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +void HTMLTextAreaElement::parseMappedAttribute(MappedAttribute* attr) +{ + if (attr->name() == rowsAttr) { + int rows = attr->value().toInt(); + if (rows <= 0) + rows = defaultRows; + if (m_rows != rows) { + m_rows = rows; + if (renderer()) + renderer()->setNeedsLayoutAndPrefWidthsRecalc(); + } + } else if (attr->name() == colsAttr) { + int cols = attr->value().toInt(); + if (cols <= 0) + cols = defaultCols; + if (m_cols != cols) { + m_cols = cols; + if (renderer()) + renderer()->setNeedsLayoutAndPrefWidthsRecalc(); + } + } else if (attr->name() == wrapAttr) { + // The virtual/physical values were a Netscape extension of HTML 3.0, now deprecated. + // The soft/hard /off values are a recommendation for HTML 4 extension by IE and NS 4. + WrapMethod wrap; + if (equalIgnoringCase(attr->value(), "physical") || equalIgnoringCase(attr->value(), "hard") || equalIgnoringCase(attr->value(), "on")) + wrap = HardWrap; + else if (equalIgnoringCase(attr->value(), "off")) + wrap = NoWrap; + else + wrap = SoftWrap; + if (wrap != m_wrap) { + m_wrap = wrap; + if (renderer()) + renderer()->setNeedsLayoutAndPrefWidthsRecalc(); + } + } else if (attr->name() == accesskeyAttr) { + // ignore for the moment + } else if (attr->name() == alignAttr) { + // Don't map 'align' attribute. This matches what Firefox, Opera and IE do. + // See http://bugs.webkit.org/show_bug.cgi?id=7075 + } else if (attr->name() == onfocusAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + else if (attr->name() == onblurAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + else if (attr->name() == onselectAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().selectEvent, attr); + else if (attr->name() == onchangeAttr) + setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + else + HTMLFormControlElementWithState::parseMappedAttribute(attr); +} + +RenderObject* HTMLTextAreaElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + return new (arena) RenderTextControl(this, true); +} + +bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool) +{ + if (name().isEmpty()) + return false; + + // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer. + // While we have no evidence this has ever been a practical problem, it would be best to fix it some day. + RenderTextControl* control = static_cast<RenderTextControl*>(renderer()); + const String& text = (m_wrap == HardWrap && control) ? control->textWithHardLineBreaks() : value(); + encoding.appendData(name(), text); + return true; +} + +void HTMLTextAreaElement::reset() +{ + setValue(defaultValue()); +} + +bool HTMLTextAreaElement::isKeyboardFocusable(KeyboardEvent*) const +{ + // If a given text area can be focused at all, then it will always be keyboard focusable. + return isFocusable(); +} + +bool HTMLTextAreaElement::isMouseFocusable() const +{ + return isFocusable(); +} + +void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection) +{ + ASSERT(renderer()); + + if (!restorePreviousSelection || m_cachedSelectionStart < 0) { + // If this is the first focus, set a caret at the beginning of the text. + // This matches some browsers' behavior; see bug 11746 Comment #15. + // http://bugs.webkit.org/show_bug.cgi?id=11746#c15 + setSelectionRange(0, 0); +#ifdef ANDROID_SELECT_TEXT_AREAS + // We need to select the entire text to match the platform text field. + select(); +#endif + } else { + // Restore the cached selection. This matches other browsers' behavior. + setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd); + } + + if (document()->frame()) + document()->frame()->revealSelection(); +} + +void HTMLTextAreaElement::defaultEventHandler(Event* event) +{ + if (renderer() && (event->isMouseEvent() || event->isDragEvent() || event->isWheelEvent() || event->type() == eventNames().blurEvent)) + static_cast<RenderTextControl*>(renderer())->forwardEvent(event); + + HTMLFormControlElementWithState::defaultEventHandler(event); +} + +void HTMLTextAreaElement::rendererWillBeDestroyed() +{ + updateValue(); +} + +void HTMLTextAreaElement::updateValue() const +{ + if (valueMatchesRenderer()) + return; + + ASSERT(renderer()); + m_value = static_cast<RenderTextControl*>(renderer())->text(); + setValueMatchesRenderer(); +} + +String HTMLTextAreaElement::value() const +{ + updateValue(); + return m_value; +} + +void HTMLTextAreaElement::setValue(const String& value) +{ + // Code elsewhere normalizes line endings added by the user via the keyboard or pasting. + // We must normalize line endings coming from JS. + m_value = value; + m_value.replace("\r\n", "\n"); + m_value.replace('\r', '\n'); + + setValueMatchesRenderer(); + if (inDocument()) + document()->updateRendering(); + if (renderer()) + renderer()->updateFromElement(); + + // Set the caret to the end of the text value. + if (document()->focusedNode() == this) { +#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS + // Make sure our UI side textfield changes to match the RenderTextControl + android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value); +#endif + unsigned endOfString = m_value.length(); + setSelectionRange(endOfString, endOfString); + } + + setChanged(); +} + +String HTMLTextAreaElement::defaultValue() const +{ + String value = ""; + + // Since there may be comments, ignore nodes other than text nodes. + for (Node* n = firstChild(); n; n = n->nextSibling()) { + if (n->isTextNode()) + value += static_cast<Text*>(n)->data(); + } + + UChar firstCharacter = value[0]; + if (firstCharacter == '\r' && value[1] == '\n') + value.remove(0, 2); + else if (firstCharacter == '\r' || firstCharacter == '\n') + value.remove(0, 1); + + return value; +} + +void HTMLTextAreaElement::setDefaultValue(const String& defaultValue) +{ + // To preserve comments, remove only the text nodes, then add a single text node. + + Vector<RefPtr<Node> > textNodes; + for (Node* n = firstChild(); n; n = n->nextSibling()) { + if (n->isTextNode()) + textNodes.append(n); + } + ExceptionCode ec; + size_t size = textNodes.size(); + for (size_t i = 0; i < size; ++i) + removeChild(textNodes[i].get(), ec); + + // Normalize line endings. + // Add an extra line break if the string starts with one, since + // the code to read default values from the DOM strips the leading one. + String value = defaultValue; + value.replace("\r\n", "\n"); + value.replace('\r', '\n'); + if (value[0] == '\n') + value = "\n" + value; + + insertBefore(document()->createTextNode(value), firstChild(), ec); + + setValue(value); +} + +void HTMLTextAreaElement::accessKeyAction(bool) +{ + focus(); +} + +const AtomicString& HTMLTextAreaElement::accessKey() const +{ + return getAttribute(accesskeyAttr); +} + +void HTMLTextAreaElement::setAccessKey(const String& value) +{ + setAttribute(accesskeyAttr, value); +} + +void HTMLTextAreaElement::setCols(int cols) +{ + setAttribute(colsAttr, String::number(cols)); +} + +void HTMLTextAreaElement::setRows(int rows) +{ + setAttribute(rowsAttr, String::number(rows)); +} + +Selection HTMLTextAreaElement::selection() const +{ + if (!renderer() || m_cachedSelectionStart < 0 || m_cachedSelectionEnd < 0) + return Selection(); + return static_cast<RenderTextControl*>(renderer())->selection(m_cachedSelectionStart, m_cachedSelectionEnd); +} + +bool HTMLTextAreaElement::shouldUseInputMethod() const +{ + return true; +} + +} // namespace diff --git a/WebCore/html/HTMLTextAreaElement.h b/WebCore/html/HTMLTextAreaElement.h new file mode 100644 index 0000000..d5b06fa --- /dev/null +++ b/WebCore/html/HTMLTextAreaElement.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 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. + * + */ + +#ifndef HTMLTextAreaElement_h +#define HTMLTextAreaElement_h + +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class Selection; + +class HTMLTextAreaElement : public HTMLFormControlElementWithState { +public: + HTMLTextAreaElement(Document*, HTMLFormElement* = 0); + + virtual bool checkDTD(const Node* newChild) { return newChild->isTextNode(); } + + int cols() const { return m_cols; } + int rows() const { return m_rows; } + + bool shouldWrapText() const { return m_wrap != NoWrap; } + + virtual bool isEnumeratable() const { return true; } + + virtual const AtomicString& type() const; + + virtual bool saveState(String& value) const; + virtual void restoreState(const String&); + + bool readOnly() const { return isReadOnlyControl(); } + + virtual bool isTextControl() const { return true; } + + int selectionStart(); + int selectionEnd(); + + void setSelectionStart(int); + void setSelectionEnd(int); + + void select(); + void setSelectionRange(int, int); + + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual void parseMappedAttribute(MappedAttribute*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual bool appendFormData(FormDataList&, bool); + virtual void reset(); + virtual void defaultEventHandler(Event*); + virtual bool isMouseFocusable() const; + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual void updateFocusAppearance(bool restorePreviousSelection); + + String value() const; + void setValue(const String&); + String defaultValue() const; + void setDefaultValue(const String&); + + void rendererWillBeDestroyed(); + + virtual void accessKeyAction(bool sendToAnyElement); + + const AtomicString& accessKey() const; + void setAccessKey(const String&); + + void setCols(int); + void setRows(int); + + void cacheSelection(int s, int e) { m_cachedSelectionStart = s; m_cachedSelectionEnd = e; }; + Selection selection() const; + + virtual bool shouldUseInputMethod() const; + +private: + enum WrapMethod { NoWrap, SoftWrap, HardWrap }; + + void updateValue() const; + + int m_rows; + int m_cols; + WrapMethod m_wrap; + mutable String m_value; + int m_cachedSelectionStart; + int m_cachedSelectionEnd; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTextAreaElement.idl b/WebCore/html/HTMLTextAreaElement.idl new file mode 100644 index 0000000..c4f144b --- /dev/null +++ b/WebCore/html/HTMLTextAreaElement.idl @@ -0,0 +1,50 @@ +/* + * 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 html { + + interface [ + GenerateConstructor, + InterfaceUUID=8b16bba6-efa9-4887-b863-308b4f9b9202, + ImplementationUUID=2414be6e-bae0-472d-b124-beed5ca82d3b + ] HTMLTextAreaElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString defaultValue; + readonly attribute HTMLFormElement form; + attribute [ConvertNullToNullString] DOMString accessKey; + attribute long cols; + attribute boolean disabled; + attribute boolean autofocus; + attribute [ConvertNullToNullString] DOMString name; + attribute boolean readOnly; + attribute long rows; + readonly attribute DOMString type; + attribute [ConvertNullToNullString] DOMString value; + + void select(); + + readonly attribute boolean willValidate; + + // WinIE & FireFox extension: + attribute long selectionStart; + attribute long selectionEnd; + void setSelectionRange(in long start, in long end); + }; + +} diff --git a/WebCore/html/HTMLTitleElement.cpp b/WebCore/html/HTMLTitleElement.cpp new file mode 100644 index 0000000..a75b1ee --- /dev/null +++ b/WebCore/html/HTMLTitleElement.cpp @@ -0,0 +1,95 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003 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 "HTMLTitleElement.h" + +#include "Document.h" +#include "HTMLNames.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLTitleElement::HTMLTitleElement(Document* doc) + : HTMLElement(titleTag, doc) + , m_title("") +{ +} + +HTMLTitleElement::~HTMLTitleElement() +{ +} + +void HTMLTitleElement::insertedIntoDocument() +{ + HTMLElement::insertedIntoDocument(); + document()->setTitle(m_title, this); +} + +void HTMLTitleElement::removedFromDocument() +{ + HTMLElement::removedFromDocument(); + document()->removeTitle(this); +} + +void HTMLTitleElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + m_title = ""; + for (Node* c = firstChild(); c != 0; c = c->nextSibling()) + if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE) + m_title += c->nodeValue(); + if (inDocument()) + document()->setTitle(m_title, this); + HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +String HTMLTitleElement::text() const +{ + String val = ""; + + for (Node *n = firstChild(); n; n = n->nextSibling()) { + if (n->isTextNode()) + val += static_cast<Text*>(n)->data(); + } + + return val; +} + +void HTMLTitleElement::setText(const String &value) +{ + ExceptionCode ec = 0; + int numChildren = childNodeCount(); + + if (numChildren == 1 && firstChild()->isTextNode()) + static_cast<Text*>(firstChild())->setData(value, ec); + else { + if (numChildren > 0) + removeChildren(); + + appendChild(document()->createTextNode(value.impl()), ec); + } +} + +} diff --git a/WebCore/html/HTMLTitleElement.h b/WebCore/html/HTMLTitleElement.h new file mode 100644 index 0000000..5bb05bc --- /dev/null +++ b/WebCore/html/HTMLTitleElement.h @@ -0,0 +1,52 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003 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 HTMLTitleElement_h +#define HTMLTitleElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLTitleElement : public HTMLElement +{ +public: + HTMLTitleElement(Document*); + ~HTMLTitleElement(); + + virtual bool checkDTD(const Node* newChild) { return newChild->isTextNode(); } + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + String text() const; + void setText(const String&); + +protected: + String m_title; +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLTitleElement.idl b/WebCore/html/HTMLTitleElement.idl new file mode 100644 index 0000000..d0f27e7 --- /dev/null +++ b/WebCore/html/HTMLTitleElement.idl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=036211fb-c1e9-4265-aac5-c5874e4a499c, + ImplementationUUID=ff577152-4ea3-404f-912d-ed1d0b64e60e + ] HTMLTitleElement : HTMLElement { + attribute [ConvertNullToNullString] DOMString text; + }; + +} diff --git a/WebCore/html/HTMLTokenizer.cpp b/WebCore/html/HTMLTokenizer.cpp new file mode 100644 index 0000000..807fb72 --- /dev/null +++ b/WebCore/html/HTMLTokenizer.cpp @@ -0,0 +1,2087 @@ +/* + Copyright (C) 1997 Martin Jones (mjones@kde.org) + (C) 1997 Torben Weis (weis@kde.org) + (C) 1998 Waldo Bastian (bastian@kde.org) + (C) 1999 Lars Knoll (knoll@kde.org) + (C) 1999 Antti Koivisto (koivisto@kde.org) + (C) 2001 Dirk Mueller (mueller@kde.org) + Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.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 "HTMLTokenizer.h" + +#include "CSSHelper.h" +#include "Cache.h" +#include "CachedScript.h" +#include "DocLoader.h" +#include "DocumentFragment.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "HTMLParser.h" +#include "HTMLScriptElement.h" +#include "HTMLViewSourceDocument.h" +#include "Page.h" +#include "PreloadScanner.h" +#include "ScriptController.h" +#include "SystemTime.h" +#include <wtf/ASCIICType.h> + +#include "HTMLEntityNames.c" + +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif + +#define PRELOAD_SCANNER_ENABLED 1 +// #define INSTRUMENT_LAYOUT_SCHEDULING 1 + +using namespace std; +using namespace WTF; + +namespace WebCore { + +using namespace HTMLNames; + +#if MOBILE +// The mobile device needs to be responsive, as such the tokenizer chunk size is reduced. +// This value is used to define how many characters the tokenizer will process before +// yeilding control. +static const int defaultTokenizerChunkSize = 256; +#else +static const int defaultTokenizerChunkSize = 4096; +#endif + +#if MOBILE +// As the chunks are smaller (above), the tokenizer should not yield for as long a period, otherwise +// it will take way to long to load a page. +static const double defaultTokenizerTimeDelay = 0.300; +#else +// FIXME: We would like this constant to be 200ms. +// Yielding more aggressively results in increased responsiveness and better incremental rendering. +// It slows down overall page-load on slower machines, though, so for now we set a value of 500. +static const double defaultTokenizerTimeDelay = 0.500; +#endif + +static const char commentStart [] = "<!--"; +static const char doctypeStart [] = "<!doctype"; +static const char publicStart [] = "public"; +static const char systemStart [] = "system"; +static const char scriptEnd [] = "</script"; +static const char xmpEnd [] = "</xmp"; +static const char styleEnd [] = "</style"; +static const char textareaEnd [] = "</textarea"; +static const char titleEnd [] = "</title"; +static const char iframeEnd [] = "</iframe"; + +// Full support for MS Windows extensions to Latin-1. +// Technically these extensions should only be activated for pages +// marked "windows-1252" or "cp1252", but +// in the standard Microsoft way, these extensions infect hundreds of thousands +// of web pages. Note that people with non-latin-1 Microsoft extensions +// are SOL. +// +// See: http://www.microsoft.com/globaldev/reference/WinCP.asp +// http://www.bbsinc.com/iso8859.html +// http://www.obviously.com/ +// +// There may be better equivalents + +// We only need this for entities. For non-entity text, we handle this in the text encoding. + +static const UChar windowsLatin1ExtensionArray[32] = { + 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, // 80-87 + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, // 88-8F + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, // 90-97 + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178 // 98-9F +}; + +static inline UChar fixUpChar(UChar c) +{ + if ((c & ~0x1F) != 0x0080) + return c; + return windowsLatin1ExtensionArray[c - 0x80]; +} + +static inline bool tagMatch(const char* s1, const UChar* s2, unsigned length) +{ + for (unsigned i = 0; i != length; ++i) { + unsigned char c1 = s1[i]; + unsigned char uc1 = toASCIIUpper(static_cast<char>(c1)); + UChar c2 = s2[i]; + if (c1 != c2 && uc1 != c2) + return false; + } + return true; +} + +inline void Token::addAttribute(Document* doc, AtomicString& attrName, const AtomicString& v, bool viewSourceMode) +{ + if (!attrName.isEmpty()) { + ASSERT(!attrName.contains('/')); + RefPtr<MappedAttribute> a = MappedAttribute::create(attrName, v); + if (!attrs) { + attrs = NamedMappedAttrMap::create(); + attrs->reserveCapacity(10); + } + attrs->insertAttribute(a.release(), viewSourceMode); + } + + attrName = emptyAtom; +} + +// ---------------------------------------------------------------------------- + +HTMLTokenizer::HTMLTokenizer(HTMLDocument* doc, bool reportErrors) + : Tokenizer() + , buffer(0) + , scriptCode(0) + , scriptCodeSize(0) + , scriptCodeMaxSize(0) + , scriptCodeResync(0) + , m_executingScript(0) + , m_requestingScript(false) + , m_hasScriptsWaitingForStylesheets(false) + , m_timer(this, &HTMLTokenizer::timerFired) + , m_doc(doc) + , parser(new HTMLParser(doc, reportErrors)) + , inWrite(false) + , m_fragment(false) +{ + begin(); +} + +HTMLTokenizer::HTMLTokenizer(HTMLViewSourceDocument* doc) + : Tokenizer(true) + , buffer(0) + , scriptCode(0) + , scriptCodeSize(0) + , scriptCodeMaxSize(0) + , scriptCodeResync(0) + , m_executingScript(0) + , m_requestingScript(false) + , m_hasScriptsWaitingForStylesheets(false) + , m_timer(this, &HTMLTokenizer::timerFired) + , m_doc(doc) + , parser(0) + , inWrite(false) + , m_fragment(false) +{ + begin(); +} + +HTMLTokenizer::HTMLTokenizer(DocumentFragment* frag) + : buffer(0) + , scriptCode(0) + , scriptCodeSize(0) + , scriptCodeMaxSize(0) + , scriptCodeResync(0) + , m_executingScript(0) + , m_requestingScript(false) + , m_hasScriptsWaitingForStylesheets(false) + , m_timer(this, &HTMLTokenizer::timerFired) + , m_doc(frag->document()) + , inWrite(false) + , m_fragment(true) +{ + parser = new HTMLParser(frag); + begin(); +} + +void HTMLTokenizer::reset() +{ + ASSERT(m_executingScript == 0); + + while (!pendingScripts.isEmpty()) { + CachedScript *cs = pendingScripts.first().get(); + pendingScripts.removeFirst(); + ASSERT(cache()->disabled() || cs->accessCount() > 0); + cs->removeClient(this); + } + + fastFree(buffer); + buffer = dest = 0; + size = 0; + + fastFree(scriptCode); + scriptCode = 0; + scriptCodeSize = scriptCodeMaxSize = scriptCodeResync = 0; + + m_timer.stop(); + m_state.setAllowYield(false); + m_state.setForceSynchronous(false); + + currToken.reset(); + m_doctypeToken.reset(); + m_doctypeSearchCount = 0; + m_doctypeSecondarySearchCount = 0; +} + +void HTMLTokenizer::begin() +{ + m_executingScript = 0; + m_requestingScript = false; + m_hasScriptsWaitingForStylesheets = false; + m_state.setLoadingExtScript(false); + reset(); + size = 254; + buffer = static_cast<UChar*>(fastMalloc(sizeof(UChar) * 254)); + dest = buffer; + tquote = NoQuote; + searchCount = 0; + m_state.setEntityState(NoEntity); + scriptSrc = String(); + pendingSrc.clear(); + currentPrependingSrc = 0; + noMoreData = false; + brokenComments = false; + brokenServer = false; + m_lineNumber = 0; + scriptStartLineno = 0; + tagStartLineno = 0; + m_state.setForceSynchronous(false); + + Page* page = m_doc->page(); + if (page && page->hasCustomHTMLTokenizerTimeDelay()) + m_tokenizerTimeDelay = page->customHTMLTokenizerTimeDelay(); + else + m_tokenizerTimeDelay = defaultTokenizerTimeDelay; + + if (page && page->hasCustomHTMLTokenizerChunkSize()) + m_tokenizerChunkSize = page->customHTMLTokenizerChunkSize(); + else + m_tokenizerChunkSize = defaultTokenizerChunkSize; +} + +void HTMLTokenizer::setForceSynchronous(bool force) +{ + m_state.setForceSynchronous(force); +} + +HTMLTokenizer::State HTMLTokenizer::processListing(SegmentedString list, State state) +{ + // This function adds the listing 'list' as + // preformatted text-tokens to the token-collection + while (!list.isEmpty()) { + if (state.skipLF()) { + state.setSkipLF(false); + if (*list == '\n') { + list.advance(); + continue; + } + } + + checkBuffer(); + + if (*list == '\n' || *list == '\r') { + if (state.discardLF()) + // Ignore this LF + state.setDiscardLF(false); // We have discarded 1 LF + else + *dest++ = '\n'; + + /* Check for MS-DOS CRLF sequence */ + if (*list == '\r') + state.setSkipLF(true); + + list.advance(); + } else { + state.setDiscardLF(false); + *dest++ = *list; + list.advance(); + } + } + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseSpecial(SegmentedString &src, State state) +{ + ASSERT(state.inTextArea() || state.inTitle() || state.inIFrame() || !state.hasEntityState()); + ASSERT(!state.hasTagState()); + ASSERT(state.inXmp() + state.inTextArea() + state.inTitle() + state.inStyle() + state.inScript() + state.inIFrame() == 1 ); + if (state.inScript() && !scriptStartLineno) + scriptStartLineno = m_lineNumber + 1; // Script line numbers are 1 based. + + if (state.inComment()) + state = parseComment(src, state); + + int lastDecodedEntityPosition = -1; + while ( !src.isEmpty() ) { + checkScriptBuffer(); + UChar ch = *src; + + if (!scriptCodeResync && !brokenComments && + !state.inXmp() && ch == '-' && scriptCodeSize >= 3 && !src.escaped() && + scriptCode[scriptCodeSize-3] == '<' && scriptCode[scriptCodeSize-2] == '!' && scriptCode[scriptCodeSize-1] == '-' && + (lastDecodedEntityPosition < scriptCodeSize - 3)) { + state.setInComment(true); + state = parseComment(src, state); + continue; + } + if (scriptCodeResync && !tquote && ch == '>') { + src.advancePastNonNewline(); + scriptCodeSize = scriptCodeResync-1; + scriptCodeResync = 0; + scriptCode[ scriptCodeSize ] = scriptCode[ scriptCodeSize + 1 ] = 0; + if (state.inScript()) + state = scriptHandler(state); + else { + state = processListing(SegmentedString(scriptCode, scriptCodeSize), state); + processToken(); + if (state.inStyle()) { + currToken.tagName = styleTag.localName(); + currToken.beginTag = false; + } else if (state.inTextArea()) { + currToken.tagName = textareaTag.localName(); + currToken.beginTag = false; + } else if (state.inTitle()) { + currToken.tagName = titleTag.localName(); + currToken.beginTag = false; + } else if (state.inXmp()) { + currToken.tagName = xmpTag.localName(); + currToken.beginTag = false; + } else if (state.inIFrame()) { + currToken.tagName = iframeTag.localName(); + currToken.beginTag = false; + } + processToken(); + state.setInStyle(false); + state.setInScript(false); + state.setInTextArea(false); + state.setInTitle(false); + state.setInXmp(false); + state.setInIFrame(false); + tquote = NoQuote; + scriptCodeSize = scriptCodeResync = 0; + } + return state; + } + // possible end of tagname, lets check. + if (!scriptCodeResync && !state.escaped() && !src.escaped() && (ch == '>' || ch == '/' || isASCIISpace(ch)) && + scriptCodeSize >= searchStopperLen && + tagMatch(searchStopper, scriptCode + scriptCodeSize - searchStopperLen, searchStopperLen) && + (lastDecodedEntityPosition < scriptCodeSize - searchStopperLen)) { + scriptCodeResync = scriptCodeSize-searchStopperLen+1; + tquote = NoQuote; + continue; + } + if (scriptCodeResync && !state.escaped()) { + if (ch == '\"') + tquote = (tquote == NoQuote) ? DoubleQuote : ((tquote == SingleQuote) ? SingleQuote : NoQuote); + else if (ch == '\'') + tquote = (tquote == NoQuote) ? SingleQuote : (tquote == DoubleQuote) ? DoubleQuote : NoQuote; + else if (tquote != NoQuote && (ch == '\r' || ch == '\n')) + tquote = NoQuote; + } + state.setEscaped(!state.escaped() && ch == '\\'); + if (!scriptCodeResync && (state.inTextArea() || state.inTitle() || state.inIFrame()) && !src.escaped() && ch == '&') { + UChar* scriptCodeDest = scriptCode+scriptCodeSize; + src.advancePastNonNewline(); + state = parseEntity(src, scriptCodeDest, state, m_cBufferPos, true, false); + if (scriptCodeDest == scriptCode + scriptCodeSize) + lastDecodedEntityPosition = scriptCodeSize; + else + scriptCodeSize = scriptCodeDest - scriptCode; + } else { + scriptCode[scriptCodeSize++] = ch; + src.advance(m_lineNumber); + } + } + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::scriptHandler(State state) +{ + // We are inside a <script> + bool doScriptExec = false; + int startLine = scriptStartLineno; + + // Reset scriptStartLineno to indicate that we've finished parsing the current script element + scriptStartLineno = 0; + + // (Bugzilla 3837) Scripts following a frameset element should not execute or, + // in the case of extern scripts, even load. + bool followingFrameset = (m_doc->body() && m_doc->body()->hasTagName(framesetTag)); + + CachedScript* cs = 0; + // don't load external scripts for standalone documents (for now) + if (!inViewSourceMode()) { + if (!scriptSrc.isEmpty() && m_doc->frame()) { + // forget what we just got; load from src url instead + if (!parser->skipMode() && !followingFrameset) { +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("Requesting script at time %d\n", m_doc->elapsedTime()); +#endif + // The parser might have been stopped by for example a window.close call in an earlier script. + // If so, we don't want to load scripts. + if (!m_parserStopped && (cs = m_doc->docLoader()->requestScript(scriptSrc, scriptSrcCharset))) + pendingScripts.append(cs); + else + scriptNode = 0; + } else + scriptNode = 0; + scriptSrc = String(); + } else { + // Parse scriptCode containing <script> info +#if USE(LOW_BANDWIDTH_DISPLAY) + if (m_doc->inLowBandwidthDisplay()) { + // ideal solution is only skipping internal JavaScript if there is external JavaScript. + // but internal JavaScript can use document.write() to create an external JavaScript, + // so we have to skip internal JavaScript all the time. + m_doc->frame()->loader()->needToSwitchOutLowBandwidthDisplay(); + doScriptExec = false; + } else +#endif + doScriptExec = static_cast<HTMLScriptElement*>(scriptNode.get())->shouldExecuteAsJavaScript(); + scriptNode = 0; + } + } + + state = processListing(SegmentedString(scriptCode, scriptCodeSize), state); + RefPtr<Node> node = processToken(); + String scriptString = node ? node->textContent() : ""; + currToken.tagName = scriptTag.localName(); + currToken.beginTag = false; + processToken(); + + state.setInScript(false); + scriptCodeSize = scriptCodeResync = 0; + + // FIXME: The script should be syntax highlighted. + if (inViewSourceMode()) + return state; + + SegmentedString *savedPrependingSrc = currentPrependingSrc; + SegmentedString prependingSrc; + currentPrependingSrc = &prependingSrc; + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::recordNoCounter(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); +#endif + + if (!parser->skipMode() && !followingFrameset) { + if (cs) { + if (savedPrependingSrc) + savedPrependingSrc->append(src); + else + pendingSrc.prepend(src); + setSrc(SegmentedString()); + + // the ref() call below may call notifyFinished if the script is already in cache, + // and that mucks with the state directly, so we must write it back to the object. + m_state = state; + bool savedRequestingScript = m_requestingScript; + m_requestingScript = true; + cs->addClient(this); + m_requestingScript = savedRequestingScript; + state = m_state; + // will be 0 if script was already loaded and ref() executed it + if (!pendingScripts.isEmpty()) + state.setLoadingExtScript(true); + } else if (!m_fragment && doScriptExec) { + if (!m_executingScript) + pendingSrc.prepend(src); + else + prependingSrc = src; + setSrc(SegmentedString()); + state = scriptExecution(scriptString, state, String(), startLine); + } + } + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::ParsingTimeCounter); +#endif + + if (!m_executingScript && !state.loadingExtScript()) { + src.append(pendingSrc); + pendingSrc.clear(); + } else if (!prependingSrc.isEmpty()) { + // restore first so that the write appends in the right place + // (does not hurt to do it again below) + currentPrependingSrc = savedPrependingSrc; + + // we need to do this slightly modified bit of one of the write() cases + // because we want to prepend to pendingSrc rather than appending + // if there's no previous prependingSrc + if (!pendingScripts.isEmpty()) { + if (currentPrependingSrc) { + currentPrependingSrc->append(prependingSrc); + } else { + pendingSrc.prepend(prependingSrc); + } + } else { + m_state = state; + write(prependingSrc, false); + state = m_state; + } + } + + +#if PRELOAD_SCANNER_ENABLED + if (!pendingScripts.isEmpty() && !m_executingScript) { + if (!m_preloadScanner) + m_preloadScanner.set(new PreloadScanner(m_doc)); + if (!m_preloadScanner->inProgress()) { + m_preloadScanner->begin(); + m_preloadScanner->write(pendingSrc); + } + } +#endif + currentPrependingSrc = savedPrependingSrc; + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::scriptExecution(const String& str, State state, const String& scriptURL, int baseLine) +{ + if (m_fragment || !m_doc->frame()) + return state; + m_executingScript++; + String url = scriptURL.isNull() ? m_doc->frame()->document()->url().string() : scriptURL; + + SegmentedString *savedPrependingSrc = currentPrependingSrc; + SegmentedString prependingSrc; + currentPrependingSrc = &prependingSrc; + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("beginning script execution at %d\n", m_doc->elapsedTime()); +#endif + + m_state = state; + m_doc->frame()->loader()->executeScript(url, baseLine, str); + state = m_state; + + state.setAllowYield(true); + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("ending script execution at %d\n", m_doc->elapsedTime()); +#endif + + m_executingScript--; + + if (!m_executingScript && !state.loadingExtScript()) { + pendingSrc.prepend(prependingSrc); + src.append(pendingSrc); + pendingSrc.clear(); + } else if (!prependingSrc.isEmpty()) { + // restore first so that the write appends in the right place + // (does not hurt to do it again below) + currentPrependingSrc = savedPrependingSrc; + + // we need to do this slightly modified bit of one of the write() cases + // because we want to prepend to pendingSrc rather than appending + // if there's no previous prependingSrc + if (!pendingScripts.isEmpty()) { + if (currentPrependingSrc) + currentPrependingSrc->append(prependingSrc); + else + pendingSrc.prepend(prependingSrc); + +#if PRELOAD_SCANNER_ENABLED + // We are stuck waiting for another script. Lets check the source that + // was just document.write()n for anything to load. + PreloadScanner documentWritePreloadScanner(m_doc); + documentWritePreloadScanner.begin(); + documentWritePreloadScanner.write(prependingSrc); + documentWritePreloadScanner.end(); +#endif + } else { + m_state = state; + write(prependingSrc, false); + state = m_state; + } + } + + currentPrependingSrc = savedPrependingSrc; + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseComment(SegmentedString &src, State state) +{ + // FIXME: Why does this code even run for comments inside <script> and <style>? This seems bogus. + checkScriptBuffer(src.length()); + while (!src.isEmpty()) { + UChar ch = *src; + scriptCode[scriptCodeSize++] = ch; + if (ch == '>') { + bool handleBrokenComments = brokenComments && !(state.inScript() || state.inStyle()); + int endCharsCount = 1; // start off with one for the '>' character + if (scriptCodeSize > 2 && scriptCode[scriptCodeSize-3] == '-' && scriptCode[scriptCodeSize-2] == '-') { + endCharsCount = 3; + } else if (scriptCodeSize > 3 && scriptCode[scriptCodeSize-4] == '-' && scriptCode[scriptCodeSize-3] == '-' && + scriptCode[scriptCodeSize-2] == '!') { + // Other browsers will accept --!> as a close comment, even though it's + // not technically valid. + endCharsCount = 4; + } + if (handleBrokenComments || endCharsCount > 1) { + src.advancePastNonNewline(); + if (!(state.inTitle() || state.inScript() || state.inXmp() || state.inTextArea() || state.inStyle() || state.inIFrame())) { + checkScriptBuffer(); + scriptCode[scriptCodeSize] = 0; + scriptCode[scriptCodeSize + 1] = 0; + currToken.tagName = commentAtom; + currToken.beginTag = true; + state = processListing(SegmentedString(scriptCode, scriptCodeSize - endCharsCount), state); + processToken(); + currToken.tagName = commentAtom; + currToken.beginTag = false; + processToken(); + scriptCodeSize = 0; + } + state.setInComment(false); + return state; // Finished parsing comment + } + } + src.advance(m_lineNumber); + } + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseServer(SegmentedString& src, State state) +{ + checkScriptBuffer(src.length()); + while (!src.isEmpty()) { + UChar ch = *src; + scriptCode[scriptCodeSize++] = ch; + if (ch == '>' && scriptCodeSize > 1 && scriptCode[scriptCodeSize-2] == '%') { + src.advancePastNonNewline(); + state.setInServer(false); + scriptCodeSize = 0; + return state; // Finished parsing server include + } + src.advance(m_lineNumber); + } + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseProcessingInstruction(SegmentedString &src, State state) +{ + UChar oldchar = 0; + while (!src.isEmpty()) { + UChar chbegin = *src; + if (chbegin == '\'') + tquote = tquote == SingleQuote ? NoQuote : SingleQuote; + else if (chbegin == '\"') + tquote = tquote == DoubleQuote ? NoQuote : DoubleQuote; + // Look for '?>' + // Some crappy sites omit the "?" before it, so + // we look for an unquoted '>' instead. (IE compatible) + else if (chbegin == '>' && (!tquote || oldchar == '?')) { + // We got a '?>' sequence + state.setInProcessingInstruction(false); + src.advancePastNonNewline(); + state.setDiscardLF(true); + return state; // Finished parsing comment! + } + src.advance(m_lineNumber); + oldchar = chbegin; + } + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseText(SegmentedString &src, State state) +{ + while (!src.isEmpty()) { + UChar cc = *src; + + if (state.skipLF()) { + state.setSkipLF(false); + if (cc == '\n') { + src.advancePastNewline(m_lineNumber); + continue; + } + } + + // do we need to enlarge the buffer? + checkBuffer(); + + if (cc == '\r') { + state.setSkipLF(true); + *dest++ = '\n'; + } else + *dest++ = cc; + src.advance(m_lineNumber); + } + + return state; +} + + +HTMLTokenizer::State HTMLTokenizer::parseEntity(SegmentedString &src, UChar*& dest, State state, unsigned &cBufferPos, bool start, bool parsingTag) +{ + if (start) + { + cBufferPos = 0; + state.setEntityState(SearchEntity); + EntityUnicodeValue = 0; + } + + while(!src.isEmpty()) + { + UChar cc = *src; + switch(state.entityState()) { + case NoEntity: + ASSERT(state.entityState() != NoEntity); + return state; + + case SearchEntity: + if (cc == '#') { + cBuffer[cBufferPos++] = cc; + src.advancePastNonNewline(); + state.setEntityState(NumericSearch); + } else + state.setEntityState(EntityName); + break; + + case NumericSearch: + if (cc == 'x' || cc == 'X') { + cBuffer[cBufferPos++] = cc; + src.advancePastNonNewline(); + state.setEntityState(Hexadecimal); + } else if (cc >= '0' && cc <= '9') + state.setEntityState(Decimal); + else + state.setEntityState(SearchSemicolon); + break; + + case Hexadecimal: { + int ll = min(src.length(), 10 - cBufferPos); + while (ll--) { + cc = *src; + if (!((cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'f') || (cc >= 'A' && cc <= 'F'))) { + state.setEntityState(SearchSemicolon); + break; + } + int digit; + if (cc < 'A') + digit = cc - '0'; + else + digit = (cc - 'A' + 10) & 0xF; // handle both upper and lower case without a branch + EntityUnicodeValue = EntityUnicodeValue * 16 + digit; + cBuffer[cBufferPos++] = cc; + src.advancePastNonNewline(); + } + if (cBufferPos == 10) + state.setEntityState(SearchSemicolon); + break; + } + case Decimal: + { + int ll = min(src.length(), 9-cBufferPos); + while(ll--) { + cc = *src; + + if (!(cc >= '0' && cc <= '9')) { + state.setEntityState(SearchSemicolon); + break; + } + + EntityUnicodeValue = EntityUnicodeValue * 10 + (cc - '0'); + cBuffer[cBufferPos++] = cc; + src.advancePastNonNewline(); + } + if (cBufferPos == 9) + state.setEntityState(SearchSemicolon); + break; + } + case EntityName: + { + int ll = min(src.length(), 9-cBufferPos); + while(ll--) { + cc = *src; + + if (!((cc >= 'a' && cc <= 'z') || (cc >= '0' && cc <= '9') || (cc >= 'A' && cc <= 'Z'))) { + state.setEntityState(SearchSemicolon); + break; + } + + cBuffer[cBufferPos++] = cc; + src.advancePastNonNewline(); + } + if (cBufferPos == 9) + state.setEntityState(SearchSemicolon); + if (state.entityState() == SearchSemicolon) { + if(cBufferPos > 1) { + // Since the maximum length of entity name is 9, + // so a single char array which is allocated on + // the stack, its length is 10, should be OK. + // Also if we have an illegal character, we treat it + // as illegal entity name. + unsigned testedEntityNameLen = 0; + char tmpEntityNameBuffer[10]; + + ASSERT(cBufferPos < 10); + for (; testedEntityNameLen < cBufferPos; ++testedEntityNameLen) { + if (cBuffer[testedEntityNameLen] > 0x7e) + break; + tmpEntityNameBuffer[testedEntityNameLen] = cBuffer[testedEntityNameLen]; + } + + const Entity *e; + + if (testedEntityNameLen == cBufferPos) + e = findEntity(tmpEntityNameBuffer, cBufferPos); + else + e = 0; + + if(e) + EntityUnicodeValue = e->code; + + // be IE compatible + if(parsingTag && EntityUnicodeValue > 255 && *src != ';') + EntityUnicodeValue = 0; + } + } + else + break; + } + case SearchSemicolon: + // Don't allow values that are more than 21 bits. + if (EntityUnicodeValue > 0 && EntityUnicodeValue <= 0x10FFFF) { + if (!inViewSourceMode()) { + if (*src == ';') + src.advancePastNonNewline(); + if (EntityUnicodeValue <= 0xFFFF) { + checkBuffer(); + src.push(fixUpChar(EntityUnicodeValue)); + } else { + // Convert to UTF-16, using surrogate code points. + checkBuffer(2); + src.push(U16_LEAD(EntityUnicodeValue)); + src.push(U16_TRAIL(EntityUnicodeValue)); + } + } else { + // FIXME: We should eventually colorize entities by sending them as a special token. + checkBuffer(11); + *dest++ = '&'; + for (unsigned i = 0; i < cBufferPos; i++) + dest[i] = cBuffer[i]; + dest += cBufferPos; + if (*src == ';') { + *dest++ = ';'; + src.advancePastNonNewline(); + } + } + } else { + checkBuffer(10); + // ignore the sequence, add it to the buffer as plaintext + *dest++ = '&'; + for (unsigned i = 0; i < cBufferPos; i++) + dest[i] = cBuffer[i]; + dest += cBufferPos; + } + + state.setEntityState(NoEntity); + return state; + } + } + + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseDoctype(SegmentedString& src, State state) +{ + ASSERT(state.inDoctype()); + while (!src.isEmpty() && state.inDoctype()) { + UChar c = *src; + bool isWhitespace = c == '\r' || c == '\n' || c == '\t' || c == ' '; + switch (m_doctypeToken.state()) { + case DoctypeBegin: { + m_doctypeToken.setState(DoctypeBeforeName); + if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + } + case DoctypeBeforeName: { + if (c == '>') { + // Malformed. Just exit. + src.advancePastNonNewline(); + state.setInDoctype(false); + if (inViewSourceMode()) + processDoctypeToken(); + } else if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else + m_doctypeToken.setState(DoctypeName); + break; + } + case DoctypeName: { + if (c == '>') { + // Valid doctype. Emit it. + src.advancePastNonNewline(); + state.setInDoctype(false); + processDoctypeToken(); + } else if (isWhitespace) { + m_doctypeSearchCount = 0; // Used now to scan for PUBLIC + m_doctypeSecondarySearchCount = 0; // Used now to scan for SYSTEM + m_doctypeToken.setState(DoctypeAfterName); + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else { + src.advancePastNonNewline(); + m_doctypeToken.m_name.append(c); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + } + case DoctypeAfterName: { + if (c == '>') { + // Valid doctype. Emit it. + src.advancePastNonNewline(); + state.setInDoctype(false); + processDoctypeToken(); + } else if (!isWhitespace) { + src.advancePastNonNewline(); + if (toASCIILower(c) == publicStart[m_doctypeSearchCount]) { + m_doctypeSearchCount++; + if (m_doctypeSearchCount == 6) + // Found 'PUBLIC' sequence + m_doctypeToken.setState(DoctypeBeforePublicID); + } else if (m_doctypeSearchCount > 0) { + m_doctypeSearchCount = 0; + m_doctypeToken.setState(DoctypeBogus); + } else if (toASCIILower(c) == systemStart[m_doctypeSecondarySearchCount]) { + m_doctypeSecondarySearchCount++; + if (m_doctypeSecondarySearchCount == 6) + // Found 'SYSTEM' sequence + m_doctypeToken.setState(DoctypeBeforeSystemID); + } else { + m_doctypeSecondarySearchCount = 0; + m_doctypeToken.setState(DoctypeBogus); + } + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else { + src.advance(m_lineNumber); // Whitespace keeps us in the after name state. + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + } + case DoctypeBeforePublicID: { + if (c == '\"' || c == '\'') { + tquote = c == '\"' ? DoubleQuote : SingleQuote; + m_doctypeToken.setState(DoctypePublicID); + src.advancePastNonNewline(); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else if (c == '>') { + // Considered bogus. Don't process the doctype. + src.advancePastNonNewline(); + state.setInDoctype(false); + if (inViewSourceMode()) + processDoctypeToken(); + } else if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else + m_doctypeToken.setState(DoctypeBogus); + break; + } + case DoctypePublicID: { + if ((c == '\"' && tquote == DoubleQuote) || (c == '\'' && tquote == SingleQuote)) { + src.advancePastNonNewline(); + m_doctypeToken.setState(DoctypeAfterPublicID); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else if (c == '>') { + // Considered bogus. Don't process the doctype. + src.advancePastNonNewline(); + state.setInDoctype(false); + if (inViewSourceMode()) + processDoctypeToken(); + } else { + m_doctypeToken.m_publicID.append(c); + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + } + case DoctypeAfterPublicID: + if (c == '\"' || c == '\'') { + tquote = c == '\"' ? DoubleQuote : SingleQuote; + m_doctypeToken.setState(DoctypeSystemID); + src.advancePastNonNewline(); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else if (c == '>') { + // Valid doctype. Emit it now. + src.advancePastNonNewline(); + state.setInDoctype(false); + processDoctypeToken(); + } else if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else + m_doctypeToken.setState(DoctypeBogus); + break; + case DoctypeBeforeSystemID: + if (c == '\"' || c == '\'') { + tquote = c == '\"' ? DoubleQuote : SingleQuote; + m_doctypeToken.setState(DoctypeSystemID); + src.advancePastNonNewline(); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else if (c == '>') { + // Considered bogus. Don't process the doctype. + src.advancePastNonNewline(); + state.setInDoctype(false); + } else if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else + m_doctypeToken.setState(DoctypeBogus); + break; + case DoctypeSystemID: + if ((c == '\"' && tquote == DoubleQuote) || (c == '\'' && tquote == SingleQuote)) { + src.advancePastNonNewline(); + m_doctypeToken.setState(DoctypeAfterSystemID); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else if (c == '>') { + // Considered bogus. Don't process the doctype. + src.advancePastNonNewline(); + state.setInDoctype(false); + if (inViewSourceMode()) + processDoctypeToken(); + } else { + m_doctypeToken.m_systemID.append(c); + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + case DoctypeAfterSystemID: + if (c == '>') { + // Valid doctype. Emit it now. + src.advancePastNonNewline(); + state.setInDoctype(false); + processDoctypeToken(); + } else if (isWhitespace) { + src.advance(m_lineNumber); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } else + m_doctypeToken.setState(DoctypeBogus); + break; + case DoctypeBogus: + if (c == '>') { + // Done with the bogus doctype. + src.advancePastNonNewline(); + state.setInDoctype(false); + if (inViewSourceMode()) + processDoctypeToken(); + } else { + src.advance(m_lineNumber); // Just keep scanning for '>' + if (inViewSourceMode()) + m_doctypeToken.m_source.append(c); + } + break; + default: + break; + } + } + return state; +} + +HTMLTokenizer::State HTMLTokenizer::parseTag(SegmentedString &src, State state) +{ + ASSERT(!state.hasEntityState()); + + unsigned cBufferPos = m_cBufferPos; + + bool lastIsSlash = false; + + while (!src.isEmpty()) { + checkBuffer(); + switch(state.tagState()) { + case NoTag: + { + m_cBufferPos = cBufferPos; + return state; + } + case TagName: + { + if (searchCount > 0) { + if (*src == commentStart[searchCount]) { + searchCount++; + if (searchCount == 2) + m_doctypeSearchCount++; // A '!' is also part of a doctype, so we are moving through that still as well. + else + m_doctypeSearchCount = 0; + if (searchCount == 4) { + // Found '<!--' sequence + src.advancePastNonNewline(); + dest = buffer; // ignore the previous part of this tag + state.setInComment(true); + state.setTagState(NoTag); + + // Fix bug 34302 at kde.bugs.org. Go ahead and treat + // <!--> as a valid comment, since both mozilla and IE on windows + // can handle this case. Only do this in quirks mode. -dwh + if (!src.isEmpty() && *src == '>' && m_doc->inCompatMode()) { + state.setInComment(false); + src.advancePastNonNewline(); + if (!src.isEmpty()) + cBuffer[cBufferPos++] = *src; + } else + state = parseComment(src, state); + + m_cBufferPos = cBufferPos; + return state; // Finished parsing tag! + } + cBuffer[cBufferPos++] = *src; + src.advancePastNonNewline(); + break; + } else + searchCount = 0; // Stop looking for '<!--' sequence + } + + if (m_doctypeSearchCount > 0) { + if (toASCIILower(*src) == doctypeStart[m_doctypeSearchCount]) { + m_doctypeSearchCount++; + cBuffer[cBufferPos++] = *src; + src.advancePastNonNewline(); + if (m_doctypeSearchCount == 9) { + // Found '<!DOCTYPE' sequence + state.setInDoctype(true); + state.setTagState(NoTag); + m_doctypeToken.reset(); + if (inViewSourceMode()) + m_doctypeToken.m_source.append(cBuffer, cBufferPos); + state = parseDoctype(src, state); + m_cBufferPos = cBufferPos; + return state; + } + break; + } else + m_doctypeSearchCount = 0; // Stop looking for '<!DOCTYPE' sequence + } + + bool finish = false; + unsigned int ll = min(src.length(), CBUFLEN - cBufferPos); + while (ll--) { + UChar curchar = *src; + if (isASCIISpace(curchar) || curchar == '>' || curchar == '<') { + finish = true; + break; + } + + // tolower() shows up on profiles. This is faster! + if (curchar >= 'A' && curchar <= 'Z' && !inViewSourceMode()) + cBuffer[cBufferPos++] = curchar + ('a' - 'A'); + else + cBuffer[cBufferPos++] = curchar; + src.advancePastNonNewline(); + } + + // Disadvantage: we add the possible rest of the tag + // as attribute names. ### judge if this causes problems + if(finish || CBUFLEN == cBufferPos) { + bool beginTag; + UChar* ptr = cBuffer; + unsigned int len = cBufferPos; + cBuffer[cBufferPos] = '\0'; + if ((cBufferPos > 0) && (*ptr == '/')) { + // End Tag + beginTag = false; + ptr++; + len--; + } + else + // Start Tag + beginTag = true; + + // Ignore the / in fake xml tags like <br/>. We trim off the "/" so that we'll get "br" as the tag name and not "br/". + if (len > 1 && ptr[len-1] == '/' && !inViewSourceMode()) + ptr[--len] = '\0'; + + // Now that we've shaved off any invalid / that might have followed the name), make the tag. + // FIXME: FireFox and WinIE turn !foo nodes into comments, we ignore comments. (fast/parser/tag-with-exclamation-point.html) + if (ptr[0] != '!' || inViewSourceMode()) { + currToken.tagName = AtomicString(ptr); + currToken.beginTag = beginTag; + } + dest = buffer; + state.setTagState(SearchAttribute); + cBufferPos = 0; + } + break; + } + case SearchAttribute: +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("SearchAttribute"); +#endif + while(!src.isEmpty()) { + UChar curchar = *src; + // In this mode just ignore any quotes we encounter and treat them like spaces. + if (!isASCIISpace(curchar) && curchar != '\'' && curchar != '"') { + if (curchar == '<' || curchar == '>') + state.setTagState(SearchEnd); + else + state.setTagState(AttributeName); + + cBufferPos = 0; + break; + } + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + src.advance(m_lineNumber); + } + break; + case AttributeName: + { +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("AttributeName"); +#endif + int ll = min(src.length(), CBUFLEN-cBufferPos); + while(ll--) { + UChar curchar = *src; + // If we encounter a "/" when scanning an attribute name, treat it as a delimiter. This allows the + // cases like <input type=checkbox checked/> to work (and accommodates XML-style syntax as per HTML5). + if (curchar <= '>' && (curchar >= '<' || isASCIISpace(curchar) || curchar == '/')) { + cBuffer[cBufferPos] = '\0'; + attrName = AtomicString(cBuffer); + dest = buffer; + *dest++ = 0; + state.setTagState(SearchEqual); + if (inViewSourceMode()) + currToken.addViewSourceChar('a'); + break; + } + + // tolower() shows up on profiles. This is faster! + if (curchar >= 'A' && curchar <= 'Z' && !inViewSourceMode()) + cBuffer[cBufferPos++] = curchar + ('a' - 'A'); + else + cBuffer[cBufferPos++] = curchar; + + src.advance(m_lineNumber); + } + if ( cBufferPos == CBUFLEN ) { + cBuffer[cBufferPos] = '\0'; + attrName = AtomicString(cBuffer); + dest = buffer; + *dest++ = 0; + state.setTagState(SearchEqual); + if (inViewSourceMode()) + currToken.addViewSourceChar('a'); + } + break; + } + case SearchEqual: +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("SearchEqual"); +#endif + while(!src.isEmpty()) { + UChar curchar = *src; + + if (lastIsSlash && curchar == '>') { + // This is a quirk (with a long sad history). We have to do this + // since widgets do <script src="foo.js"/> and expect the tag to close. + if (currToken.tagName == scriptTag) + currToken.flat = true; + currToken.brokenXMLStyle = true; + } + + // In this mode just ignore any quotes or slashes we encounter and treat them like spaces. + if (!isASCIISpace(curchar) && curchar != '\'' && curchar != '"' && curchar != '/') { + if (curchar == '=') { +#ifdef TOKEN_DEBUG + kdDebug(6036) << "found equal" << endl; +#endif + state.setTagState(SearchValue); + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + src.advancePastNonNewline(); + } else { + currToken.addAttribute(m_doc, attrName, emptyAtom, inViewSourceMode()); + dest = buffer; + state.setTagState(SearchAttribute); + lastIsSlash = false; + } + break; + } + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + + lastIsSlash = curchar == '/'; + + src.advance(m_lineNumber); + } + break; + case SearchValue: + while (!src.isEmpty()) { + UChar curchar = *src; + if (!isASCIISpace(curchar)) { + if (curchar == '\'' || curchar == '\"') { + tquote = curchar == '\"' ? DoubleQuote : SingleQuote; + state.setTagState(QuotedValue); + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + src.advancePastNonNewline(); + } else + state.setTagState(Value); + + break; + } + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + src.advance(m_lineNumber); + } + break; + case QuotedValue: +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("QuotedValue"); +#endif + while (!src.isEmpty()) { + checkBuffer(); + + UChar curchar = *src; + if (curchar <= '>' && !src.escaped()) { + if (curchar == '>' && attrName.isEmpty()) { + // Handle a case like <img '>. Just go ahead and be willing + // to close the whole tag. Don't consume the character and + // just go back into SearchEnd while ignoring the whole + // value. + // FIXME: Note that this is actually not a very good solution. + // It doesn't handle the general case of + // unmatched quotes among attributes that have names. -dwh + while (dest > buffer + 1 && (dest[-1] == '\n' || dest[-1] == '\r')) + dest--; // remove trailing newlines + AtomicString v(buffer + 1, dest - buffer - 1); + if (!v.contains('/')) + attrName = v; // Just make the name/value match. (FIXME: Is this some WinIE quirk?) + currToken.addAttribute(m_doc, attrName, v, inViewSourceMode()); + if (inViewSourceMode()) + currToken.addViewSourceChar('x'); + state.setTagState(SearchAttribute); + dest = buffer; + tquote = NoQuote; + break; + } + + if (curchar == '&') { + src.advancePastNonNewline(); + state = parseEntity(src, dest, state, cBufferPos, true, true); + break; + } + + if ((tquote == SingleQuote && curchar == '\'') || (tquote == DoubleQuote && curchar == '\"')) { + // some <input type=hidden> rely on trailing spaces. argh + while (dest > buffer + 1 && (dest[-1] == '\n' || dest[-1] == '\r')) + dest--; // remove trailing newlines + AtomicString v(buffer + 1, dest - buffer - 1); + if (attrName.isEmpty() && !v.contains('/')) { + attrName = v; // Make the name match the value. (FIXME: Is this a WinIE quirk?) + if (inViewSourceMode()) + currToken.addViewSourceChar('x'); + } else if (inViewSourceMode()) + currToken.addViewSourceChar('v'); + currToken.addAttribute(m_doc, attrName, v, inViewSourceMode()); + dest = buffer; + state.setTagState(SearchAttribute); + tquote = NoQuote; + if (inViewSourceMode()) + currToken.addViewSourceChar(curchar); + src.advancePastNonNewline(); + break; + } + } + + *dest++ = curchar; + src.advance(m_lineNumber); + } + break; + case Value: +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("Value"); +#endif + while(!src.isEmpty()) { + checkBuffer(); + UChar curchar = *src; + if (curchar <= '>' && !src.escaped()) { + // parse Entities + if (curchar == '&') { + src.advancePastNonNewline(); + state = parseEntity(src, dest, state, cBufferPos, true, true); + break; + } + // no quotes. Every space means end of value + // '/' does not delimit in IE! + if (isASCIISpace(curchar) || curchar == '>') { + AtomicString v(buffer+1, dest-buffer-1); + currToken.addAttribute(m_doc, attrName, v, inViewSourceMode()); + if (inViewSourceMode()) + currToken.addViewSourceChar('v'); + dest = buffer; + state.setTagState(SearchAttribute); + break; + } + } + + *dest++ = curchar; + src.advance(m_lineNumber); + } + break; + case SearchEnd: + { +#if defined(TOKEN_DEBUG) && TOKEN_DEBUG > 1 + qDebug("SearchEnd"); +#endif + while (!src.isEmpty()) { + UChar ch = *src; + if (ch == '>' || ch == '<') + break; + if (ch == '/') + currToken.flat = true; + if (inViewSourceMode()) + currToken.addViewSourceChar(ch); + src.advance(m_lineNumber); + } + if (src.isEmpty()) break; + + searchCount = 0; // Stop looking for '<!--' sequence + state.setTagState(NoTag); + tquote = NoQuote; + + if (*src != '<') + src.advance(m_lineNumber); + + if (currToken.tagName == nullAtom) { //stop if tag is unknown + m_cBufferPos = cBufferPos; + return state; + } + + AtomicString tagName = currToken.tagName; + + // Handle <script src="foo"/> like Mozilla/Opera. We have to do this now for Dashboard + // compatibility. + bool isSelfClosingScript = currToken.flat && currToken.beginTag && currToken.tagName == scriptTag; + bool beginTag = !currToken.flat && currToken.beginTag; + if (currToken.beginTag && currToken.tagName == scriptTag && !inViewSourceMode() && !parser->skipMode()) { + Attribute* a = 0; + scriptSrc = String(); + scriptSrcCharset = String(); + if (currToken.attrs && !m_fragment) { + if (m_doc->frame() && m_doc->frame()->script()->isEnabled()) { + if ((a = currToken.attrs->getAttributeItem(srcAttr))) + scriptSrc = m_doc->completeURL(parseURL(a->value())).string(); + } + } + } + + RefPtr<Node> n = processToken(); + m_cBufferPos = cBufferPos; + if (n || inViewSourceMode()) { + if ((tagName == preTag || tagName == listingTag) && !inViewSourceMode()) { + if (beginTag) + state.setDiscardLF(true); // Discard the first LF after we open a pre. + } else if (tagName == scriptTag) { + ASSERT(!scriptNode); + scriptNode = n; + if (n) + scriptSrcCharset = static_cast<HTMLScriptElement*>(n.get())->scriptCharset(); + if (beginTag) { + searchStopper = scriptEnd; + searchStopperLen = 8; + state.setInScript(true); + state = parseSpecial(src, state); + } else if (isSelfClosingScript) { // Handle <script src="foo"/> + state.setInScript(true); + state = scriptHandler(state); + } + } else if (tagName == styleTag) { + if (beginTag) { + searchStopper = styleEnd; + searchStopperLen = 7; + state.setInStyle(true); + state = parseSpecial(src, state); + } + } else if (tagName == textareaTag) { + if (beginTag) { + searchStopper = textareaEnd; + searchStopperLen = 10; + state.setInTextArea(true); + state = parseSpecial(src, state); + } + } else if (tagName == titleTag) { + if (beginTag) { + searchStopper = titleEnd; + searchStopperLen = 7; + State savedState = state; + SegmentedString savedSrc = src; + long savedLineno = m_lineNumber; + state.setInTitle(true); + state = parseSpecial(src, state); + if (state.inTitle() && src.isEmpty()) { + // We just ate the rest of the document as the title #text node! + // Reset the state then retokenize without special title handling. + // Let the parser clean up the missing </title> tag. + // FIXME: This is incorrect, because src.isEmpty() doesn't mean we're + // at the end of the document unless noMoreData is also true. We need + // to detect this case elsewhere, and save the state somewhere other + // than a local variable. + state = savedState; + src = savedSrc; + m_lineNumber = savedLineno; + scriptCodeSize = 0; + } + } + } else if (tagName == xmpTag) { + if (beginTag) { + searchStopper = xmpEnd; + searchStopperLen = 5; + state.setInXmp(true); + state = parseSpecial(src, state); + } + } else if (tagName == iframeTag) { + if (beginTag) { + searchStopper = iframeEnd; + searchStopperLen = 8; + state.setInIFrame(true); + state = parseSpecial(src, state); + } + } + } + if (tagName == plaintextTag) + state.setInPlainText(beginTag); + return state; // Finished parsing tag! + } + } // end switch + } + m_cBufferPos = cBufferPos; + return state; +} + +inline bool HTMLTokenizer::continueProcessing(int& processedCount, double startTime, State &state) +{ + // We don't want to be checking elapsed time with every character, so we only check after we've + // processed a certain number of characters. + bool allowedYield = state.allowYield(); + state.setAllowYield(false); + if (!state.loadingExtScript() && !state.forceSynchronous() && !m_executingScript && (processedCount > m_tokenizerChunkSize || allowedYield)) { + processedCount = 0; + if (currentTime() - startTime > m_tokenizerTimeDelay) { + /* FIXME: We'd like to yield aggressively to give stylesheets the opportunity to + load, but this hurts overall performance on slower machines. For now turn this + off. + || (!m_doc->haveStylesheetsLoaded() && + (m_doc->documentElement()->id() != ID_HTML || m_doc->body()))) {*/ + // Schedule the timer to keep processing as soon as possible. + m_timer.startOneShot(0); +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (currentTime() - startTime > m_tokenizerTimeDelay) + printf("Deferring processing of data because 500ms elapsed away from event loop.\n"); +#endif + return false; + } + } + + processedCount++; + return true; +} + +bool HTMLTokenizer::write(const SegmentedString& str, bool appendData) +{ +#ifdef TOKEN_DEBUG + kdDebug( 6036 ) << this << " Tokenizer::write(\"" << str.toString() << "\"," << appendData << ")" << endl; +#endif + + if (!buffer) + return false; + + if (m_parserStopped) + return false; + + SegmentedString source(str); + if (m_executingScript) + source.setExcludeLineNumbers(); + + if ((m_executingScript && appendData) || !pendingScripts.isEmpty()) { + // don't parse; we will do this later + if (currentPrependingSrc) + currentPrependingSrc->append(source); + else { + pendingSrc.append(source); +#if PRELOAD_SCANNER_ENABLED + if (m_preloadScanner && m_preloadScanner->inProgress() && appendData) + m_preloadScanner->write(source); +#endif + } + return false; + } + + +#if PRELOAD_SCANNER_ENABLED + if (m_preloadScanner && m_preloadScanner->inProgress() && appendData) + m_preloadScanner->end(); +#endif + + if (!src.isEmpty()) + src.append(source); + else + setSrc(source); + + // Once a timer is set, it has control of when the tokenizer continues. + if (m_timer.isActive()) + return false; + + bool wasInWrite = inWrite; + inWrite = true; + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("Beginning write at time %d\n", m_doc->elapsedTime()); +#endif + + int processedCount = 0; + double startTime = currentTime(); +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::ParsingTimeCounter); +#endif + + Frame *frame = m_doc->frame(); + + State state = m_state; + + while (!src.isEmpty() && (!frame || !frame->loader()->isScheduledLocationChangePending())) { + if (!continueProcessing(processedCount, startTime, state)) + break; + + // do we need to enlarge the buffer? + checkBuffer(); + + UChar cc = *src; + + bool wasSkipLF = state.skipLF(); + if (wasSkipLF) + state.setSkipLF(false); + + if (wasSkipLF && (cc == '\n')) + src.advance(); + else if (state.needsSpecialWriteHandling()) { + // it's important to keep needsSpecialWriteHandling with the flags this block tests + if (state.hasEntityState()) + state = parseEntity(src, dest, state, m_cBufferPos, false, state.hasTagState()); + else if (state.inPlainText()) + state = parseText(src, state); + else if (state.inAnySpecial()) + state = parseSpecial(src, state); + else if (state.inComment()) + state = parseComment(src, state); + else if (state.inDoctype()) + state = parseDoctype(src, state); + else if (state.inServer()) + state = parseServer(src, state); + else if (state.inProcessingInstruction()) + state = parseProcessingInstruction(src, state); + else if (state.hasTagState()) + state = parseTag(src, state); + else if (state.startTag()) { + state.setStartTag(false); + + switch(cc) { + case '/': + break; + case '!': { + // <!-- comment --> or <!DOCTYPE ...> + searchCount = 1; // Look for '<!--' sequence to start comment or '<!DOCTYPE' sequence to start doctype + m_doctypeSearchCount = 1; + break; + } + case '?': { + // xml processing instruction + state.setInProcessingInstruction(true); + tquote = NoQuote; + state = parseProcessingInstruction(src, state); + continue; + + break; + } + case '%': + if (!brokenServer) { + // <% server stuff, handle as comment %> + state.setInServer(true); + tquote = NoQuote; + state = parseServer(src, state); + continue; + } + // else fall through + default: { + if( ((cc >= 'a') && (cc <= 'z')) || ((cc >= 'A') && (cc <= 'Z'))) { + // Start of a Start-Tag + } else { + // Invalid tag + // Add as is + *dest = '<'; + dest++; + continue; + } + } + }; // end case + + processToken(); + + m_cBufferPos = 0; + state.setTagState(TagName); + state = parseTag(src, state); + } + } else if (cc == '&' && !src.escaped()) { + src.advancePastNonNewline(); + state = parseEntity(src, dest, state, m_cBufferPos, true, state.hasTagState()); + } else if (cc == '<' && !src.escaped()) { + tagStartLineno = m_lineNumber; + src.advancePastNonNewline(); + state.setStartTag(true); + state.setDiscardLF(false); + } else if (cc == '\n' || cc == '\r') { + if (state.discardLF()) + // Ignore this LF + state.setDiscardLF(false); // We have discarded 1 LF + else { + // Process this LF + *dest++ = '\n'; + if (cc == '\r' && !src.excludeLineNumbers()) + m_lineNumber++; + } + + /* Check for MS-DOS CRLF sequence */ + if (cc == '\r') + state.setSkipLF(true); + src.advance(m_lineNumber); + } else { + state.setDiscardLF(false); + *dest++ = cc; + src.advancePastNonNewline(); + } + } + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("Ending write at time %d\n", m_doc->elapsedTime()); +#endif + + inWrite = wasInWrite; + + m_state = state; + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); +#endif + + if (noMoreData && !inWrite && !state.loadingExtScript() && !m_executingScript && !m_timer.isActive()) { + end(); // this actually causes us to be deleted + return true; + } + return false; +} + +void HTMLTokenizer::stopParsing() +{ + Tokenizer::stopParsing(); + m_timer.stop(); + + // The part needs to know that the tokenizer has finished with its data, + // regardless of whether it happened naturally or due to manual intervention. + if (!m_fragment && m_doc->frame()) + m_doc->frame()->loader()->tokenizerProcessedData(); +} + +bool HTMLTokenizer::processingData() const +{ + return m_timer.isActive() || inWrite; +} + +void HTMLTokenizer::timerFired(Timer<HTMLTokenizer>*) +{ +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("Beginning timer write at time %d\n", m_doc->elapsedTime()); +#endif + +#ifdef ANDROID_MOBILE + if (m_doc->view() && m_doc->view()->layoutPending() && !m_doc->minimumLayoutDelay() && !m_doc->extraLayoutDelay()) { +#else + if (m_doc->view() && m_doc->view()->layoutPending() && !m_doc->minimumLayoutDelay()) { +#endif + // Restart the timer and let layout win. This is basically a way of ensuring that the layout + // timer has higher priority than our timer. + m_timer.startOneShot(0); + return; + } + + // Invoke write() as though more data came in. This might cause us to get deleted. + write(SegmentedString(), true); +} + +void HTMLTokenizer::end() +{ + ASSERT(!m_timer.isActive()); + m_timer.stop(); // Only helps if assertion above fires, but do it anyway. + + if (buffer) { + // parseTag is using the buffer for different matters + if (!m_state.hasTagState()) + processToken(); + + fastFree(scriptCode); + scriptCode = 0; + scriptCodeSize = scriptCodeMaxSize = scriptCodeResync = 0; + + fastFree(buffer); + buffer = 0; + } + + if (!inViewSourceMode()) + parser->finished(); + else + m_doc->finishedParsing(); +} + +void HTMLTokenizer::finish() +{ + // do this as long as we don't find matching comment ends + while ((m_state.inComment() || m_state.inServer()) && scriptCode && scriptCodeSize) { + // we've found an unmatched comment start + if (m_state.inComment()) + brokenComments = true; + else + brokenServer = true; + checkScriptBuffer(); + scriptCode[scriptCodeSize] = 0; + scriptCode[scriptCodeSize + 1] = 0; + int pos; + String food; + if (m_state.inScript() || m_state.inStyle() || m_state.inTextArea()) + food = String(scriptCode, scriptCodeSize); + else if (m_state.inServer()) { + food = "<"; + food.append(scriptCode, scriptCodeSize); + } else { + pos = find(scriptCode, scriptCodeSize, '>'); + food = String(scriptCode + pos + 1, scriptCodeSize - pos - 1); + } + fastFree(scriptCode); + scriptCode = 0; + scriptCodeSize = scriptCodeMaxSize = scriptCodeResync = 0; + m_state.setInComment(false); + m_state.setInServer(false); + if (!food.isEmpty()) + write(food, true); + } + // this indicates we will not receive any more data... but if we are waiting on + // an external script to load, we can't finish parsing until that is done + noMoreData = true; + if (!inWrite && !m_state.loadingExtScript() && !m_executingScript && !m_timer.isActive()) + end(); // this actually causes us to be deleted +} + +PassRefPtr<Node> HTMLTokenizer::processToken() +{ + ScriptController* jsProxy = (!m_fragment && m_doc->frame()) ? m_doc->frame()->script() : 0; + if (jsProxy && m_doc->frame()->script()->isEnabled()) + jsProxy->setEventHandlerLineno(tagStartLineno + 1); // Script line numbers are 1 based. + if (dest > buffer) { + currToken.text = StringImpl::createStrippingNullCharacters(buffer, dest - buffer); + if (currToken.tagName != commentAtom) + currToken.tagName = textAtom; + } else if (currToken.tagName == nullAtom) { + currToken.reset(); + if (jsProxy) + jsProxy->setEventHandlerLineno(m_lineNumber + 1); // Script line numbers are 1 based. + return 0; + } + + dest = buffer; + + RefPtr<Node> n; + + if (!m_parserStopped) { + if (NamedMappedAttrMap* map = currToken.attrs.get()) + map->shrinkToLength(); + if (inViewSourceMode()) + static_cast<HTMLViewSourceDocument*>(m_doc)->addViewSourceToken(&currToken); + else + // pass the token over to the parser, the parser DOES NOT delete the token + n = parser->parseToken(&currToken); + } + currToken.reset(); + if (jsProxy) + jsProxy->setEventHandlerLineno(0); + + return n.release(); +} + +void HTMLTokenizer::processDoctypeToken() +{ + if (inViewSourceMode()) + static_cast<HTMLViewSourceDocument*>(m_doc)->addViewSourceDoctypeToken(&m_doctypeToken); + else + parser->parseDoctypeToken(&m_doctypeToken); +} + +HTMLTokenizer::~HTMLTokenizer() +{ + ASSERT(!inWrite); + reset(); + delete parser; +} + + +void HTMLTokenizer::enlargeBuffer(int len) +{ + int newSize = max(size * 2, size + len); + int oldOffset = dest - buffer; + buffer = static_cast<UChar*>(fastRealloc(buffer, newSize * sizeof(UChar))); + dest = buffer + oldOffset; + size = newSize; +} + +void HTMLTokenizer::enlargeScriptBuffer(int len) +{ + int newSize = max(scriptCodeMaxSize * 2, scriptCodeMaxSize + len); + scriptCode = static_cast<UChar*>(fastRealloc(scriptCode, newSize * sizeof(UChar))); + scriptCodeMaxSize = newSize; +} + +void HTMLTokenizer::executeScriptsWaitingForStylesheets() +{ + ASSERT(m_doc->haveStylesheetsLoaded()); + + if (m_hasScriptsWaitingForStylesheets) + notifyFinished(0); +} + +void HTMLTokenizer::notifyFinished(CachedResource*) +{ +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("script loaded at %d\n", m_doc->elapsedTime()); +#endif + + ASSERT(!pendingScripts.isEmpty()); + + // Make external scripts wait for external stylesheets. + // FIXME: This needs to be done for inline scripts too. + m_hasScriptsWaitingForStylesheets = !m_doc->haveStylesheetsLoaded(); + if (m_hasScriptsWaitingForStylesheets) + return; + + bool finished = false; + while (!finished && pendingScripts.first()->isLoaded()) { + CachedScript *cs = pendingScripts.first().get(); + pendingScripts.removeFirst(); + ASSERT(cache()->disabled() || cs->accessCount() > 0); + + String scriptSource = cs->script(); + setSrc(SegmentedString()); + + // make sure we forget about the script before we execute the new one + // infinite recursion might happen otherwise + String cachedScriptUrl(cs->url()); + bool errorOccurred = cs->errorOccurred(); + cs->removeClient(this); + RefPtr<Node> n = scriptNode.release(); + +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("external script beginning execution at %d\n", m_doc->elapsedTime()); +#endif + + if (errorOccurred) + EventTargetNodeCast(n.get())->dispatchEventForType(eventNames().errorEvent, true, false); + else { + if (static_cast<HTMLScriptElement*>(n.get())->shouldExecuteAsJavaScript()) + m_state = scriptExecution(scriptSource, m_state, cachedScriptUrl); + EventTargetNodeCast(n.get())->dispatchEventForType(eventNames().loadEvent, false, false); + } + + // The state of pendingScripts.isEmpty() can change inside the scriptExecution() + // call above, so test afterwards. + finished = pendingScripts.isEmpty(); + if (finished) { + m_state.setLoadingExtScript(false); +#ifdef INSTRUMENT_LAYOUT_SCHEDULING + if (!m_doc->ownerElement()) + printf("external script finished execution at %d\n", m_doc->elapsedTime()); +#endif + } + + // 'm_requestingScript' is true when we are called synchronously from + // scriptHandler(). In that case scriptHandler() will take care + // of pendingSrc. + if (!m_requestingScript) { + SegmentedString rest = pendingSrc; + pendingSrc.clear(); + write(rest, false); + // we might be deleted at this point, do not access any members. + } + } +} + +bool HTMLTokenizer::isWaitingForScripts() const +{ + return m_state.loadingExtScript(); +} + +void HTMLTokenizer::setSrc(const SegmentedString &source) +{ + src = source; +} + +void parseHTMLDocumentFragment(const String& source, DocumentFragment* fragment) +{ + HTMLTokenizer tok(fragment); + tok.setForceSynchronous(true); + tok.write(source, true); + tok.finish(); + ASSERT(!tok.processingData()); // make sure we're done (see 3963151) +} + +UChar decodeNamedEntity(const char* name) +{ + const Entity* e = findEntity(name, strlen(name)); + return e ? e->code : 0; +} + +} diff --git a/WebCore/html/HTMLTokenizer.h b/WebCore/html/HTMLTokenizer.h new file mode 100644 index 0000000..0d175db --- /dev/null +++ b/WebCore/html/HTMLTokenizer.h @@ -0,0 +1,420 @@ +/* + Copyright (C) 1997 Martin Jones (mjones@kde.org) + (C) 1997 Torben Weis (weis@kde.org) + (C) 1998 Waldo Bastian (bastian@kde.org) + (C) 2001 Dirk Mueller (mueller@kde.org) + Copyright (C) 2003, 2004, 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. +*/ + +#ifndef HTMLTokenizer_h +#define HTMLTokenizer_h + +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include "NamedMappedAttrMap.h" +#include "SegmentedString.h" +#include "Timer.h" +#include "Tokenizer.h" +#include <wtf/Deque.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CachedScript; +class DocumentFragment; +class Document; +class HTMLDocument; +class HTMLViewSourceDocument; +class FrameView; +class HTMLParser; +class Node; +class PreloadScanner; + +/** + * @internal + * represents one HTML tag. Consists of a numerical id, and the list + * of attributes. Can also represent text. In this case the id = 0 and + * text contains the text. + */ +class Token { +public: + Token() : beginTag(true), flat(false), brokenXMLStyle(false), m_sourceInfo(0) { } + ~Token() { } + + void addAttribute(Document*, AtomicString& attrName, const AtomicString& v, bool viewSourceMode); + + bool isOpenTag(const QualifiedName& fullName) const { return beginTag && fullName.localName() == tagName; } + bool isCloseTag(const QualifiedName& fullName) const { return !beginTag && fullName.localName() == tagName; } + + void reset() + { + attrs = 0; + text = 0; + tagName = nullAtom; + beginTag = true; + flat = false; + brokenXMLStyle = false; + if (m_sourceInfo) + m_sourceInfo->clear(); + } + + void addViewSourceChar(UChar c) { if (!m_sourceInfo.get()) m_sourceInfo.set(new Vector<UChar>); m_sourceInfo->append(c); } + + RefPtr<NamedMappedAttrMap> attrs; + RefPtr<StringImpl> text; + AtomicString tagName; + bool beginTag; + bool flat; + bool brokenXMLStyle; + OwnPtr<Vector<UChar> > m_sourceInfo; +}; + +enum DoctypeState { + DoctypeBegin, + DoctypeBeforeName, + DoctypeName, + DoctypeAfterName, + DoctypeBeforePublicID, + DoctypePublicID, + DoctypeAfterPublicID, + DoctypeBeforeSystemID, + DoctypeSystemID, + DoctypeAfterSystemID, + DoctypeBogus +}; + +class DoctypeToken { +public: + DoctypeToken() {} + + void reset() + { + m_name.clear(); + m_publicID.clear(); + m_systemID.clear(); + m_state = DoctypeBegin; + m_source.clear(); + } + + DoctypeState state() { return m_state; } + void setState(DoctypeState s) { m_state = s; } + + Vector<UChar> m_name; + Vector<UChar> m_publicID; + Vector<UChar> m_systemID; + DoctypeState m_state; + + Vector<UChar> m_source; +}; + +//----------------------------------------------------------------------------- + +class HTMLTokenizer : public Tokenizer, public CachedResourceClient { +public: + HTMLTokenizer(HTMLDocument*, bool reportErrors); + HTMLTokenizer(HTMLViewSourceDocument*); + HTMLTokenizer(DocumentFragment*); + virtual ~HTMLTokenizer(); + + virtual bool write(const SegmentedString&, bool appendData); + virtual void finish(); + virtual void setForceSynchronous(bool force); + virtual bool isWaitingForScripts() const; + virtual void stopParsing(); + virtual bool processingData() const; + virtual int executingScript() const { return m_executingScript; } + + virtual int lineNumber() const { return m_lineNumber; } + virtual int columnNumber() const { return 1; } + + bool processingContentWrittenByScript() const { return src.excludeLineNumbers(); } + + virtual void executeScriptsWaitingForStylesheets(); + + virtual bool isHTMLTokenizer() const { return true; } + HTMLParser* htmlParser() const { return parser; } + +private: + class State; + + // Where we are in parsing a tag + void begin(); + void end(); + + void reset(); + + PassRefPtr<Node> processToken(); + void processDoctypeToken(); + + State processListing(SegmentedString, State); + State parseComment(SegmentedString&, State); + State parseDoctype(SegmentedString&, State); + State parseServer(SegmentedString&, State); + State parseText(SegmentedString&, State); + State parseSpecial(SegmentedString&, State); + State parseTag(SegmentedString&, State); + State parseEntity(SegmentedString&, UChar*& dest, State, unsigned& _cBufferPos, bool start, bool parsingTag); + State parseProcessingInstruction(SegmentedString&, State); + State scriptHandler(State); + State scriptExecution(const String& script, State, const String& scriptURL, int baseLine = 1); + void setSrc(const SegmentedString&); + + // check if we have enough space in the buffer. + // if not enlarge it + inline void checkBuffer(int len = 10) + { + if ((dest - buffer) > size - len) + enlargeBuffer(len); + } + + inline void checkScriptBuffer(int len = 10) + { + if (scriptCodeSize + len >= scriptCodeMaxSize) + enlargeScriptBuffer(len); + } + + void enlargeBuffer(int len); + void enlargeScriptBuffer(int len); + + bool continueProcessing(int& processedCount, double startTime, State&); + void timerFired(Timer<HTMLTokenizer>*); + void allDataProcessed(); + + // from CachedResourceClient + void notifyFinished(CachedResource *finishedObj); + + // Internal buffers + /////////////////// + UChar* buffer; + UChar* dest; + + Token currToken; + + // the size of buffer + int size; + + // Tokenizer flags + ////////////////// + // are we in quotes within a html tag + enum { NoQuote, SingleQuote, DoubleQuote } tquote; + + // Are we in a &... character entity description? + enum EntityState { + NoEntity = 0, + SearchEntity = 1, + NumericSearch = 2, + Hexadecimal = 3, + Decimal = 4, + EntityName = 5, + SearchSemicolon = 6 + }; + unsigned EntityUnicodeValue; + + enum TagState { + NoTag = 0, + TagName = 1, + SearchAttribute = 2, + AttributeName = 3, + SearchEqual = 4, + SearchValue = 5, + QuotedValue = 6, + Value = 7, + SearchEnd = 8 + }; + + class State { + public: + State() : m_bits(0) { } + + TagState tagState() const { return static_cast<TagState>(m_bits & TagMask); } + void setTagState(TagState t) { m_bits = (m_bits & ~TagMask) | t; } + EntityState entityState() const { return static_cast<EntityState>((m_bits & EntityMask) >> EntityShift); } + void setEntityState(EntityState e) { m_bits = (m_bits & ~EntityMask) | (e << EntityShift); } + + bool inScript() const { return testBit(InScript); } + void setInScript(bool v) { setBit(InScript, v); } + bool inStyle() const { return testBit(InStyle); } + void setInStyle(bool v) { setBit(InStyle, v); } + bool inXmp() const { return testBit(InXmp); } + void setInXmp(bool v) { setBit(InXmp, v); } + bool inTitle() const { return testBit(InTitle); } + void setInTitle(bool v) { setBit(InTitle, v); } + bool inIFrame() const { return testBit(InIFrame); } + void setInIFrame(bool v) { setBit(InIFrame, v); } + bool inPlainText() const { return testBit(InPlainText); } + void setInPlainText(bool v) { setBit(InPlainText, v); } + bool inProcessingInstruction() const { return testBit(InProcessingInstruction); } + void setInProcessingInstruction(bool v) { return setBit(InProcessingInstruction, v); } + bool inComment() const { return testBit(InComment); } + void setInComment(bool v) { setBit(InComment, v); } + bool inDoctype() const { return testBit(InDoctype); } + void setInDoctype(bool v) { setBit(InDoctype, v); } + bool inTextArea() const { return testBit(InTextArea); } + void setInTextArea(bool v) { setBit(InTextArea, v); } + bool escaped() const { return testBit(Escaped); } + void setEscaped(bool v) { setBit(Escaped, v); } + bool inServer() const { return testBit(InServer); } + void setInServer(bool v) { setBit(InServer, v); } + bool skipLF() const { return testBit(SkipLF); } + void setSkipLF(bool v) { setBit(SkipLF, v); } + bool startTag() const { return testBit(StartTag); } + void setStartTag(bool v) { setBit(StartTag, v); } + bool discardLF() const { return testBit(DiscardLF); } + void setDiscardLF(bool v) { setBit(DiscardLF, v); } + bool allowYield() const { return testBit(AllowYield); } + void setAllowYield(bool v) { setBit(AllowYield, v); } + bool loadingExtScript() const { return testBit(LoadingExtScript); } + void setLoadingExtScript(bool v) { setBit(LoadingExtScript, v); } + bool forceSynchronous() const { return testBit(ForceSynchronous); } + void setForceSynchronous(bool v) { setBit(ForceSynchronous, v); } + + bool inAnySpecial() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle | InIFrame); } + bool hasTagState() const { return m_bits & TagMask; } + bool hasEntityState() const { return m_bits & EntityMask; } + + bool needsSpecialWriteHandling() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle | InIFrame | TagMask | EntityMask | InPlainText | InComment | InDoctype | InServer | InProcessingInstruction | StartTag); } + + private: + static const int EntityShift = 4; + enum StateBits { + TagMask = (1 << 4) - 1, + EntityMask = (1 << 7) - (1 << 4), + InScript = 1 << 7, + InStyle = 1 << 8, + // Bit 9 unused + InXmp = 1 << 10, + InTitle = 1 << 11, + InPlainText = 1 << 12, + InProcessingInstruction = 1 << 13, + InComment = 1 << 14, + InTextArea = 1 << 15, + Escaped = 1 << 16, + InServer = 1 << 17, + SkipLF = 1 << 18, + StartTag = 1 << 19, + DiscardLF = 1 << 20, // FIXME: should clarify difference between skip and discard + AllowYield = 1 << 21, + LoadingExtScript = 1 << 22, + ForceSynchronous = 1 << 23, + InIFrame = 1 << 24, + InDoctype = 1 << 25 + }; + + void setBit(StateBits bit, bool value) + { + if (value) + m_bits |= bit; + else + m_bits &= ~bit; + } + bool testBit(StateBits bit) const { return m_bits & bit; } + + unsigned m_bits; + }; + + State m_state; + + DoctypeToken m_doctypeToken; + int m_doctypeSearchCount; + int m_doctypeSecondarySearchCount; + + bool brokenServer; + + // Name of an attribute that we just scanned. + AtomicString attrName; + + // Used to store the code of a scripting sequence + UChar* scriptCode; + // Size of the script sequenze stored in @ref #scriptCode + int scriptCodeSize; + // Maximal size that can be stored in @ref #scriptCode + int scriptCodeMaxSize; + // resync point of script code size + int scriptCodeResync; + + // Stores characters if we are scanning for a string like "</script>" + UChar searchBuffer[10]; + + // Counts where we are in the string we are scanning for + int searchCount; + // the stopper string + const char* searchStopper; + // the stopper len + int searchStopperLen; + + // if no more data is coming, just parse what we have (including ext scripts that + // may be still downloading) and finish + bool noMoreData; + // URL to get source code of script from + String scriptSrc; + String scriptSrcCharset; + // the HTML code we will parse after the external script we are waiting for has loaded + SegmentedString pendingSrc; + + // the HTML code we will parse after this particular script has + // loaded, but before all pending HTML + SegmentedString *currentPrependingSrc; + + // true if we are executing a script while parsing a document. This causes the parsing of + // the output of the script to be postponed until after the script has finished executing + int m_executingScript; + Deque<CachedResourceHandle<CachedScript> > pendingScripts; + RefPtr<Node> scriptNode; + + bool m_requestingScript; + bool m_hasScriptsWaitingForStylesheets; + + // if we found one broken comment, there are most likely others as well + // store a flag to get rid of the O(n^2) behaviour in such a case. + bool brokenComments; + // current line number + int m_lineNumber; + // line number at which the current <script> started + int scriptStartLineno; + int tagStartLineno; + + double m_tokenizerTimeDelay; + int m_tokenizerChunkSize; + + // The timer for continued processing. + Timer<HTMLTokenizer> m_timer; + +// This buffer can hold arbitrarily long user-defined attribute names, such as in EMBED tags. +// So any fixed number might be too small, but rather than rewriting all usage of this buffer +// we'll just make it large enough to handle all imaginable cases. +#define CBUFLEN 1024 + UChar cBuffer[CBUFLEN + 2]; + unsigned int m_cBufferPos; + + SegmentedString src; + Document* m_doc; + HTMLParser* parser; + bool inWrite; + bool m_fragment; + + OwnPtr<PreloadScanner> m_preloadScanner; +}; + +void parseHTMLDocumentFragment(const String&, DocumentFragment*); + +UChar decodeNamedEntity(const char*); + +} // namespace WebCore + +#endif // HTMLTokenizer_h diff --git a/WebCore/html/HTMLUListElement.cpp b/WebCore/html/HTMLUListElement.cpp new file mode 100644 index 0000000..4557294 --- /dev/null +++ b/WebCore/html/HTMLUListElement.cpp @@ -0,0 +1,76 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ +#include "config.h" +#include "HTMLUListElement.h" + +#include "CSSPropertyNames.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLUListElement::HTMLUListElement(Document* doc) + : HTMLElement(HTMLNames::ulTag, doc) +{ +} + +bool HTMLUListElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const +{ + if (attrName == typeAttr) { + result = eUnorderedList; + return false; + } + + return HTMLElement::mapToEntry(attrName, result); +} + +void HTMLUListElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == typeAttr) + addCSSProperty(attr, CSSPropertyListStyleType, attr->value()); + else + HTMLElement::parseMappedAttribute(attr); +} + +bool HTMLUListElement::compact() const +{ + return !getAttribute(compactAttr).isNull(); +} + +void HTMLUListElement::setCompact(bool b) +{ + setAttribute(compactAttr, b ? "" : 0); +} + +String HTMLUListElement::type() const +{ + return getAttribute(typeAttr); +} + +void HTMLUListElement::setType(const String &value) +{ + setAttribute(typeAttr, value); +} + +} diff --git a/WebCore/html/HTMLUListElement.h b/WebCore/html/HTMLUListElement.h new file mode 100644 index 0000000..0136dd0 --- /dev/null +++ b/WebCore/html/HTMLUListElement.h @@ -0,0 +1,51 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@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. + * + */ + +#ifndef HTMLUListElement_h +#define HTMLUListElement_h + +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLUListElement : public HTMLElement +{ +public: + HTMLUListElement(Document*); + + virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } + virtual int tagPriority() const { return 5; } + + virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const; + virtual void parseMappedAttribute(MappedAttribute*); + + bool compact() const; + void setCompact(bool); + + String type() const; + void setType(const String&); +}; + +} //namespace + +#endif diff --git a/WebCore/html/HTMLUListElement.idl b/WebCore/html/HTMLUListElement.idl new file mode 100644 index 0000000..c49b058 --- /dev/null +++ b/WebCore/html/HTMLUListElement.idl @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor, + InterfaceUUID=6877dee4-be67-4fb0-af8c-5023b108a1b0, + ImplementationUUID=23e9c21a-618e-42ac-a053-df85918118df + ] HTMLUListElement : HTMLElement { + attribute boolean compact; + attribute [ConvertNullToNullString] DOMString type; + }; + +} diff --git a/WebCore/html/HTMLVideoElement.cpp b/WebCore/html/HTMLVideoElement.cpp new file mode 100644 index 0000000..2fb4a19 --- /dev/null +++ b/WebCore/html/HTMLVideoElement.cpp @@ -0,0 +1,174 @@ +/* + * 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" + +#if ENABLE(VIDEO) +#include "HTMLVideoElement.h" + +#include "CSSHelper.h" +#include "CSSPropertyNames.h" +#include "Document.h" +#include "HTMLImageLoader.h" +#include "HTMLNames.h" +#include "RenderImage.h" +#include "RenderVideo.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLVideoElement::HTMLVideoElement(Document* doc) + : HTMLMediaElement(HTMLNames::videoTag, doc) + , m_shouldShowPosterImage(false) +{ +} + +bool HTMLVideoElement::rendererIsNeeded(RenderStyle* style) +{ + return HTMLElement::rendererIsNeeded(style); +} + +RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + if (m_shouldShowPosterImage) + return new (arena) RenderImage(this); + return new (arena) RenderVideo(this); +} + +void HTMLVideoElement::attach() +{ + HTMLMediaElement::attach(); + + if (m_shouldShowPosterImage) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + if (renderer() && renderer()->isImage()) { + RenderImage* imageRenderer = static_cast<RenderImage*>(renderer()); + imageRenderer->setCachedImage(m_imageLoader->image()); + } + } + +} + +void HTMLVideoElement::detach() +{ + HTMLMediaElement::detach(); + + if (!m_shouldShowPosterImage) + if (m_imageLoader) + m_imageLoader.clear(); +} + +void HTMLVideoElement::parseMappedAttribute(MappedAttribute* attr) +{ + const QualifiedName& attrName = attr->name(); + + if (attrName == posterAttr) { + updatePosterImage(); + if (m_shouldShowPosterImage) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + } + } else if (attrName == widthAttr) + addCSSLength(attr, CSSPropertyWidth, attr->value()); + else if (attrName == heightAttr) + addCSSLength(attr, CSSPropertyHeight, attr->value()); + else + HTMLMediaElement::parseMappedAttribute(attr); +} + +unsigned HTMLVideoElement::videoWidth() const +{ + if (!m_player) + return 0; + return m_player->naturalSize().width(); +} + +unsigned HTMLVideoElement::videoHeight() const +{ + if (!m_player) + return 0; + return m_player->naturalSize().height(); +} + +unsigned HTMLVideoElement::width() const +{ + bool ok; + unsigned w = getAttribute(widthAttr).string().toUInt(&ok); + return ok ? w : 0; +} + +void HTMLVideoElement::setWidth(unsigned value) +{ + setAttribute(widthAttr, String::number(value)); +} + +unsigned HTMLVideoElement::height() const +{ + bool ok; + unsigned h = getAttribute(heightAttr).string().toUInt(&ok); + return ok ? h : 0; +} + +void HTMLVideoElement::setHeight(unsigned value) +{ + setAttribute(heightAttr, String::number(value)); +} + +KURL HTMLVideoElement::poster() const +{ + return document()->completeURL(getAttribute(posterAttr)); +} + +void HTMLVideoElement::setPoster(const String& value) +{ + setAttribute(posterAttr, value); +} + +bool HTMLVideoElement::isURLAttribute(Attribute* attr) const +{ + return attr->name() == posterAttr; +} + +const QualifiedName& HTMLVideoElement::imageSourceAttributeName() const +{ + return posterAttr; +} + +void HTMLVideoElement::updatePosterImage() +{ + bool oldShouldShowPosterImage = m_shouldShowPosterImage; + m_shouldShowPosterImage = !poster().isEmpty() && m_networkState < LOADED_FIRST_FRAME; + if (attached() && oldShouldShowPosterImage != m_shouldShowPosterImage) { + detach(); + attach(); + } +} + +} +#endif diff --git a/WebCore/html/HTMLVideoElement.h b/WebCore/html/HTMLVideoElement.h new file mode 100644 index 0000000..e424e3d --- /dev/null +++ b/WebCore/html/HTMLVideoElement.h @@ -0,0 +1,74 @@ +/* + * 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 HTMLVideoElement_h +#define HTMLVideoElement_h + +#if ENABLE(VIDEO) + +#include "HTMLMediaElement.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class HTMLImageLoader; + +class HTMLVideoElement : public HTMLMediaElement +{ +public: + HTMLVideoElement(Document*); + + virtual int tagPriority() const { return 5; } + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void attach(); + virtual void detach(); + virtual void parseMappedAttribute(MappedAttribute* attr); + virtual bool isVideo() const { return true; } + virtual bool isURLAttribute(Attribute*) const; + virtual const QualifiedName& imageSourceAttributeName() const; + + unsigned width() const; + void setWidth(unsigned); + unsigned height() const; + void setHeight(unsigned); + + unsigned videoWidth() const; + unsigned videoHeight() const; + + KURL poster() const; + void setPoster(const String&); + + void updatePosterImage(); + +private: + OwnPtr<HTMLImageLoader> m_imageLoader; + bool m_shouldShowPosterImage; +}; + +} //namespace + +#endif +#endif diff --git a/WebCore/html/HTMLVideoElement.idl b/WebCore/html/HTMLVideoElement.idl new file mode 100644 index 0000000..c78594f --- /dev/null +++ b/WebCore/html/HTMLVideoElement.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 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 html { + interface [GenerateConstructor, Conditional=VIDEO] HTMLVideoElement : HTMLMediaElement { + attribute unsigned long width; + attribute unsigned long height; + readonly attribute unsigned long videoWidth; + readonly attribute unsigned long videoHeight; + attribute [ConvertNullToNullString] DOMString poster; + }; +} diff --git a/WebCore/html/HTMLViewSourceDocument.cpp b/WebCore/html/HTMLViewSourceDocument.cpp new file mode 100644 index 0000000..7b141d1 --- /dev/null +++ b/WebCore/html/HTMLViewSourceDocument.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2006, 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, + * 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 "HTMLViewSourceDocument.h" + +#include "DOMImplementation.h" +#include "HTMLTokenizer.h" +#include "HTMLHtmlElement.h" +#include "HTMLAnchorElement.h" +#include "HTMLBodyElement.h" +#include "HTMLDivElement.h" +#include "HTMLTableElement.h" +#include "HTMLTableCellElement.h" +#include "HTMLTableRowElement.h" +#include "HTMLTableSectionElement.h" +#include "Text.h" +#include "TextDocument.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const String& mimeType) + : HTMLDocument(frame) + , m_type(mimeType) + , m_current(0) + , m_tbody(0) + , m_td(0) +{ +} + +Tokenizer* HTMLViewSourceDocument::createTokenizer() +{ + if (implementation()->isTextMIMEType(m_type)) + return createTextTokenizer(this); + return new HTMLTokenizer(this); +} + +void HTMLViewSourceDocument::createContainingTable() +{ + RefPtr<Element> html = new HTMLHtmlElement(this); + addChild(html); + html->attach(); + RefPtr<Element> body = new HTMLBodyElement(this); + html->addChild(body); + body->attach(); + + // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole + // document. + RefPtr<Element> div = new HTMLDivElement(this); + RefPtr<NamedMappedAttrMap> attrs = NamedMappedAttrMap::create(); + attrs->insertAttribute(MappedAttribute::create(classAttr, "webkit-line-gutter-backdrop"), true); + div->setAttributeMap(attrs.release()); + body->addChild(div); + div->attach(); + + RefPtr<Element> table = new HTMLTableElement(this); + body->addChild(table); + table->attach(); + m_tbody = new HTMLTableSectionElement(tbodyTag, this); + table->addChild(m_tbody); + m_tbody->attach(); + m_current = m_tbody; +} + +void HTMLViewSourceDocument::addViewSourceText(const String& text) +{ + if (!m_current) + createContainingTable(); + addText(text, ""); +} + +void HTMLViewSourceDocument::addViewSourceToken(Token* token) +{ + if (!m_current) + createContainingTable(); + + if (token->tagName == textAtom) + addText(token->text.get(), ""); + else if (token->tagName == commentAtom) { + if (token->beginTag) { + m_current = addSpanWithClassName("webkit-html-comment"); + addText(String("<!--") + token->text.get() + "-->", "webkit-html-comment"); + } + } else { + // Handle the tag. + String classNameStr = "webkit-html-tag"; + m_current = addSpanWithClassName(classNameStr); + + String text = "<"; + if (!token->beginTag) + text += "/"; + text += token->tagName; + Vector<UChar>* guide = token->m_sourceInfo.get(); + if (!guide || !guide->size()) + text += ">"; + + addText(text, classNameStr); + + // Walk our guide string that tells us where attribute names/values should go. + if (guide && guide->size()) { + unsigned size = guide->size(); + unsigned begin = 0; + unsigned currAttr = 0; + RefPtr<Attribute> attr = 0; + for (unsigned i = 0; i < size; i++) { + if (guide->at(i) == 'a' || guide->at(i) == 'x' || guide->at(i) == 'v') { + // Add in the string. + addText(String(static_cast<UChar*>(guide->data()) + begin, i - begin), classNameStr); + + begin = i + 1; + + if (guide->at(i) == 'a') { + if (token->attrs && currAttr < token->attrs->length()) + attr = token->attrs->attributeItem(currAttr++); + else + attr = 0; + } + if (attr) { + if (guide->at(i) == 'a') { + String name = attr->name().toString(); + + m_current = addSpanWithClassName("webkit-html-attribute-name"); + addText(name, "webkit-html-attribute-name"); + if (m_current != m_tbody) + m_current = static_cast<Element*>(m_current->parent()); + } else { + const String& value = attr->value().string(); + // FIXME: XML could use namespace prefixes and confuse us. + if (equalIgnoringCase(attr->name().localName(), "src") || equalIgnoringCase(attr->name().localName(), "href")) + m_current = addLink(value, equalIgnoringCase(token->tagName, "a")); + else + m_current = addSpanWithClassName("webkit-html-attribute-value"); + addText(value, "webkit-html-attribute-value"); + if (m_current != m_tbody) + m_current = static_cast<Element*>(m_current->parent()); + } + } + } + } + + // Add in any string that might be left. + if (begin < size) + addText(String(static_cast<UChar*>(guide->data()) + begin, size - begin), classNameStr); + + // Add in the end tag. + addText(">", classNameStr); + } + + m_current = m_td; + } +} + +void HTMLViewSourceDocument::addViewSourceDoctypeToken(DoctypeToken* doctypeToken) +{ + if (!m_current) + createContainingTable(); + m_current = addSpanWithClassName("webkit-html-doctype"); + String text = "<"; + text += String::adopt(doctypeToken->m_source); + text += ">"; + addText(text, "webkit-html-doctype"); +} + +Element* HTMLViewSourceDocument::addSpanWithClassName(const String& className) +{ + if (m_current == m_tbody) { + addLine(className); + return m_current; + } + + Element* span = new HTMLElement(spanTag, this); + RefPtr<NamedMappedAttrMap> attrs = NamedMappedAttrMap::create(); + attrs->insertAttribute(MappedAttribute::create(classAttr, className), true); + span->setAttributeMap(attrs.release()); + m_current->addChild(span); + span->attach(); + return span; +} + +void HTMLViewSourceDocument::addLine(const String& className) +{ + // Create a table row. + RefPtr<Element> trow = new HTMLTableRowElement(this); + m_tbody->addChild(trow); + trow->attach(); + + // Create a cell that will hold the line number (it is generated in the stylesheet using counters). + Element* td = new HTMLTableCellElement(tdTag, this); + RefPtr<NamedMappedAttrMap> attrs = NamedMappedAttrMap::create(); + attrs->insertAttribute(MappedAttribute::create(classAttr, "webkit-line-number"), true); + td->setAttributeMap(attrs.release()); + trow->addChild(td); + td->attach(); + + // Create a second cell for the line contents + td = new HTMLTableCellElement(tdTag, this); + attrs = NamedMappedAttrMap::create(); + attrs->insertAttribute(MappedAttribute::create(classAttr, "webkit-line-content"), true); + td->setAttributeMap(attrs.release()); + trow->addChild(td); + td->attach(); + m_current = m_td = td; + +#ifdef DEBUG_LINE_NUMBERS + RefPtr<Text> lineNumberText = new Text(this, String::number(tokenizer()->lineNumber() + 1) + " "); + td->addChild(lineNumberText); + lineNumberText->attach(); +#endif + + // Open up the needed spans. + if (!className.isEmpty()) { + if (className == "webkit-html-attribute-name" || className == "webkit-html-attribute-value") + m_current = addSpanWithClassName("webkit-html-tag"); + m_current = addSpanWithClassName(className); + } +} + +void HTMLViewSourceDocument::addText(const String& text, const String& className) +{ + if (text.isEmpty()) + return; + + // Add in the content, splitting on newlines. + Vector<String> lines; + text.split('\n', true, lines); + unsigned size = lines.size(); + for (unsigned i = 0; i < size; i++) { + String substring = lines[i]; + if (substring.isEmpty()) { + if (i == size - 1) + break; + substring = " "; + } + if (m_current == m_tbody) + addLine(className); + RefPtr<Text> t = new Text(this, substring); + m_current->addChild(t); + t->attach(); + if (i < size - 1) + m_current = m_tbody; + } + + // Set current to m_tbody if the last character was a newline. + if (text[text.length() - 1] == '\n') + m_current = m_tbody; +} + +Element* HTMLViewSourceDocument::addLink(const String& url, bool isAnchor) +{ + if (m_current == m_tbody) + addLine("webkit-html-tag"); + + // Now create a link for the attribute value instead of a span. + Element* anchor = new HTMLAnchorElement(aTag, this); + RefPtr<NamedMappedAttrMap> attrs = NamedMappedAttrMap::create(); + const char* classValue; + if (isAnchor) + classValue = "webkit-html-attribute-value webkit-html-external-link"; + else + classValue = "webkit-html-attribute-value webkit-html-resource-link"; + attrs->insertAttribute(MappedAttribute::create(classAttr, classValue), true); + attrs->insertAttribute(MappedAttribute::create(targetAttr, "_blank"), true); + attrs->insertAttribute(MappedAttribute::create(hrefAttr, url), true); + anchor->setAttributeMap(attrs.release()); + m_current->addChild(anchor); + anchor->attach(); + return anchor; +} + +} diff --git a/WebCore/html/HTMLViewSourceDocument.h b/WebCore/html/HTMLViewSourceDocument.h new file mode 100644 index 0000000..99c1ee4 --- /dev/null +++ b/WebCore/html/HTMLViewSourceDocument.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006, 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, + * 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 HTMLViewSourceDocument_h +#define HTMLViewSourceDocument_h + +#include "HTMLDocument.h" + +namespace WebCore { + +class DoctypeToken; +class Token; + +class HTMLViewSourceDocument : public HTMLDocument { +public: + static PassRefPtr<HTMLViewSourceDocument> create(Frame* frame, const String& mimeType) + { + return new HTMLViewSourceDocument(frame, mimeType); + } + + virtual Tokenizer* createTokenizer(); + + void addViewSourceToken(Token*); // Used by the HTML tokenizer. + void addViewSourceText(const String&); // Used by the plaintext tokenizer. + void addViewSourceDoctypeToken(DoctypeToken*); + +private: + HTMLViewSourceDocument(Frame*, const String& mimeType); + + void createContainingTable(); + Element* addSpanWithClassName(const String&); + void addLine(const String& className); + void addText(const String& text, const String& className); + Element* addLink(const String& url, bool isAnchor); + + String m_type; + Element* m_current; + Element* m_tbody; + Element* m_td; +}; + +} + +#endif // HTMLViewSourceDocument_h diff --git a/WebCore/html/ImageData.cpp b/WebCore/html/ImageData.cpp new file mode 100644 index 0000000..3653031 --- /dev/null +++ b/WebCore/html/ImageData.cpp @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#include "config.h" +#include "ImageData.h" + +#include "CanvasPixelArray.h" + +namespace WebCore { + +PassRefPtr<ImageData> ImageData::create(unsigned width, unsigned height) +{ + return adoptRef(new ImageData(width, height)); +} + +ImageData::ImageData(unsigned width, unsigned height) + : m_width(width) + , m_height(height) + , m_data(CanvasPixelArray::create(width * height * 4)) +{ +} + +} + diff --git a/WebCore/html/ImageData.h b/WebCore/html/ImageData.h new file mode 100644 index 0000000..21af1f9 --- /dev/null +++ b/WebCore/html/ImageData.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. + * 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 ImageData_h +#define ImageData_h + +#include "CanvasPixelArray.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + + class ImageData : public RefCounted<ImageData> { + public: + static PassRefPtr<ImageData> create(unsigned width, unsigned height); + + unsigned width() const { return m_width; } + unsigned height() const { return m_height; } + CanvasPixelArray* data() const { return m_data.get(); } + + private: + ImageData(unsigned width, unsigned height); + unsigned m_width; + unsigned m_height; + RefPtr<CanvasPixelArray> m_data; + }; + +} // namespace WebCore + +#endif // ImageData_h diff --git a/WebCore/html/ImageData.idl b/WebCore/html/ImageData.idl new file mode 100644 index 0000000..246632f --- /dev/null +++ b/WebCore/html/ImageData.idl @@ -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. + * 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 html { + + interface [ + GenerateConstructor, + GenerateToJS + ] ImageData { + readonly attribute long width; + readonly attribute long height; + readonly attribute CanvasPixelArray data; + }; + +} diff --git a/WebCore/html/MediaError.h b/WebCore/html/MediaError.h new file mode 100644 index 0000000..fbf375f --- /dev/null +++ b/WebCore/html/MediaError.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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. + */ + +#ifndef MediaError_h +#define MediaError_h + +#if ENABLE(VIDEO) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class MediaError : public RefCounted<MediaError> { +public: + enum Code { MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE }; + + static PassRefPtr<MediaError> create(Code code) { return adoptRef(new MediaError(code)); } + + Code code() const { return m_code; } + +private: + MediaError(Code code) : m_code(code) { } + + Code m_code; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/WebCore/html/MediaError.idl b/WebCore/html/MediaError.idl new file mode 100644 index 0000000..5b4f0a2 --- /dev/null +++ b/WebCore/html/MediaError.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 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 html { + interface [GenerateConstructor, Conditional=VIDEO] MediaError { + const unsigned short MEDIA_ERR_ABORTED = 1; + const unsigned short MEDIA_ERR_NETWORK = 2; + const unsigned short MEDIA_ERR_DECODE = 3; + readonly attribute unsigned short code; + }; +} diff --git a/WebCore/html/PreloadScanner.cpp b/WebCore/html/PreloadScanner.cpp new file mode 100644 index 0000000..1580230 --- /dev/null +++ b/WebCore/html/PreloadScanner.cpp @@ -0,0 +1,853 @@ +/* + * 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 "PreloadScanner.h" + +#include "AtomicString.h" +#include "CachedCSSStyleSheet.h" +#include "CachedImage.h" +#include "CachedResource.h" +#include "CachedResourceClient.h" +#include "CachedScript.h" +#include "CSSHelper.h" +#include "CString.h" +#include "DocLoader.h" +#include "Document.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLLinkElement.h" +#include "HTMLNames.h" +#include "SystemTime.h" +#include <wtf/unicode/Unicode.h> + +#ifdef __GNUC__ +// The main tokenizer includes this too so we are getting two copies of the data. However, this way the code gets inlined. +#include "HTMLEntityNames.c" +#else +// Not inlined for non-GCC compilers +struct Entity { + const char* name; + int code; +}; +const struct Entity* findEntity(register const char* str, register unsigned int len); +#endif + +#define PRELOAD_DEBUG 0 + +using namespace WTF; + +namespace WebCore { + +using namespace HTMLNames; + +PreloadScanner::PreloadScanner(Document* doc) + : m_inProgress(false) + , m_timeUsed(0) + , m_bodySeen(false) + , m_document(doc) +{ +#if PRELOAD_DEBUG + printf("CREATING PRELOAD SCANNER FOR %s\n", m_document->url().string().latin1().data()); +#endif +} + +PreloadScanner::~PreloadScanner() +{ +#if PRELOAD_DEBUG + printf("DELETING PRELOAD SCANNER FOR %s\n", m_document->url().string().latin1().data()); + printf("TOTAL TIME USED %.4fs\n", m_timeUsed); +#endif +} + +void PreloadScanner::begin() +{ + ASSERT(!m_inProgress); + reset(); + m_inProgress = true; +} + +void PreloadScanner::end() +{ + ASSERT(m_inProgress); + m_inProgress = false; +} + +void PreloadScanner::reset() +{ + m_source.clear(); + + m_state = Data; + m_escape = false; + m_contentModel = PCDATA; + m_commentPos = 0; + + m_closeTag = false; + m_tagName.clear(); + m_attributeName.clear(); + m_attributeValue.clear(); + m_lastStartTag = AtomicString(); + + m_urlToLoad = String(); + m_charset = String(); + m_linkIsStyleSheet = false; + m_lastCharacterIndex = 0; + clearLastCharacters(); + + m_cssState = CSSInitial; + m_cssRule.clear(); + m_cssRuleValue.clear(); +} + +bool PreloadScanner::scanningBody() const +{ + return m_document->body() || m_bodySeen; +} + +void PreloadScanner::write(const SegmentedString& source) +{ + double startTime = currentTime(); + tokenize(source); + m_timeUsed += currentTime() - startTime; +} + +static inline bool isWhitespace(UChar c) +{ + return c == ' ' || c == '\n' || c == '\r' || c == '\t'; +} + +inline void PreloadScanner::clearLastCharacters() +{ + memset(m_lastCharacters, 0, lastCharactersBufferSize * sizeof(UChar)); +} + +inline void PreloadScanner::rememberCharacter(UChar c) +{ + m_lastCharacterIndex = (m_lastCharacterIndex + 1) % lastCharactersBufferSize; + m_lastCharacters[m_lastCharacterIndex] = c; +} + +inline bool PreloadScanner::lastCharactersMatch(const char* chars, unsigned count) const +{ + unsigned pos = m_lastCharacterIndex; + while (count) { + if (chars[count - 1] != m_lastCharacters[pos]) + return false; + --count; + if (!pos) + pos = lastCharactersBufferSize; + --pos; + } + return true; +} + +static inline unsigned legalEntityFor(unsigned value) +{ + // FIXME There is a table for more exceptions in the HTML5 specification. + if (value == 0 || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF)) + return 0xFFFD; + return value; +} + +unsigned PreloadScanner::consumeEntity(SegmentedString& source, bool& notEnoughCharacters) +{ + enum EntityState { + Initial, + NumberType, + MaybeHex, + Hex, + Decimal, + Named + }; + EntityState entityState = Initial; + unsigned result = 0; + Vector<UChar, 10> seenChars; + Vector<char, 10> entityName; + + while (!source.isEmpty()) { + UChar cc = *source; + seenChars.append(cc); + switch (entityState) { + case Initial: + if (isWhitespace(cc) || cc == '<' || cc == '&') + return 0; + else if (cc == '#') + entityState = NumberType; + else if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) { + entityName.append(cc); + entityState = Named; + } else + return 0; + break; + case NumberType: + if (cc == 'x' || cc == 'X') + entityState = MaybeHex; + else if (cc >= '0' && cc <= '9') { + entityState = Decimal; + result = cc - '0'; + } else { + source.push('#'); + return 0; + } + break; + case MaybeHex: + if (cc >= '0' && cc <= '9') + result = cc - '0'; + else if (cc >= 'a' && cc <= 'f') + result = 10 + cc - 'a'; + else if (cc >= 'A' && cc <= 'F') + result = 10 + cc - 'A'; + else { + source.push(seenChars[1]); + source.push('#'); + return 0; + } + entityState = Hex; + break; + case Hex: + if (cc >= '0' && cc <= '9') + result = result * 16 + cc - '0'; + else if (cc >= 'a' && cc <= 'f') + result = result * 16 + 10 + cc - 'a'; + else if (cc >= 'A' && cc <= 'F') + result = result * 16 + 10 + cc - 'A'; + else if (cc == ';') { + source.advance(); + return legalEntityFor(result); + } else + return legalEntityFor(result); + break; + case Decimal: + if (cc >= '0' && cc <= '9') + result = result * 10 + cc - '0'; + else if (cc == ';') { + source.advance(); + return legalEntityFor(result); + } else + return legalEntityFor(result); + break; + case Named: + // This is the attribute only version, generic version matches somewhat differently + while (entityName.size() <= 8) { + if (cc == ';') { + const Entity* entity = findEntity(entityName.data(), entityName.size()); + if (entity) { + source.advance(); + return entity->code; + } + break; + } + if (!(cc >= 'a' && cc <= 'z') && !(cc >= 'A' && cc <= 'Z') && !(cc >= '0' && cc <= '9')) { + const Entity* entity = findEntity(entityName.data(), entityName.size()); + if (entity) + return entity->code; + break; + } + entityName.append(cc); + source.advance(); + if (source.isEmpty()) + goto outOfCharacters; + cc = *source; + seenChars.append(cc); + } + if (seenChars.size() == 2) + source.push(seenChars[0]); + else if (seenChars.size() == 3) { + source.push(seenChars[1]); + source.push(seenChars[0]); + } else + source.prepend(SegmentedString(String(seenChars.data(), seenChars.size() - 1))); + return 0; + } + source.advance(); + } +outOfCharacters: + notEnoughCharacters = true; + source.prepend(SegmentedString(String(seenChars.data(), seenChars.size()))); + return 0; +} + +void PreloadScanner::tokenize(const SegmentedString& source) +{ + ASSERT(m_inProgress); + + m_source.append(source); + + // This is a simplified HTML5 Tokenizer + // http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0 + while (!m_source.isEmpty()) { + UChar cc = *m_source; + switch (m_state) { + case Data: + while (1) { + rememberCharacter(cc); + if (cc == '&') { + if (m_contentModel == PCDATA || m_contentModel == RCDATA) { + m_state = EntityData; + break; + } + } else if (cc == '-') { + if ((m_contentModel == RCDATA || m_contentModel == CDATA) && !m_escape) { + if (lastCharactersMatch("<!--", 4)) + m_escape = true; + } + } else if (cc == '<') { + if (m_contentModel == PCDATA || ((m_contentModel == RCDATA || m_contentModel == CDATA) && !m_escape)) { + m_state = TagOpen; + break; + } + } else if (cc == '>') { + if ((m_contentModel == RCDATA || m_contentModel == CDATA) && m_escape) { + if (lastCharactersMatch("-->", 3)) + m_escape = false; + } + } + emitCharacter(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case EntityData: + // should try to consume the entity but we only care about entities in attributes + m_state = Data; + break; + case TagOpen: + if (m_contentModel == RCDATA || m_contentModel == CDATA) { + if (cc == '/') + m_state = CloseTagOpen; + else { + m_state = Data; + continue; + } + } else if (m_contentModel == PCDATA) { + if (cc == '!') + m_state = MarkupDeclarationOpen; + else if (cc == '/') + m_state = CloseTagOpen; + else if (cc >= 'A' && cc <= 'Z') { + m_tagName.clear(); + m_charset = String(); + m_tagName.append(cc + 0x20); + m_closeTag = false; + m_state = TagName; + } else if (cc >= 'a' && cc <= 'z') { + m_tagName.clear(); + m_charset = String(); + m_tagName.append(cc); + m_closeTag = false; + m_state = TagName; + } else if (cc == '>') { + m_state = Data; + } else if (cc == '?') { + m_state = BogusComment; + } else { + m_state = Data; + continue; + } + } + break; + case CloseTagOpen: + if (m_contentModel == RCDATA || m_contentModel == CDATA) { + if (!m_lastStartTag.length()) { + m_state = Data; + continue; + } + if (m_source.length() < m_lastStartTag.length() + 1) + return; + Vector<UChar> tmpString; + UChar tmpChar = 0; + bool match = true; + for (unsigned n = 0; n < m_lastStartTag.length() + 1; n++) { + tmpChar = Unicode::toLower(*m_source); + if (n < m_lastStartTag.length() && tmpChar != m_lastStartTag[n]) + match = false; + tmpString.append(tmpChar); + m_source.advance(); + } + m_source.prepend(SegmentedString(String(tmpString.data(), tmpString.size()))); + if (!match || (!isWhitespace(tmpChar) && tmpChar != '>' && tmpChar != '/')) { + m_state = Data; + continue; + } + } + if (cc >= 'A' && cc <= 'Z') { + m_tagName.clear(); + m_charset = String(); + m_tagName.append(cc + 0x20); + m_closeTag = true; + m_state = TagName; + } else if (cc >= 'a' && cc <= 'z') { + m_tagName.clear(); + m_charset = String(); + m_tagName.append(cc); + m_closeTag = true; + m_state = TagName; + } else if (cc == '>') { + m_state = Data; + } else + m_state = BogusComment; + break; + case TagName: + while (1) { + if (isWhitespace(cc)) { + m_state = BeforeAttributeName; + break; + } + if (cc == '>') { + emitTag(); + m_state = Data; + break; + } + if (cc == '/') { + m_state = BeforeAttributeName; + break; + } + if (cc >= 'A' && cc <= 'Z') + m_tagName.append(cc + 0x20); + else + m_tagName.append(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case BeforeAttributeName: + if (isWhitespace(cc)) + ; + else if (cc == '>') { + emitTag(); + m_state = Data; + } else if (cc >= 'A' && cc <= 'Z') { + m_attributeName.clear(); + m_attributeValue.clear(); + m_attributeName.append(cc + 0x20); + m_state = AttributeName; + } else if (cc == '/') + ; + else { + m_attributeName.clear(); + m_attributeValue.clear(); + m_attributeName.append(cc); + m_state = AttributeName; + } + break; + case AttributeName: + while (1) { + if (isWhitespace(cc)) { + m_state = AfterAttributeName; + break; + } + if (cc == '=') { + m_state = BeforeAttributeValue; + break; + } + if (cc == '>') { + emitTag(); + m_state = Data; + break; + } + if (cc == '/') { + m_state = BeforeAttributeName; + break; + } + if (cc >= 'A' && cc <= 'Z') + m_attributeName.append(cc + 0x20); + else + m_attributeName.append(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case AfterAttributeName: + if (isWhitespace(cc)) + ; + else if (cc == '=') + m_state = BeforeAttributeValue; + else if (cc == '>') { + emitTag(); + m_state = Data; + } else if (cc >= 'A' && cc <= 'Z') { + m_attributeName.clear(); + m_attributeValue.clear(); + m_attributeName.append(cc + 0x20); + m_state = AttributeName; + } else if (cc == '/') + m_state = BeforeAttributeName; + else { + m_attributeName.clear(); + m_attributeValue.clear(); + m_attributeName.append(cc); + m_state = AttributeName; + } + break; + case BeforeAttributeValue: + if (isWhitespace(cc)) + ; + else if (cc == '"') + m_state = AttributeValueDoubleQuoted; + else if (cc == '&') { + m_state = AttributeValueUnquoted; + continue; + } else if (cc == '\'') + m_state = AttributeValueSingleQuoted; + else if (cc == '>') { + emitTag(); + m_state = Data; + } else { + m_attributeValue.append(cc); + m_state = AttributeValueUnquoted; + } + break; + case AttributeValueDoubleQuoted: + while (1) { + if (cc == '"') { + processAttribute(); + m_state = BeforeAttributeName; + break; + } + if (cc == '&') { + m_stateBeforeEntityInAttributeValue = m_state; + m_state = EntityInAttributeValue; + break; + } + m_attributeValue.append(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case AttributeValueSingleQuoted: + while (1) { + if (cc == '\'') { + processAttribute(); + m_state = BeforeAttributeName; + break; + } + if (cc == '&') { + m_stateBeforeEntityInAttributeValue = m_state; + m_state = EntityInAttributeValue; + break; + } + m_attributeValue.append(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case AttributeValueUnquoted: + while (1) { + if (isWhitespace(cc)) { + processAttribute(); + m_state = BeforeAttributeName; + break; + } + if (cc == '&') { + m_stateBeforeEntityInAttributeValue = m_state; + m_state = EntityInAttributeValue; + break; + } + if (cc == '>') { + processAttribute(); + emitTag(); + m_state = Data; + break; + } + m_attributeValue.append(cc); + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case EntityInAttributeValue: + { + bool notEnoughCharacters = false; + unsigned entity = consumeEntity(m_source, notEnoughCharacters); + if (notEnoughCharacters) + return; + if (entity > 0xFFFF) { + m_attributeValue.append(U16_LEAD(entity)); + m_attributeValue.append(U16_TRAIL(entity)); + } else if (entity) + m_attributeValue.append(entity); + else + m_attributeValue.append('&'); + } + m_state = m_stateBeforeEntityInAttributeValue; + continue; + case BogusComment: + while (1) { + if (cc == '>') { + m_state = Data; + break; + } + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case MarkupDeclarationOpen: { + if (cc == '-') { + if (m_source.length() < 2) + return; + m_source.advance(); + cc = *m_source; + if (cc == '-') + m_state = CommentStart; + else { + m_state = BogusComment; + continue; + } + // If we cared about the DOCTYPE we would test to enter those states here + } else { + m_state = BogusComment; + continue; + } + break; + } + case CommentStart: + if (cc == '-') + m_state = CommentStartDash; + else if (cc == '>') + m_state = Data; + else + m_state = Comment; + break; + case CommentStartDash: + if (cc == '-') + m_state = CommentEnd; + else if (cc == '>') + m_state = Data; + else + m_state = Comment; + break; + case Comment: + while (1) { + if (cc == '-') { + m_state = CommentEndDash; + break; + } + m_source.advance(); + if (m_source.isEmpty()) + return; + cc = *m_source; + } + break; + case CommentEndDash: + if (cc == '-') + m_state = CommentEnd; + else + m_state = Comment; + break; + case CommentEnd: + if (cc == '>') + m_state = Data; + else if (cc == '-') + ; + else + m_state = Comment; + break; + } + m_source.advance(); + } +} + +void PreloadScanner::processAttribute() +{ + AtomicString tag = AtomicString(m_tagName.data(), m_tagName.size()); + AtomicString attribute = AtomicString(m_attributeName.data(), m_attributeName.size()); + + String value(m_attributeValue.data(), m_attributeValue.size()); + if (tag == scriptTag || tag == imgTag) { + if (attribute == srcAttr && m_urlToLoad.isEmpty()) + m_urlToLoad = parseURL(value); + else if (attribute == charsetAttr) + m_charset = value; + } else if (tag == linkTag) { + if (attribute == hrefAttr && m_urlToLoad.isEmpty()) + m_urlToLoad = parseURL(value); + else if (attribute == relAttr) { + bool styleSheet = false; + bool alternate = false; + bool icon = false; + bool dnsPrefetch = false; + HTMLLinkElement::tokenizeRelAttribute(value, styleSheet, alternate, icon, dnsPrefetch); + m_linkIsStyleSheet = styleSheet && !alternate && !icon && !dnsPrefetch; + } else if (attribute == charsetAttr) + m_charset = value; + } +} + +inline void PreloadScanner::emitCharacter(UChar c) +{ + if (m_contentModel == CDATA && m_lastStartTag == styleTag) + tokenizeCSS(c); +} + +inline void PreloadScanner::tokenizeCSS(UChar c) +{ + // We are just interested in @import rules, no need for real tokenization here + // Searching for other types of resources is probably low payoff + switch (m_cssState) { + case CSSInitial: + if (c == '@') + m_cssState = CSSRuleStart; + else if (c == '/') + m_cssState = CSSMaybeComment; + break; + case CSSMaybeComment: + if (c == '*') + m_cssState = CSSComment; + else + m_cssState = CSSInitial; + break; + case CSSComment: + if (c == '*') + m_cssState = CSSMaybeCommentEnd; + break; + case CSSMaybeCommentEnd: + if (c == '/') + m_cssState = CSSInitial; + else if (c == '*') + ; + else + m_cssState = CSSComment; + break; + case CSSRuleStart: + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + m_cssRule.clear(); + m_cssRuleValue.clear(); + m_cssRule.append(c); + m_cssState = CSSRule; + } else + m_cssState = CSSInitial; + break; + case CSSRule: + if (isWhitespace(c)) + m_cssState = CSSAfterRule; + else if (c == ';') + m_cssState = CSSInitial; + else + m_cssRule.append(c); + break; + case CSSAfterRule: + if (isWhitespace(c)) + ; + else if (c == ';') + m_cssState = CSSInitial; + else { + m_cssState = CSSRuleValue; + m_cssRuleValue.append(c); + } + break; + case CSSRuleValue: + if (isWhitespace(c)) + m_cssState = CSSAferRuleValue; + else if (c == ';') { + emitCSSRule(); + m_cssState = CSSInitial; + } else + m_cssRuleValue.append(c); + break; + case CSSAferRuleValue: + if (isWhitespace(c)) + ; + else if (c == ';') { + emitCSSRule(); + m_cssState = CSSInitial; + } else { + // FIXME media rules + m_cssState = CSSInitial; + } + break; + } +} + +void PreloadScanner::emitTag() +{ + if (m_closeTag) { + m_contentModel = PCDATA; + m_cssState = CSSInitial; + clearLastCharacters(); + return; + } + + AtomicString tag(m_tagName.data(), m_tagName.size()); + m_lastStartTag = tag; + + if (tag == textareaTag || tag == titleTag) + m_contentModel = RCDATA; + else if (tag == styleTag || tag == xmpTag || tag == scriptTag || tag == iframeTag || tag == noembedTag || tag == noframesTag) + m_contentModel = CDATA; + else if (tag == noscriptTag) + // we wouldn't be here if scripts were disabled + m_contentModel = CDATA; + else if (tag == plaintextTag) + m_contentModel = PLAINTEXT; + else + m_contentModel = PCDATA; + + if (tag == bodyTag) + m_bodySeen = true; + + if (m_urlToLoad.isEmpty()) { + m_linkIsStyleSheet = false; + return; + } + + if (tag == scriptTag) + m_document->docLoader()->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody()); + else if (tag == imgTag) + m_document->docLoader()->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody()); + else if (tag == linkTag && m_linkIsStyleSheet) + m_document->docLoader()->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody()); + + m_urlToLoad = String(); + m_charset = String(); + m_linkIsStyleSheet = false; +} + +void PreloadScanner::emitCSSRule() +{ + String rule(m_cssRule.data(), m_cssRule.size()); + if (equalIgnoringCase(rule, "import") && !m_cssRuleValue.isEmpty()) { + String value(m_cssRuleValue.data(), m_cssRuleValue.size()); + String url = parseURL(value); + if (!url.isEmpty()) + m_document->docLoader()->preload(CachedResource::CSSStyleSheet, url, String(), scanningBody()); + } + m_cssRule.clear(); + m_cssRuleValue.clear(); +} + +} diff --git a/WebCore/html/PreloadScanner.h b/WebCore/html/PreloadScanner.h new file mode 100644 index 0000000..b5908cf --- /dev/null +++ b/WebCore/html/PreloadScanner.h @@ -0,0 +1,144 @@ +/* + * 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 PreloadScanner_h +#define PreloadScanner_h + +#include "AtomicString.h" +#include "SegmentedString.h" +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class CachedResource; + class CachedResourceClient; + class Document; + + class PreloadScanner : Noncopyable { + public: + PreloadScanner(Document*); + ~PreloadScanner(); + void begin(); + void write(const SegmentedString&); + void end(); + bool inProgress() const { return m_inProgress; } + + bool scanningBody() const; + + static unsigned consumeEntity(SegmentedString&, bool& notEnoughCharacters); + + private: + void tokenize(const SegmentedString&); + void reset(); + + void emitTag(); + void emitCharacter(UChar); + + void tokenizeCSS(UChar); + void emitCSSRule(); + + void processAttribute(); + + + void clearLastCharacters(); + void rememberCharacter(UChar); + bool lastCharactersMatch(const char*, unsigned count) const; + + bool m_inProgress; + SegmentedString m_source; + + enum State { + Data, + EntityData, + TagOpen, + CloseTagOpen, + TagName, + BeforeAttributeName, + AttributeName, + AfterAttributeName, + BeforeAttributeValue, + AttributeValueDoubleQuoted, + AttributeValueSingleQuoted, + AttributeValueUnquoted, + EntityInAttributeValue, + BogusComment, + MarkupDeclarationOpen, + CommentStart, + CommentStartDash, + Comment, + CommentEndDash, + CommentEnd + }; + State m_state; + bool m_escape; + enum ContentModel { + PCDATA, + RCDATA, + CDATA, + PLAINTEXT + }; + ContentModel m_contentModel; + unsigned m_commentPos; + State m_stateBeforeEntityInAttributeValue; + + static const unsigned lastCharactersBufferSize = 8; + UChar m_lastCharacters[lastCharactersBufferSize]; + unsigned m_lastCharacterIndex; + + bool m_closeTag; + Vector<UChar, 32> m_tagName; + Vector<UChar, 32> m_attributeName; + Vector<UChar> m_attributeValue; + AtomicString m_lastStartTag; + + String m_urlToLoad; + String m_charset; + bool m_linkIsStyleSheet; + + enum CSSState { + CSSInitial, + CSSMaybeComment, + CSSComment, + CSSMaybeCommentEnd, + CSSRuleStart, + CSSRule, + CSSAfterRule, + CSSRuleValue, + CSSAferRuleValue + }; + CSSState m_cssState; + Vector<UChar, 16> m_cssRule; + Vector<UChar> m_cssRuleValue; + + double m_timeUsed; + + bool m_bodySeen; + Document* m_document; + }; + +} + +#endif diff --git a/WebCore/html/TextMetrics.h b/WebCore/html/TextMetrics.h new file mode 100644 index 0000000..34a3378 --- /dev/null +++ b/WebCore/html/TextMetrics.h @@ -0,0 +1,50 @@ +/* + * 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 TextMetrics_h +#define TextMetrics_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class TextMetrics : public RefCounted<TextMetrics> { +public: + static PassRefPtr<TextMetrics> create() { return adoptRef(new TextMetrics); } + + unsigned width() const { return m_width; } + void setWidth(float w) { m_width = w; } + +private: + TextMetrics() + : m_width(0) + { } + + float m_width; +}; + +} // namespace WebCore + +#endif // TextMetrics_h diff --git a/WebCore/html/TextMetrics.idl b/WebCore/html/TextMetrics.idl new file mode 100644 index 0000000..dc88716 --- /dev/null +++ b/WebCore/html/TextMetrics.idl @@ -0,0 +1,34 @@ +/* + * 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. + */ + +module html { + + interface [ + GenerateConstructor + ] TextMetrics { + readonly attribute float width; + }; + +} diff --git a/WebCore/html/TimeRanges.cpp b/WebCore/html/TimeRanges.cpp new file mode 100644 index 0000000..ad81ac8 --- /dev/null +++ b/WebCore/html/TimeRanges.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 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. + */ + +#include "config.h" + +#include "TimeRanges.h" + +using namespace WebCore; + +TimeRanges::TimeRanges(float start, float end) +{ + add(start, end); +} + +float TimeRanges::start(unsigned index, ExceptionCode& ec) const +{ + if (index >= length()) { + ec = INDEX_SIZE_ERR; + return 0; + } + return m_ranges[index].m_start; +} + +float TimeRanges::end(unsigned index, ExceptionCode& ec) const +{ + if (index >= length()) { + ec = INDEX_SIZE_ERR; + return 0; + } + return m_ranges[index].m_end; +} + +void TimeRanges::add(float start, float end) +{ + m_ranges.append(Range(start, end)); + // FIXME normalize +} + +bool TimeRanges::contain(float time) const +{ + ExceptionCode unused; + for (unsigned n = 0; n < length(); n++) { + if (time >= start(n, unused) && time <= end(n, unused)) + return true; + } + return false; +} diff --git a/WebCore/html/TimeRanges.h b/WebCore/html/TimeRanges.h new file mode 100644 index 0000000..eb54f6b --- /dev/null +++ b/WebCore/html/TimeRanges.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 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. + */ + +#ifndef TimeRanges_h +#define TimeRanges_h + +#include "ExceptionCode.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class TimeRanges : public RefCounted<TimeRanges> { +public: + static PassRefPtr<TimeRanges> create() + { + return adoptRef(new TimeRanges); + } + static PassRefPtr<TimeRanges> create(float start, float end) + { + return adoptRef(new TimeRanges(start, end)); + } + + unsigned length() const { return m_ranges.size(); } + float start(unsigned index, ExceptionCode&) const; + float end(unsigned index, ExceptionCode&) const; + + void add(float start, float end); + + bool contain(float time) const; + +private: + TimeRanges() { } + TimeRanges(float start, float end); + + struct Range { + Range() { } + Range(float start, float end) { + m_start = start; + m_end = end; + } + float m_start; + float m_end; + }; + + Vector<Range> m_ranges; +}; + +} // namespace WebCore + +#endif diff --git a/WebCore/html/TimeRanges.idl b/WebCore/html/TimeRanges.idl new file mode 100644 index 0000000..c6776a9 --- /dev/null +++ b/WebCore/html/TimeRanges.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 html { + +interface TimeRanges { + readonly attribute unsigned long length; + float start(in unsigned long index) + raises (DOMException); + float end(in unsigned long index) + raises (DOMException); +}; + +} diff --git a/WebCore/html/VoidCallback.h b/WebCore/html/VoidCallback.h new file mode 100644 index 0000000..c220411 --- /dev/null +++ b/WebCore/html/VoidCallback.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 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. + */ + +#ifndef VoidCallback_h +#define VoidCallback_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class VoidCallback : public RefCounted<VoidCallback> { +public: + virtual ~VoidCallback() { } + + virtual void handleEvent() = 0; + +protected: + VoidCallback() {} +}; + +} // namespace WebCore + +#endif diff --git a/WebCore/html/VoidCallback.idl b/WebCore/html/VoidCallback.idl new file mode 100644 index 0000000..3682cf7 --- /dev/null +++ b/WebCore/html/VoidCallback.idl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 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 html { + interface [CustomNativeConverter] VoidCallback { + void handleEvent(); + }; +} |