diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering')
208 files changed, 9737 insertions, 3614 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp index 3749782ff5..fdbec52a3b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp @@ -382,7 +382,7 @@ int AutoTableLayout::calcEffectiveWidth() float spanMax = max(maxWidth, cMaxWidth); tMaxWidth = max(tMaxWidth, spanMax * 100 * percentScaleFactor / w.rawValue()); - // all non percent columns in the span get percent vlaues to sum up correctly. + // all non percent columns in the span get percent values to sum up correctly. int percentMissing = w.rawValue() - totalPercent; float totalWidth = 0; for (unsigned int pos = col; pos < lastCol; pos++) { @@ -664,8 +664,8 @@ void AutoTableLayout::layout() } } - // if we have overallocated, reduce every cell according to the difference between desired width and minwidth - // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing. + // If we have overallocated, reduce every cell according to the difference between desired width and minwidth + // this seems to produce to the pixel exact results with IE. Wonder is some of this also holds for width distributing. if (available < 0) { // Need to reduce cells with the following prioritization: // (1) Auto diff --git a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h index 641a68b952..f1ef7681db 100644 --- a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h +++ b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) * diff --git a/src/3rdparty/webkit/WebCore/rendering/BidiRun.cpp b/src/3rdparty/webkit/WebCore/rendering/BidiRun.cpp new file mode 100644 index 0000000000..ac130469b3 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/BidiRun.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 "BidiRun.h" +#include "InlineBox.h" +#include "RenderArena.h" +#include <wtf/RefCountedLeakCounter.h> + +using namespace WTF; + +namespace WebCore { + +#ifndef NDEBUG +static RefCountedLeakCounter bidiRunCounter("BidiRun"); + +static bool inBidiRunDestroy; +#endif + +void BidiRun::destroy() +{ +#ifndef NDEBUG + inBidiRunDestroy = true; +#endif + RenderArena* renderArena = m_object->renderArena(); + delete this; +#ifndef NDEBUG + inBidiRunDestroy = false; +#endif + + // Recover the size left there for us by operator delete and free the memory. + renderArena->free(*reinterpret_cast<size_t*>(this), this); +} + +void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw() +{ +#ifndef NDEBUG + bidiRunCounter.increment(); +#endif + return renderArena->allocate(sz); +} + +void BidiRun::operator delete(void* ptr, size_t sz) +{ +#ifndef NDEBUG + bidiRunCounter.decrement(); +#endif + ASSERT(inBidiRunDestroy); + + // Stash size where destroy() can find it. + *(size_t*)ptr = sz; +} + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/BidiRun.h b/src/3rdparty/webkit/WebCore/rendering/BidiRun.h new file mode 100644 index 0000000000..542081a720 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/BidiRun.h @@ -0,0 +1,65 @@ +/** + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 BidiRun_h +#define BidiRun_h + +#include <wtf/StdLibExtras.h> +#include "BidiResolver.h" +#include "RenderText.h" + +namespace WebCore { + +class BidiContext; +class InlineBox; + +struct BidiRun : BidiCharacterRun { + BidiRun(int start, int stop, RenderObject* object, BidiContext* context, WTF::Unicode::Direction dir) + : BidiCharacterRun(start, stop, context, dir) + , m_object(object) + , m_box(0) + { + } + + void destroy(); + + // Overloaded new operator. + void* operator new(size_t, RenderArena*) throw(); + + // Overridden to prevent the normal delete from being called. + void operator delete(void*, size_t); + + BidiRun* next() { return static_cast<BidiRun*>(m_next); } + +private: + // The normal operator new is disallowed. + void* operator new(size_t) throw(); + +public: + RenderObject* m_object; + InlineBox* m_box; +}; + +} + +#endif // BidiRun_h diff --git a/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp b/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp index f546abb113..c164c81a48 100644 --- a/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * @@ -24,20 +22,14 @@ #include "config.h" #include "CounterNode.h" +#include "RenderCounter.h" #include "RenderObject.h" #include <stdio.h> -// FIXME: There's currently no strategy for getting the counter tree updated when new -// elements with counter-reset and counter-increment styles are added to the render tree. -// Also, the code can't handle changes where an existing node needs to change into a -// "reset" node, or from a "reset" node back to not a "reset" node. As of this writing, -// at least some of these problems manifest as failures in the t1204-increment and -// t1204-reset tests in the CSS 2.1 test suite. - namespace WebCore { -CounterNode::CounterNode(RenderObject* o, bool isReset, int value) - : m_isReset(isReset) +CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value) + : m_hasResetType(hasResetType) , m_value(value) , m_countInParent(0) , m_renderer(o) @@ -46,38 +38,95 @@ CounterNode::CounterNode(RenderObject* o, bool isReset, int value) , m_nextSibling(0) , m_firstChild(0) , m_lastChild(0) -{ +{ +} + +CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const +{ + if (this == stayWithin) + return 0; + + const CounterNode* current = this; + CounterNode* next; + while (!(next = current->m_nextSibling)) { + current = current->m_parent; + if (!current || current == stayWithin) + return 0; + } + return next; +} + +CounterNode* CounterNode::nextInPreOrder(const CounterNode* stayWithin) const +{ + if (CounterNode* next = m_firstChild) + return next; + + return nextInPreOrderAfterChildren(stayWithin); +} + +CounterNode* CounterNode::lastDescendant() const +{ + CounterNode* last = m_lastChild; + if (!last) + return 0; + + while (CounterNode* lastChild = last->m_lastChild) + last = lastChild; + + return last; +} + +CounterNode* CounterNode::previousInPreOrder() const +{ + CounterNode* previous = m_previousSibling; + if (!previous) + return m_parent; + + while (CounterNode* lastChild = previous->m_lastChild) + previous = lastChild; + + return previous; } int CounterNode::computeCountInParent() const { - int increment = m_isReset ? 0 : m_value; + int increment = actsAsReset() ? 0 : m_value; if (m_previousSibling) return m_previousSibling->m_countInParent + increment; ASSERT(m_parent->m_firstChild == this); return m_parent->m_value + increment; } -void CounterNode::recount() +void CounterNode::resetRenderer(const AtomicString& identifier) const { - for (CounterNode* c = this; c; c = c->m_nextSibling) { - int oldCount = c->m_countInParent; - int newCount = c->computeCountInParent(); + if (!m_renderer || m_renderer->documentBeingDestroyed()) + return; + if (RenderObjectChildList* children = m_renderer->virtualChildren()) + children->invalidateCounters(m_renderer, identifier); +} + +void CounterNode::resetRenderers(const AtomicString& identifier) const +{ + const CounterNode* node = this; + do { + node->resetRenderer(identifier); + node = node->nextInPreOrder(this); + } while (node); +} + +void CounterNode::recount(const AtomicString& identifier) +{ + for (CounterNode* node = this; node; node = node->m_nextSibling) { + int oldCount = node->m_countInParent; + int newCount = node->computeCountInParent(); if (oldCount == newCount) break; - c->m_countInParent = newCount; - // m_renderer contains the parent of the render node - // corresponding to a CounterNode. Let's find the counter - // child and make this re-layout. - for (RenderObject* o = c->m_renderer->firstChild(); o; o = o->nextSibling()) - if (!o->documentBeingDestroyed() && o->isCounter()) { - o->setNeedsLayoutAndPrefWidthsRecalc(); - break; - } + node->m_countInParent = newCount; + node->resetRenderers(identifier); } } -void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild) +void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, const AtomicString& identifier) { ASSERT(newChild); ASSERT(!newChild->m_parent); @@ -85,6 +134,11 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild) ASSERT(!newChild->m_nextSibling); ASSERT(!refChild || refChild->m_parent == this); + if (newChild->m_hasResetType) { + while (m_lastChild != refChild) + RenderCounter::destroyCounterNode(m_lastChild->renderer(), identifier); + } + CounterNode* next; if (refChild) { @@ -95,91 +149,106 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild) m_firstChild = newChild; } - if (next) { - ASSERT(next->m_previousSibling == refChild); - next->m_previousSibling = newChild; - } else { - ASSERT(m_lastChild == refChild); - m_lastChild = newChild; - } - newChild->m_parent = this; newChild->m_previousSibling = refChild; - newChild->m_nextSibling = next; - newChild->m_countInParent = newChild->computeCountInParent(); + if (!newChild->m_firstChild || newChild->m_hasResetType) { + newChild->m_nextSibling = next; + if (next) { + ASSERT(next->m_previousSibling == refChild); + next->m_previousSibling = newChild; + } else { + ASSERT(m_lastChild == refChild); + m_lastChild = newChild; + } + + newChild->m_countInParent = newChild->computeCountInParent(); + newChild->resetRenderers(identifier); + if (next) + next->recount(identifier); + return; + } + + // The code below handles the case when a formerly root increment counter is loosing its root position + // and therefore its children become next siblings. + CounterNode* last = newChild->m_lastChild; + CounterNode* first = newChild->m_firstChild; + + newChild->m_nextSibling = first; + first->m_previousSibling = newChild; + // The case when the original next sibling of the inserted node becomes a child of + // one of the former children of the inserted node is not handled as it is believed + // to be impossible since: + // 1. if the increment counter node lost it's root position as a result of another + // counter node being created, it will be inserted as the last child so next is null. + // 2. if the increment counter node lost it's root position as a result of a renderer being + // inserted into the document's render tree, all its former children counters are attached + // to children of the inserted renderer and hence cannot be in scope for counter nodes + // attached to renderers that were already in the document's render tree. + last->m_nextSibling = next; if (next) - next->recount(); + next->m_previousSibling = last; + else + m_lastChild = last; + for (next = first; ; next = next->m_nextSibling) { + next->m_parent = this; + if (last == next) + break; + } + newChild->m_firstChild = 0; + newChild->m_lastChild = 0; + newChild->m_countInParent = newChild->computeCountInParent(); + newChild->resetRenderer(identifier); + first->recount(identifier); } -void CounterNode::removeChild(CounterNode* oldChild) +void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identifier) { ASSERT(oldChild); ASSERT(!oldChild->m_firstChild); ASSERT(!oldChild->m_lastChild); CounterNode* next = oldChild->m_nextSibling; - CounterNode* prev = oldChild->m_previousSibling; + CounterNode* previous = oldChild->m_previousSibling; oldChild->m_nextSibling = 0; oldChild->m_previousSibling = 0; oldChild->m_parent = 0; - if (prev) - prev->m_nextSibling = next; + if (previous) + previous->m_nextSibling = next; else { ASSERT(m_firstChild == oldChild); m_firstChild = next; } - + if (next) - next->m_previousSibling = prev; + next->m_previousSibling = previous; else { ASSERT(m_lastChild == oldChild); - m_lastChild = prev; + m_lastChild = previous; } - + if (next) - next->recount(); + next->recount(identifier); } #ifndef NDEBUG -static const CounterNode* nextInPreOrderAfterChildren(const CounterNode* node) -{ - CounterNode* next = node->nextSibling(); - if (!next) { - next = node->parent(); - while (next && !next->nextSibling()) - next = next->parent(); - if (next) - next = next->nextSibling(); - } - return next; -} - -static const CounterNode* nextInPreOrder(const CounterNode* node) -{ - if (CounterNode* child = node->firstChild()) - return child; - return nextInPreOrderAfterChildren(node); -} - static void showTreeAndMark(const CounterNode* node) { const CounterNode* root = node; while (root->parent()) root = root->parent(); - for (const CounterNode* c = root; c; c = nextInPreOrder(c)) { - if (c == node) - fprintf(stderr, "*"); - for (const CounterNode* d = c; d && d != root; d = d->parent()) - fprintf(stderr, "\t"); - if (c->isReset()) - fprintf(stderr, "reset: %d %d\n", c->value(), c->countInParent()); - else - fprintf(stderr, "increment: %d %d\n", c->value(), c->countInParent()); + for (const CounterNode* current = root; current; current = current->nextInPreOrder()) { + fwrite((current == node) ? "*" : " ", 1, 1, stderr); + for (const CounterNode* parent = current; parent && parent != root; parent = parent->parent()) + fwrite(" ", 1, 2, stderr); + fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n", + current, current->actsAsReset() ? "reset____" : "increment", current->value(), + current->countInParent(), current->parent(), current->previousSibling(), + current->nextSibling(), current->renderer()); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/CounterNode.h b/src/3rdparty/webkit/WebCore/rendering/CounterNode.h index b432e1d5ce..15f2eb8f19 100644 --- a/src/3rdparty/webkit/WebCore/rendering/CounterNode.h +++ b/src/3rdparty/webkit/WebCore/rendering/CounterNode.h @@ -35,13 +35,15 @@ namespace WebCore { +class AtomicString; class RenderObject; class CounterNode : public Noncopyable { public: CounterNode(RenderObject*, bool isReset, int value); - bool isReset() const { return m_isReset; } + bool actsAsReset() const { return m_hasResetType || !m_parent; } + bool hasResetType() const { return m_hasResetType; } int value() const { return m_value; } int countInParent() const { return m_countInParent; } RenderObject* renderer() const { return m_renderer; } @@ -51,15 +53,30 @@ public: CounterNode* nextSibling() const { return m_nextSibling; } CounterNode* firstChild() const { return m_firstChild; } CounterNode* lastChild() const { return m_lastChild; } + CounterNode* lastDescendant() const; + CounterNode* previousInPreOrder() const; + CounterNode* nextInPreOrder(const CounterNode* stayWithin = 0) const; + CounterNode* nextInPreOrderAfterChildren(const CounterNode* stayWithin = 0) const; - void insertAfter(CounterNode* newChild, CounterNode* beforeChild); - void removeChild(CounterNode*); + void insertAfter(CounterNode* newChild, CounterNode* beforeChild, const AtomicString& identifier); + + // identifier must match the identifier of this counter. + void removeChild(CounterNode*, const AtomicString& identifier); private: int computeCountInParent() const; - void recount(); + void recount(const AtomicString& identifier); + + // Invalidates the text in the renderer of this counter, if any. + // identifier must match the identifier of this counter. + void resetRenderer(const AtomicString& identifier) const; + + // Invalidates the text in the renderer of this counter, if any, + // and in the renderers of all descendants of this counter, if any. + // identifier must match the identifier of this counter. + void resetRenderers(const AtomicString& identifier) const; - bool m_isReset; + bool m_hasResetType; int m_value; int m_countInParent; RenderObject* m_renderer; diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp index db9a101fde..6ec31950ce 100644 --- a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp @@ -1,6 +1,4 @@ /** -* This file is part of the html renderer for KDE. - * * Copyright (C) 2003, 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or @@ -25,6 +23,7 @@ #include "Document.h" #include "GraphicsContext.h" #include "HitTestResult.h" +#include "RootInlineBox.h" namespace WebCore { @@ -34,17 +33,30 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) RenderStyle* style = m_renderer->style(m_firstLine); Color textColor = style->color(); if (textColor != context->fillColor()) - context->setFillColor(textColor); + context->setFillColor(textColor, style->colorSpace()); bool setShadow = false; if (style->textShadow()) { context->setShadow(IntSize(style->textShadow()->x, style->textShadow()->y), - style->textShadow()->blur, style->textShadow()->color); + style->textShadow()->blur, style->textShadow()->color, style->colorSpace()); setShadow = true; } + if (selectionState() != RenderObject::SelectionNone) { + paintSelection(context, tx, ty, style, style->font()); + + // Select the correct color for painting the text. + Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor(); + if (foreground.isValid() && foreground != textColor) + context->setFillColor(foreground, style->colorSpace()); + } + const String& str = m_str; context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->font().ascent())); + // Restore the regular fill color. + if (textColor != context->fillColor()) + context->setFillColor(textColor, style->colorSpace()); + if (setShadow) context->clearShadow(); @@ -56,6 +68,35 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) } } +IntRect EllipsisBox::selectionRect(int tx, int ty) +{ + RenderStyle* style = m_renderer->style(m_firstLine); + const Font& f = style->font(); + return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()), + IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight())); +} + +void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font) +{ + Color textColor = style->color(); + Color c = m_renderer->selectionBackgroundColor(); + if (!c.isValid() || !c.alpha()) + return; + + // If the text color ends up being the same as the selection background, invert the selection + // background. + if (textColor == c) + c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); + + context->save(); + int y = root()->selectionTop(); + int h = root()->selectionHeight(); + context->clip(IntRect(m_x + tx, y + ty, m_width, h)); + context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()), + IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace()); + context->restore(); +} + bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) { tx += m_x; diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h index 9dbd27f994..087fc722c8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h @@ -1,6 +1,4 @@ /** -* This file is part of the html renderer for KDE. - * * Copyright (C) 2003, 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or @@ -37,18 +35,24 @@ public: , m_height(height) , m_str(ellipsisStr) , m_markupBox(markupBox) + , m_selectionState(RenderObject::SelectionNone) { } virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; } + IntRect selectionRect(int tx, int ty); private: virtual int height() const { return m_height; } + virtual RenderObject::SelectionState selectionState() { return m_selectionState; } + void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&); int m_height; AtomicString m_str; InlineBox* m_markupBox; + RenderObject::SelectionState m_selectionState; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp index 4852708eba..09af518c43 100644 --- a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2006 Apple Computer, Inc. diff --git a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h index ed7c089e09..758ddbb3f2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h +++ b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) * diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h index 46dd7b8af1..ca1445ae02 100644 --- a/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h +++ b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2006 Apple Computer, Inc. * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ * diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h index 25e10585c5..d1906ba64b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h +++ b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp index baea956bc0..23dc4e7ba6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp @@ -165,7 +165,7 @@ void InlineFlowBox::attachLineBoxToRenderObject() void InlineFlowBox::adjustPosition(int dx, int dy) { - InlineRunBox::adjustPosition(dx, dy); + InlineBox::adjustPosition(dx, dy); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->adjustPosition(dx, dy); if (m_overflow) @@ -429,7 +429,7 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi } lineHeight = baseline + baselineToBottom; } else if (parentLineHeight.isPercent()) { - lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize(), true); + lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize()); baseline = 0; for (size_t i = 0; i < usedFonts.size(); ++i) { int halfLeading = (lineHeight - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2; @@ -532,9 +532,6 @@ void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool st // Any spillage outside of the line top and bottom is not considered overflow. We just ignore this, since it only happens // from the "your ascent/descent don't affect the line" quirk. - // FIXME: Technically this means there can be repaint errors in the case where a line box has a shadow or background that spills - // outside of the block. We should consider making any line box that has anything to render just stop respecting the quirk or making - // boxes that render something set visual overflow. int topOverflow = max(y(), lineTop); int bottomOverflow = min(y() + boxHeight, lineBottom); @@ -706,11 +703,11 @@ void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, con // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) + for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) xOffsetOnLine += curr->width(); int startX = tx - xOffsetOnLine; int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) totalWidth += curr->width(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); @@ -735,13 +732,24 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; - // Move x/y to our coordinates. - tx += m_x; - ty += m_y; - + int x = m_x; + int y = m_y; int w = width(); int h = height(); + // Constrain our background/border painting to the line top and bottom if necessary. + bool strictMode = renderer()->document()->inStrictMode(); + if (!hasTextChildren() && !strictMode) { + RootInlineBox* rootBox = root(); + int bottom = min(rootBox->lineBottom(), y + h); + y = max(rootBox->lineTop(), y); + h = bottom - y; + } + + // Move x/y to our coordinates. + tx += x; + ty += y; + GraphicsContext* context = paintInfo.context; // You can use p::first-line to specify a background. If so, the root line boxes for @@ -780,11 +788,11 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) + for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) xOffsetOnLine += curr->width(); int startX = tx - xOffsetOnLine; int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) totalWidth += curr->width(); context->save(); context->clip(IntRect(tx, ty, w, h)); @@ -800,13 +808,24 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; - // Move x/y to our coordinates. - tx += m_x; - ty += m_y; - + int x = m_x; + int y = m_y; int w = width(); int h = height(); + // Constrain our background/border painting to the line top and bottom if necessary. + bool strictMode = renderer()->document()->inStrictMode(); + if (!hasTextChildren() && !strictMode) { + RootInlineBox* rootBox = root(); + int bottom = min(rootBox->lineBottom(), y + h); + y = max(rootBox->lineTop(), y); + h = bottom - y; + } + + // Move x/y to our coordinates. + tx += x; + ty += y; + const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage(); StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image(); @@ -840,11 +859,11 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty // We have a mask image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) + for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) xOffsetOnLine += curr->width(); int startX = tx - xOffsetOnLine; int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) totalWidth += curr->width(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, w, h)); @@ -974,6 +993,7 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int setClip = true; } + ColorSpace colorSpace = renderer()->style()->colorSpace(); bool setShadow = false; do { if (shadow) { @@ -982,24 +1002,24 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int ty -= extraOffset; extraOffset = 0; } - context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color); + context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color, colorSpace); setShadow = true; shadow = shadow->next; } if (paintUnderline) { - context->setStrokeColor(underline); + context->setStrokeColor(underline, colorSpace); context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting); } if (paintOverline) { - context->setStrokeColor(overline); + context->setStrokeColor(overline, colorSpace); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), w, isPrinting); } if (paintLineThrough) { - context->setStrokeColor(linethrough); + context->setStrokeColor(linethrough, colorSpace); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting); } diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h index 23b5cc99e2..ecb4724b0d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h @@ -21,7 +21,7 @@ #ifndef InlineFlowBox_h #define InlineFlowBox_h -#include "InlineRunBox.h" +#include "InlineBox.h" #include "RenderOverflow.h" namespace WebCore { @@ -30,12 +30,14 @@ class HitTestRequest; class HitTestResult; class RenderLineBoxList; -class InlineFlowBox : public InlineRunBox { +class InlineFlowBox : public InlineBox { public: InlineFlowBox(RenderObject* obj) - : InlineRunBox(obj) + : InlineBox(obj) , m_firstChild(0) , m_lastChild(0) + , m_prevLineBox(0) + , m_nextLineBox(0) , m_includeLeftEdge(false) , m_includeRightEdge(false) #ifndef NDEBUG @@ -54,8 +56,10 @@ public: virtual ~InlineFlowBox(); #endif - InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); } - InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); } + InlineFlowBox* prevLineBox() const { return m_prevLineBox; } + InlineFlowBox* nextLineBox() const { return m_nextLineBox; } + void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; } + void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; } InlineBox* firstChild() const { checkConsistency(); return m_firstChild; } InlineBox* lastChild() const { checkConsistency(); return m_lastChild; } @@ -164,12 +168,14 @@ public: protected: OwnPtr<RenderOverflow> m_overflow; -private: virtual bool isInlineFlowBox() const { return true; } InlineBox* m_firstChild; InlineBox* m_lastChild; + InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject + InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject + bool m_includeLeftEdge : 1; bool m_includeRightEdge : 1; bool m_hasTextChildren : 1; diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineIterator.h b/src/3rdparty/webkit/WebCore/rendering/InlineIterator.h new file mode 100644 index 0000000000..9310ea8ab8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/InlineIterator.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef InlineIterator_h +#define InlineIterator_h + +#include "BidiRun.h" +#include "RenderBlock.h" +#include "RenderText.h" +#include <wtf/AlwaysInline.h> +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +class InlineIterator { +public: + InlineIterator() + : block(0) + , obj(0) + , pos(0) + , nextBreakablePosition(-1) + { + } + + InlineIterator(RenderBlock* b, RenderObject* o, unsigned p) + : block(b) + , obj(o) + , pos(p) + , nextBreakablePosition(-1) + { + } + + void increment(InlineBidiResolver* resolver = 0); + bool atEnd() const; + + UChar current() const; + WTF::Unicode::Direction direction() const; + + RenderBlock* block; + RenderObject* obj; + unsigned pos; + int nextBreakablePosition; +}; + +inline bool operator==(const InlineIterator& it1, const InlineIterator& it2) +{ + return it1.pos == it2.pos && it1.obj == it2.obj; +} + +inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2) +{ + return it1.pos != it2.pos || it1.obj != it2.obj; +} + +static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0) +{ + RenderObject* next = 0; + bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; + bool endOfInline = false; + + while (current) { + next = 0; + if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) { + next = current->firstChild(); + if (next && resolver && next->isRenderInline()) { + EUnicodeBidi ub = next->style()->unicodeBidi(); + if (ub != UBNormal) { + TextDirection dir = next->style()->direction(); + WTF::Unicode::Direction d = (ub == Embed + ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding) + : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride)); + resolver->embed(d); + } + } + } + + if (!next) { + if (!skipInlines && !oldEndOfInline && current->isRenderInline()) { + next = current; + endOfInline = true; + break; + } + + while (current && current != block) { + if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal) + resolver->embed(WTF::Unicode::PopDirectionalFormat); + + next = current->nextSibling(); + if (next) { + if (resolver && next->isRenderInline()) { + EUnicodeBidi ub = next->style()->unicodeBidi(); + if (ub != UBNormal) { + TextDirection dir = next->style()->direction(); + WTF::Unicode::Direction d = (ub == Embed + ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding: WTF::Unicode::LeftToRightEmbedding) + : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride)); + resolver->embed(d); + } + } + break; + } + + current = current->parent(); + if (!skipInlines && current && current != block && current->isRenderInline()) { + next = current; + endOfInline = true; + break; + } + } + } + + if (!next) + break; + + if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned() + || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. + && next->isRenderInline())) + break; + current = next; + } + + if (endOfInlinePtr) + *endOfInlinePtr = endOfInline; + + return next; +} + +static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true) +{ + if (!block->firstChild()) + return 0; + + RenderObject* o = block->firstChild(); + if (o->isRenderInline()) { + if (resolver) { + EUnicodeBidi ub = o->style()->unicodeBidi(); + if (ub != UBNormal) { + TextDirection dir = o->style()->direction(); + WTF::Unicode::Direction d = (ub == Embed + ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding) + : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride)); + resolver->embed(d); + } + } + if (skipInlines && o->firstChild()) + o = bidiNext(block, o, resolver, skipInlines); + else { + // Never skip empty inlines. + if (resolver) + resolver->commitExplicitEmbedding(); + return o; + } + } + + if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned()) + o = bidiNext(block, o, resolver, skipInlines); + + if (resolver) + resolver->commitExplicitEmbedding(); + return o; +} + +inline void InlineIterator::increment(InlineBidiResolver* resolver) +{ + if (!obj) + return; + if (obj->isText()) { + pos++; + if (pos >= toRenderText(obj)->textLength()) { + obj = bidiNext(block, obj, resolver); + pos = 0; + nextBreakablePosition = -1; + } + } else { + obj = bidiNext(block, obj, resolver); + pos = 0; + nextBreakablePosition = -1; + } +} + +inline bool InlineIterator::atEnd() const +{ + return !obj; +} + +inline UChar InlineIterator::current() const +{ + if (!obj || !obj->isText()) + return 0; + + RenderText* text = toRenderText(obj); + if (pos >= text->textLength()) + return 0; + + return text->characters()[pos]; +} + +ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const +{ + if (UChar c = current()) + return WTF::Unicode::direction(c); + + if (obj && obj->isListMarker()) + return obj->style()->direction() == LTR ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; + + return WTF::Unicode::OtherNeutral; +} + +template<> +inline void InlineBidiResolver::increment() +{ + current.increment(this); +} + +template <> +inline void InlineBidiResolver::appendRun() +{ + if (!emptyRun && !eor.atEnd()) { + int start = sor.pos; + RenderObject *obj = sor.obj; + while (obj && obj != eor.obj && obj != endOfLine.obj) { + RenderBlock::appendRunsForObject(start, obj->length(), obj, *this); + start = 0; + obj = bidiNext(sor.block, obj); + } + if (obj) { + unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX; + if (obj == endOfLine.obj && endOfLine.pos <= pos) { + reachedEndOfLine = true; + pos = endOfLine.pos; + } + // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be + int end = obj->length() ? pos+1 : 0; + RenderBlock::appendRunsForObject(start, end, obj, *this); + } + + eor.increment(); + sor = eor; + } + + m_direction = WTF::Unicode::OtherNeutral; + m_status.eor = WTF::Unicode::OtherNeutral; +} + +} + +#endif // InlineIterator_h diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h deleted file mode 100644 index 0f7c29bf1b..0000000000 --- a/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the line box implementation for KDE. - * - * 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. - * - */ - -#ifndef InlineRunBox_h -#define InlineRunBox_h - -#include "InlineBox.h" - -namespace WebCore { - -class InlineRunBox : public InlineBox { -public: - InlineRunBox(RenderObject* obj) - : InlineBox(obj) - , m_prevLine(0) - , m_nextLine(0) - { - } - - InlineRunBox* prevLineBox() const { return m_prevLine; } - InlineRunBox* nextLineBox() const { return m_nextLine; } - void setNextLineBox(InlineRunBox* n) { m_nextLine = n; } - void setPreviousLineBox(InlineRunBox* p) { m_prevLine = p; } - - virtual void paintBoxDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/) { } - virtual void paintTextDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/, bool /*paintedChildren*/ = false) { } - -protected: - InlineRunBox* m_prevLine; // The previous box that also uses our RenderObject - InlineRunBox* m_nextLine; // The next box that also uses our RenderObject -}; - -} // namespace WebCore - -#endif // InlineRunBox_h diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp index 751340d5f4..9f17b0c05d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp @@ -23,9 +23,11 @@ #include "config.h" #include "InlineTextBox.h" +#include "Chrome.h" #include "ChromeClient.h" #include "Document.h" #include "Editor.h" +#include "EllipsisBox.h" #include "Frame.h" #include "GraphicsContext.h" #include "HitTestResult.h" @@ -81,6 +83,23 @@ RenderObject::SelectionState InlineTextBox::selectionState() else if (state == RenderObject::SelectionBoth) state = RenderObject::SelectionNone; } + + // If there are ellipsis following, make sure their selection is updated. + if (m_truncation != cNoTruncation && root()->ellipsisBox()) { + EllipsisBox* ellipsis = root()->ellipsisBox(); + if (state != RenderObject::SelectionNone) { + int start, end; + selectionStartEnd(start, end); + // The ellipsis should be considered to be selected if the end of + // the selection is past the beginning of the truncation and the + // beginning of the selection is before or at the beginning of the + // truncation. + ellipsis->setSelectionState(end >= m_truncation && start <= m_truncation ? + RenderObject::SelectionInside : RenderObject::SelectionNone); + } else + ellipsis->setSelectionState(RenderObject::SelectionNone); + } + return state; } @@ -89,7 +108,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos) int sPos = max(startPos - m_start, 0); int ePos = min(endPos - m_start, (int)m_len); - if (sPos >= ePos) + if (sPos > ePos) return IntRect(); RenderText* textObj = textRenderer(); @@ -214,7 +233,7 @@ Color correctedTextColor(Color textColor, Color backgroundColor) return textColor.light(); } -void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness) +void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness, ColorSpace colorSpace) { int mode = context->textDrawingMode(); if (strokeThickness > 0) { @@ -225,12 +244,12 @@ void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, con } } - if (mode & cTextFill && fillColor != context->fillColor()) - context->setFillColor(fillColor); + if (mode & cTextFill && (fillColor != context->fillColor() || colorSpace != context->fillColorSpace())) + context->setFillColor(fillColor, colorSpace); if (mode & cTextStroke) { if (strokeColor != context->strokeColor()) - context->setStrokeColor(strokeColor); + context->setStrokeColor(strokeColor, colorSpace); if (strokeThickness != context->strokeThickness()) context->setStrokeThickness(strokeThickness); } @@ -254,12 +273,13 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in return false; } -static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) +static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) { Color fillColor = context->fillColor(); + ColorSpace fillColorSpace = context->fillColorSpace(); bool opaque = fillColor.alpha() == 255; if (!opaque) - context->setFillColor(Color::black); + context->setFillColor(Color::black, fillColorSpace); do { IntSize extraOffset; @@ -279,17 +299,17 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur); shadowOffset -= extraOffset; } - context->setShadow(shadowOffset, shadowBlur, shadowColor); + context->setShadow(shadowOffset, shadowBlur, shadowColor, fillColorSpace); } else if (!opaque) - context->setFillColor(fillColor); + context->setFillColor(fillColor, fillColorSpace); if (startOffset <= endOffset) context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset); - if (startOffset < textRun.length()) - context->drawText(font, textRun, textOrigin + extraOffset, startOffset); + if (startOffset < truncationPoint) + context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint); } if (!shadow) @@ -459,18 +479,25 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) if (paintSelectedTextOnly || paintSelectedTextSeparately) selectionStartEnd(sPos, ePos); + int length = m_len; + if (m_truncation != cNoTruncation) { + sPos = min<int>(sPos, m_truncation); + ePos = min<int>(ePos, m_truncation); + length = m_truncation; + } + if (!paintSelectedTextOnly) { // For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side // effect, so only when we know we're stroking, do a save/restore. if (textStrokeWidth > 0) context->save(); - updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth); + updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace()); if (!paintSelectedTextSeparately || ePos <= sPos) { // FIXME: Truncate right-to-left text correctly. - paintTextWithShadows(context, font, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); } else - paintTextWithShadows(context, font, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); if (textStrokeWidth > 0) context->restore(); @@ -481,8 +508,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) if (selectionStrokeWidth > 0) context->save(); - updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth); - paintTextWithShadows(context, font, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); + updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth, styleToUse->colorSpace()); + paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); if (selectionStrokeWidth > 0) context->restore(); @@ -490,7 +517,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) // Paint decorations if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && styleToUse->htmlHacks()) { - context->setStrokeColor(styleToUse->color()); + context->setStrokeColor(styleToUse->color(), styleToUse->colorSpace()); paintDecoration(context, tx, ty, d, textShadow); } @@ -561,13 +588,16 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); context->save(); - updateGraphicsContext(context, c, c, 0); // Don't draw text at all! + updateGraphicsContext(context, c, c, 0, style->colorSpace()); // Don't draw text at all! int y = selectionTop(); int h = selectionHeight(); + // If the text is truncated, let the thing being painted in the truncation + // draw its own highlight. + int length = m_truncation != cNoTruncation ? m_truncation : m_len; context->clip(IntRect(m_x + tx, y + ty, m_width, h)); - context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, + context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, length, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos); context->restore(); } @@ -584,13 +614,13 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, Color c = Color(225, 221, 85); - updateGraphicsContext(context, c, c, 0); // Don't draw text at all! + updateGraphicsContext(context, c, c, 0, style->colorSpace()); // Don't draw text at all! int y = selectionTop(); int h = selectionHeight(); context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos); context->restore(); } @@ -660,6 +690,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in setClip = true; } + ColorSpace colorSpace = renderer()->style()->colorSpace(); bool setShadow = false; do { @@ -669,24 +700,24 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in ty -= extraOffset; extraOffset = 0; } - context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color); + context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color, colorSpace); setShadow = true; shadow = shadow->next; } if (deco & UNDERLINE) { - context->setStrokeColor(underline); + context->setStrokeColor(underline, colorSpace); context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. context->drawLineForText(IntPoint(tx, ty + baseline + 1), width, isPrinting); } if (deco & OVERLINE) { - context->setStrokeColor(overline); + context->setStrokeColor(overline, colorSpace); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), width, isPrinting); } if (deco & LINE_THROUGH) { - context->setStrokeColor(linethrough); + context->setStrokeColor(linethrough, colorSpace); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty + 2 * baseline / 3), width, isPrinting); } @@ -698,7 +729,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in context->clearShadow(); } -void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font, bool grammar) +void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font, bool grammar) { // Never print spelling/grammar markers (5327887) if (textRenderer()->document()->printing()) @@ -737,8 +768,11 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in // Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to // display a toolTip. We don't do this for misspelling markers. - if (grammar) + if (grammar) { + markerRect.move(-tx, -ty); + markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); + } } // IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to @@ -761,7 +795,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in pt->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar); } -void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font) +void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font) { // Use same y positioning and height as for selection, so that when the selection and this highlight are on // the same word there are no pieces sticking out. @@ -771,10 +805,10 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do int sPos = max(marker.startOffset - m_start, (unsigned)0); int ePos = min(marker.endOffset - m_start, (unsigned)m_len); TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); - IntPoint startPoint = IntPoint(m_x + tx, y + ty); - // Always compute and store the rect associated with this marker - IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); + // Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates. + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(m_x, y), h, sPos, ePos)); + markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); // Optionally highlight the text @@ -783,14 +817,14 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do renderer()->theme()->platformActiveTextSearchHighlightColor() : renderer()->theme()->platformInactiveTextSearchHighlightColor(); pt->save(); - updateGraphicsContext(pt, color, color, 0); // Don't draw text at all! + updateGraphicsContext(pt, color, color, 0, style->colorSpace()); // Don't draw text at all! pt->clip(IntRect(tx + m_x, ty + y, m_width, h)); - pt->drawHighlightForText(font, run, startPoint, h, color, sPos, ePos); + pt->drawHighlightForText(font, run, IntPoint(m_x + tx, y + ty), h, color, style->colorSpace(), sPos, ePos); pt->restore(); } } -void InlineTextBox::computeRectForReplacementMarker(int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font) +void InlineTextBox::computeRectForReplacementMarker(int /*tx*/, int /*ty*/, const DocumentMarker& marker, RenderStyle* style, const Font& font) { // Replacement markers are not actually drawn, but their rects need to be computed for hit testing. int y = selectionTop(); @@ -799,10 +833,11 @@ void InlineTextBox::computeRectForReplacementMarker(int tx, int ty, DocumentMark int sPos = max(marker.startOffset - m_start, (unsigned)0); int ePos = min(marker.endOffset - m_start, (unsigned)m_len); TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); - IntPoint startPoint = IntPoint(m_x + tx, y + ty); + IntPoint startPoint = IntPoint(m_x, y); // Compute and store the rect associated with this marker. IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); + markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox(); renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); } @@ -817,7 +852,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re // Give any document markers that touch this run a chance to draw before the text has been drawn. // Note end() points at the last char, not one past it like endOffset and ranges do. for ( ; markerIt != markers.end(); markerIt++) { - DocumentMarker marker = *markerIt; + const DocumentMarker& marker = *markerIt; // Paint either the background markers or the foreground markers, but not both switch (marker.type) { @@ -911,7 +946,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int start += 1; width -= 2; - ctx->setStrokeColor(underline.color); + ctx->setStrokeColor(underline.color, renderer()->style()->colorSpace()); ctx->setStrokeThickness(lineThickness); ctx->drawLineForText(IntPoint(tx + start, ty + height() - lineThickness), width, textRenderer()->document()->printing()); } @@ -936,7 +971,7 @@ int InlineTextBox::textPos() const if (x() == 0) return 0; - RenderBlock *blockElement = renderer()->containingBlock(); + RenderBlock* blockElement = renderer()->containingBlock(); return direction() == RTL ? x() - blockElement->borderRight() - blockElement->paddingRight() : x() - blockElement->borderLeft() - blockElement->paddingLeft(); } @@ -947,7 +982,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const return 0; RenderText* text = toRenderText(renderer()); - RenderStyle *style = text->style(m_firstLine); + RenderStyle* style = text->style(m_firstLine); const Font* f = &style->font(); return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), _x - m_x, includePartialGlyphs); diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h index 3bbb4537ad..96ca4c3873 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h @@ -23,7 +23,7 @@ #ifndef InlineTextBox_h #define InlineTextBox_h -#include "InlineRunBox.h" +#include "InlineBox.h" #include "RenderText.h" // so textRenderer() can be inline namespace WebCore { @@ -34,21 +34,25 @@ const unsigned short cNoTruncation = USHRT_MAX; const unsigned short cFullTruncation = USHRT_MAX - 1; // Helper functions shared by InlineTextBox / SVGRootInlineBox -void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness); +void updateGraphicsContext(GraphicsContext*, const Color& fillColor, const Color& strokeColor, float strokeThickness, ColorSpace); Color correctedTextColor(Color textColor, Color backgroundColor); -class InlineTextBox : public InlineRunBox { +class InlineTextBox : public InlineBox { public: InlineTextBox(RenderObject* obj) - : InlineRunBox(obj) + : InlineBox(obj) + , m_prevTextBox(0) + , m_nextTextBox(0) , m_start(0) , m_len(0) , m_truncation(cNoTruncation) { } - InlineTextBox* nextTextBox() const { return static_cast<InlineTextBox*>(nextLineBox()); } - InlineTextBox* prevTextBox() const { return static_cast<InlineTextBox*>(prevLineBox()); } + InlineTextBox* prevTextBox() const { return m_prevTextBox; } + InlineTextBox* nextTextBox() const { return m_nextTextBox; } + void setNextTextBox(InlineTextBox* n) { m_nextTextBox = n; } + void setPreviousTextBox(InlineTextBox* p) { m_prevTextBox = p; } unsigned start() const { return m_start; } unsigned end() const { return m_len ? m_start + m_len - 1 : m_start; } @@ -62,6 +66,8 @@ public: void setFallbackFonts(const HashSet<const SimpleFontData*>&); void takeFallbackFonts(Vector<const SimpleFontData*>&); + unsigned short truncation() { return m_truncation; } + private: virtual int selectionTop(); virtual int selectionHeight(); @@ -114,6 +120,9 @@ public: bool containsCaretOffset(int offset) const; // false for offset after line break private: + InlineTextBox* m_prevTextBox; // The previous box that also uses our RenderObject + InlineTextBox* m_nextTextBox; // The next box that also uses our RenderObject + int m_start; unsigned short m_len; @@ -131,9 +140,9 @@ protected: private: void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData*); void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&); - void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&, bool grammar); - void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&); - void computeRectForReplacementMarker(int tx, int ty, DocumentMarker, RenderStyle*, const Font&); + void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&, bool grammar); + void paintTextMatchMarker(GraphicsContext*, int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&); + void computeRectForReplacementMarker(int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&); }; inline RenderText* InlineTextBox::textRenderer() const diff --git a/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp index 883f74d563..c94e77b702 100644 --- a/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp @@ -62,20 +62,17 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& m_clipped = !fixed && prev->m_clipped; if (m_clipped) m_clipRect = prev->m_clipRect; + if (renderer->hasOverflowClip()) { - int x = m_offset.width(); - int y = m_offset.height(); RenderLayer* layer = renderer->layer(); - IntRect clipRect(x, y, layer->width(), layer->height()); - clipRect.move(renderer->view()->layoutDelta()); + IntRect clipRect(toPoint(m_offset) + renderer->view()->layoutDelta(), layer->size()); if (m_clipped) m_clipRect.intersect(clipRect); else { m_clipRect = clipRect; m_clipped = true; } - layer->subtractScrolledContentOffset(x, y); - m_offset = IntSize(x, y); + m_offset -= layer->scrolledContentOffset(); } m_layoutDelta = m_next->m_layoutDelta; diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp index 9611660427..569f214845 100644 --- a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp @@ -38,6 +38,7 @@ #include "HTMLNames.h" #include "LocalizedStrings.h" #include "MouseEvent.h" +#include "Page.h" #include "RenderMedia.h" #include "RenderSlider.h" #include "RenderTheme.h" @@ -347,6 +348,9 @@ MediaControlInputElement::MediaControlInputElement(Document* document, PseudoId case MEDIA_CONTROLS_VOLUME_SLIDER: m_displayType = MediaVolumeSlider; break; + case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON: + m_displayType = MediaShowClosedCaptionsButton; + break; default: ASSERT_NOT_REACHED(); break; @@ -500,7 +504,7 @@ void MediaControlSeekButtonElement::defaultEventHandler(Event* event) m_capturing = true; frame->eventHandler()->setCapturingMouseEventsNode(this); } - m_mediaElement->pause(); + m_mediaElement->pause(event->fromUserGesture()); m_seekTimer.startRepeating(cSeekRepeatDelay); event->setDefaultHandled(); } else if (event->type() == eventNames().mouseupEvent) { @@ -577,6 +581,29 @@ void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event // ---------------------------- +MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* doc, HTMLMediaElement* element) + : MediaControlInputElement(doc, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, "button", element) +{ +} + +void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) +{ + if (event->type() == eventNames().clickEvent) { + m_mediaElement->setClosedCaptionsVisible(!m_mediaElement->closedCaptionsVisible()); + setChecked(m_mediaElement->closedCaptionsVisible()); + event->setDefaultHandled(); + } + HTMLInputElement::defaultEventHandler(event); +} + +void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() +{ + setDisplayType(m_mediaElement->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); +} + + +// ---------------------------- + MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element) : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element) { @@ -588,6 +615,9 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) return; + if (!attached()) + return; + if (event->type() == eventNames().mousedownEvent) m_mediaElement->beginScrubbing(); @@ -633,6 +663,9 @@ void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) return; + if (!attached()) + return; + MediaControlInputElement::defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) @@ -649,10 +682,9 @@ void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) void MediaControlVolumeSliderElement::update() { float volume = m_mediaElement->volume(); - if (value().toFloat() != volume) { + if (value().toFloat() != volume) setValue(String::number(volume)); - MediaControlInputElement::update(); - } + MediaControlInputElement::update(); } // ---------------------------- @@ -705,30 +737,9 @@ void MediaControlTimeDisplayElement::setVisible(bool visible) renderer()->setStyle(style.get()); } -String MediaControlTimeDisplayElement::formatTime(float time) -{ - if (!isfinite(time)) - time = 0; - int seconds = (int)fabsf(time); - int hours = seconds / (60 * 60); - int minutes = (seconds / 60) % 60; - seconds %= 60; - if (hours) { - if (hours > 9) - return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); - - return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); - } - - return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds); -} - void MediaControlTimeDisplayElement::setCurrentValue(float time) { m_currentValue = time; - - ExceptionCode ec; - setInnerText(formatTime(m_currentValue), ec); } diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h index 8b297733fd..21831ceef7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h +++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h @@ -54,6 +54,8 @@ enum MediaControlElementType { MediaSliderThumb, MediaRewindButton, MediaReturnToRealtimeButton, + MediaShowClosedCaptionsButton, + MediaHideClosedCaptionsButton, MediaUnMuteButton, MediaPauseButton, MediaTimelineContainer, @@ -221,6 +223,15 @@ public: // ---------------------------- +class MediaControlToggleClosedCaptionsButtonElement : public MediaControlInputElement { +public: + MediaControlToggleClosedCaptionsButtonElement(Document*, HTMLMediaElement*); + virtual void defaultEventHandler(Event*); + virtual void updateDisplayType(); +}; + +// ---------------------------- + class MediaControlTimelineElement : public MediaControlInputElement { public: MediaControlTimelineElement(Document*, HTMLMediaElement*); @@ -257,8 +268,6 @@ public: float currentValue() const { return m_currentValue; } private: - String formatTime(float time); - float m_currentValue; bool m_isVisible; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp index 214fb096a0..ababcfd40f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp @@ -1,8 +1,6 @@ /* Copyright (C) 2007 Rob Buis <buis@kde.org> - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either diff --git a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h index 3d8939a76a..c17c19c7b7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h +++ b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h @@ -1,8 +1,6 @@ /* Copyright (C) 2007 Rob Buis <buis@kde.org> - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp index 34325d4be9..1dafb2f1c5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp @@ -114,7 +114,7 @@ void RenderArena::free(size_t size, void* ptr) // Use standard free so that memory debugging tools work. RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1; ASSERT(header->signature == signature); - ASSERT(header->size == size); + ASSERT_UNUSED(size, header->size == size); ASSERT(header->arena == this); header->signature = signatureDead; ::free(header); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderArena.h b/src/3rdparty/webkit/WebCore/rendering/RenderArena.h index 3c27d15455..32139fbd77 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderArena.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderArena.h @@ -36,12 +36,13 @@ #define RenderArena_h #include "Arena.h" +#include <wtf/Noncopyable.h> namespace WebCore { static const size_t gMaxRecycledSize = 400; -class RenderArena { +class RenderArena : public Noncopyable { public: RenderArena(unsigned arenaSize = 4096); ~RenderArena(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp index e05c8b4733..340d6b7927 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp @@ -1,6 +1,4 @@ /** - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * Copyright (C) 2006 Apple Computer, Inc. * @@ -64,7 +62,7 @@ int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const return s->font().lineSpacing(); } if (lh.isPercent()) - return lh.calcMinValue(s->fontSize(), true); + return lh.calcMinValue(s->fontSize()); return lh.value(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.h b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h index 7eae8ea407..8850d4693f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBR.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * * This library is free software; you can redistribute it and/or diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp index d5bb7787c4..a7b8a0227f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -44,6 +44,7 @@ #include "RenderView.h" #include "SelectionController.h" #include "Settings.h" +#include "TransformState.h" #include <wtf/StdLibExtras.h> using namespace std; @@ -58,13 +59,7 @@ static const int verticalLineClickFudgeFactor = 3; using namespace HTMLNames; -static void moveChild(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* from, RenderObjectChildList* fromChildList, RenderObject* child) -{ - ASSERT(from == child->parent()); - toChildList->appendChildNode(to, fromChildList->removeChildNode(from, child, false), false); -} - -struct ColumnInfo { +struct ColumnInfo : public Noncopyable { ColumnInfo() : m_desiredColumnWidth(0) , m_desiredColumnCount(1) @@ -188,7 +183,7 @@ void RenderBlock::destroy() // that will outlast this block. In the non-anonymous block case those // children will be destroyed by the time we return from this function. if (isAnonymousBlock()) { - for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) { + for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) { while (InlineBox* childBox = box->firstChild()) childBox->remove(); } @@ -266,8 +261,14 @@ void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId) void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) { // Make sure we don't append things after :after-generated content if we have it. - if (!beforeChild && isAfterContent(lastChild())) - beforeChild = lastChild(); + if (!beforeChild) { + RenderObject* lastRenderer = lastChild(); + + if (isAfterContent(lastRenderer)) + beforeChild = lastRenderer; + else if (lastRenderer && lastRenderer->isAnonymousBlock() && isAfterContent(lastRenderer->lastChild())) + beforeChild = lastRenderer->lastChild(); + } bool madeBoxesNonInline = false; @@ -402,6 +403,44 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox() m_lineBoxes.appendLineBox(rootBox); return rootBox; } + +void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child) +{ + ASSERT(this == child->parent()); + toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); +} + +void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child) +{ + ASSERT(this == child->parent()); + ASSERT(!beforeChild || to == beforeChild->parent()); + toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); +} + +void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList) +{ + RenderObject* nextChild = children()->firstChild(); + while (nextChild) { + RenderObject* child = nextChild; + nextChild = child->nextSibling(); + toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); + } +} + +void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild) +{ + ASSERT(!beforeChild || to == beforeChild->parent()); + if (!beforeChild) { + moveAllChildrenTo(to, toChildList); + return; + } + RenderObject* nextChild = children()->firstChild(); + while (nextChild) { + RenderObject* child = nextChild; + nextChild = child->nextSibling(); + toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); + } +} void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) { @@ -439,9 +478,9 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) RenderObject* no = o; o = no->nextSibling(); - moveChild(block, block->children(), this, children(), no); + moveChildTo(block, block->children(), no); } - moveChild(block, block->children(), this, children(), inlineRunEnd); + moveChildTo(block, block->children(), inlineRunEnd); } #ifndef NDEBUG @@ -509,20 +548,12 @@ void RenderBlock::removeChild(RenderObject* oldChild) // Take all the children out of the |next| block and put them in // the |prev| block. prev->setNeedsLayoutAndPrefWidthsRecalc(); - RenderObject* o = next->firstChild(); - RenderBlock* nextBlock = toRenderBlock(next); RenderBlock* prevBlock = toRenderBlock(prev); - while (o) { - RenderObject* no = o; - o = no->nextSibling(); - moveChild(prevBlock, prevBlock->children(), nextBlock, nextBlock->children(), no); - } - + nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children()); + // Delete the now-empty block's lines and nuke it. nextBlock->deleteLineBoxTree(); - - // Nuke the now-empty block. - next->destroy(); + nextBlock->destroy(); } RenderBox::removeChild(oldChild); @@ -535,17 +566,15 @@ void RenderBlock::removeChild(RenderObject* oldChild) setNeedsLayoutAndPrefWidthsRecalc(); RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); setChildrenInline(true); - RenderObject* o = anonBlock->firstChild(); - while (o) { - RenderObject* no = o; - o = no->nextSibling(); - moveChild(this, children(), anonBlock, anonBlock->children(), no); - } - + anonBlock->moveAllChildrenTo(this, children()); // Delete the now-empty block's lines and nuke it. anonBlock->deleteLineBoxTree(); anonBlock->destroy(); } + + // If this was our last child be sure to clear out our line boxes. + if (childrenInline() && !firstChild()) + lineBoxes()->deleteLineBoxes(renderArena()); } bool RenderBlock::isSelfCollapsingBlock() const @@ -609,15 +638,15 @@ void RenderBlock::finishDelayUpdateScrollInfo() if (gDelayUpdateScrollInfo == 0) { ASSERT(gDelayedUpdateScrollInfoSet); - for (DelayedUpdateScrollInfoSet::iterator it = gDelayedUpdateScrollInfoSet->begin(); it != gDelayedUpdateScrollInfoSet->end(); ++it) { + OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet); + gDelayedUpdateScrollInfoSet = 0; + + for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { RenderBlock* block = *it; if (block->hasOverflowClip()) { block->layer()->updateScrollInfoAfterLayout(); } } - - delete gDelayedUpdateScrollInfoSet; - gDelayedUpdateScrollInfoSet = 0; } } @@ -747,8 +776,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (previousHeight != height()) relayoutChildren = true; - // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't - // able to be propagated up the render tree yet. Overflow information is however. This check is designed to catch anyone + // This check is designed to catch anyone // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor. if (isRoot() || expandsToEncloseOverhangingFloats()) addOverflowFromFloats(); @@ -788,11 +816,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (hasOverflowClip()) { // Adjust repaint rect for scroll offset - int x = repaintRect.x(); - int y = repaintRect.y(); - layer()->subtractScrolledContentOffset(x, y); - repaintRect.setX(x); - repaintRect.setY(y); + repaintRect.move(-layer()->scrolledContentOffset()); // Don't allow this rect to spill out of our overflow box. repaintRect.intersect(IntRect(0, 0, width(), height())); @@ -860,7 +884,11 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg } y += (collapsedTopPos - collapsedTopNeg) - marginTop; } - child->layer()->setStaticY(y); + RenderLayer* childLayer = child->layer(); + if (childLayer->staticY() != y) { + child->layer()->setStaticY(y); + child->setChildNeedsLayout(true, false); + } } } @@ -949,7 +977,7 @@ bool RenderBlock::handleRunInChild(RenderBox* child) // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already // been regenerated by the new inline. for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { - if (runInIsGenerated || runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER) { + if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) { blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. } @@ -1512,7 +1540,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with // z-index. We paint after we painted the background/border, so that the scrollbars will // sit above the background/border. - if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground)) + if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo)) layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); } @@ -1630,9 +1658,18 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Check for page-break-before: always, and if it's set, break and bail. - if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && - inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && - (ty + child->y()) < paintInfo.rect.bottom()) { + if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS + && (ty + child->y()) > paintInfo.rect.y() + && (ty + child->y()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y(), this, true); + return; + } + + // Check for page-break-inside: avoid, and it it's set, break and bail. + if (isPrinting && !childrenInline() && child->style()->pageBreakInside() == PBAVOID + && ty + child->y() > paintInfo.rect.y() + && ty + child->y() < paintInfo.rect.bottom() + && ty + child->y() + child->height() > paintInfo.rect.bottom()) { view()->setBestTruncatedAt(ty + child->y(), this, true); return; } @@ -1641,9 +1678,9 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) child->paint(info, tx, ty); // Check for page-break-after: always, and if it's set, break and bail. - if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && - inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && - (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { + if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS + && (ty + child->y() + child->height()) > paintInfo.rect.y() + && (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); return; } @@ -1663,7 +1700,7 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ offsetForContents(tx, ty); if (type == CursorCaret) - document()->frame()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); + document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); else document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); } @@ -1690,11 +1727,14 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) if (paintPhase == PaintPhaseBlockBackground) return; - // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s + // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div). int scrolledX = tx; int scrolledY = ty; - if (hasOverflowClip()) - layer()->subtractScrolledContentOffset(scrolledX, scrolledY); + if (hasOverflowClip()) { + IntSize offset = layer()->scrolledContentOffset(); + scrolledX -= offset.width(); + scrolledY -= offset.height(); + } // 2. paint contents if (paintPhase != PaintPhaseSelfOutline) { @@ -1896,23 +1936,26 @@ bool RenderBlock::isSelectionRoot() const return false; } -GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* /*repaintContainer*/) +GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer) { ASSERT(!needsLayout()); if (!shouldPaintSelectionGaps()) return GapRects(); - // FIXME: this is broken with transforms and a non-null repaintContainer - FloatPoint absContentPoint = localToAbsolute(FloatPoint()); + // FIXME: this is broken with transforms + TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); + mapLocalToContainer(repaintContainer, false, false, transformState); + IntPoint offsetFromRepaintContainer = roundedIntPoint(transformState.mappedPoint()); + if (hasOverflowClip()) - absContentPoint -= layer()->scrolledContentOffset(); + offsetFromRepaintContainer -= layer()->scrolledContentOffset(); int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); - return fillSelectionGaps(this, absContentPoint.x(), absContentPoint.y(), absContentPoint.x(), absContentPoint.y(), lastTop, lastLeft, lastRight); + return fillSelectionGaps(this, offsetFromRepaintContainer.x(), offsetFromRepaintContainer.y(), offsetFromRepaintContainer.x(), offsetFromRepaintContainer.y(), lastTop, lastLeft, lastRight); } void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) @@ -1922,7 +1965,18 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); paintInfo.context->save(); - fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo); + IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo); + if (!gapRectsBounds.isEmpty()) { + if (RenderLayer* layer = enclosingLayer()) { + gapRectsBounds.move(IntSize(-tx, -ty)); + if (!hasLayer()) { + FloatRect localBounds(gapRectsBounds); + gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox(); + gapRectsBounds.move(layer->scrolledContentOffset()); + } + layer->addBlockSelectionGapsBounds(gapRectsBounds); + } + } paintInfo.context->restore(); } } @@ -2109,7 +2163,7 @@ IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, return IntRect(); IntRect gapRect(xPos, yPos, width, height); if (paintInfo && selObj->style()->visibility() == VISIBLE) - paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor()); + paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); return gapRect; } @@ -2130,7 +2184,7 @@ IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int las IntRect gapRect(left, top, width, height); if (paintInfo) - paintInfo->context->fillRect(gapRect, selectionBackgroundColor()); + paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace()); return gapRect; } @@ -2146,7 +2200,7 @@ IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yP IntRect gapRect(left, top, width, height); if (paintInfo) - paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor()); + paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); return gapRect; } @@ -2162,7 +2216,7 @@ IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int y IntRect gapRect(left, top, width, height); if (paintInfo) - paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor()); + paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); return gapRect; } @@ -2304,8 +2358,14 @@ void RenderBlock::removeFloatingObject(RenderBox* o) DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); while (it.current()) { if (it.current()->m_renderer == o) { - if (childrenInline()) - markLinesDirtyInVerticalRange(0, it.current()->m_bottom); + if (childrenInline()) { + int bottom = it.current()->m_bottom; + // Special-case zero- and less-than-zero-height floats: those don't touch + // the line that they're on, but it still needs to be dirtied. This is + // accomplished by pretending they have a height of 1. + bottom = max(bottom, it.current()->m_top + 1); + markLinesDirtyInVerticalRange(0, bottom); + } m_floatingObjects->removeRef(it.current()); } ++it; @@ -2584,30 +2644,15 @@ RenderBlock::floatBottom() const return bottom; } -IntRect RenderBlock::floatRect() const -{ - IntRect result; - if (!m_floatingObjects || hasOverflowClip() || hasColumns()) - return result; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (; (r = it.current()); ++it) { - if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { - IntRect childRect = r->m_renderer->visibleOverflowRect(); - childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); - result.unite(childRect); - } - } - - return result; -} - int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { int bottom = includeSelf && width() > 0 ? height() : 0; if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) return bottom; + + if (!firstChild() && (!width() || !height())) + return bottom; if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. @@ -2700,6 +2745,9 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) return right; + if (!firstChild() && (!width() || !height())) + return right; + if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. // For now, we have to descend into all the children, since we may have a huge abs div inside @@ -2764,7 +2812,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel if (!includeSelf) { right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset); if (childrenInline()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { + for (InlineFlowBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { int childRightEdge = currBox->x() + currBox->width(); // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. @@ -2794,6 +2842,9 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) return left; + if (!firstChild() && (!width() || !height())) + return left; + if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. // For now, we have to descend into all the children, since we may have a huge abs div inside @@ -2856,7 +2907,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf } if (!includeSelf && firstLineBox()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) + for (InlineFlowBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) left = min(left, (int)currBox->x() + relativeOffset); } @@ -2891,7 +2942,7 @@ RenderBlock::rightBottom() return bottom; } -void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom) +void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest) { if (top >= bottom) return; @@ -2903,7 +2954,7 @@ void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom) lowestDirtyLine = lowestDirtyLine->prevRootBox(); } - while (afterLowest && afterLowest->blockHeight() >= top) { + while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) { afterLowest->markDirty(); afterLowest = afterLowest->prevRootBox(); } @@ -2965,8 +3016,8 @@ void RenderBlock::clearFloats() addIntrudingFloats(block, xoffset, offset); if (childrenInline()) { - int changeTop = INT_MAX; - int changeBottom = INT_MIN; + int changeTop = numeric_limits<int>::max(); + int changeBottom = numeric_limits<int>::min(); if (m_floatingObjects) { for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); @@ -3143,6 +3194,32 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove } } +int RenderBlock::visibleTopOfHighestFloatExtendingBelow(int bottom, int maxHeight) const +{ + int top = bottom; + if (m_floatingObjects) { + FloatingObject* floatingObject; + for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); (floatingObject = it.current()); ++it) { + RenderBox* floatingBox = floatingObject->m_renderer; + IntRect visibleOverflow = floatingBox->visibleOverflowRect(); + visibleOverflow.move(floatingBox->x(), floatingBox->y()); + if (visibleOverflow.y() < top && visibleOverflow.bottom() > bottom && visibleOverflow.height() <= maxHeight && floatingBox->containingBlock() == this) + top = visibleOverflow.y(); + } + } + + if (!childrenInline()) { + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (child->isFloatingOrPositioned() || !child->isRenderBlock()) + continue; + RenderBlock* childBlock = toRenderBlock(child); + top = min(top, childBlock->y() + childBlock->visibleTopOfHighestFloatExtendingBelow(bottom - childBlock->y(), maxHeight)); + } + } + + return top; +} + int RenderBlock::getClearDelta(RenderBox* child, int yPos) { // There is no need to compute clearance if we have no floats. @@ -3167,18 +3244,35 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos) } // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default). - // FIXME: Note that the remaining space checks aren't quite accurate, since you should be able to clear only some floats (the minimum # needed - // to fit) and not all (we should be using nextFloatBottomBelow and looping). int result = clearSet ? max(0, bottom - yPos) : 0; if (!result && child->avoidsFloats()) { - int oldYPos = child->y(); - int oldWidth = child->width(); - child->setY(yPos); - child->calcWidth(); - if (child->width() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth()) - result = max(0, floatBottom() - yPos); - child->setY(oldYPos); - child->setWidth(oldWidth); + int availableWidth = this->availableWidth(); + if (child->minPrefWidth() > availableWidth) + return 0; + + int y = yPos; + while (true) { + int widthAtY = lineWidth(y, false); + if (widthAtY == availableWidth) + return y - yPos; + + int oldChildY = child->y(); + int oldChildWidth = child->width(); + child->setY(y); + child->calcWidth(); + int childWidthAtY = child->width(); + child->setY(oldChildY); + child->setWidth(oldChildWidth); + + if (childWidthAtY <= widthAtY) + return y - yPos; + + y = nextFloatBottomBelow(y); + ASSERT(y >= yPos); + if (y < yPos) + break; + } + ASSERT_NOT_REACHED(); } return result; } @@ -3217,8 +3311,11 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Hit test descendants first. int scrolledX = tx; int scrolledY = ty; - if (hasOverflowClip()) - layer()->subtractScrolledContentOffset(scrolledX, scrolledY); + if (hasOverflowClip()) { + IntSize offset = layer()->scrolledContentOffset(); + scrolledX -= offset.width(); + scrolledY -= offset.height(); + } // Hit test contents if we don't have columns. if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) @@ -3395,7 +3492,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& RootInlineBox* firstRootBoxWithChildren = 0; RootInlineBox* lastRootBoxWithChildren = 0; for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { - if (!root->firstChild()) + if (!root->firstLeafChild()) continue; if (!firstRootBoxWithChildren) firstRootBoxWithChildren = root; @@ -3493,15 +3590,16 @@ VisiblePosition RenderBlock::positionForPoint(const IntPoint& point) void RenderBlock::offsetForContents(int& tx, int& ty) const { + IntPoint contentsPoint(tx, ty); + if (hasOverflowClip()) - layer()->addScrolledContentOffset(tx, ty); + contentsPoint += layer()->scrolledContentOffset(); - if (hasColumns()) { - IntPoint contentsPoint(tx, ty); + if (hasColumns()) adjustPointToColumnContents(contentsPoint); - tx = contentsPoint.x(); - ty = contentsPoint.y(); - } + + tx = contentsPoint.x(); + ty = contentsPoint.y(); } int RenderBlock::availableWidth() const @@ -3542,11 +3640,15 @@ void RenderBlock::calcColumnWidth() desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; } else if (colGap < availWidth) { desiredColumnCount = availWidth / colGap; + if (desiredColumnCount < 1) + desiredColumnCount = 1; desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; } } else if (style()->hasAutoColumnCount()) { if (colWidth < availWidth) { desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); + if (desiredColumnCount < 1) + desiredColumnCount = 1; desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; } } else { @@ -3556,6 +3658,8 @@ void RenderBlock::calcColumnWidth() desiredColumnWidth = colWidth; } else if (colWidth < availWidth) { desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); + if (desiredColumnCount < 1) + desiredColumnCount = 1; desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; } } @@ -3606,7 +3710,7 @@ Vector<IntRect>* RenderBlock::columnRects() const return &gColumnInfoMap->get(this)->m_columnRects; } -int RenderBlock::layoutColumns(int endOfContent) +int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight) { // Don't do anything if we have no columns if (!hasColumns()) @@ -3619,17 +3723,20 @@ int RenderBlock::layoutColumns(int endOfContent) bool computeIntrinsicHeight = (endOfContent == -1); - // Fill the columns in to the available height. Attempt to balance the height of the columns - int availableHeight = contentHeight(); - int colHeight = computeIntrinsicHeight ? availableHeight / desiredColumnCount : availableHeight; - + // Fill the columns in to the available height. Attempt to balance the height of the columns. // Add in half our line-height to help with best-guess initial balancing. int columnSlop = lineHeight(false) / 2; int remainingSlopSpace = columnSlop * desiredColumnCount; + int availableHeight = contentHeight(); + int colHeight; + if (computeIntrinsicHeight && requestedColumnHeight >= 0) + colHeight = requestedColumnHeight; + else if (computeIntrinsicHeight) + colHeight = availableHeight / desiredColumnCount + columnSlop; + else + colHeight = availableHeight; + int originalColHeight = colHeight; - if (computeIntrinsicHeight) - colHeight += columnSlop; - int colGap = columnGap(); // Compute a collection of column rects. @@ -3645,7 +3752,8 @@ int RenderBlock::layoutColumns(int endOfContent) int currY = top; unsigned colCount = desiredColumnCount; int maxColBottom = borderTop() + paddingTop(); - int contentBottom = top + availableHeight; + int contentBottom = top + availableHeight; + int minimumColumnHeight = -1; for (unsigned i = 0; i < colCount; i++) { // If we aren't constrained, then the last column can just get all the remaining space. if (computeIntrinsicHeight && i == colCount - 1) @@ -3653,11 +3761,13 @@ int RenderBlock::layoutColumns(int endOfContent) // This represents the real column position. IntRect colRect(currX, top, desiredColumnWidth, colHeight); - + + int truncationPoint = visibleTopOfHighestFloatExtendingBelow(currY + colHeight, colHeight); + // For the simulated paint, we pretend like everything is in one long strip. - IntRect pageRect(left, currY, desiredColumnWidth, colHeight); + IntRect pageRect(left, currY, desiredColumnWidth, truncationPoint - currY); v->setPrintRect(pageRect); - v->setTruncatedAt(currY + colHeight); + v->setTruncatedAt(truncationPoint); GraphicsContext context((PlatformGraphicsContext*)0); RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0); @@ -3665,9 +3775,14 @@ int RenderBlock::layoutColumns(int endOfContent) paintObject(paintInfo, 0, 0); setHasColumns(true); + if (computeIntrinsicHeight && v->minimumColumnHeight() > originalColHeight) { + // The initial column height was too small to contain one line of text. + minimumColumnHeight = max(minimumColumnHeight, v->minimumColumnHeight()); + } + int adjustedBottom = v->bestTruncatedAt(); if (adjustedBottom <= currY) - adjustedBottom = currY + colHeight; + adjustedBottom = truncationPoint; colRect.setHeight(adjustedBottom - currY); @@ -3701,6 +3816,11 @@ int RenderBlock::layoutColumns(int endOfContent) colCount++; } + if (minimumColumnHeight >= 0) { + // If originalColHeight was too small, we need to try to layout again. + return layoutColumns(endOfContent, minimumColumnHeight); + } + int overflowRight = max(width(), currX - colGap); int overflowLeft = min(0, currX + desiredColumnWidth + colGap); int overflowHeight = maxColBottom; @@ -3737,8 +3857,20 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const // Add in half the column gap to the left and right of the rect. IntRect colRect = colRects->at(i); IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height()); - - if (gapAndColumnRect.contains(point)) { + + if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.right()) { + // FIXME: The clamping that follows is not completely right for right-to-left + // content. + // Clamp everything above the column to its top left. + if (point.y() < gapAndColumnRect.y()) + point = gapAndColumnRect.location(); + // Clamp everything below the column to the next column's top left. If there is + // no next column, this still maps to just after this column. + else if (point.y() >= gapAndColumnRect.bottom()) { + point = gapAndColumnRect.location(); + point.move(0, gapAndColumnRect.height()); + } + // We're inside the column. Translate the x and y into our column coordinate space. point.move(columnPoint.x() - colRect.x(), yOffset); return; @@ -3786,6 +3918,31 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const r = result; } +void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const +{ + if (!hasColumns()) + return; + + // FIXME: This is incorrect for right-to-left columns. + + Vector<IntRect>& columnRects = *this->columnRects(); + + int gapWidth = columnGap(); + int xOffset = 0; + int yOffset = 0; + size_t columnCount = columnRects.size(); + for (size_t i = 0; i < columnCount; ++i) { + IntRect columnRect = columnRects[i]; + if (point.y() < columnRect.bottom() + yOffset) { + offset.expand(xOffset, -yOffset); + return; + } + + xOffset += columnRect.width() + gapWidth; + yOffset += columnRect.height(); + } +} + void RenderBlock::calcPrefWidths() { ASSERT(prefWidthsDirty()); @@ -4181,6 +4338,10 @@ void RenderBlock::calcInlinePrefWidths() } else inlineMax += childMax; } + + // Ignore spaces after a list marker. + if (child->isListMarker()) + stripFrontSpaces = true; } else { m_minPrefWidth = max(inlineMin, m_minPrefWidth); m_maxPrefWidth = max(inlineMax, m_maxPrefWidth); @@ -4484,7 +4645,7 @@ void RenderBlock::updateFirstLetter() // Drill into inlines looking for our first text child. RenderObject* currChild = firstLetterBlock->firstChild(); - while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) { + while (currChild && currChild->needsLayout() && ((!currChild->isReplaced() && !currChild->isRenderButton() && !currChild->isMenuList()) || currChild->isFloatingOrPositioned()) && !currChild->isText()) { if (currChild->isFloatingOrPositioned()) { if (currChild->style()->styleType() == FIRST_LETTER) break; @@ -4582,17 +4743,6 @@ void RenderBlock::updateFirstLetter() } } -bool RenderBlock::inRootBlockContext() const -{ - if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip()) - return false; - - if (isRoot() || isRenderView()) - return true; - - return containingBlock()->inRootBlockContext(); -} - // Helper methods for obtaining the last line, computing line counts and heights for line counts // (crawling into blocks). static bool shouldCheckLines(RenderObject* obj) @@ -4943,7 +5093,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* return IntRect(x, y, caretWidth, height); } -void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { // For blocks inside inlines, we go ahead and include margins so that we run right up to the // inline boxes above and below us (thus getting merged with them to form a single irregular @@ -4955,16 +5105,19 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox(); int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0; int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0; - graphicsContext->addFocusRingRect(IntRect(tx, ty - topMargin, - width(), height() + topMargin + bottomMargin)); - } else - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); + IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin); + if (!rect.isEmpty()) + rects.append(rect); + } else if (width() && height()) + rects.append(IntRect(tx, ty, width(), height())); if (!hasOverflowClip() && !hasControlClip()) { for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { int top = max(curr->lineTop(), curr->y()); int bottom = min(curr->lineBottom(), curr->y() + curr->height()); - graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + top, curr->width(), bottom - top)); + IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top); + if (!rect.isEmpty()) + rects.append(rect); } for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { @@ -4976,13 +5129,13 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in pos = curr->localToAbsolute(); else pos = FloatPoint(tx + box->x(), ty + box->y()); - box->addFocusRingRects(graphicsContext, pos.x(), pos.y()); + box->addFocusRingRects(rects, pos.x(), pos.y()); } } } if (inlineContinuation()) - inlineContinuation()->addFocusRingRects(graphicsContext, + inlineContinuation()->addFocusRingRects(rects, tx - x() + inlineContinuation()->containingBlock()->x(), ty - y() + inlineContinuation()->containingBlock()->y()); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h index 3300d01117..184f98384c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,7 +34,6 @@ namespace WebCore { class InlineIterator; class RenderInline; -class RootInlineBox; struct BidiRun; @@ -91,8 +90,6 @@ public: bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } bool containsFloat(RenderObject*); - IntRect floatRect() const; - int lineWidth(int y, bool firstLine) const; virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; @@ -130,6 +127,7 @@ public: void clearTruncation(); void adjustRectForColumns(IntRect&) const; + virtual void adjustForColumns(IntSize&, const IntPoint&) const; void addContinuationWithOutline(RenderInline*); @@ -140,7 +138,15 @@ public: // style from this RenderBlock. RenderBlock* createAnonymousBlock(bool isFlexibleBox = false) const; + static void appendRunsForObject(int start, int end, RenderObject*, InlineBidiResolver&); + static bool requiresLineBox(const InlineIterator&, bool isLineEmpty = true, bool previousLineBrokeCleanly = true); + protected: + void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child); + void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child); + void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList); + void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild); + int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); } int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); } int maxBottomPosMargin() const { return m_maxMargin ? m_maxMargin->m_bottomPos : MaxMargin::bottomPosDefault(this); } @@ -310,7 +316,6 @@ private: // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline // children. virtual RenderBlock* firstLineBlock() const; - bool inRootBlockContext() const; virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); virtual RenderStyle* outlineStyleForRepaint() const; @@ -349,12 +354,12 @@ private: virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); void adjustPointToColumnContents(IntPoint&) const; void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust - void markLinesDirtyInVerticalRange(int top, int bottom); + void markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest = 0); void newLine(EClear); @@ -366,13 +371,14 @@ private: void offsetForContents(int& tx, int& ty) const; void calcColumnWidth(); - int layoutColumns(int endOfContent = -1); + int layoutColumns(int endOfContent = -1, int requestedColumnHeight = -1); + int visibleTopOfHighestFloatExtendingBelow(int bottom, int maxHeight) const; bool expandsToEncloseOverhangingFloats() const; void updateScrollInfoAfterLayout(); - struct FloatingObject { + struct FloatingObject : Noncopyable { enum Type { FloatLeft, FloatRight @@ -488,7 +494,7 @@ private: RenderInline* m_inlineContinuation; // Allocated only when some of these fields have non-default values - struct MaxMargin { + struct MaxMargin : Noncopyable { MaxMargin(const RenderBlock* o) : m_topPos(topPosDefault(o)) , m_topNeg(topNegDefault(o)) @@ -514,6 +520,10 @@ private: RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>. mutable int m_lineHeight; + + // RenderRubyBase objects need to be able to split and merge, moving their children around + // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline). + friend class RenderRubyBase; }; inline RenderBlock* toRenderBlock(RenderObject* object) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlockLineLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBlockLineLayout.cpp index 19923f15c0..6e890606c5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlockLineLayout.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 Apple Inc. All right reserved. + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,12 +24,14 @@ #include "BidiResolver.h" #include "CharacterNames.h" +#include "InlineIterator.h" #include "InlineTextBox.h" #include "Logging.h" #include "RenderArena.h" #include "RenderInline.h" #include "RenderListMarker.h" #include "RenderView.h" +#include "TrailingFloatsRootInlineBox.h" #include "break_lines.h" #include <wtf/AlwaysInline.h> #include <wtf/RefCountedLeakCounter.h> @@ -44,36 +47,6 @@ namespace WebCore { // We don't let our line box tree for a single line get any deeper than this. const unsigned cMaxLineDepth = 200; -class InlineIterator { -public: - InlineIterator() - : block(0) - , obj(0) - , pos(0) - , nextBreakablePosition(-1) - { - } - - InlineIterator(RenderBlock* b, RenderObject* o, unsigned p) - : block(b) - , obj(o) - , pos(p) - , nextBreakablePosition(-1) - { - } - - void increment(InlineBidiResolver* resolver = 0); - bool atEnd() const; - - UChar current() const; - Direction direction() const; - - RenderBlock* block; - RenderObject* obj; - unsigned pos; - int nextBreakablePosition; -}; - static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) { bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline; @@ -98,247 +71,6 @@ static int inlineWidth(RenderObject* child, bool start = true, bool end = true) return extraWidth; } -struct BidiRun : BidiCharacterRun { - BidiRun(int start, int stop, RenderObject* object, BidiContext* context, Direction dir) - : BidiCharacterRun(start, stop, context, dir) - , m_object(object) - , m_box(0) - { - } - - void destroy(); - - // Overloaded new operator. - void* operator new(size_t, RenderArena*) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void*, size_t); - - BidiRun* next() { return static_cast<BidiRun*>(m_next); } - -private: - // The normal operator new is disallowed. - void* operator new(size_t) throw(); - -public: - RenderObject* m_object; - InlineBox* m_box; -}; - -#ifndef NDEBUG -static RefCountedLeakCounter bidiRunCounter("BidiRun"); - -static bool inBidiRunDestroy; -#endif - -void BidiRun::destroy() -{ -#ifndef NDEBUG - inBidiRunDestroy = true; -#endif - RenderArena* renderArena = m_object->renderArena(); - delete this; -#ifndef NDEBUG - inBidiRunDestroy = false; -#endif - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*reinterpret_cast<size_t*>(this), this); -} - -void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw() -{ -#ifndef NDEBUG - bidiRunCounter.increment(); -#endif - return renderArena->allocate(sz); -} - -void BidiRun::operator delete(void* ptr, size_t sz) -{ -#ifndef NDEBUG - bidiRunCounter.decrement(); -#endif - ASSERT(inBidiRunDestroy); - - // Stash size where destroy() can find it. - *(size_t*)ptr = sz; -} - -// --------------------------------------------------------------------- - -inline bool operator==(const InlineIterator& it1, const InlineIterator& it2) -{ - return it1.pos == it2.pos && it1.obj == it2.obj; -} - -inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2) -{ - return it1.pos != it2.pos || it1.obj != it2.obj; -} - -static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0) -{ - RenderObject* next = 0; - bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; - bool endOfInline = false; - - while (current) { - next = 0; - if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) { - next = current->firstChild(); - if (next && resolver && next->isRenderInline()) { - EUnicodeBidi ub = next->style()->unicodeBidi(); - if (ub != UBNormal) { - TextDirection dir = next->style()->direction(); - Direction d = (ub == Embed - ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding) - : (dir == RTL ? RightToLeftOverride : LeftToRightOverride)); - resolver->embed(d); - } - } - } - - if (!next) { - if (!skipInlines && !oldEndOfInline && current->isRenderInline()) { - next = current; - endOfInline = true; - break; - } - - while (current && current != block) { - if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal) - resolver->embed(PopDirectionalFormat); - - next = current->nextSibling(); - if (next) { - if (resolver && next->isRenderInline()) { - EUnicodeBidi ub = next->style()->unicodeBidi(); - if (ub != UBNormal) { - TextDirection dir = next->style()->direction(); - Direction d = (ub == Embed - ? (dir == RTL ? RightToLeftEmbedding: LeftToRightEmbedding) - : (dir == RTL ? RightToLeftOverride : LeftToRightOverride)); - resolver->embed(d); - } - } - break; - } - - current = current->parent(); - if (!skipInlines && current && current != block && current->isRenderInline()) { - next = current; - endOfInline = true; - break; - } - } - } - - if (!next) - break; - - if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned() - || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. - && next->isRenderInline())) - break; - current = next; - } - - if (endOfInlinePtr) - *endOfInlinePtr = endOfInline; - - return next; -} - -static RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true) -{ - if (!block->firstChild()) - return 0; - - RenderObject* o = block->firstChild(); - if (o->isRenderInline()) { - if (resolver) { - EUnicodeBidi ub = o->style()->unicodeBidi(); - if (ub != UBNormal) { - TextDirection dir = o->style()->direction(); - Direction d = (ub == Embed - ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding) - : (dir == RTL ? RightToLeftOverride : LeftToRightOverride)); - resolver->embed(d); - } - } - if (skipInlines && o->firstChild()) - o = bidiNext(block, o, resolver, skipInlines); - else { - // Never skip empty inlines. - if (resolver) - resolver->commitExplicitEmbedding(); - return o; - } - } - - if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned()) - o = bidiNext(block, o, resolver, skipInlines); - - if (resolver) - resolver->commitExplicitEmbedding(); - return o; -} - -inline void InlineIterator::increment(InlineBidiResolver* resolver) -{ - if (!obj) - return; - if (obj->isText()) { - pos++; - if (pos >= toRenderText(obj)->textLength()) { - obj = bidiNext(block, obj, resolver); - pos = 0; - nextBreakablePosition = -1; - } - } else { - obj = bidiNext(block, obj, resolver); - pos = 0; - nextBreakablePosition = -1; - } -} - -template<> -inline void InlineBidiResolver::increment() -{ - current.increment(this); -} - -inline bool InlineIterator::atEnd() const -{ - return !obj; -} - -inline UChar InlineIterator::current() const -{ - if (!obj || !obj->isText()) - return 0; - - RenderText* text = toRenderText(obj); - if (pos >= text->textLength()) - return 0; - - return text->characters()[pos]; -} - -ALWAYS_INLINE Direction InlineIterator::direction() const -{ - if (UChar c = current()) - return Unicode::direction(c); - - if (obj && obj->isListMarker()) - return obj->style()->direction() == LTR ? LeftToRight : RightToLeft; - - return OtherNeutral; -} - -// ------------------------------------------------------------------------------------------------- - static void chopMidpointsAt(LineMidpointState& lineMidpointState, RenderObject* obj, unsigned pos) { if (!lineMidpointState.numMidpoints) @@ -396,7 +128,7 @@ static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterat midpoints[lineMidpointState.numMidpoints++] = midpoint; } -static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) +void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) { if (start > end || obj->isFloating() || (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline())) @@ -439,36 +171,6 @@ static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBid } } -template <> -void InlineBidiResolver::appendRun() -{ - if (!emptyRun && !eor.atEnd()) { - int start = sor.pos; - RenderObject *obj = sor.obj; - while (obj && obj != eor.obj && obj != endOfLine.obj) { - appendRunsForObject(start, obj->length(), obj, *this); - start = 0; - obj = bidiNext(sor.block, obj); - } - if (obj) { - unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX; - if (obj == endOfLine.obj && endOfLine.pos <= pos) { - reachedEndOfLine = true; - pos = endOfLine.pos; - } - // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be - int end = obj->length() ? pos+1 : 0; - appendRunsForObject(start, end, obj, *this); - } - - eor.increment(); - sor = eor; - } - - m_direction = OtherNeutral; - m_status.eor = OtherNeutral; -} - static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) { if (isRootLineBox) @@ -823,7 +525,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // Figure out if we should clear out our line boxes. // FIXME: Handle resize eventually! - bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren; + bool fullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren; if (fullLayout) lineBoxes()->deleteLineBoxes(renderArena()); @@ -843,6 +545,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool endOfInline = false; RenderObject* o = bidiFirst(this, 0, false); Vector<FloatWithRect> floats; + bool hasInlineChild = false; while (o) { if (o->isReplaced() || o->isFloating() || o->isPositioned()) { RenderBox* box = toRenderBox(o); @@ -865,6 +568,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i o->layoutIfNeeded(); } } else if (o->isText() || (o->isRenderInline() && !endOfInline)) { + hasInlineChild = true; if (fullLayout || o->selfNeedsLayout()) dirtyLineBoxesForRenderer(o, fullLayout); o->setNeedsLayout(false); @@ -881,7 +585,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool previousLineBrokeCleanly = true; RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex); - if (fullLayout && !selfNeedsLayout()) { + if (fullLayout && hasInlineChild && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like // we're supposed to. RenderView* v = view(); @@ -942,7 +646,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool endLineMatched = false; bool checkForEndLineMatch = endLine; bool checkForFloatsFromLastLine = false; - int lastHeight = height(); bool isLineEmpty = true; @@ -1067,8 +770,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i } else m_floatingObjects->first(); for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) { - if (f->m_bottom > lastHeight) - lastRootBox()->floats().append(f->m_renderer); + lastRootBox()->floats().append(f->m_renderer); ASSERT(f->m_renderer == floats[floatIndex].object); // If a float's geometry has changed, give up on syncing with clean lines. if (floats[floatIndex].rect != IntRect(f->m_left, f->m_top, f->m_width, f->m_bottom - f->m_top)) @@ -1078,7 +780,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i lastFloat = m_floatingObjects->last(); } - lastHeight = height(); lineMidpointState.reset(); resolver.setPosition(end); } @@ -1122,16 +823,24 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // In case we have a float on the last line, it might not be positioned up to now. // This has to be done before adding in the bottom border/padding, or the float will // include the padding incorrectly. -dwh + if (checkForFloatsFromLastLine) { + int bottomVisualOverflow = lastRootBox()->bottomVisualOverflow(); + int bottomLayoutOverflow = lastRootBox()->bottomLayoutOverflow(); + TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); + m_lineBoxes.appendLineBox(trailingFloatsLineBox); + trailingFloatsLineBox->setConstructed(); + trailingFloatsLineBox->verticallyAlignBoxes(height()); + trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0); + trailingFloatsLineBox->setBlockHeight(height()); + } if (lastFloat) { for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) { } m_floatingObjects->next(); } else m_floatingObjects->first(); - for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) { - if (f->m_bottom > lastHeight) - lastRootBox()->floats().append(f->m_renderer); - } + for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) + lastRootBox()->floats().append(f->m_renderer); lastFloat = m_floatingObjects->last(); } size_t floatCount = floats.size(); @@ -1184,7 +893,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa if (floats[floatIndex].rect.size() != newSize) { int floatTop = floats[floatIndex].rect.y(); curr->markDirty(); - markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height())); + markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()), curr); floats[floatIndex].rect.setSize(newSize); dirtiedByFloat = true; } @@ -1430,7 +1139,7 @@ static bool inlineFlowRequiresLineBox(RenderInline* flow) return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); } -static inline bool requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) +bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) { if (it.obj->isFloatingOrPositioned()) return false; @@ -1769,10 +1478,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool currentCharacterIsSpace = false; currentCharacterIsWS = false; trailingSpaceObject = 0; - + // Optimize for a common case. If we can't find whitespace after the list // item, then this is all moot. -dwh - if (o->isListMarker() && !toRenderListMarker(o)->isInside()) { + if (o->isListMarker()) { if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { // Like with inline flows, we start ignoring spaces to make sure that any // additional spaces we see will be discarded. @@ -1780,6 +1489,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool currentCharacterIsWS = true; ignoringSpaces = true; } + if (toRenderListMarker(o)->isInside()) + tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o); } else tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o); } else if (o->isText()) { @@ -1799,6 +1510,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool int wordSpacing = o->style()->wordSpacing(); int lastSpaceWordSpacing = 0; + // Non-zero only when kerning is enabled, in which case we measure words with their trailing + // space, then subtract its width. + int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.spaceWidth() + wordSpacing : 0; + int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true); int charWidth = 0; bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE; @@ -1893,7 +1608,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } } - int additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + int additionalTmpW; + if (wordTrailingSpaceWidth && currentCharacterIsSpace) + additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; + else + additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; tmpW += additionalTmpW; if (!appliedStartWidth) { tmpW += inlineWidth(o, true, false); @@ -1925,7 +1644,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } } if (lineWasTooWide || w + tmpW > width) { - if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') { + if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') { if (!stoppedIgnoringSpaces && pos > 0) { // We need to stop right before the newline and then start up again. addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop @@ -2134,19 +1853,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool lBreak.nextBreakablePosition = -1; } } else if (lBreak.obj) { - if (last != o && !last->isListMarker()) { - // better to break between object boundaries than in the middle of a word (except for list markers) - lBreak.obj = o; - lBreak.pos = 0; - lBreak.nextBreakablePosition = -1; - } else { - // Don't ever break in the middle of a word if we can help it. - // There's no room at all. We just have to be on this line, - // even though we'll spill out. - lBreak.obj = o; - lBreak.pos = pos; - lBreak.nextBreakablePosition = -1; - } + // Don't ever break in the middle of a word if we can help it. + // There's no room at all. We just have to be on this line, + // even though we'll spill out. + lBreak.obj = o; + lBreak.pos = pos; + lBreak.nextBreakablePosition = -1; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp index 7ca2ff84fc..1c0e837394 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp @@ -26,6 +26,7 @@ #include "RenderBox.h" #include "CachedImage.h" +#include "Chrome.h" #include "ChromeClient.h" #include "Document.h" #include "FrameView.h" @@ -339,12 +340,12 @@ IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContaine return box; } -void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); + if (width() && height()) + rects.append(IntRect(tx, ty, width(), height())); } - IntRect RenderBox::reflectionBox() const { IntRect result; @@ -572,13 +573,14 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { const FillLayer* bgLayer = style()->backgroundLayers(); Color bgColor = style()->backgroundColor(); + RenderObject* bodyObject = 0; if (!style()->hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) { // Locate the <body> element using the DOM. This is easier than trying // to crawl around a render tree with potential :before/:after content and // anonymous blocks created by inline <body> tags etc. We can locate the <body> // render object very easily via the DOM. HTMLElement* body = document()->body(); - RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; + bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; if (bodyObject) { bgLayer = bodyObject->style()->backgroundLayers(); bgColor = bodyObject->style()->backgroundColor(); @@ -606,7 +608,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw); int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh); - paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh); + paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh, CompositeSourceOver, bodyObject); if (style()->hasBorder() && style()->display() != INLINE) paintBorder(paintInfo.context, tx, ty, w, h, style()); @@ -674,9 +676,25 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int bool compositedMask = hasLayer() && layer()->hasCompositedMask(); CompositeOperator compositeOp = CompositeSourceOver; + bool allMaskImagesLoaded = true; + if (!compositedMask) { StyleImage* maskBoxImage = style()->maskBoxImage().image(); - if (maskBoxImage && style()->maskLayers()->hasImage()) { + const FillLayer* maskLayers = style()->maskLayers(); + + // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content. + if (maskBoxImage) + allMaskImagesLoaded &= maskBoxImage->isLoaded(); + + if (maskLayers) + allMaskImagesLoaded &= maskLayers->imagesAreLoaded(); + + // Before all images have loaded, just use an empty transparency layer as the mask. + if (!allMaskImagesLoaded) + pushTransparencyLayer = true; + + if (maskBoxImage && maskLayers->hasImage()) { + // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask. pushTransparencyLayer = true; } else { // We have to use an extra image buffer to hold the mask. Multiple mask images need @@ -686,7 +704,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int // and composite that buffer as the mask. // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering // before pushing the transparency layer. - for (const FillLayer* fillLayer = style()->maskLayers()->next(); fillLayer; fillLayer = fillLayer->next()) { + for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) { if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) { pushTransparencyLayer = true; // We found one image that can be used in rendering, exit the loop @@ -703,8 +721,10 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int } } - paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp); - paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp); + if (allMaskImagesLoaded) { + paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp); + paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp); + } if (pushTransparencyLayer) paintInfo.context->endTransparencyLayer(); @@ -729,18 +749,18 @@ IntRect RenderBox::maskClipRect() return result; } -void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op) +void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject) { if (!fillLayer) return; - paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op); - paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op); + paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject); + paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject); } -void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op) +void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject) { - paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op); + paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op, backgroundObject); } void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) @@ -950,19 +970,21 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool } } - if (style()->position() == FixedPosition) - fixed = true; - bool containerSkipped; RenderObject* o = container(repaintContainer, &containerSkipped); if (!o) return; + bool isFixedPos = style()->position() == FixedPosition; bool hasTransform = hasLayer() && layer()->transform(); - if (hasTransform) - fixed = false; // Elements with transforms act as a containing block for fixed position descendants - - IntSize containerOffset = offsetFromContainer(o); + if (hasTransform) { + // If this box has a transform, it acts as a fixed position container for fixed descendants, + // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position. + fixed &= isFixedPos; + } else + fixed |= isFixedPos; + + IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint())); bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (useTransforms && shouldUseTransformFromContainer(o)) { @@ -988,12 +1010,14 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor // We don't expect absoluteToLocal() to be called during layout (yet) ASSERT(!view() || !view()->layoutStateEnabled()); - if (style()->position() == FixedPosition) - fixed = true; - + bool isFixedPos = style()->position() == FixedPosition; bool hasTransform = hasLayer() && layer()->transform(); - if (hasTransform) - fixed = false; // Elements with transforms act as a containing block for fixed position descendants + if (hasTransform) { + // If this box has a transform, it acts as a fixed position container for fixed descendants, + // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position. + fixed &= isFixedPos; + } else + fixed |= isFixedPos; RenderObject* o = container(); if (!o) @@ -1001,7 +1025,7 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); - IntSize containerOffset = offsetFromContainer(o); + IntSize containerOffset = offsetFromContainer(o, IntPoint()); bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (useTransforms && shouldUseTransformFromContainer(o)) { @@ -1012,7 +1036,7 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } -IntSize RenderBox::offsetFromContainer(RenderObject* o) const +IntSize RenderBox::offsetFromContainer(RenderObject* o, const IntPoint& point) const { ASSERT(o == container()); @@ -1021,14 +1045,9 @@ IntSize RenderBox::offsetFromContainer(RenderObject* o) const offset += relativePositionOffset(); if (!isInline() || isReplaced()) { - RenderBlock* cb; - if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition - && (cb = toRenderBlock(o))->hasColumns()) { - IntRect rect(x(), y(), 1, 1); - cb->adjustRectForColumns(rect); - offset.expand(rect.x(), rect.y()); - } else - offset.expand(x(), y()); + if (style()->position() != AbsolutePosition && style()->position() != FixedPosition) + o->adjustForColumns(offset, IntPoint(point.x() + x(), point.y() + y())); + offset.expand(x(), y()); } if (o->hasOverflowClip()) @@ -1481,7 +1500,7 @@ void RenderBox::calcHeight() // height since we don't set a height in RenderView when we're printing. So without this quirk, the // height has nothing to be a percentage of, and it ends up being 0. That is bad. bool printingNeedsBaseHeight = document()->printing() && h.isPercent() - && (isRoot() || isBody() && document()->documentElement()->renderer()->style()->height().isPercent()); + && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->height().isPercent())); if (stretchesToViewHeight() || printingNeedsBaseHeight) { int margins = collapsedMarginTop() + collapsedMarginBottom(); int visHeight = document()->printing() ? view()->frameView()->visibleHeight() : view()->viewHeight(); @@ -1926,7 +1945,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos) { // 'left' and 'right' cannot both be 'auto' because one would of been - // converted to the static postion already + // converted to the static position already ASSERT(!(left.isAuto() && right.isAuto())); int leftValue = 0; @@ -1960,7 +1979,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO if (marginLeft.isAuto() && marginRight.isAuto()) { // Both margins auto, solve for equality if (availableSpace >= 0) { - marginLeftValue = availableSpace / 2; // split the diference + marginLeftValue = availableSpace / 2; // split the difference marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences } else { // see FIXME 1 @@ -2245,7 +2264,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject* if (marginTop.isAuto() && marginBottom.isAuto()) { // Both margins auto, solve for equality // NOTE: This may result in negative values. - marginTopValue = availableSpace / 2; // split the diference + marginTopValue = availableSpace / 2; // split the difference marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences } else if (marginTop.isAuto()) { // Solve for top margin @@ -2323,7 +2342,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject* void RenderBox::calcAbsoluteHorizontalReplaced() { // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements" + // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements" // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width> // (block-style-comments in this function correspond to text from the spec and // the numbers correspond to numbers in spec) @@ -2414,7 +2433,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() int difference = availableSpace - (leftValue + rightValue); if (difference > 0) { - m_marginLeft = difference / 2; // split the diference + m_marginLeft = difference / 2; // split the difference m_marginRight = difference - m_marginLeft; // account for odd valued differences } else { // see FIXME 1 @@ -2501,7 +2520,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() void RenderBox::calcAbsoluteVerticalReplaced() { // The following is based off of the W3C Working Draft from April 11, 2006 of - // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements" + // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements" // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height> // (block-style-comments in this function correspond to text from the spec and // the numbers correspond to numbers in spec) @@ -2565,7 +2584,7 @@ void RenderBox::calcAbsoluteVerticalReplaced() int bottomValue = 0; if (marginTop.isAuto() && marginBottom.isAuto()) { - // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded. + // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined. ASSERT(!(top.isAuto() || bottom.isAuto())); topValue = top.calcValue(containerHeight); @@ -2705,7 +2724,7 @@ VisiblePosition RenderBox::positionForPoint(const IntPoint& point) { // no children...return this render object's element, if there is one, and offset 0 if (!firstChild()) - return createVisiblePosition(firstDeepEditingPositionForNode(node())); + return createVisiblePosition(node() ? firstDeepEditingPositionForNode(node()) : Position(0, 0)); int xPos = point.x(); int yPos = point.y(); @@ -2885,9 +2904,9 @@ void RenderBox::clearLayoutOverflow() #if ENABLE(SVG) -TransformationMatrix RenderBox::localTransform() const +AffineTransform RenderBox::localTransform() const { - return TransformationMatrix(1, 0, 0, 1, x(), y()); + return AffineTransform(1, 0, 0, 1, x(), y()); } #endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h index 9050dcbe14..90a17ae0bb 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h @@ -74,7 +74,7 @@ public: // Bounds of the outline box in absolute coords. Respects transforms virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const; - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); // Use this with caution! No type checking is done! RenderBox* previousSiblingBox() const; @@ -173,7 +173,7 @@ public: int overrideHeight() const; virtual void setOverrideSize(int); - virtual IntSize offsetFromContainer(RenderObject*) const; + virtual IntSize offsetFromContainer(RenderObject*, const IntPoint&) const; int calcBorderBoxWidth(int width) const; int calcBorderBoxHeight(int height) const; @@ -271,9 +271,9 @@ public: virtual void paintMask(PaintInfo&, int tx, int ty); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - // Called when a positioned object moves but doesn't change size. A simplified layout is done - // that just updates the object's position. - virtual void tryLayoutDoingPositionedMovementOnly() + // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted + // that just updates the object's position. If the size does change, the object remains dirty. + void tryLayoutDoingPositionedMovementOnly() { int oldWidth = width(); calcWidth(); @@ -297,7 +297,7 @@ public: virtual bool avoidsFloats() const; #if ENABLE(SVG) - virtual TransformationMatrix localTransform() const; + virtual AffineTransform localTransform() const; #endif protected: @@ -305,8 +305,8 @@ protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateBoxModelInfoFromStyle(); - void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); - void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); + void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject); + void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp index 9d0f1edf43..ba4b8dd904 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp @@ -33,6 +33,7 @@ #include "RenderInline.h" #include "RenderLayer.h" #include "RenderView.h" +#include <wtf/CurrentTime.h> using namespace std; @@ -44,6 +45,142 @@ bool RenderBoxModelObject::s_wasFloating = false; bool RenderBoxModelObject::s_hadLayer = false; bool RenderBoxModelObject::s_layerWasSelfPainting = false; +static const double cInterpolationCutoff = 800. * 800.; +static const double cLowQualityTimeThreshold = 0.500; // 500 ms + +class RenderBoxModelScaleData : public Noncopyable { +public: + RenderBoxModelScaleData(RenderBoxModelObject* object, const IntSize& size, const AffineTransform& transform, double time, bool lowQualityScale) + : m_size(size) + , m_transform(transform) + , m_lastPaintTime(time) + , m_lowQualityScale(lowQualityScale) + , m_highQualityRepaintTimer(object, &RenderBoxModelObject::highQualityRepaintTimerFired) + { + } + + ~RenderBoxModelScaleData() + { + m_highQualityRepaintTimer.stop(); + } + + Timer<RenderBoxModelObject>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; } + + const IntSize& size() const { return m_size; } + void setSize(const IntSize& s) { m_size = s; } + double lastPaintTime() const { return m_lastPaintTime; } + void setLastPaintTime(double t) { m_lastPaintTime = t; } + bool useLowQualityScale() const { return m_lowQualityScale; } + const AffineTransform& transform() const { return m_transform; } + void setTransform(const AffineTransform& transform) { m_transform = transform; } + void setUseLowQualityScale(bool b) + { + m_highQualityRepaintTimer.stop(); + m_lowQualityScale = b; + if (b) + m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold); + } + +private: + IntSize m_size; + AffineTransform m_transform; + double m_lastPaintTime; + bool m_lowQualityScale; + Timer<RenderBoxModelObject> m_highQualityRepaintTimer; +}; + +class RenderBoxModelScaleObserver { +public: + static bool shouldPaintBackgroundAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const IntSize&); + + static void boxModelObjectDestroyed(RenderBoxModelObject* object) + { + if (gBoxModelObjects) { + RenderBoxModelScaleData* data = gBoxModelObjects->take(object); + delete data; + if (!gBoxModelObjects->size()) { + delete gBoxModelObjects; + gBoxModelObjects = 0; + } + } + } + + static void highQualityRepaintTimerFired(RenderBoxModelObject* object) + { + RenderBoxModelScaleObserver::boxModelObjectDestroyed(object); + object->repaint(); + } + + static HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* gBoxModelObjects; +}; + +bool RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const IntSize& size) +{ + // If the image is not a bitmap image, then none of this is relevant and we just paint at high + // quality. + if (!image || !image->isBitmapImage()) + return false; + + // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image + // is actually being scaled. + IntSize imageSize(image->width(), image->height()); + + // Look ourselves up in the hashtable. + RenderBoxModelScaleData* data = 0; + if (gBoxModelObjects) + data = gBoxModelObjects->get(object); + + const AffineTransform& currentTransform = context->getCTM(); + bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped(); + if (!contextIsScaled && imageSize == size) { + // There is no scale in effect. If we had a scale in effect before, we can just delete this data. + if (data) { + gBoxModelObjects->remove(object); + delete data; + } + return false; + } + + // There is no need to hash scaled images that always use low quality mode when the page demands it. This is the iChat case. + if (object->document()->page()->inLowQualityImageInterpolationMode()) { + double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height()); + if (totalPixels > cInterpolationCutoff) + return true; + } + + // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens + // very soon. + if (!data) { + data = new RenderBoxModelScaleData(object, size, currentTransform, currentTime(), false); + if (!gBoxModelObjects) + gBoxModelObjects = new HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>; + gBoxModelObjects->set(object, data); + return false; + } + + const AffineTransform& tr = data->transform(); + bool scaleUnchanged = tr.a() == currentTransform.a() && tr.b() == currentTransform.b() && tr.c() == currentTransform.c() && tr.d() == currentTransform.d(); + // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with. + if ((!contextIsScaled || scaleUnchanged) && data->size() == size) + return data->useLowQualityScale(); + + // We have data and our size just changed. If this change happened quickly, go into low quality mode and then set a repaint + // timer to paint in high quality mode. Otherwise it is ok to just paint in high quality mode. + double newTime = currentTime(); + data->setUseLowQualityScale(newTime - data->lastPaintTime() < cLowQualityTimeThreshold); + data->setLastPaintTime(newTime); + data->setTransform(currentTransform); + data->setSize(size); + return data->useLowQualityScale(); +} + +HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* RenderBoxModelScaleObserver::gBoxModelObjects = 0; + +void RenderBoxModelObject::highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*) +{ + RenderBoxModelScaleObserver::highQualityRepaintTimerFired(this); +} + RenderBoxModelObject::RenderBoxModelObject(Node* node) : RenderObject(node) , m_layer(0) @@ -55,6 +192,7 @@ RenderBoxModelObject::~RenderBoxModelObject() // Our layer should have been destroyed and cleared by now ASSERT(!hasLayer()); ASSERT(!m_layer); + RenderBoxModelScaleObserver::boxModelObjectDestroyed(this); } void RenderBoxModelObject::destroyLayer() @@ -304,9 +442,12 @@ int RenderBoxModelObject::paddingRight(bool) const } -void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) +void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op, RenderObject* backgroundObject) { GraphicsContext* context = paintInfo.context; + if (context->paintingDisabled()) + return; + bool includeLeftEdge = box ? box->includeLeftEdge() : true; bool includeRightEdge = box ? box->includeRightEdge() : true; int bLeft = includeLeftEdge ? borderLeft() : 0; @@ -340,7 +481,9 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co context->clip(toRenderBox(this)->overflowClipRect(tx, ty)); // Now adjust our tx, ty, w, h to reflect a scrolled content box with borders at the ends. - layer()->subtractScrolledContentOffset(tx, ty); + IntSize offset = layer()->scrolledContentOffset(); + tx -= offset.width(); + ty -= offset.height(); w = bLeft + layer()->scrollWidth() + bRight; h = borderTop() + layer()->scrollHeight() + borderBottom(); } @@ -441,14 +584,14 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (baseColor.alpha() > 0) { context->save(); context->setCompositeOperation(CompositeCopy); - context->fillRect(rect, baseColor); + context->fillRect(rect, baseColor, style()->colorSpace()); context->restore(); } else context->clearRect(rect); } if (bgColor.isValid() && bgColor.alpha() > 0) - context->fillRect(rect, bgColor); + context->fillRect(rect, bgColor, style()->colorSpace()); } // no progressive loading of the background image @@ -463,21 +606,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (!destRect.isEmpty()) { phase += destRect.location() - destOrigin; CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; - RenderObject* clientForBackgroundImage = this; - // Check if this is the root element painting a background layer propagated from <body>, - // and pass the body's renderer as the client in that case. - if (isRoot && !style()->hasBackground()) { - ASSERT(node()->hasTagName(htmlTag)); - HTMLElement* body = document()->body(); - ASSERT(body); - ASSERT(body->hasLocalName(bodyTag)); - ASSERT(body->renderer()); - if (body) { - if (RenderObject* bodyRenderer = body->renderer()) - clientForBackgroundImage = bodyRenderer; - } - } - context->drawTiledImage(bg->image(clientForBackgroundImage, tileSize), destRect, phase, tileSize, compositeOp); + RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; + Image* image = bg->image(clientForBackgroundImage, tileSize); + bool useLowQualityScaling = RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(context, this, image, tileSize); + context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling); } } @@ -663,7 +795,8 @@ int RenderBoxModelObject::verticalPosition(bool firstLine) const vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine) / 2 + baselinePosition(firstLine); else if (va == TEXT_BOTTOM) { vpos += f.descent(); - if (!isReplaced()) // lineHeight - baselinePosition is always 0 for replaced elements, so don't bother wasting time in that case. + // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. + if (!isReplaced() || style()->display() == INLINE_BLOCK) vpos -= (lineHeight(firstLine) - baselinePosition(firstLine)); } else if (va == BASELINE_MIDDLE) vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine); @@ -717,6 +850,7 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0; Image* image = styleImage->image(this, imageSize); + ColorSpace colorSpace = style->colorSpace(); if (drawLeft) { // Paint the top and bottom left corners. @@ -724,18 +858,18 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // The top left corner rect is (tx, ty, leftWidth, topWidth) // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice) if (drawTop) - graphicsContext->drawImage(image, IntRect(tx, ty, leftWidth, topWidth), + graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty, leftWidth, topWidth), IntRect(0, 0, leftSlice, topSlice), op); // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth) // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice) if (drawBottom) - graphicsContext->drawImage(image, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth), + graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth), IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op); // Paint the left edge. // Have to scale and tile into the border rect. - graphicsContext->drawTiledImage(image, IntRect(tx, ty + topWidth, leftWidth, + graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx, ty + topWidth, leftWidth, h - topWidth - bottomWidth), IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice), Image::StretchTile, (Image::TileRule)vRule, op); @@ -746,17 +880,17 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, topWidth) // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice) if (drawTop) - graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth), + graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth), IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op); // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth) // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice) if (drawBottom) - graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth), + graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth), IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op); // Paint the right edge. - graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, + graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, h - topWidth - bottomWidth), IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice), Image::StretchTile, (Image::TileRule)vRule, op); @@ -764,20 +898,20 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // Paint the top edge. if (drawTop) - graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth), + graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth), IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice), (Image::TileRule)hRule, Image::StretchTile, op); // Paint the bottom edge. if (drawBottom) - graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + h - bottomWidth, + graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + h - bottomWidth, w - leftWidth - rightWidth, bottomWidth), IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice), (Image::TileRule)hRule, Image::StretchTile, op); // Paint the middle. if (drawMiddle) - graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth, + graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth, h - topWidth - bottomWidth), IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice), (Image::TileRule)hRule, (Image::TileRule)vRule, op); @@ -1209,7 +1343,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int shadowOffset -= extraOffset; fillRect.move(extraOffset); - context->setShadow(shadowOffset, shadowBlur, shadowColor); + context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); if (hasBorderRadius) { IntRect rectToClipOut = rect; IntSize topLeftToClipOut = topLeft; @@ -1252,7 +1386,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (!rectToClipOut.isEmpty()) context->clipOutRoundedRect(rectToClipOut, topLeftToClipOut, topRightToClipOut, bottomLeftToClipOut, bottomRightToClipOut); - context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black, s->colorSpace()); } else { IntRect rectToClipOut = rect; @@ -1261,7 +1395,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path // by one pixel. if (hasOpaqueBackground) { - TransformationMatrix currentTransformation = context->getCTM(); + AffineTransform currentTransformation = context->getCTM(); if (currentTransformation.a() != 1 || (currentTransformation.d() != 1 && currentTransformation.d() != -1) || currentTransformation.b() || currentTransformation.c()) rectToClipOut.inflate(-1); @@ -1269,7 +1403,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (!rectToClipOut.isEmpty()) context->clipOut(rectToClipOut); - context->fillRect(fillRect, Color::black); + context->fillRect(fillRect, Color::black, s->colorSpace()); } context->restore(); @@ -1280,9 +1414,9 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (holeRect.isEmpty()) { if (hasBorderRadius) - context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor); + context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor, s->colorSpace()); else - context->fillRect(rect, shadowColor); + context->fillRect(rect, shadowColor, s->colorSpace()); continue; } if (!begin) { @@ -1331,8 +1465,8 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int context->addPath(Path::createRectangle(holeRect)); context->setFillRule(RULE_EVENODD); - context->setFillColor(fillColor); - context->setShadow(shadowOffset, shadowBlur, shadowColor); + context->setFillColor(fillColor, s->colorSpace()); + context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); context->fillPath(); context->restore(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h index c9a4a0a0e1..db7538d9ed 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h @@ -90,7 +90,7 @@ public: void paintBorder(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true); bool paintNinePieceImage(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver); void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, ShadowStyle, bool begin = true, bool end = true); - void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver); + void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); // The difference between this inline's baseline position and the line's baseline position. int verticalPosition(bool firstLine) const; @@ -98,6 +98,8 @@ public: // Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed void destroyLayer(); + void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*); + protected: void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp index f3ae5580f3..3ecd38247d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp @@ -1,6 +1,4 @@ /** - * This file is part of the html renderer for KDE. - * * Copyright (C) 2005 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.h b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h index 3a74589677..7fd6ab0437 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderButton.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h @@ -1,6 +1,4 @@ /* - * This file is part of the html renderer for KDE. - * * Copyright (C) 2005 Apple Computer * * This library is free software; you can redistribute it and/or diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp index 17c6dad211..3cb9a078f0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp @@ -38,7 +38,7 @@ using namespace HTMLNames; typedef HashMap<RefPtr<AtomicStringImpl>, CounterNode*> CounterMap; typedef HashMap<const RenderObject*, CounterMap*> CounterMaps; -static CounterNode* counter(RenderObject*, const AtomicString& counterName, bool alwaysCreateCounter); +static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter); static CounterMaps& counterMaps() { @@ -53,31 +53,7 @@ static inline RenderObject* previousSiblingOrParent(RenderObject* object) return object->parent(); } -static CounterNode* lastDescendant(CounterNode* node) -{ - CounterNode* last = node->lastChild(); - if (!last) - return 0; - - while (CounterNode* lastChild = last->lastChild()) - last = lastChild; - - return last; -} - -static CounterNode* previousInPreOrder(CounterNode* node) -{ - CounterNode* previous = node->previousSibling(); - if (!previous) - return node->parent(); - - while (CounterNode* lastChild = previous->lastChild()) - previous = lastChild; - - return previous; -} - -static bool planCounter(RenderObject* object, const AtomicString& counterName, bool& isReset, int& value) +static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value) { ASSERT(object); @@ -90,7 +66,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b ASSERT(style); if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) { - CounterDirectives directives = directivesMap->get(counterName.impl()); + CounterDirectives directives = directivesMap->get(identifier.impl()); if (directives.m_reset) { value = directives.m_resetValue; if (directives.m_increment) @@ -105,7 +81,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b } } - if (counterName == "list-item") { + if (identifier == "list-item") { if (object->isListItem()) { if (toRenderListItem(object)->hasExplicitValue()) { value = toRenderListItem(object)->explicitValue(); @@ -133,83 +109,142 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b return false; } -static bool findPlaceForCounter(RenderObject* object, const AtomicString& counterName, - bool isReset, CounterNode*& parent, CounterNode*& previousSibling) +// - Finds the insertion point for the counter described by counterOwner, isReset and +// identifier in the CounterNode tree for identifier and sets parent and +// previousSibling accordingly. +// - The function returns true if the counter whose insertion point is searched is NOT +// the root of the tree. +// - The root of the tree is a counter reference that is not in the scope of any other +// counter with the same identifier. +// - All the counter references with the same identifier as this one that are in +// children or subsequent siblings of the renderer that owns the root of the tree +// form the rest of of the nodes of the tree. +// - The root of the tree is always a reset type reference. +// - A subtree rooted at any reset node in the tree is equivalent to all counter +// references that are in the scope of the counter or nested counter defined by that +// reset node. +// - Non-reset CounterNodes cannot have descendants. + +static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& identifier, bool isReset, CounterNode*& parent, CounterNode*& previousSibling) { - // Find the appropriate previous sibling for insertion into the parent node - // by searching in render tree order for a child of the counter. - parent = 0; + // We cannot stop searching for counters with the same identifier before we also + // check this renderer, because it may affect the positioning in the tree of our counter. + RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner); + // We check renderers in preOrder from the renderer that our counter is attached to + // towards the begining of the document for counters with the same identifier as the one + // we are trying to find a place for. This is the next renderer to be checked. + RenderObject* currentRenderer = counterOwner->previousInPreOrder(); previousSibling = 0; - RenderObject* resetCandidate = isReset ? object->parent() : previousSiblingOrParent(object); - RenderObject* prevCounterCandidate = object; - CounterNode* candidateCounter = 0; - // When a reset counter is chosen as candidateCounter, we'll - // decide the new node should be a child of the reset node or a - // sibling or the reset node. This flag controls it. - bool createChildForReset = true; - while ((prevCounterCandidate = prevCounterCandidate->previousInPreOrder())) { - CounterNode* c = counter(prevCounterCandidate, counterName, false); - if (prevCounterCandidate == resetCandidate) { - if (!candidateCounter) { - candidateCounter = c; - createChildForReset = true; - } - if (candidateCounter) { - if (createChildForReset && candidateCounter->isReset()) { - parent = candidateCounter; - previousSibling = 0; - } else { - parent = candidateCounter->parent(); - previousSibling = candidateCounter; + while (currentRenderer) { + CounterNode* currentCounter = makeCounterNode(currentRenderer, identifier, false); + if (searchEndRenderer == currentRenderer) { + // We may be at the end of our search. + if (currentCounter) { + // We have a suitable counter on the EndSearchRenderer. + if (previousSibling) { // But we already found another counter that we come after. + if (currentCounter->actsAsReset()) { + // We found a reset counter that is on a renderer that is a sibling of ours or a parent. + if (isReset && currentRenderer->parent() == counterOwner->parent()) { + // We are also a reset counter and the previous reset was on a sibling renderer + // hence we are the next sibling of that counter if that reset is not a root or + // we are a root node if that reset is a root. + parent = currentCounter->parent(); + previousSibling = parent ? currentCounter : 0; + return parent; + } + // We are not a reset node or the previous reset must be on an ancestor of our renderer + // hence we must be a child of that reset counter. + parent = currentCounter; + ASSERT(previousSibling->parent() == currentCounter); + return true; + } + // CurrentCounter, the counter at the EndSearchRenderer, is not reset. + if (!isReset || currentRenderer->parent() != counterOwner->parent()) { + // If the node we are placing is not reset or we have found a counter that is attached + // to an ancestor of the placed counter's renderer we know we are a sibling of that node. + ASSERT(currentCounter->parent() == previousSibling->parent()); + parent = currentCounter->parent(); + return true; + } + } else { + // We are at the potential end of the search, but we had no previous sibling candidate + // In this case we follow pretty much the same logic as above but no ASSERTs about + // previousSibling, and when we are a sibling of the end counter we must set previousSibling + // to currentCounter. + if (currentCounter->actsAsReset()) { + if (isReset && currentRenderer->parent() == counterOwner->parent()) { + parent = currentCounter->parent(); + previousSibling = currentCounter; + return parent; + } + parent = currentCounter; + return true; + } + if (!isReset || currentRenderer->parent() != counterOwner->parent()) { + parent = currentCounter->parent(); + previousSibling = currentCounter; + return true; + } + previousSibling = currentCounter; } - return true; } - resetCandidate = previousSiblingOrParent(resetCandidate); - } else if (c) { - if (c->isReset()) { - if (c->parent()) { - // The new node may be the next sibling of this reset node. - createChildForReset = false; - candidateCounter = c; - } else { - createChildForReset = true; - candidateCounter = 0; - } - } else if (!candidateCounter) { - createChildForReset = true; - candidateCounter = c; + // We come here if the previous sibling or parent of our renderer had no + // good counter, or we are a reset node and the counter on the previous sibling + // of our renderer was not a reset counter. + // Set a new goal for the end of the search. + searchEndRenderer = previousSiblingOrParent(currentRenderer); + } else { + // We are searching descendants of a previous sibling of the renderer that the + // counter being placed is attached to. + if (currentCounter) { + // We found a suitable counter. + if (previousSibling) { + // Since we had a suitable previous counter before, we should only consider this one as our + // previousSibling if it is a reset counter and hence the current previousSibling is its child. + if (currentCounter->actsAsReset()) { + previousSibling = currentCounter; + // We are no longer interested in previous siblings of the currentRenderer or their children + // as counters they may have attached cannot be the previous sibling of the counter we are placing. + currentRenderer = currentRenderer->parent(); + continue; + } + } else + previousSibling = currentCounter; + currentRenderer = previousSiblingOrParent(currentRenderer); + continue; } } + // This function is designed so that the same test is not done twice in an iteration, except for this one + // which may be done twice in some cases. Rearranging the decision points though, to accommodate this + // performance improvement would create more code duplication than is worthwhile in my oppinion and may further + // impede the readability of this already complex algorithm. + if (previousSibling) + currentRenderer = previousSiblingOrParent(currentRenderer); + else + currentRenderer = currentRenderer->previousInPreOrder(); } - return false; } -static CounterNode* counter(RenderObject* object, const AtomicString& counterName, bool alwaysCreateCounter) +static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter) { ASSERT(object); if (object->m_hasCounterNodeMap) if (CounterMap* nodeMap = counterMaps().get(object)) - if (CounterNode* node = nodeMap->get(counterName.impl())) + if (CounterNode* node = nodeMap->get(identifier.impl())) return node; bool isReset = false; int value = 0; - if (!planCounter(object, counterName, isReset, value) && !alwaysCreateCounter) + if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter) return 0; CounterNode* newParent = 0; CounterNode* newPreviousSibling = 0; - CounterNode* newNode; - if (findPlaceForCounter(object, counterName, isReset, newParent, newPreviousSibling)) { - newNode = new CounterNode(object, isReset, value); - newParent->insertAfter(newNode, newPreviousSibling); - } else { - // Make a reset node for counters that aren't inside an existing reset node. - newNode = new CounterNode(object, true, value); - } - + CounterNode* newNode = new CounterNode(object, isReset, value); + if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling)) + newParent->insertAfter(newNode, newPreviousSibling, identifier); CounterMap* nodeMap; if (object->m_hasCounterNodeMap) nodeMap = counterMaps().get(object); @@ -218,8 +253,30 @@ static CounterNode* counter(RenderObject* object, const AtomicString& counterNam counterMaps().set(object, nodeMap); object->m_hasCounterNodeMap = true; } - nodeMap->set(counterName.impl(), newNode); - + nodeMap->set(identifier.impl(), newNode); + if (newNode->parent() || !object->nextInPreOrder(object->parent())) + return newNode; + // Checking if some nodes that were previously counter tree root nodes + // should become children of this node now. + CounterMaps& maps = counterMaps(); + RenderObject* stayWithin = object->parent(); + for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) { + if (!currentRenderer->m_hasCounterNodeMap) + continue; + CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl()); + if (!currentCounter) + continue; + if (currentCounter->parent()) { + ASSERT(newNode->firstChild()); + if (currentRenderer->lastChild()) + currentRenderer = currentRenderer->lastChild(); + continue; + } + if (stayWithin != currentRenderer->parent() || !currentCounter->hasResetType()) + newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); + if (currentRenderer->lastChild()) + currentRenderer = currentRenderer->lastChild(); + } return newNode; } @@ -246,15 +303,15 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const return 0; if (!m_counterNode) - m_counterNode = counter(parent(), m_counter.identifier(), true); + m_counterNode = makeCounterNode(parent(), m_counter.identifier(), true); CounterNode* child = m_counterNode; - int value = child->isReset() ? child->value() : child->countInParent(); + int value = child->actsAsReset() ? child->value() : child->countInParent(); String text = listMarkerText(m_counter.listStyle(), value); if (!m_counter.separator().isNull()) { - if (!child->isReset()) + if (!child->actsAsReset()) child = child->parent(); while (CounterNode* parent = child->parent()) { text = listMarkerText(m_counter.listStyle(), child->countInParent()) @@ -272,47 +329,156 @@ void RenderCounter::calcPrefWidths(int lead) RenderText::calcPrefWidths(lead); } -void RenderCounter::invalidate() +void RenderCounter::invalidate(const AtomicString& identifier) { + if (m_counter.identifier() != identifier) + return; m_counterNode = 0; setNeedsLayoutAndPrefWidthsRecalc(); } -static void destroyCounterNodeChildren(AtomicStringImpl* identifier, CounterNode* node) +static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node) { CounterNode* previous; - for (CounterNode* child = lastDescendant(node); child && child != node; child = previous) { - previous = previousInPreOrder(child); - child->parent()->removeChild(child); - ASSERT(counterMaps().get(child->renderer())->get(identifier) == child); - counterMaps().get(child->renderer())->remove(identifier); + for (CounterNode* child = node->lastDescendant(); child && child != node; child = previous) { + previous = child->previousInPreOrder(); + child->parent()->removeChild(child, identifier); + ASSERT(counterMaps().get(child->renderer())->get(identifier.impl()) == child); + counterMaps().get(child->renderer())->remove(identifier.impl()); if (!child->renderer()->documentBeingDestroyed()) { RenderObjectChildList* children = child->renderer()->virtualChildren(); if (children) - children->invalidateCounters(child->renderer()); + children->invalidateCounters(child->renderer(), identifier); } delete child; } + RenderObject* renderer = node->renderer(); + if (!renderer->documentBeingDestroyed()) { + if (RenderObjectChildList* children = renderer->virtualChildren()) + children->invalidateCounters(renderer, identifier); + } + if (CounterNode* parent = node->parent()) + parent->removeChild(node, identifier); + delete node; } -void RenderCounter::destroyCounterNodes(RenderObject* object) +void RenderCounter::destroyCounterNodes(RenderObject* renderer) { CounterMaps& maps = counterMaps(); - CounterMap* map = maps.get(object); - if (!map) + CounterMaps::iterator mapsIterator = maps.find(renderer); + if (mapsIterator == maps.end()) return; - maps.remove(object); - + CounterMap* map = mapsIterator->second; CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { - CounterNode* node = it->second; - destroyCounterNodeChildren(it->first.get(), node); - if (CounterNode* parent = node->parent()) - parent->removeChild(node); - delete node; + AtomicString identifier(it->first.get()); + destroyCounterNodeWithoutMapRemoval(identifier, it->second); } - + maps.remove(mapsIterator); delete map; + renderer->m_hasCounterNodeMap = false; +} + +void RenderCounter::destroyCounterNode(RenderObject* renderer, const AtomicString& identifier) +{ + CounterMap* map = counterMaps().get(renderer); + if (!map) + return; + CounterMap::iterator mapIterator = map->find(identifier.impl()); + if (mapIterator == map->end()) + return; + destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second); + map->remove(mapIterator); + // We do not delete "map" here even if empty because we expect to reuse + // it soon. In order for a renderer to lose all its counters permanently, + // a style change for the renderer involving removal of all counter + // directives must occur, in which case, RenderCounter::destroyCounterNodes() + // must be called. + // The destruction of the Renderer (possibly caused by the removal of its + // associated DOM node) is the other case that leads to the permanent + // destruction of all counters attached to a Renderer. In this case + // RenderCounter::destroyCounterNodes() must be and is now called, too. + // RenderCounter::destroyCounterNodes() handles destruction of the counter + // map associated with a renderer, so there is no risk in leaking the map. +} + +static void updateCounters(RenderObject* renderer) +{ + ASSERT(renderer->style()); + const CounterDirectiveMap* directiveMap = renderer->style()->counterDirectives(); + if (!directiveMap) + return; + CounterDirectiveMap::const_iterator end = directiveMap->end(); + if (!renderer->m_hasCounterNodeMap) { + for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) + makeCounterNode(renderer, AtomicString(it->first.get()), false); + return; + } + CounterMap* counterMap = counterMaps().get(renderer); + ASSERT(counterMap); + for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) { + CounterNode* node = counterMap->get(it->first.get()); + if (!node) { + makeCounterNode(renderer, AtomicString(it->first.get()), false); + continue; + } + CounterNode* newParent = 0; + CounterNode* newPreviousSibling; + findPlaceForCounter(renderer, AtomicString(it->first.get()), node->hasResetType(), newParent, newPreviousSibling); + CounterNode* parent = node->parent(); + if (newParent == parent && newPreviousSibling == node->previousSibling()) + continue; + if (parent) + parent->removeChild(node, it->first.get()); + if (newParent) + newParent->insertAfter(node, newPreviousSibling, it->first.get()); + } +} + +void RenderCounter::rendererSubtreeAttached(RenderObject* renderer) +{ + for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer)) + updateCounters(descendant); +} + +void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle) +{ + const CounterDirectiveMap* newCounterDirectives; + const CounterDirectiveMap* oldCounterDirectives; + if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) { + if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) { + CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end(); + CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives->end(); + for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) { + CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirectives->find(it->first); + if (oldMapIt != oldMapEnd) { + if (oldMapIt->second == it->second) + continue; + RenderCounter::destroyCounterNode(renderer, it->first.get()); + } + // We must create this node here, because the changed node may be a node with no display such as + // as those created by the increment or reset directives and the re-layout that will happen will + // not catch the change if the node had no children. + makeCounterNode(renderer, it->first.get(), false); + } + // Destroying old counters that do not exist in the new counterDirective map. + for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) { + if (!newCounterDirectives->contains(it->first)) + RenderCounter::destroyCounterNode(renderer, it->first.get()); + } + } else { + if (renderer->m_hasCounterNodeMap) + RenderCounter::destroyCounterNodes(renderer); + } + } else if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) { + CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end(); + for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) { + // We must create this node here, because the added node may be a node with no display such as + // as those created by the increment or reset directives and the re-layout that will happen will + // not catch the change if the node had no children. + makeCounterNode(renderer, it->first.get(), false); + } + } } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h index 961968e16c..10ba1dc574 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h @@ -33,9 +33,16 @@ class RenderCounter : public RenderText { public: RenderCounter(Document*, const CounterContent&); - void invalidate(); + // Removes the reference to the CounterNode associated with this renderer + // if its identifier matches the argument. + // This is used to cause a counter display update when the CounterNode + // tree for identifier changes. + void invalidate(const AtomicString& identifier); static void destroyCounterNodes(RenderObject*); + static void destroyCounterNode(RenderObject*, const AtomicString& identifier); + static void rendererSubtreeAttached(RenderObject*); + static void rendererStyleChanged(RenderObject*, const RenderStyle* oldStyle, const RenderStyle* newStyle); private: virtual const char* renderName() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.cpp new file mode 100644 index 0000000000..d2e9999b78 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.cpp @@ -0,0 +1,427 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderEmbeddedObject.h" + +#include "CSSValueKeywords.h" +#include "Font.h" +#include "FontSelector.h" +#include "Frame.h" +#include "FrameLoaderClient.h" +#include "GraphicsContext.h" +#include "HTMLEmbedElement.h" +#include "HTMLIFrameElement.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" +#include "HTMLParamElement.h" +#include "LocalizedStrings.h" +#include "MIMETypeRegistry.h" +#include "Page.h" +#include "Path.h" +#include "PluginWidget.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "RenderWidgetProtector.h" +#include "Text.h" + +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) +#include "HTMLVideoElement.h" +#endif + +#if USE(ACCELERATED_COMPOSITING) +#include "PluginWidget.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +static const float missingPluginRoundedRectHeight = 18; +static const float missingPluginRoundedRectLeftRightTextMargin = 6; +static const float missingPluginRoundedRectOpacity = 0.20f; +static const float missingPluginRoundedRectRadius = 5; +static const float missingPluginTextOpacity = 0.55f; + +RenderEmbeddedObject::RenderEmbeddedObject(Element* element) + : RenderPartObject(element) + , m_showsMissingPluginIndicator(false) +{ + view()->frameView()->setIsVisuallyNonEmpty(); +} + +RenderEmbeddedObject::~RenderEmbeddedObject() +{ + if (frameView()) + frameView()->removeWidgetToUpdate(this); +} + +#if USE(ACCELERATED_COMPOSITING) +bool RenderEmbeddedObject::requiresLayer() const +{ + if (RenderPartObject::requiresLayer()) + return true; + + return allowsAcceleratedCompositing(); +} + +bool RenderEmbeddedObject::allowsAcceleratedCompositing() const +{ + return widget() && widget()->isPluginWidget() && static_cast<PluginWidget*>(widget())->platformLayer(); +} +#endif + +static bool isURLAllowed(Document* doc, const String& url) +{ + if (doc->frame()->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. + KURL completeURL = doc->completeURL(url); + bool foundSelfReference = false; + for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) { + if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) { + if (foundSelfReference) + return false; + foundSelfReference = true; + } + } + return true; +} + +typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap; + +static ClassIdToTypeMap* createClassIdToTypeMap() +{ + ClassIdToTypeMap* map = new ClassIdToTypeMap; + map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash"); + map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin"); + map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime"); + map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director"); + map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2"); + map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2"); + return map; +} + +static String serviceTypeForClassId(const String& classId) +{ + // Return early if classId is empty (since we won't do anything below). + // Furthermore, if classId is null, calling get() below will crash. + if (classId.isEmpty()) + return String(); + + static ClassIdToTypeMap* map = createClassIdToTypeMap(); + return map->get(classId); +} + +static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues) +{ + // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP + // require "src" attribute). + int srcIndex = -1, dataIndex = -1; + for (unsigned int i = 0; i < paramNames->size(); ++i) { + if (equalIgnoringCase((*paramNames)[i], "src")) + srcIndex = i; + else if (equalIgnoringCase((*paramNames)[i], "data")) + dataIndex = i; + } + + if (srcIndex == -1 && dataIndex != -1) { + paramNames->append("src"); + paramValues->append((*paramValues)[dataIndex]); + } +} + +void RenderEmbeddedObject::updateWidget(bool onlyCreateNonNetscapePlugins) +{ + if (m_showsMissingPluginIndicator) + return; + + String url; + String serviceType; + Vector<String> paramNames; + Vector<String> paramValues; + Frame* frame = frameView()->frame(); + + // The calls to FrameLoader::requestObject within this function can result in a plug-in being initialized. + // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from + // the render tree and destroyed, causing a crash like <rdar://problem/6954546>. By extending our lifetime + // artifically to ensure that we remain alive for the duration of plug-in initialization. + RenderWidgetProtector protector(this); + + if (node()->hasTagName(objectTag)) { + HTMLObjectElement* objectElement = static_cast<HTMLObjectElement*>(node()); + + objectElement->setNeedWidgetUpdate(false); + if (!objectElement->isFinishedParsingChildren()) + return; + + // Check for a child EMBED tag. + HTMLEmbedElement* embed = 0; + for (Node* child = objectElement->firstChild(); child; ) { + if (child->hasTagName(embedTag)) { + embed = static_cast<HTMLEmbedElement*>(child); + break; + } + + if (child->hasTagName(objectTag)) + child = child->nextSibling(); // Don't descend into nested OBJECT tags + else + child = child->traverseNextNode(objectElement); // Otherwise descend (EMBEDs may be inside COMMENT tags) + } + + // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. + HTMLElement* embedOrObject; + if (embed) { + embedOrObject = embed; + url = embed->url(); + serviceType = embed->serviceType(); + } else + embedOrObject = objectElement; + + // If there was no URL or type defined in EMBED, try the OBJECT tag. + if (url.isEmpty()) + url = objectElement->url(); + if (serviceType.isEmpty()) + serviceType = objectElement->serviceType(); + + HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; + + // Scan the PARAM children. + // Get the URL and type from the params if we don't already have them. + // Get the attributes from the params if there is no EMBED tag. + Node* child = objectElement->firstChild(); + while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { + if (child->hasTagName(paramTag)) { + HTMLParamElement* p = static_cast<HTMLParamElement*>(child); + String name = p->name(); + if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) + url = p->value(); + if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { + serviceType = p->value(); + int pos = serviceType.find(";"); + if (pos != -1) + serviceType = serviceType.left(pos); + } + if (!embed && !name.isEmpty()) { + uniqueParamNames.add(name.impl()); + paramNames.append(p->name()); + paramValues.append(p->value()); + } + } + child = child->nextSibling(); + } + + // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag + // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is + // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means + // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, + // else our Java plugin will misinterpret it. [4004531] + String codebase; + if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { + codebase = "codebase"; + uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already + } + + // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. + NamedNodeMap* attributes = embedOrObject->attributes(); + if (attributes) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + const AtomicString& name = it->name().localName(); + if (embed || !uniqueParamNames.contains(name.impl())) { + paramNames.append(name.string()); + paramValues.append(it->value().string()); + } + } + } + + mapDataParamToSrc(¶mNames, ¶mValues); + + // If we still don't have a type, try to map from a specific CLASSID to a type. + if (serviceType.isEmpty()) + serviceType = serviceTypeForClassId(objectElement->classId()); + + if (!isURLAllowed(document(), url)) + return; + + // Find out if we support fallback content. + m_hasFallbackContent = false; + for (Node* child = objectElement->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { + if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) // Discount <embed> and <param> + || (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) + m_hasFallbackContent = true; + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + } + + bool success = objectElement->dispatchBeforeLoadEvent(url) && frame->loader()->requestObject(this, url, objectElement->getAttribute(nameAttr), serviceType, paramNames, paramValues); + if (!success && m_hasFallbackContent) + objectElement->renderFallbackContent(); + + } else if (node()->hasTagName(embedTag)) { + HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(node()); + embedElement->setNeedWidgetUpdate(false); + url = embedElement->url(); + serviceType = embedElement->serviceType(); + + if (url.isEmpty() && serviceType.isEmpty()) + return; + if (!isURLAllowed(document(), url)) + return; + + // add all attributes set on the embed object + NamedNodeMap* attributes = embedElement->attributes(); + if (attributes) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + } + + if (embedElement->dispatchBeforeLoadEvent(url)) + frame->loader()->requestObject(this, url, embedElement->getAttribute(nameAttr), serviceType, paramNames, paramValues); + } +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) { + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node()); + + mediaElement->setNeedWidgetUpdate(false); + if (node()->hasTagName(videoTag)) { + HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node()); + String poster = vid->poster(); + if (!poster.isEmpty()) { + paramNames.append("_media_element_poster_"); + paramValues.append(poster); + } + } + + url = mediaElement->initialURL(); + if (!url.isEmpty()) { + paramNames.append("_media_element_src_"); + paramValues.append(url); + } + + serviceType = "application/x-media-element-proxy-plugin"; + + if (mediaElement->dispatchBeforeLoadEvent(url)) + frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues); + } +#endif +} + +void RenderEmbeddedObject::paint(PaintInfo& paintInfo, int tx, int ty) +{ + if (m_showsMissingPluginIndicator) { + RenderReplaced::paint(paintInfo, tx, ty); + return; + } + + RenderPartObject::paint(paintInfo, tx, ty); +} + +void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty) +{ + if (!m_showsMissingPluginIndicator) + return; + + if (paintInfo.phase == PaintPhaseSelection) + return; + + GraphicsContext* context = paintInfo.context; + if (context->paintingDisabled()) + return; + + FloatRect pluginRect = contentBoxRect(); + pluginRect.move(tx, ty); + + FontDescription fontDescription; + RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription); + fontDescription.setWeight(FontWeightBold); + Font font(fontDescription, 0, 0); + font.update(0); + + String label = missingPluginText(); + TextRun run(label.characters(), label.length()); + run.disableRoundingHacks(); + float textWidth = font.floatWidth(run); + + FloatRect missingPluginRect; + missingPluginRect.setSize(FloatSize(textWidth + missingPluginRoundedRectLeftRightTextMargin * 2, missingPluginRoundedRectHeight)); + missingPluginRect.setLocation(FloatPoint((pluginRect.size().width() / 2 - missingPluginRect.size().width() / 2) + pluginRect.location().x(), + (pluginRect.size().height() / 2 - missingPluginRect.size().height() / 2) + pluginRect.location().y())); + + Path path = Path::createRoundedRectangle(missingPluginRect, FloatSize(missingPluginRoundedRectRadius, missingPluginRoundedRectRadius)); + context->save(); + context->clip(pluginRect); + context->beginPath(); + context->addPath(path); + context->setAlpha(missingPluginRoundedRectOpacity); + context->setFillColor(Color::white, style()->colorSpace()); + context->fillPath(); + + FloatPoint labelPoint(roundf(missingPluginRect.location().x() + (missingPluginRect.size().width() - textWidth) / 2), + roundf(missingPluginRect.location().y()+ (missingPluginRect.size().height() - font.height()) / 2 + font.ascent())); + context->setAlpha(missingPluginTextOpacity); + context->setFillColor(Color::black, style()->colorSpace()); + context->drawBidiText(font, run, labelPoint); + context->restore(); +} + +void RenderEmbeddedObject::layout() +{ + ASSERT(needsLayout()); + + calcWidth(); + calcHeight(); + + RenderPart::layout(); + + m_overflow.clear(); + addShadowOverflow(); + + if (!widget() && frameView()) + frameView()->addWidgetToUpdate(this); + + setNeedsLayout(false); +} + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.h new file mode 100644 index 0000000000..657701fd23 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderEmbeddedObject.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderEmbeddedObject_h +#define RenderEmbeddedObject_h + +#include "RenderPartObject.h" + +namespace WebCore { + +// Renderer for embeds and objects. +class RenderEmbeddedObject : public RenderPartObject { +public: + RenderEmbeddedObject(Element*); + virtual ~RenderEmbeddedObject(); + + void updateWidget(bool onlyCreateNonNetscapePlugins); + void setShowsMissingPluginIndicator(bool showsMissingPluginIndicator) { m_showsMissingPluginIndicator = showsMissingPluginIndicator; } + bool showsMissingPluginIndicator() const { return m_showsMissingPluginIndicator; } +#if USE(ACCELERATED_COMPOSITING) + virtual bool allowsAcceleratedCompositing() const; +#endif + +private: + virtual const char* renderName() const { return "RenderEmbeddedObject"; } + virtual bool isEmbeddedObject() const { return true; } + + virtual void paintReplaced(PaintInfo&, int, int); + virtual void paint(PaintInfo& paintInfo, int, int); + +#if USE(ACCELERATED_COMPOSITING) + virtual bool requiresLayer() const; +#endif + + virtual void layout(); + bool m_showsMissingPluginIndicator; +}; + +inline RenderEmbeddedObject* toRenderEmbeddedObject(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderEmbeddedObject")); + return static_cast<RenderEmbeddedObject*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderEmbeddedObject(const RenderEmbeddedObject*); + +} // namespace WebCore + +#endif // RenderEmbeddedObject_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp index 8618d11c04..889b0bc025 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp @@ -1,6 +1,4 @@ /* - * 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) @@ -121,6 +119,9 @@ RenderBox* RenderFieldset::findLegend() const void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { + if (!shouldPaintWithinRoot(paintInfo)) + return; + int w = width(); int h = height(); RenderBox* legend = findLegend(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp index 72623f73e4..14d126d247 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "RenderFileUploadControl.h" +#include "Chrome.h" #include "FileList.h" #include "Frame.h" #include "FrameView.h" @@ -63,8 +64,13 @@ private: RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input) : RenderBlock(input) , m_button(0) - , m_fileChooser(FileChooser::create(this, input->value())) { + FileList* list = input->files(); + Vector<String> filenames; + unsigned length = list ? list->length() : 0; + for (unsigned i = 0; i < length; ++i) + filenames.append(list->item(i)->path()); + m_fileChooser = FileChooser::create(this, filenames); } RenderFileUploadControl::~RenderFileUploadControl() @@ -103,15 +109,32 @@ bool RenderFileUploadControl::allowsMultipleFiles() return !input->getAttribute(multipleAttr).isNull(); } +String RenderFileUploadControl::acceptTypes() +{ + return static_cast<HTMLInputElement*>(node())->accept(); +} + +void RenderFileUploadControl::chooseIconForFiles(const Vector<String>& filenames) +{ + if (Chrome* chromePointer = chrome()) + chromePointer->chooseIconForFiles(filenames, m_fileChooser); +} + void RenderFileUploadControl::click() { + if (Chrome* chromePointer = chrome()) + chromePointer->runOpenPanel(node()->document()->frame(), m_fileChooser); +} + +Chrome* RenderFileUploadControl::chrome() const +{ Frame* frame = node()->document()->frame(); if (!frame) - return; + return 0; Page* page = frame->page(); if (!page) - return; - page->chrome()->runOpenPanel(frame, m_fileChooser); + return 0; + return page->chrome(); } void RenderFileUploadControl::updateFromElement() @@ -184,7 +207,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) } if (paintInfo.phase == PaintPhaseForeground) { - const String& displayedFilename = m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth()); + const String& displayedFilename = fileTextValue(); unsigned length = displayedFilename.length(); const UChar* string = displayedFilename.characters(); TextRun textRun(string, length, false, 0, 0, style()->direction() == RTL, style()->unicodeBidi() == Override); @@ -204,7 +227,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop() + buttonRenderer->baselinePosition(true, false); - paintInfo.context->setFillColor(style()->color()); + paintInfo.context->setFillColor(style()->color(), style()->colorSpace()); // Draw the filename paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY)); @@ -284,7 +307,7 @@ String RenderFileUploadControl::buttonValue() return m_button->value(); } -String RenderFileUploadControl::fileTextValue() +String RenderFileUploadControl::fileTextValue() const { return m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth()); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h index bd7d62a490..99dd35c365 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h @@ -26,6 +26,7 @@ namespace WebCore { +class Chrome; class HTMLInputElement; // Each RenderFileUploadControl contains a RenderButton (for opening the file chooser), and @@ -37,17 +38,15 @@ public: RenderFileUploadControl(HTMLInputElement*); virtual ~RenderFileUploadControl(); + virtual bool isFileUploadControl() const { return true; } + void click(); - void valueChanged(); - void receiveDroppedFiles(const Vector<String>&); String buttonValue(); - String fileTextValue(); + String fileTextValue() const; - bool allowsMultipleFiles(); - private: virtual const char* renderName() const { return "RenderFileUploadControl"; } @@ -57,6 +56,14 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + // FileChooserClient methods. + void valueChanged(); + void repaint() { RenderBlock::repaint(); } + bool allowsMultipleFiles(); + String acceptTypes(); + void chooseIconForFiles(const Vector<String>&); + + Chrome* chrome() const; int maxFilenameWidth() const; PassRefPtr<RenderStyle> createButtonStyle(const RenderStyle* parentStyle) const; @@ -66,10 +73,16 @@ private: inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object) { - ASSERT(!object || !strcmp(object->renderName(), "RenderFileUploadControl")); + ASSERT(!object || object->isFileUploadControl()); return static_cast<RenderFileUploadControl*>(object); } +inline const RenderFileUploadControl* toRenderFileUploadControl(const RenderObject* object) +{ + ASSERT(!object || object->isFileUploadControl()); + return static_cast<const RenderFileUploadControl*>(object); +} + // This will catch anyone doing an unnecessary cast. void toRenderFileUploadControl(const RenderFileUploadControl*); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp index 63c72fd0d0..7991b61ce8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp @@ -410,8 +410,13 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) child->layer()->setStaticX(xPos); else child->layer()->setStaticX(width() - xPos); } - if (child->style()->hasStaticY()) - child->layer()->setStaticY(yPos); + if (child->style()->hasStaticY()) { + RenderLayer* childLayer = child->layer(); + if (childLayer->staticY() != yPos) { + child->layer()->setStaticY(yPos); + child->setChildNeedsLayout(true, false); + } + } child = iterator.next(); continue; } @@ -640,7 +645,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of // mainstream block layout); this is not really part of the XUL box model. - bool haveLineClamp = style()->lineClamp() >= 0 && style()->lineClamp() <= 100; + bool haveLineClamp = !style()->lineClamp().isNone(); if (haveLineClamp) { int maxLineCount = 0; child = iterator.first(); @@ -665,7 +670,8 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // Get the # of lines and then alter all block flow children with auto height to use the // specified height. We always try to leave room for at least one line. - int numVisibleLines = max(1, static_cast<int>((maxLineCount + 1) * style()->lineClamp() / 100.0)); + LineClampValue lineClamp = style()->lineClamp(); + int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value(); if (numVisibleLines < maxLineCount) { for (child = iterator.first(); child; child = iterator.next()) { if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow()) @@ -696,28 +702,25 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (!lastLine) continue; - // See if the last item is an anchor - InlineBox* anchorBox = lastLine->lastChild(); - if (!anchorBox) - continue; - if (!anchorBox->renderer()->node()) - continue; - if (!anchorBox->renderer()->node()->isLink()) - continue; - RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1); if (!lastVisibleLine) continue; const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' }; DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2)); - + DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1)); const Font& font = style(numVisibleLines == 1)->font(); - int ellipsisAndSpaceWidth = font.width(TextRun(ellipsisAndSpace, 2)); - // Get ellipsis width + " " + anchor width - int totalWidth = ellipsisAndSpaceWidth + anchorBox->width(); - + // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too + int totalWidth; + InlineBox* anchorBox = lastLine->lastChild(); + if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink()) + totalWidth = anchorBox->width() + font.width(TextRun(ellipsisAndSpace, 2)); + else { + anchorBox = 0; + totalWidth = font.width(TextRun(&horizontalEllipsis, 1)); + } + // See if this width can be accommodated on the last visible line RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer()); RenderBlock* srcBlock = toRenderBlock(lastLine->renderer()); @@ -739,7 +742,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) continue; // Let the truncation code kick in. - lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox); + lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox); destBlock->setHasMarkupTruncation(true); } } @@ -769,8 +772,13 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) else child->layer()->setStaticX(borderRight()+paddingRight()); } - if (child->style()->hasStaticY()) - child->layer()->setStaticY(height()); + if (child->style()->hasStaticY()) { + RenderLayer* childLayer = child->layer(); + if (childLayer->staticY() != height()) { + child->layer()->setStaticY(height()); + child->setChildNeedsLayout(true, false); + } + } child = iterator.next(); continue; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp index b15d55c347..aa28ff08e6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Apple Computer, Inc. * Copyright (C) 2009 Google, Inc. + * Copyright (C) Research In Motion Limited 2010. 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 @@ -27,9 +28,9 @@ #include "GraphicsContext.h" #include "RenderView.h" #include "SVGForeignObjectElement.h" -#include "SVGLength.h" #include "SVGRenderSupport.h" -#include "SVGTransformList.h" +#include "SVGSVGElement.h" +#include "TransformState.h" namespace WebCore { @@ -38,22 +39,18 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node) { } -TransformationMatrix RenderForeignObject::translationForAttributes() const -{ - SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); - return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign)); -} - void RenderForeignObject::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled()) return; - // Copy the paint info so that modifications to the damage rect do not affect callers - PaintInfo childPaintInfo = paintInfo; + PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); - applyTransformToPaintInfo(childPaintInfo, localToParentTransform()); - childPaintInfo.context->clip(clipRect(0, 0)); + + applyTransformToPaintInfo(childPaintInfo, localTransform()); + + if (SVGRenderBase::isOverflowHidden(this)) + childPaintInfo.context->clip(m_viewport); float opacity = style()->opacity(); if (opacity < 1.0f) @@ -67,29 +64,33 @@ void RenderForeignObject::paint(PaintInfo& paintInfo, int, int) childPaintInfo.context->restore(); } -FloatRect RenderForeignObject::objectBoundingBox() const +IntRect RenderForeignObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { - return borderBoxRect(); + return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer); } -FloatRect RenderForeignObject::repaintRectInLocalCoordinates() const +void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) { - // HACK: to maintain historical LayoutTest results for now. - // RenderForeignObject is a RenderBlock (not a RenderSVGModelObject) so this - // should not affect repaint correctness. But it should really be: - // return borderBoxRect(); - return FloatRect(); + SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); } -void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) +const AffineTransform& RenderForeignObject::localToParentTransform() const { - rect = localToParentTransform().mapRect(rect); - RenderBlock::computeRectForRepaint(repaintContainer, rect, fixed); + m_localToParentTransform = localTransform(); + m_localToParentTransform.translate(m_viewport.x(), m_viewport.y()); + return m_localToParentTransform; } -TransformationMatrix RenderForeignObject::localToParentTransform() const +void RenderForeignObject::calcWidth() { - return localTransform() * translationForAttributes(); + // FIXME: Investigate in size rounding issues + setWidth(static_cast<int>(roundf(m_viewport.width()))); +} + +void RenderForeignObject::calcHeight() +{ + // FIXME: Investigate in size rounding issues + setHeight(static_cast<int>(roundf(m_viewport.height()))); } void RenderForeignObject::layout() @@ -98,18 +99,36 @@ void RenderForeignObject::layout() ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - m_localTransform = static_cast<SVGForeignObjectElement*>(node())->animatedLocalTransform(); + SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); + m_localTransform = foreign->animatedLocalTransform(); + + // Cache viewport boundaries + FloatPoint viewportLocation(foreign->x().value(foreign), foreign->y().value(foreign)); + m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width().value(foreign), foreign->height().value(foreign))); + + // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct + // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those + // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS. + + // FIXME: Investigate in location rounding issues - only affects RenderForeignObject & RenderSVGText + setLocation(roundedIntPoint(viewportLocation)); RenderBlock::layout(); - repainter.repaintAfterLayout(); + repainter.repaintAfterLayout(); setNeedsLayout(false); } bool RenderForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); - return RenderBlock::nodeAtPoint(request, result, static_cast<int>(localPoint.x()), static_cast<int>(localPoint.y()), 0, 0, hitTestAction); + FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent); + + // Early exit if local point is not contained in clipped viewport area + if (SVGRenderBase::isOverflowHidden(this) && !m_viewport.contains(localPoint)) + return false; + + IntPoint roundedLocalPoint = roundedIntPoint(localPoint); + return RenderBlock::nodeAtPoint(request, result, roundedLocalPoint.x(), roundedLocalPoint.y(), 0, 0, hitTestAction); } bool RenderForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) @@ -118,6 +137,14 @@ bool RenderForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int return false; } -} // namespace WebCore +void RenderForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const +{ + // When crawling up the hierachy starting from foreignObject child content, useTransforms may not be set to true. + if (!useTransforms) + useTransforms = true; + SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); +} + +} -#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h index e014f22a5d..bb6b555636 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h @@ -21,9 +21,10 @@ #ifndef RenderForeignObject_h #define RenderForeignObject_h -#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) -#include "TransformationMatrix.h" +#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) +#include "AffineTransform.h" +#include "FloatPoint.h" #include "RenderSVGBlock.h" namespace WebCore { @@ -38,28 +39,35 @@ public: virtual void paint(PaintInfo&, int parentX, int parentY); - virtual TransformationMatrix localToParentTransform() const; - + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + virtual bool requiresLayer() const { return false; } virtual void layout(); - virtual FloatRect objectBoundingBox() const; - virtual FloatRect repaintRectInLocalCoordinates() const; + virtual FloatRect objectBoundingBox() const { return m_viewport; } + virtual FloatRect strokeBoundingBox() const { return m_viewport; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_viewport; } virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual bool isSVGForeignObject() const { return true; } + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const; + private: - TransformationMatrix translationForAttributes() const; + virtual void calcWidth(); + virtual void calcHeight(); - virtual TransformationMatrix localTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const; + virtual AffineTransform localTransform() const { return m_localTransform; } - TransformationMatrix m_localTransform; + FloatRect m_viewport; + AffineTransform m_localTransform; + mutable AffineTransform m_localToParentTransform; }; -} // namespace WebCore +} -#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) -#endif // RenderForeignObject_h +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp index a7b131b2b6..5f87417cc6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp @@ -26,6 +26,7 @@ #include "FrameView.h" #include "HTMLFrameElement.h" +#include "RenderView.h" namespace WebCore { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp index 2fe1ddbf1f..7855b2d8f7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp @@ -1,6 +1,4 @@ /** - * This file is part of the KDE project. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> * (C) 2000 Stefan Schimanski (1Stein@gmx.de) @@ -38,6 +36,7 @@ #include "MouseEvent.h" #include "RenderFrame.h" #include "RenderView.h" +#include "Settings.h" namespace WebCore { @@ -87,13 +86,14 @@ void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect // Fill first. GraphicsContext* context = paintInfo.context; - context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor()); + ColorSpace colorSpace = style()->colorSpace(); + context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor(), colorSpace); // Now stroke the edges but only if we have enough room to paint both edges with a little // bit of the fill color showing through. if (borderRect.width() >= 3) { - context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor()); - context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor()); + context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor(), colorSpace); } } @@ -106,13 +106,14 @@ void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& b // Fill first. GraphicsContext* context = paintInfo.context; - context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor()); + ColorSpace colorSpace = style()->colorSpace(); + context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor(), colorSpace); // Now stroke the edges but only if we have enough room to paint both edges with a little // bit of the fill color showing through. if (borderRect.height() >= 3) { - context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor()); - context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor()); + context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace); } } @@ -473,7 +474,10 @@ void RenderFrameSet::layout() layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); - positionFrames(); + if (flattenFrameSet()) + positionFramesWithFlattening(); + else + positionFrames(); RenderBox::layout(); @@ -532,6 +536,119 @@ void RenderFrameSet::positionFrames() } } +void RenderFrameSet::positionFramesWithFlattening() +{ + RenderBox* child = firstChildBox(); + if (!child) + return; + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + + int borderThickness = frameSet()->border(); + bool repaintNeeded = false; + + // calculate frameset height based on actual content height to eliminate scrolling + bool out = false; + for (int r = 0; r < rows && !out; r++) { + int extra = 0; + int height = m_rows.m_sizes[r]; + + for (int c = 0; c < cols; c++) { + IntRect oldFrameRect = child->frameRect(); + + int width = m_cols.m_sizes[c]; + + bool fixedWidth = frameSet()->colLengths() && frameSet()->colLengths()[c].isFixed(); + bool fixedHeight = frameSet()->rowLengths() && frameSet()->rowLengths()[r].isFixed(); + + // has to be resized and itself resize its contents + if (!fixedWidth) + child->setWidth(width ? width + extra / (cols - c) : 0); + else + child->setWidth(width); + child->setHeight(height); + + child->setNeedsLayout(true); + + if (child->isFrameSet()) + toRenderFrameSet(child)->layout(); + else + toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight); + + if (child->height() > m_rows.m_sizes[r]) + m_rows.m_sizes[r] = child->height(); + if (child->width() > m_cols.m_sizes[c]) + m_cols.m_sizes[c] = child->width(); + + if (child->frameRect() != oldFrameRect) + repaintNeeded = true; + + // difference between calculated frame width and the width it actually decides to have + extra += width - m_cols.m_sizes[c]; + + child = child->nextSiblingBox(); + if (!child) { + out = true; + break; + } + } + } + + int xPos = 0; + int yPos = 0; + out = false; + child = firstChildBox(); + for (int r = 0; r < rows && !out; r++) { + xPos = 0; + for (int c = 0; c < cols; c++) { + // ensure the rows and columns are filled + IntRect oldRect = child->frameRect(); + + child->setLocation(xPos, yPos); + child->setHeight(m_rows.m_sizes[r]); + child->setWidth(m_cols.m_sizes[c]); + + if (child->frameRect() != oldRect) { + repaintNeeded = true; + + // update to final size + child->setNeedsLayout(true); + if (child->isFrameSet()) + toRenderFrameSet(child)->layout(); + else + toRenderFrame(child)->layoutWithFlattening(true, true); + } + + xPos += m_cols.m_sizes[c] + borderThickness; + child = child->nextSiblingBox(); + if (!child) { + out = true; + break; + } + } + yPos += m_rows.m_sizes[r] + borderThickness; + } + + setWidth(xPos - borderThickness); + setHeight(yPos - borderThickness); + + if (repaintNeeded) + repaint(); + + // all the remaining frames are hidden to avoid ugly spurious unflowed frames + for (; child; child = child->nextSiblingBox()) { + child->setWidth(0); + child->setHeight(0); + child->setNeedsLayout(false); + } +} + +bool RenderFrameSet::flattenFrameSet() const +{ + return document()->frame() && document()->frame()->settings()->frameFlatteningEnabled(); +} + void RenderFrameSet::startResizing(GridAxis& axis, int position) { int split = hitTestSplit(axis, position); @@ -560,6 +677,9 @@ void RenderFrameSet::continueResizing(GridAxis& axis, int position) bool RenderFrameSet::userResize(MouseEvent* evt) { + if (flattenFrameSet()) + return false; + if (!m_isResizing) { if (needsLayout()) return false; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h index 26bf73281d..d0ab346be9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h @@ -95,15 +95,18 @@ private: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual void paint(PaintInfo&, int tx, int ty); virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; - + inline HTMLFrameSetElement* frameSet() const; + bool flattenFrameSet() const; + void setIsResizing(bool); void layOutAxis(GridAxis&, const Length*, int availableSpace); void computeEdgeInfo(); void fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c); void positionFrames(); + void positionFramesWithFlattening(); int splitPosition(const GridAxis&, int split) const; int hitTestSplit(const GridAxis&, int position) const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp index 4206b1cf1c..a14ab2753c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp @@ -4,7 +4,7 @@ * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,14 +26,19 @@ #include "config.h" #include "RenderImage.h" +#include "Frame.h" #include "GraphicsContext.h" +#include "HTMLAreaElement.h" +#include "HTMLCollection.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" #include "HTMLMapElement.h" #include "HTMLNames.h" #include "HitTestResult.h" #include "Page.h" +#include "RenderTheme.h" #include "RenderView.h" +#include "SelectionController.h" #include <wtf/CurrentTime.h> #include <wtf/UnusedParam.h> @@ -49,7 +54,7 @@ namespace WebCore { static const double cInterpolationCutoff = 800. * 800.; static const double cLowQualityTimeThreshold = 0.050; // 50 ms -class RenderImageScaleData { +class RenderImageScaleData : public Noncopyable { public: RenderImageScaleData(RenderImage* image, const IntSize& size, double time, bool lowQualityScale) : m_size(size) @@ -364,8 +369,8 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) if (cWidth > 2 && cHeight > 2) { // Draw an outline rect where the image should be. context->setStrokeStyle(SolidStroke); - context->setStrokeColor(Color::lightGray); - context->setFillColor(Color::transparent); + context->setStrokeColor(Color::lightGray, style()->colorSpace()); + context->setFillColor(Color::transparent, style()->colorSpace()); context->drawRect(IntRect(tx + leftBorder + leftPad, ty + topBorder + topPad, cWidth, cHeight)); bool errorPictureDrawn = false; @@ -386,13 +391,13 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) centerY = 0; imageX = leftBorder + leftPad + centerX + 1; imageY = topBorder + topPad + centerY + 1; - context->drawImage(image(), IntPoint(tx + imageX, ty + imageY)); + context->drawImage(image(), style()->colorSpace(), IntPoint(tx + imageX, ty + imageY)); errorPictureDrawn = true; } if (!m_altText.isEmpty()) { String text = document()->displayStringModifiedByEncoding(m_altText); - context->setFillColor(style()->color()); + context->setFillColor(style()->color(), style()->colorSpace()); int ax = tx + leftBorder + leftPad; int ay = ty + topBorder + topPad; const Font& font = style()->font(); @@ -420,20 +425,77 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) #endif IntSize contentSize(cWidth, cHeight); - bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, contentSize); IntRect rect(IntPoint(tx + leftBorder + leftPad, ty + topBorder + topPad), contentSize); - HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0; - CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; - context->drawImage(image(cWidth, cHeight), rect, compositeOperator, useLowQualityScaling); + paintIntoRect(context, rect); } } +void RenderImage::paint(PaintInfo& paintInfo, int tx, int ty) +{ + RenderReplaced::paint(paintInfo, tx, ty); + + if (paintInfo.phase == PaintPhaseOutline) + paintFocusRings(paintInfo, style()); +} + +void RenderImage::paintFocusRings(PaintInfo& paintInfo, const RenderStyle* style) +{ + // Don't draw focus rings if printing. + if (document()->printing() || !document()->frame()->selection()->isFocusedAndActive()) + return; + + if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) + return; + + HTMLMapElement* mapElement = imageMap(); + if (!mapElement) + return; + + Document* document = mapElement->document(); + if (!document) + return; + + Node* focusedNode = document->focusedNode(); + if (!focusedNode) + return; + + RefPtr<HTMLCollection> areas = mapElement->areas(); + unsigned numAreas = areas->length(); + + // FIXME: Clip the paths to the image bounding box. + for (unsigned k = 0; k < numAreas; ++k) { + HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(areas->item(k)); + if (focusedNode != areaElement) + continue; + + Vector<Path> focusRingPaths; + focusRingPaths.append(areaElement->getPath(this)); + paintInfo.context->drawFocusRing(focusRingPaths, style->outlineWidth(), style->outlineOffset(), style->outlineColor()); + break; + } +} + +void RenderImage::paintIntoRect(GraphicsContext* context, const IntRect& rect) +{ + if (!hasImage() || errorOccurred() || rect.width() <= 0 || rect.height() <= 0) + return; + + Image* img = image(rect.width(), rect.height()); + if (!img || img->isNull()) + return; + + HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0; + CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; + bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, rect.size()); + context->drawImage(image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling); +} + int RenderImage::minimumReplacedHeight() const { return errorOccurred() ? intrinsicSize().height() : 0; } -HTMLMapElement* RenderImage::imageMap() +HTMLMapElement* RenderImage::imageMap() const { HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0; return i ? i->document()->getImageMap(i->getAttribute(usemapAttr)) : 0; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h index 2224412ae1..b89a65249d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderImage.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -43,7 +43,7 @@ public: void setCachedImage(CachedImage*); CachedImage* cachedImage() const { return m_cachedImage.get(); } - HTMLMapElement* imageMap(); + HTMLMapElement* imageMap() const; void resetAnimation(); @@ -57,6 +57,15 @@ protected: virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void paintIntoRect(GraphicsContext*, const IntRect&); + void paintFocusRings(PaintInfo&, const RenderStyle*); + virtual void paint(PaintInfo&, int tx, int ty); + + bool isWidthSpecified() const; + bool isHeightSpecified() const; + + virtual void intrinsicSizeChanged() { imageChanged(imagePtr()); } + private: virtual const char* renderName() const { return "RenderImage"; } @@ -82,14 +91,9 @@ private: virtual IntSize imageSize(float multiplier) const { return m_cachedImage ? m_cachedImage->imageSize(multiplier) : IntSize(); } virtual WrappedImagePtr imagePtr() const { return m_cachedImage.get(); } - virtual void intrinsicSizeChanged() { imageChanged(imagePtr()); } - int calcAspectRatioWidth() const; int calcAspectRatioHeight() const; - bool isWidthSpecified() const; - bool isHeightSpecified() const; - protected: // The image we are rendering. CachedResourceHandle<CachedImage> m_cachedImage; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp index 2f9a247a5e..1d76742efe 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp @@ -23,6 +23,7 @@ #include "config.h" #include "RenderInline.h" +#include "Chrome.h" #include "FloatQuad.h" #include "GraphicsContext.h" #include "HitTestResult.h" @@ -79,7 +80,7 @@ void RenderInline::destroy() // not have a parent that means they are either already disconnected or // root lines that can just be destroyed without disconnecting. if (firstLineBox()->parent()) { - for (InlineRunBox* box = firstLineBox(); box; box = box->nextLineBox()) + for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) box->remove(); } } else if (isInline() && parent()) @@ -409,7 +410,7 @@ void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty) void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { - if (InlineRunBox* curr = firstLineBox()) { + if (InlineFlowBox* curr = firstLineBox()) { for (; curr; curr = curr->nextLineBox()) rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())); } else @@ -428,7 +429,7 @@ void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty) void RenderInline::absoluteQuads(Vector<FloatQuad>& quads) { - if (InlineRunBox* curr = firstLineBox()) { + if (InlineFlowBox* curr = firstLineBox()) { for (; curr; curr = curr->nextLineBox()) { FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height()); quads.append(localToAbsoluteQuad(localRect)); @@ -533,7 +534,7 @@ IntRect RenderInline::linesBoundingBox() const // Return the width of the minimal left side and the maximal right side. int leftSide = 0; int rightSide = 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { if (curr == firstLineBox() || curr->x() < leftSide) leftSide = curr->x(); if (curr == firstLineBox() || curr->x() + curr->width() > rightSide) @@ -556,7 +557,7 @@ IntRect RenderInline::linesVisibleOverflowBoundingBox() const // Return the width of the minimal left side and the maximal right side. int leftSide = numeric_limits<int>::max(); int rightSide = numeric_limits<int>::min(); - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { leftSide = min(leftSide, curr->leftVisibleOverflow()); rightSide = max(rightSide, curr->rightVisibleOverflow()); } @@ -598,11 +599,10 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repain // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. - int x = r.x(); - int y = r.y(); + IntRect repaintRect(r); + repaintRect.move(-cb->layer()->scrolledContentOffset()); // For overflow:auto/scroll/hidden. + IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height()); - cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. - IntRect repaintRect(x, y, r.width(), r.height()); r = intersection(repaintRect, boxRect); } @@ -709,7 +709,7 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, o->computeRectForRepaint(repaintContainer, rect, fixed); } -IntSize RenderInline::offsetFromContainer(RenderObject* container) const +IntSize RenderInline::offsetFromContainer(RenderObject* container, const IntPoint& point) const { ASSERT(container == this->container()); @@ -717,13 +717,7 @@ IntSize RenderInline::offsetFromContainer(RenderObject* container) const if (isRelPositioned()) offset += relativePositionOffset(); - if (!isInline() || isReplaced()) { - RenderBlock* cb; - if (container->isBlockFlow() && (cb = toRenderBlock(container))->hasColumns()) { - IntRect rect(0, 0, 1, 1); - cb->adjustRectForColumns(rect); - } - } + container->adjustForColumns(offset, point); if (container->hasOverflowClip()) offset -= toRenderBox(container)->layer()->scrolledContentOffset(); @@ -752,7 +746,7 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; - IntSize containerOffset = offsetFromContainer(o); + IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint())); bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (useTransforms && shouldUseTransformFromContainer(o)) { @@ -784,7 +778,7 @@ void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Trans o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); - IntSize containerOffset = offsetFromContainer(o); + IntSize containerOffset = offsetFromContainer(o, IntPoint()); bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (useTransforms && shouldUseTransformFromContainer(o)) { @@ -931,13 +925,15 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } -void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox* root = curr->root(); int top = max(root->lineTop(), curr->y()); int bottom = min(root->lineBottom(), curr->y() + curr->height()); - graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + top, curr->width(), bottom - top)); + IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top); + if (!rect.isEmpty()) + rects.append(rect); } for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { @@ -948,17 +944,17 @@ void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, i pos = curr->localToAbsolute(); else if (curr->isBox()) pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y()); - curr->addFocusRingRects(graphicsContext, pos.x(), pos.y()); + curr->addFocusRingRects(rects, pos.x(), pos.y()); } } if (continuation()) { if (continuation()->isInline()) - continuation()->addFocusRingRects(graphicsContext, + continuation()->addFocusRingRects(rects, tx - containingBlock()->x() + continuation()->containingBlock()->x(), ty - containingBlock()->y() + continuation()->containingBlock()->y()); else - continuation()->addFocusRingRects(graphicsContext, + continuation()->addFocusRingRects(rects, tx - containingBlock()->x() + toRenderBox(continuation())->x(), ty - containingBlock()->y() + toRenderBox(continuation())->y()); } @@ -975,13 +971,12 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty if (!oc.isValid()) oc = style()->color(); - graphicsContext->initFocusRing(ow, style()->outlineOffset()); - addFocusRingRects(graphicsContext, tx, ty); + Vector<IntRect> focusRingRects; + addFocusRingRects(focusRingRects, tx, ty); if (style()->outlineStyleIsAuto()) - graphicsContext->drawFocusRing(oc); + graphicsContext->drawFocusRing(focusRingRects, ow, style()->outlineOffset(), oc); else - addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); - graphicsContext->clearFocusRing(); + addPDFURLRect(graphicsContext, unionRect(focusRingRects)); } if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE) @@ -990,7 +985,7 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty Vector<IntRect> rects; rects.append(IntRect()); - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox* root = curr->root(); int top = max(root->lineTop(), curr->y()); int bottom = min(root->lineBottom(), curr->y() + curr->height()); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h index 8e9715ccbd..7fcb5161bc 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderInline.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h @@ -44,7 +44,7 @@ public: virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); - virtual IntSize offsetFromContainer(RenderObject*) const; + virtual IntSize offsetFromContainer(RenderObject*, const IntPoint&) const; IntRect linesBoundingBox() const; IntRect linesVisibleOverflowBoundingBox() const; @@ -65,7 +65,7 @@ public: IntSize relativePositionedInlineOffset(const RenderBox* child) const; - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); void paintOutline(GraphicsContext*, int tx, int ty); int verticalPositionFromCache(bool firstLine) const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp index fea61c9feb..15ffb64b49 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -73,11 +73,13 @@ #include "RenderScrollbar.h" #include "RenderScrollbarPart.h" #include "RenderTheme.h" +#include "RenderTreeAsText.h" #include "RenderView.h" #include "ScaleTransformOperation.h" #include "Scrollbar.h" #include "ScrollbarTheme.h" #include "SelectionController.h" +#include "TextStream.h" #include "TransformationMatrix.h" #include "TransformState.h" #include "TranslateTransformOperation.h" @@ -243,14 +245,6 @@ bool RenderLayer::hasAcceleratedCompositing() const #endif } -void RenderLayer::setStaticY(int staticY) -{ - if (m_staticY == staticY) - return; - m_staticY = staticY; - renderer()->setChildNeedsLayout(true, false); -} - void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) { if (flags & DoFullRepaint) { @@ -295,7 +289,7 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) if (newRect != m_repaintRect) renderer()->repaintUsingContainer(repaintContainer, newRect); } else - renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox); + renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox, &newRect, &newOutlineBox); } } m_repaintRect = newRect; @@ -383,6 +377,20 @@ TransformationMatrix RenderLayer::currentTransform() const return *m_transform; } +TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const +{ + if (!m_transform) + return TransformationMatrix(); + + if (paintBehavior & PaintBehaviorFlattenCompositingLayers) { + TransformationMatrix matrix = *m_transform; + makeMatrixRenderable(matrix, false /* flatten 3d */); + return matrix; + } + + return *m_transform; +} + void RenderLayer::setHasVisibleContent(bool b) { if (m_hasVisibleContent == b && !m_visibleContentStatusDirty) @@ -563,15 +571,20 @@ void RenderLayer::updateLayerPosition() RenderLayer* positionedParent = enclosingPositionedAncestor(); // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. - positionedParent->subtractScrolledContentOffset(x, y); + IntSize offset = positionedParent->scrolledContentOffset(); + x -= offset.width(); + y -= offset.height(); if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) { IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer())); x += offset.width(); y += offset.height(); } - } else if (parent()) - parent()->subtractScrolledContentOffset(x, y); + } else if (parent()) { + IntSize offset = parent()->scrolledContentOffset(); + x -= offset.width(); + y -= offset.height(); + } // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. @@ -651,6 +664,12 @@ static inline bool isPositionedContainer(RenderLayer* layer) return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform(); } +static inline bool isFixedPositionedContainer(RenderLayer* layer) +{ + RenderObject* o = layer->renderer(); + return o->isRenderView() || layer->hasTransform(); +} + RenderLayer* RenderLayer::enclosingPositionedAncestor() const { RenderLayer* curr = parent(); @@ -689,6 +708,32 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const } #endif +RenderLayer* RenderLayer::clippingRoot() const +{ +#if USE(ACCELERATED_COMPOSITING) + if (isComposited()) + return const_cast<RenderLayer*>(this); +#endif + + const RenderLayer* current = this; + while (current) { + if (current->renderer()->isRenderView()) + return const_cast<RenderLayer*>(current); + + current = compositingContainer(current); + ASSERT(current); + if (current->transform() +#if USE(ACCELERATED_COMPOSITING) + || current->isComposited() +#endif + ) + return const_cast<RenderLayer*>(current); + } + + ASSERT_NOT_REACHED(); + return 0; +} + IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const { // We don't use convertToLayerCoords because it doesn't know about transforms @@ -727,46 +772,18 @@ RenderLayer* RenderLayer::transparentPaintingAncestor() return 0; } -static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer) -{ - // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the - // paintDirtyRect, and that should cut down on the amount we have to paint. Still it - // would be better to respect clips. - - if (rootLayer != l && l->paintsWithTransform()) { - // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass - // the transformed layer and all of its children. - int x = 0; - int y = 0; - l->convertToLayerCoords(rootLayer, x, y); - - TransformationMatrix transform; - transform.translate(x, y); - transform = *l->transform() * transform; - transform = transform * enclosingTransform; +static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior); - // We now have a transform that will produce a rectangle in our view's space. - IntRect clipRect = transform.mapRect(l->boundingBox(l)); - - // Now shift the root layer to be us and pass down the new enclosing transform. - for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) { - if (!l->reflection() || l->reflectionLayer() != curr) - clipRect.unite(transparencyClipBox(transform, curr, l)); - } - - return clipRect; - } - - // Note: we don't have to walk z-order lists since transparent elements always establish - // a stacking context. This means we can just walk the layer tree directly. - IntRect clipRect = l->boundingBox(rootLayer); - +static void expandClipRectForDescendantsAndReflection(IntRect& clipRect, const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior) +{ // If we have a mask, then the clip is limited to the border box area (and there is // no need to examine child layers). if (!l->renderer()->hasMask()) { + // Note: we don't have to walk z-order lists since transparent elements always establish + // a stacking context. This means we can just walk the layer tree directly. for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) { if (!l->reflection() || l->reflectionLayer() != curr) - clipRect.unite(transparencyClipBox(enclosingTransform, curr, rootLayer)); + clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior)); } } @@ -782,25 +799,54 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor clipRect.unite(l->renderBox()->reflectedRect(clipRect)); clipRect.move(deltaX, deltaY); } +} + +static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior) +{ + // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the + // paintDirtyRect, and that should cut down on the amount we have to paint. Still it + // would be better to respect clips. + + if (rootLayer != l && l->paintsWithTransform(paintBehavior)) { + // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass + // the transformed layer and all of its children. + int x = 0; + int y = 0; + l->convertToLayerCoords(rootLayer, x, y); - // Now map the clipRect via the enclosing transform - return enclosingTransform.mapRect(clipRect); + TransformationMatrix transform; + transform.translate(x, y); + transform = *l->transform() * transform; + + IntRect clipRect = l->boundingBox(l); + expandClipRectForDescendantsAndReflection(clipRect, l, l, paintBehavior); + return transform.mapRect(clipRect); + } + + IntRect clipRect = l->boundingBox(rootLayer); + expandClipRectForDescendantsAndReflection(clipRect, l, rootLayer, paintBehavior); + return clipRect; } -void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer) +void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer, PaintBehavior paintBehavior) { - if (p->paintingDisabled() || (paintsWithTransparency() && m_usedTransparency)) + if (p->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency)) return; RenderLayer* ancestor = transparentPaintingAncestor(); if (ancestor) - ancestor->beginTransparencyLayers(p, rootLayer); + ancestor->beginTransparencyLayers(p, rootLayer, paintBehavior); - if (paintsWithTransparency()) { + if (paintsWithTransparency(paintBehavior)) { m_usedTransparency = true; p->save(); - p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer)); + IntRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior); + p->clip(clipRect); p->beginTransparencyLayer(renderer()->opacity()); +#ifdef REVEAL_TRANSPARENCY_LAYERS + p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), DeviceColorSpace); + p->fillRect(clipRect); +#endif } } @@ -958,9 +1004,10 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i { if (ancestorLayer == this) return; - - if (renderer()->style()->position() == FixedPosition) { - // Add in the offset of the view. We can obtain this by calling + + EPosition position = renderer()->style()->position(); + if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) { + // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling // localToAbsolute() on the RenderView. FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true); xPos += absPos.x(); @@ -968,9 +1015,43 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i return; } + if (position == FixedPosition) { + // For a fixed layers, we need to walk up to the root to see if there's a fixed position container + // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform, + // so we should always find the ancestor at or before we find the fixed position container. + RenderLayer* fixedPositionContainerLayer = 0; + bool foundAncestor = false; + for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) { + if (currLayer == ancestorLayer) + foundAncestor = true; + + if (isFixedPositionedContainer(currLayer)) { + fixedPositionContainerLayer = currLayer; + ASSERT(foundAncestor); + break; + } + } + + ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least. + + if (fixedPositionContainerLayer != ancestorLayer) { + int fixedContainerX = 0; + int fixedContainerY = 0; + convertToLayerCoords(fixedPositionContainerLayer, fixedContainerX, fixedContainerY); + + int ancestorX = 0; + int ancestorY = 0; + ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorX, ancestorY); + + xPos += (fixedContainerX - ancestorX); + yPos += (fixedContainerY - ancestorY); + return; + } + } + RenderLayer* parentLayer; - if (renderer()->style()->position() == AbsolutePosition) { - // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way + if (position == AbsolutePosition || position == FixedPosition) { + // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way. parentLayer = parent(); bool foundAncestorFirst = false; while (parentLayer) { @@ -1061,7 +1142,7 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) bool restrictedByLineClamp = false; if (renderer()->parent()) - restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; + restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { int newOffsetX = scrollXOffset() + xDelta; @@ -1086,7 +1167,7 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) frame->eventHandler()->updateAutoscrollRenderer(); } } else if (renderer()->view()->frameView()) { - // If we are here, we were called on a renderer that can be programatically scrolled, but doesn't + // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't // have an overflow clip. Which means that it is a document node that can be scrolled. renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement? @@ -1094,21 +1175,6 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) } } - -void -RenderLayer::addScrolledContentOffset(int& x, int& y) const -{ - x += scrollXOffset() + m_scrollLeftOverflow; - y += scrollYOffset(); -} - -void -RenderLayer::subtractScrolledContentOffset(int& x, int& y) const -{ - x -= scrollXOffset() + m_scrollLeftOverflow; - y -= scrollYOffset(); -} - void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint) { RenderBox* box = renderBox(); @@ -1146,7 +1212,9 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { - if (RenderLayer* compositingAncestor = ancestorCompositingLayer()) { + // Our stacking context is guaranteed to contain all of our descendants that may need + // repositioning, so update compositing layers from there. + if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { bool isUpdateRoot = true; compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); } @@ -1167,15 +1235,24 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai view->updateWidgetPositions(); } - // The caret rect needs to be invalidated after scrolling + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); + IntRect rectForRepaint = renderer()->clippedOverflowRectForRepaint(repaintContainer); + Frame* frame = renderer()->document()->frame(); - if (frame) - frame->invalidateSelection(); + if (frame) { + // The caret rect needs to be invalidated after scrolling + frame->selection()->setNeedsLayout(); + + FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint); + if (repaintContainer) + quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); + frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); + } // Just schedule a full repaint of our object. - if (repaint) - renderer()->repaint(); - + if (view && repaint) + renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); + if (updateScrollbars) { if (m_hBar) m_hBar->setValue(scrollXOffset()); @@ -1205,7 +1282,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, bool restrictedByLineClamp = false; if (renderer()->parent()) { parentLayer = renderer()->parent()->enclosingLayer(); - restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; + restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); } if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { @@ -1673,6 +1750,11 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const return localPoint - bottomRight; } +bool RenderLayer::hasOverflowControls() const +{ + return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE; +} + void RenderLayer::positionOverflowControls(int tx, int ty) { if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) @@ -1858,17 +1940,23 @@ RenderLayer::updateScrollInfoAfterLayout() // Set up the range (and page step/line step). if (m_hBar) { int clientWidth = box->clientWidth(); - int pageStep = (clientWidth - cAmountToKeepWhenPaging); - if (pageStep < 0) pageStep = clientWidth; - m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); + int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1); + m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_hBar->setProportion(clientWidth, m_scrollWidth); + // Explicitly set the horizontal scroll value. This ensures that when a + // right-to-left scrollable area's width (or content width) changes, the + // top right corner of the content doesn't shift with respect to the top + // right corner of the area. Conceptually, right-to-left areas have + // their origin at the top-right, but RenderLayer is top-left oriented, + // so this is needed to keep everything working (see how scrollXOffset() + // differs from scrollYOffset() to get an idea of why the horizontal and + // vertical scrollbars need to be treated differently). m_hBar->setValue(scrollXOffset()); } if (m_vBar) { int clientHeight = box->clientHeight(); - int pageStep = (clientHeight - cAmountToKeepWhenPaging); - if (pageStep < 0) pageStep = clientHeight; - m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); + int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1); + m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_vBar->setProportion(clientHeight, m_scrollHeight); } @@ -1921,7 +2009,7 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co return; } - context->fillRect(absRect, Color::white); + context->fillRect(absRect, Color::white, box->style()->colorSpace()); } void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) @@ -1950,7 +2038,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I // Paint the resizer control. DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner"))); IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height()); - context->drawImage(resizeCornerImage.get(), imagePoint); + context->drawImage(resizeCornerImage.get(), box->style()->colorSpace(), imagePoint); // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. // Clipping will exclude the right and bottom edges of this frame. @@ -1959,9 +2047,9 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I context->clip(absRect); IntRect largerCorner = absRect; largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1)); - context->setStrokeColor(Color(makeRGB(217, 217, 217))); + context->setStrokeColor(Color(makeRGB(217, 217, 217)), DeviceColorSpace); context->setStrokeThickness(1.0f); - context->setFillColor(Color::transparent); + context->setFillColor(Color::transparent, DeviceColorSpace); context->drawRect(largerCorner); context->restore(); } @@ -2044,10 +2132,10 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit return (didHorizontalScroll || didVerticalScroll); } -void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot) +void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot) { RenderObject::OverlapTestRequestMap overlapTestRequests; - paintLayer(this, p, damageRect, paintRestriction, paintingRoot, &overlapTestRequests); + paintLayer(this, p, damageRect, paintBehavior, paintingRoot, &overlapTestRequests); RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) it->first->setOverlapTestResult(false); @@ -2091,7 +2179,7 @@ static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflect #endif void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, - const IntRect& paintDirtyRect, PaintRestriction paintRestriction, + const IntRect& paintDirtyRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, PaintLayerFlags paintFlags) { @@ -2099,7 +2187,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, if (isComposited()) { // The updatingControlTints() painting pass goes through compositing layers, // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. - if (p->updatingControlTints()) + if (p->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers)) paintFlags |= PaintLayerTemporaryClipRects; else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). @@ -2118,19 +2206,20 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, if (!renderer()->opacity()) return; - if (paintsWithTransparency()) + if (paintsWithTransparency(paintBehavior)) paintFlags |= PaintLayerHaveTransparency; // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate. - if (paintsWithTransform() && !(paintFlags & PaintLayerAppliedTransform)) { + if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) { + TransformationMatrix layerTransform = renderableTransform(paintBehavior); // If the transform can't be inverted, then don't paint anything. - if (!m_transform->isInvertible()) + if (!layerTransform.isInvertible()) return; // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency // layer from the parent now. if (paintFlags & PaintLayerHaveTransparency) - parent()->beginTransparencyLayers(p, rootLayer); + parent()->beginTransparencyLayers(p, rootLayer, paintBehavior); // Make sure the parent's clip rects have been calculated. IntRect clipRect = paintDirtyRect; @@ -2147,16 +2236,15 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); - TransformationMatrix transform; - transform.translate(x, y); - transform = *m_transform * transform; + TransformationMatrix transform(layerTransform); + transform.translateRight(x, y); // Apply the transform. p->save(); - p->concatCTM(transform); + p->concatCTM(transform.toAffineTransform()); // Now do a paint with the root layer shifted to be us. - paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintRestriction, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform); + paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform); p->restore(); @@ -2173,7 +2261,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, if (m_reflection && !m_paintingInsideReflection) { // Mark that we are now inside replica painting. m_paintingInsideReflection = true; - reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); + reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); m_paintingInsideReflection = false; } @@ -2188,13 +2276,13 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Ensure our lists are up-to-date. updateCompositingAndLayerListsIfNeeded(); - bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; - bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; + bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; + bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). // Else, our renderer tree may or may not contain the painting root, so we pass that root along - // so it will be tested against as we decend through the renderers. + // so it will be tested against as we descend through the renderers. RenderObject* paintingRootForRenderer = 0; if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) paintingRootForRenderer = paintingRoot; @@ -2207,7 +2295,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(p, rootLayer); + beginTransparencyLayers(p, rootLayer, paintBehavior); // Paint our background first, before painting any child layers. // Establish the clip used to paint our background. @@ -2224,13 +2312,13 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Now walk the sorted list of children with negative z-indices. if (m_negZOrderList) for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); // Now establish the appropriate clip and paint our child RenderObjects. if (shouldPaint && !clipRectToApply.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(p, rootLayer); + beginTransparencyLayers(p, rootLayer, paintBehavior); // Set up the clip used when painting our children. setClip(p, paintDirtyRect, clipRectToApply); @@ -2263,12 +2351,12 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Paint any child layers that have overflow. if (m_normalFlowList) for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); // Now walk the sorted list of children with positive z-indices. if (m_posZOrderList) for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { setClip(p, paintDirtyRect, damageRect); @@ -2317,15 +2405,10 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) } } - // Now determine if the result is inside an anchor; make sure an image map wins if - // it already set URLElement and only use the innermost. + // Now determine if the result is inside an anchor - if the urlElement isn't already set. Node* node = result.innerNode(); - while (node) { - // for imagemaps, URLElement is the associated area element not the image itself - if (node->isLink() && !result.URLElement() && !node->hasTagName(imgTag)) - result.setURLElement(static_cast<Element*>(node)); - node = node->eventParentNode(); - } + if (node && !result.URLElement()) + result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf())); // Next set up the correct :hover/:active state along the new chain. updateHoverActiveState(request, result); @@ -2569,7 +2652,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. if (fgRect.contains(hitTestPoint) && isSelfPaintingLayer()) { - // Hit test with a temporary HitTestResult, because we onlyl want to commit to 'result' if we know we're frontmost. + // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. HitTestResult tempResult(result.point()); if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { @@ -2808,17 +2891,49 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa IntRect RenderLayer::childrenClipRect() const { RenderLayer* rootLayer = renderer()->view()->layer(); + RenderLayer* clippingRootLayer = clippingRoot(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; - calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); - return foregroundRect; + calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); + return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect)).enclosingBoundingBox(); } IntRect RenderLayer::selfClipRect() const { RenderLayer* rootLayer = renderer()->view()->layer(); + RenderLayer* clippingRootLayer = clippingRoot(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; - calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); - return backgroundRect; + calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); + return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect)).enclosingBoundingBox(); +} + +void RenderLayer::addBlockSelectionGapsBounds(const IntRect& bounds) +{ + m_blockSelectionGapsBounds.unite(bounds); +} + +void RenderLayer::clearBlockSelectionGapsBounds() +{ + m_blockSelectionGapsBounds = IntRect(); + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) + child->clearBlockSelectionGapsBounds(); +} + +void RenderLayer::repaintBlockSelectionGaps() +{ + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) + child->repaintBlockSelectionGaps(); + + if (m_blockSelectionGapsBounds.isEmpty()) + return; + + IntRect rect = m_blockSelectionGapsBounds; + rect.move(-scrolledContentOffset()); + if (renderer()->hasOverflowClip()) + rect.intersect(toRenderBox(renderer())->overflowClipRect(0, 0)); + if (renderer()->hasClip()) + rect.intersect(toRenderBox(renderer())->clipRect(0, 0)); + if (!rect.isEmpty()) + renderer()->repaintRectangle(rect); } bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const @@ -2866,7 +2981,7 @@ IntRect RenderLayer::localBoundingBox() const int top = firstBox->topVisibleOverflow(); int bottom = inlineFlow->lastLineBox()->bottomVisibleOverflow(); int left = firstBox->x(); - for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) left = min(left, curr->x()); result = IntRect(left, top, width(), bottom - top); } else if (renderer()->isTableRow()) { @@ -3172,7 +3287,7 @@ void RenderLayer::updateCompositingAndLayerListsIfNeeded() #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty) - compositor()->updateCompositingLayers(this); + compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this); return; } #endif @@ -3233,7 +3348,7 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject bool RenderLayer::shouldBeNormalFlowOnly() const { - return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo()) && + return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject()) && !renderer()->isPositioned() && !renderer()->isRelPositioned() && !renderer()->hasTransform() && @@ -3242,7 +3357,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const bool RenderLayer::isSelfPaintingLayer() const { - return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo(); + return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject(); } void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) @@ -3256,7 +3371,7 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) dirtyStackingContextZOrderLists(); } - if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) { + if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) { if (!m_marquee) m_marquee = new RenderMarquee(this); m_marquee->updateMarqueeStyle(); @@ -3390,3 +3505,16 @@ void RenderLayer::updateReflectionStyle() } } // namespace WebCore + +#ifndef NDEBUG +void showLayerTree(const WebCore::RenderLayer* layer) +{ + if (!layer) + return; + + if (WebCore::Frame* frame = layer->renderer()->document()->frame()) { + WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers); + fprintf(stderr, "%s\n", output.utf8().data()); + } +} +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h index a274638586..9210e95c92 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h @@ -202,9 +202,10 @@ public: bool isTransparent() const; RenderLayer* transparentPaintingAncestor(); - void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer); + void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, PaintBehavior); bool hasReflection() const { return renderer()->hasReflection(); } + bool isReflection() const { return renderer()->isReplica(); } RenderReplica* reflection() const { return m_reflection; } RenderLayer* reflectionLayer() const; @@ -226,6 +227,8 @@ public: int width() const { return m_width; } int height() const { return m_height; } + IntSize size() const { return IntSize(m_width, m_height); } + void setWidth(int w) { m_width = w; } void setHeight(int h) { m_height = h; } @@ -236,8 +239,7 @@ public: // Scrolling methods for layers that can scroll their overflow. void scrollByRecursively(int xDelta, int yDelta); - void addScrolledContentOffset(int& x, int& y) const; - void subtractScrolledContentOffset(int& x, int& y) const; + IntSize scrolledContentOffset() const { return IntSize(scrollXOffset() + m_scrollLeftOverflow, scrollYOffset()); } int scrollXOffset() const { return m_scrollX + m_scrollOriginX; } @@ -262,6 +264,7 @@ public: int verticalScrollbarWidth() const; int horizontalScrollbarHeight() const; + bool hasOverflowControls() const; void positionOverflowControls(int tx, int ty); bool isPointInResizeControl(const IntPoint& absolutePoint) const; bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint); @@ -312,6 +315,10 @@ public: void clearClipRectsIncludingDescendants(); void clearClipRects(); + void addBlockSelectionGapsBounds(const IntRect&); + void clearBlockSelectionGapsBounds(); + void repaintBlockSelectionGaps(); + // Get the enclosing stacking context for this layer. A stacking context is a layer // that has a non-auto z-index. RenderLayer* stackingContext() const; @@ -336,6 +343,9 @@ public: // the <html> layer and the root layer). RenderLayer* enclosingPositionedAncestor() const; + // The layer relative to which clipping rects for this layer are computed. + RenderLayer* clippingRoot() const; + #if USE(ACCELERATED_COMPOSITING) // Enclosing compositing layer; if includeSelf is true, may return this. RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const; @@ -352,7 +362,7 @@ public: // paints the layers that intersect the damage rect from back to // front. The hitTest method looks for mouse events by walking // layers that intersect the point from front to back. - void paint(GraphicsContext*, const IntRect& damageRect, PaintRestriction = PaintRestrictionNone, RenderObject* paintingRoot = 0); + void paint(GraphicsContext*, const IntRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0); bool hitTest(const HitTestRequest&, HitTestResult&); // This method figures out our layerBounds in coordinates relative to @@ -390,7 +400,7 @@ public: int staticX() const { return m_staticX; } int staticY() const { return m_staticY; } void setStaticX(int staticX) { m_staticX = staticX; } - void setStaticY(int staticY); + void setStaticY(int staticY) { m_staticY = staticY; } bool hasTransform() const { return renderer()->hasTransform(); } // Note that this transform has the transform-origin baked in. @@ -399,6 +409,7 @@ public: // resulting transform has transform-origin baked in. If the layer does not have a transform, // returns the identity matrix. TransformationMatrix currentTransform() const; + TransformationMatrix renderableTransform(PaintBehavior) const; // Get the perspective transform, which is applied to transformed sublayers. // Returns true if the layer has a -webkit-perspective. @@ -426,14 +437,14 @@ public: bool hasCompositedMask() const { return false; } #endif - bool paintsWithTransparency() const + bool paintsWithTransparency(PaintBehavior paintBehavior) const { - return isTransparent() && !isComposited(); + return isTransparent() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || !isComposited()); } - bool paintsWithTransform() const + bool paintsWithTransform(PaintBehavior paintBehavior) const { - return transform() && !isComposited(); + return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || !isComposited()); } private: @@ -465,7 +476,7 @@ private: typedef unsigned PaintLayerFlags; void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - PaintRestriction, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0, + PaintBehavior, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0, PaintLayerFlags paintFlags = 0); RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, @@ -644,6 +655,9 @@ protected: RenderScrollbarPart* m_scrollCorner; RenderScrollbarPart* m_resizer; +private: + IntRect m_blockSelectionGapsBounds; + #if USE(ACCELERATED_COMPOSITING) OwnPtr<RenderLayerBacking> m_backing; #endif @@ -651,4 +665,9 @@ protected: } // namespace WebCore +#ifndef NDEBUG +// Outside the WebCore namespace for ease of invocation from gdb. +void showLayerTree(const WebCore::RenderLayer* layer); +#endif + #endif // RenderLayer_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp index d7248d49f0..b5f74c6710 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp @@ -28,7 +28,9 @@ #if USE(ACCELERATED_COMPOSITING) #include "AnimationController.h" -#include "CanvasRenderingContext3D.h" +#if ENABLE(3D_CANVAS) +#include "WebGLRenderingContext.h" +#endif #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" #include "FrameView.h" @@ -36,12 +38,18 @@ #include "GraphicsLayer.h" #include "HTMLCanvasElement.h" #include "HTMLElement.h" +#include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "InspectorTimelineAgent.h" +#include "KeyframeList.h" +#include "PluginWidget.h" #include "RenderBox.h" #include "RenderImage.h" #include "RenderLayerCompositor.h" +#include "RenderEmbeddedObject.h" #include "RenderVideo.h" #include "RenderView.h" +#include "Settings.h" #include "RenderLayerBacking.h" @@ -52,12 +60,22 @@ namespace WebCore { using namespace HTMLNames; static bool hasBorderOutlineOrShadow(const RenderStyle*); -static bool hasBoxDecorations(const RenderStyle*); -static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle*); +static bool hasBoxDecorationsOrBackground(const RenderStyle*); +static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*); + +static inline bool is3DCanvas(RenderObject* renderer) +{ +#if ENABLE(3D_CANVAS) + if (renderer->isCanvas()) + return static_cast<HTMLCanvasElement*>(renderer->node())->is3D(); +#else + UNUSED_PARAM(renderer); +#endif + return false; +} RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) : m_owningLayer(layer) - , m_hasDirectlyCompositedContent(false) , m_artificiallyInflatedBounds(false) { createGraphicsLayer(); @@ -81,11 +99,13 @@ void RenderLayerBacking::createGraphicsLayer() m_graphicsLayer->setName("Document Node"); else { if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID()) - m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->getAttribute(idAttr)); + m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->getIDAttribute()); else m_graphicsLayer->setName(renderer()->renderName()); } - } else + } else if (m_owningLayer->isReflection()) + m_graphicsLayer->setName("Reflection"); + else m_graphicsLayer->setName("Anonymous Node"); #endif // NDEBUG @@ -181,29 +201,35 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() if (updateMaskLayer(m_owningLayer->renderer()->hasMask())) m_graphicsLayer->setMaskLayer(m_maskLayer.get()); - m_hasDirectlyCompositedContent = false; - if (canUseDirectCompositing()) { - if (renderer()->isImage()) { - updateImageContents(); - m_hasDirectlyCompositedContent = true; - m_graphicsLayer->setDrawsContent(false); - } -#if ENABLE(3D_CANVAS) - else if (renderer()->isCanvas()) { - HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); - if (canvas->is3D()) { - CanvasRenderingContext3D* context = static_cast<CanvasRenderingContext3D*>(canvas->renderingContext()); - if (context->graphicsContext3D()->platformGraphicsContext3D()) - m_graphicsLayer->setContentsToGraphicsContext3D(context->graphicsContext3D()); - } + if (m_owningLayer->hasReflection()) { + if (m_owningLayer->reflectionLayer()->backing()) { + GraphicsLayer* reflectionLayer = m_owningLayer->reflectionLayer()->backing()->graphicsLayer(); + m_graphicsLayer->setReplicatedByLayer(reflectionLayer); } -#endif + } else + m_graphicsLayer->setReplicatedByLayer(0); + + if (isDirectlyCompositedImage()) + updateImageContents(); - if (rendererHasBackground()) - m_graphicsLayer->setBackgroundColor(rendererBackgroundColor()); - else - m_graphicsLayer->clearBackgroundColor(); + if (renderer()->isEmbeddedObject() && toRenderEmbeddedObject(renderer())->allowsAcceleratedCompositing()) { + PluginWidget* pluginWidget = static_cast<PluginWidget*>(toRenderEmbeddedObject(renderer())->widget()); + m_graphicsLayer->setContentsToMedia(pluginWidget->platformLayer()); + } +#if ENABLE(VIDEO) + else if (renderer()->isVideo()) { + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(renderer()->node()); + m_graphicsLayer->setContentsToMedia(mediaElement->platformLayer()); } +#endif +#if ENABLE(3D_CANVAS) + else if (is3DCanvas(renderer())) { + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); + WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(canvas->renderingContext()); + if (context->graphicsContext3D()->platformGraphicsContext3D()) + m_graphicsLayer->setContentsToGraphicsContext3D(context->graphicsContext3D()); + } +#endif return layerConfigChanged; } @@ -224,7 +250,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() updateLayerOpacity(renderer()->style()); RenderStyle* style = renderer()->style(); - m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D); + m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection()); m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); @@ -345,9 +371,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_foregroundLayer->setOffsetFromRenderer(foregroundOffset); } + if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) { + RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing(); + reflectionBacking->updateGraphicsLayerGeometry(); + + // The reflection layer has the bounds of m_owningLayer->reflectionLayer(), + // but the reflected layer is the bounds of this layer, so we need to position it appropriately. + FloatRect layerBounds = compositedBounds(); + FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds(); + reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location())); + } + m_graphicsLayer->setContentsRect(contentsBox()); - if (!m_hasDirectlyCompositedContent) - m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow() && !m_artificiallyInflatedBounds); + m_graphicsLayer->setDrawsContent(containsPaintedContent()); } void RenderLayerBacking::updateInternalHierarchy() @@ -388,7 +424,7 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs if (needsDescendantClip) { if (!m_clippingLayer) { - m_clippingLayer = GraphicsLayer::create(0); + m_clippingLayer = GraphicsLayer::create(this); #ifndef NDEBUG m_clippingLayer->setName("Child clipping Layer"); #endif @@ -493,12 +529,12 @@ static bool hasBorderOutlineOrShadow(const RenderStyle* style) return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow(); } -static bool hasBoxDecorations(const RenderStyle* style) +static bool hasBoxDecorationsOrBackground(const RenderStyle* style) { return hasBorderOutlineOrShadow(style) || style->hasBackground(); } -static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style) +static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style) { return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage(); } @@ -558,7 +594,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const // Reject anything that has a border, a border-radius or outline, // or any background (color or image). // FIXME: we could optimize layers for simple backgrounds. - if (hasBoxDecorations(style)) + if (hasBoxDecorationsOrBackground(style)) return false; // If we have got this far and the renderer has no children, then we're ok. @@ -575,7 +611,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const // Reject anything that has a border, a border-radius or outline, // or is not a simple background (no background, or solid color). - if (hasBoxDecorationsWithBackgroundImage(style)) + if (hasBoxDecorationsOrBackgroundImage(style)) return false; // Now look at the body's renderer. @@ -586,7 +622,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const style = bodyObject->style(); - if (hasBoxDecorationsWithBackgroundImage(style)) + if (hasBoxDecorationsOrBackgroundImage(style)) return false; // Ceck to see if all the body's children are compositing layers. @@ -603,9 +639,11 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const return true; } +// Conservative test for having no rendered children. bool RenderLayerBacking::hasNonCompositingContent() const { - // Conservative test for having no rendered children. + if (m_owningLayer->hasOverflowControls()) + return true; // Some HTML can cause whitespace text nodes to have renderers, like: // <div> @@ -622,7 +660,6 @@ bool RenderLayerBacking::hasNonCompositingContent() const } } - // FIXME: test for overflow controls. if (m_owningLayer->isStackingContext()) { // Use the m_hasCompositingDescendant bit to optimize? if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) { @@ -656,51 +693,43 @@ bool RenderLayerBacking::hasNonCompositingContent() const return false; } -// A layer can use direct compositing if the render layer's object is a replaced object and has no children. -// This allows the GraphicsLayer to display the RenderLayer contents directly; it's used for images. -bool RenderLayerBacking::canUseDirectCompositing() const +bool RenderLayerBacking::containsPaintedContent() const { - RenderObject* renderObject = renderer(); - - // Canvas3D is always direct composited -#if ENABLE(3D_CANVAS) - if (renderer()->isCanvas()) { - HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); - return canvas->is3D(); - } -#endif - - // Reject anything that isn't an image - if (!renderObject->isImage() && !renderObject->isVideo()) + if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) return false; - - if (renderObject->hasMask() || renderObject->hasReflection()) + + if (isDirectlyCompositedImage()) return false; - // Video can use an inner layer even if it has box decorations; we draw those into another layer. - if (renderObject->isVideo()) - return true; - - // Reject anything that would require the image to be drawn via the GraphicsContext, - // like border, shadows etc. Solid background color is OK. - return !hasBoxDecorationsWithBackgroundImage(renderObject->style()); + // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely, + // and set background color on the layer in that case, instead of allocating backing store and painting. + if (renderer()->isVideo() || is3DCanvas(renderer())) + return hasBoxDecorationsOrBackground(renderer()->style()); + + return true; } - + +// An image can be directly compositing if it's the sole content of the layer, and has no box decorations +// that require painting. Direct compositing saves backing store. +bool RenderLayerBacking::isDirectlyCompositedImage() const +{ + RenderObject* renderObject = renderer(); + return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject->style()); +} + void RenderLayerBacking::rendererContentChanged() { - if (canUseDirectCompositing()) { - if (renderer()->isImage()) - updateImageContents(); - else { + if (isDirectlyCompositedImage()) { + updateImageContents(); + return; + } + #if ENABLE(3D_CANVAS) - if (renderer()->isCanvas()) { - HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); - if (canvas->is3D()) - m_graphicsLayer->setGraphicsContext3DNeedsDisplay(); - } -#endif - } + if (is3DCanvas(renderer())) { + m_graphicsLayer->setGraphicsContext3DNeedsDisplay(); + return; } +#endif } void RenderLayerBacking::updateImageContents() @@ -849,7 +878,7 @@ static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const // Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase? void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, const IntRect& paintDirtyRect, // in the coords of rootLayer - PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase, + PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase, RenderObject* paintingRoot) { if (paintingGoesToWindow()) { @@ -859,14 +888,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* m_owningLayer->updateLayerListsIfNeeded(); - // Paint the reflection first if we have one. - if (m_owningLayer->hasReflection()) { - // Mark that we are now inside replica painting. - m_owningLayer->setPaintingInsideReflection(true); - m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection); - m_owningLayer->setPaintingInsideReflection(false); - } - // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); @@ -899,9 +920,9 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* int rw; int rh; - if (box->view()->frameView()) { - rw = box->view()->frameView()->contentsWidth(); - rh = box->view()->frameView()->contentsHeight(); + if (FrameView* frameView = box->view()->frameView()) { + rw = frameView->contentsWidth(); + rh = frameView->contentsHeight(); } else { rw = box->view()->width(); rh = box->view()->height(); @@ -930,8 +951,8 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* restoreClip(context, paintDirtyRect, damageRect); } - bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; - bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; + bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; + bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; if (shouldPaint && (paintingPhase & GraphicsLayerPaintForeground)) { // Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint. @@ -939,7 +960,7 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); if (negZOrderList) { for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot); } // Set up the clip used when painting our children. @@ -975,14 +996,14 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList(); if (normalFlowList) { for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot); } // Now walk the sorted list of children with positive z-indices. Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); if (posZOrderList) { for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot); } } @@ -1002,9 +1023,27 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* ASSERT(!m_owningLayer->m_usedTransparency); } +#if ENABLE(INSPECTOR) +static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer) +{ + Frame* frame = renderer->document()->frame(); + if (!frame) + return 0; + Page* page = frame->page(); + if (!page) + return 0; + return page->inspectorTimelineAgent(); +} +#endif + // Up-call from compositing layer drawing callback. void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) { +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer())) + timelineAgent->willPaint(clip); +#endif + // We have to use the same root as for hit testing, because both methods // can compute and cache clipRects. IntRect enclosingBBox = compositedBounds(); @@ -1021,10 +1060,25 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co IntRect dirtyRect = enclosingBBox; dirtyRect.intersect(clipRect); - paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintRestrictionNone, paintingPhase, renderer()); + paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); + +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer())) + timelineAgent->didPaint(); +#endif +} + +bool RenderLayerBacking::showDebugBorders() const +{ + return compositor() ? compositor()->showDebugBorders() : false; +} + +bool RenderLayerBacking::showRepaintCounter() const +{ + return compositor() ? compositor()->showRepaintCounter() : false; } -bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes) +bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes) { bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform); @@ -1055,10 +1109,10 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, bool didAnimateTransform = !hasTransform; bool didAnimateOpacity = !hasOpacity; - if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), beginTime)) + if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), timeOffset)) didAnimateTransform = true; - if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime)) + if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset)) didAnimateOpacity = true; bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity; @@ -1068,7 +1122,7 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, return runningAcceleratedAnimation; } -bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) +bool RenderLayerBacking::startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) { bool didAnimate = false; ASSERT(property != cAnimateAll); @@ -1080,7 +1134,7 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity()))); opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity()))); // The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here. - if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), beginTime)) { + if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), timeOffset)) { // To ensure that the correct opacity is visible when the animation ends, also set the final opacity. updateLayerOpacity(toStyle); didAnimate = true; @@ -1094,7 +1148,7 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform())); transformVector.insert(new TransformAnimationValue(1, &toStyle->transform())); - if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), beginTime)) { + if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), timeOffset)) { // To ensure that the correct transform is visible when the animation ends, also set the final opacity. updateLayerTransform(toStyle); didAnimate = true; @@ -1124,9 +1178,9 @@ void RenderLayerBacking::animationFinished(const String& animationName) m_graphicsLayer->removeAnimationsForKeyframes(animationName); } -void RenderLayerBacking::animationPaused(const String& animationName) +void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName) { - m_graphicsLayer->pauseAnimation(animationName); + m_graphicsLayer->pauseAnimation(animationName, timeOffset); } void RenderLayerBacking::transitionFinished(int property) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h index 17bcaf707f..a6907e7f5e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h @@ -46,7 +46,7 @@ class RenderLayerCompositor; // // There is one RenderLayerBacking for each RenderLayer that is composited. -class RenderLayerBacking : public GraphicsLayerClient { +class RenderLayerBacking : public GraphicsLayerClient, public Noncopyable { public: RenderLayerBacking(RenderLayer*); ~RenderLayerBacking(); @@ -97,10 +97,10 @@ public: void rendererContentChanged(); // Interface to start, finish, suspend and resume animations and transitions - bool startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes); - bool startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle); + bool startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes); + bool startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle); void animationFinished(const String& name); - void animationPaused(const String& name); + void animationPaused(double timeOffset, const String& name); void transitionFinished(int property); void suspendAnimations(double time = 0); @@ -119,6 +119,9 @@ public: virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clip); + virtual bool showDebugBorders() const; + virtual bool showRepaintCounter() const; + IntRect contentsBox() const; private: @@ -146,12 +149,12 @@ private: // Return the opacity value that this layer should use for compositing. float compositingOpacity(float rendererOpacity) const; - // Returns true if this RenderLayer only has content that can be rendered directly - // by the compositing layer, without drawing (e.g. solid background color). + // Returns true if this compositing layer has no visible content. bool isSimpleContainerCompositingLayer() const; - // Returns true if we can optimize the RenderLayer to draw the replaced content - // directly into a compositing buffer - bool canUseDirectCompositing() const; + // Returns true if this layer has content that needs to be rendered by painting into the backing store. + bool containsPaintedContent() const; + // Returns true if the RenderLayer just contains an image that we can composite directly. + bool isDirectlyCompositedImage() const; void updateImageContents(); bool rendererHasBackground() const; @@ -160,7 +163,7 @@ private: bool hasNonCompositingContent() const; void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - PaintRestriction paintRestriction, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); + PaintBehavior paintBehavior, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); static int graphicsLayerToCSSProperty(AnimatedPropertyID); static AnimatedPropertyID cssToGraphicsLayerProperty(int); @@ -176,7 +179,6 @@ private: IntRect m_compositedBounds; - bool m_hasDirectlyCompositedContent; bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp index 5201287eb9..93af664778 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp @@ -29,6 +29,7 @@ #include "RenderLayerCompositor.h" #include "AnimationController.h" +#include "Chrome.h" #include "ChromeClient.h" #include "CSSPropertyNames.h" #include "Frame.h" @@ -37,7 +38,9 @@ #include "HitTestResult.h" #include "HTMLCanvasElement.h" #include "Page.h" +#include "RenderEmbeddedObject.h" #include "RenderLayerBacking.h" +#include "RenderReplica.h" #include "RenderVideo.h" #include "RenderView.h" #include "Settings.h" @@ -58,6 +61,8 @@ bool WebCoreHas3DRendering = true; namespace WebCore { +using namespace HTMLNames; + struct CompositingState { CompositingState(RenderLayer* compAncestor) : m_compositingAncestor(compAncestor) @@ -79,6 +84,8 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) : m_renderView(renderView) , m_rootPlatformLayer(0) , m_hasAcceleratedCompositing(true) + , m_showDebugBorders(false) + , m_showRepaintCounter(false) , m_compositingConsultsOverlap(true) , m_compositing(false) , m_rootLayerAttached(false) @@ -109,16 +116,24 @@ void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) } } -void RenderLayerCompositor::cacheAcceleratedCompositingEnabledFlag() +void RenderLayerCompositor::cacheAcceleratedCompositingFlags() { bool hasAcceleratedCompositing = false; - if (Settings* settings = m_renderView->document()->settings()) + bool showDebugBorders = false; + bool showRepaintCounter = false; + + if (Settings* settings = m_renderView->document()->settings()) { hasAcceleratedCompositing = settings->acceleratedCompositingEnabled(); + showDebugBorders = settings->showDebugBorders(); + showRepaintCounter = settings->showRepaintCounter(); + } - if (hasAcceleratedCompositing != m_hasAcceleratedCompositing) + if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showDebugBorders != m_showDebugBorders || showRepaintCounter != m_showRepaintCounter) setCompositingLayersNeedRebuild(); m_hasAcceleratedCompositing = hasAcceleratedCompositing; + m_showDebugBorders = showDebugBorders; + m_showRepaintCounter = showRepaintCounter; } void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild) @@ -137,16 +152,30 @@ void RenderLayerCompositor::scheduleSync() page->chrome()->client()->scheduleCompositingLayerSync(); } -void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) +void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType updateType, RenderLayer* updateRoot) { - // When m_compositingConsultsOverlap is true, then layer positions affect compositing, - // so we can only bail here when we're not looking at overlap. - if (!m_compositingLayersNeedRebuild && !m_compositingConsultsOverlap) + bool checkForHierarchyUpdate = false; + bool needGeometryUpdate = false; + + switch (updateType) { + case CompositingUpdateAfterLayoutOrStyleChange: + case CompositingUpdateOnPaitingOrHitTest: + checkForHierarchyUpdate = true; + break; + case CompositingUpdateOnScroll: + if (m_compositingConsultsOverlap) + checkForHierarchyUpdate = true; // Overlap can change with scrolling, so need to check for hierarchy updates. + + needGeometryUpdate = true; + break; + } + + if (!checkForHierarchyUpdate && !needGeometryUpdate) return; ASSERT(inCompositingMode()); - bool needLayerRebuild = m_compositingLayersNeedRebuild; + bool needHierarchyUpdate = m_compositingLayersNeedRebuild; if (!updateRoot) { // Only clear the flag if we're updating the entire hierarchy. m_compositingLayersNeedRebuild = false; @@ -159,26 +188,38 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) double startTime = WTF::currentTime(); #endif - // Go through the layers in presentation order, so that we can compute which - // RLs need compositing layers. - // FIXME: we could maybe do this in one pass, but the parenting logic would be more - // complex. - { + if (checkForHierarchyUpdate) { + // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers. + // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex. CompositingState compState(updateRoot); - bool layersChanged; + bool layersChanged = false; if (m_compositingConsultsOverlap) { OverlapMap overlapTestRequestMap; computeCompositingRequirements(updateRoot, &overlapTestRequestMap, compState, layersChanged); } else computeCompositingRequirements(updateRoot, 0, compState, layersChanged); - needLayerRebuild |= layersChanged; + needHierarchyUpdate |= layersChanged; } - // Now create and parent the compositing layers. - { + if (needHierarchyUpdate) { + // Update the hierarchy of the compositing layers. CompositingState compState(updateRoot); - rebuildCompositingLayerTree(updateRoot, compState, needLayerRebuild); + Vector<GraphicsLayer*> childList; + rebuildCompositingLayerTree(updateRoot, compState, childList); + + // Host the document layer in the RenderView's root layer. + if (updateRoot == rootRenderLayer()) { + if (childList.isEmpty()) { + willMoveOffscreen(); + m_rootPlatformLayer = 0; + } else + m_rootPlatformLayer->setChildren(childList); + } + } else if (needGeometryUpdate) { + // We just need to do a geometry update. This is only used for position:fixed scrolling; + // most of the time, geometry is updated via RenderLayer::styleChanged(). + updateLayerTreeGeometry(updateRoot); } #if PROFILE_LAYER_REBUILD @@ -215,6 +256,17 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR } } else { if (layer->backing()) { + // If we're removing backing on a reflection, clear the source GraphicsLayer's pointer to + // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection + // are both either composited, or not composited. + if (layer->isReflection()) { + RenderLayer* sourceLayer = toRenderBoxModelObject(layer->renderer()->parent())->layer(); + if (RenderLayerBacking* backing = sourceLayer->backing()) { + ASSERT(backing->graphicsLayer()->replicaLayer() == layer->backing()->graphicsLayer()); + backing->graphicsLayer()->setReplicatedByLayer(0); + } + } + layer->clearBacking(); layerChanged = true; @@ -328,7 +380,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye } } - if (layer->paintsWithTransform()) { + if (layer->paintsWithTransform(PaintBehaviorNormal)) { TransformationMatrix* affineTrans = layer->transform(); boundingBoxRect = affineTrans->mapRect(boundingBoxRect); unionBounds = affineTrans->mapRect(unionBounds); @@ -391,6 +443,9 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* if (!boundsComputed) { layerBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + // Empty rects never intersect, but we need them to for the purposes of overlap testing. + if (layerBounds.isEmpty()) + layerBounds.setSize(IntSize(1, 1)); boundsComputed = true; } @@ -434,6 +489,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (overlapMap && !overlapMap->isEmpty()) { // If we're testing for overlap, we only need to composite if we overlap something that is already composited. absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + // Empty rects never intersect, but we need them to for the purposes of overlap testing. + if (absBounds.isEmpty()) + absBounds.setSize(IntSize(1, 1)); haveComputedBounds = true; mustOverlapCompositedLayers = overlapsCompositedLayers(*overlapMap, absBounds); } @@ -448,7 +506,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O ++childState.m_depth; #endif - const bool willBeComposited = needsToBeComposited(layer); + bool willBeComposited = needsToBeComposited(layer); if (willBeComposited) { // Tell the parent it has compositing descendants. compositingState.m_subtreeIsCompositing = true; @@ -476,7 +534,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // If we have to make a layer for this child, make one now so we can have a contents layer // (since we need to ensure that the -ve z-order child renders underneath our contents). - if (childState.m_subtreeIsCompositing) { + if (!willBeComposited && childState.m_subtreeIsCompositing) { // make layer compositing layer->setMustOverlapCompositedLayers(true); childState.m_compositingAncestor = layer; @@ -509,28 +567,50 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // If we have a software transform, and we have layers under us, we need to also // be composited. Also, if we have opacity < 1, then we need to be a layer so that // the child layers are opaque, then rendered with opacity on this layer. - if (childState.m_subtreeIsCompositing && requiresCompositingWhenDescendantsAreCompositing(layer->renderer())) { + if (!willBeComposited && childState.m_subtreeIsCompositing && requiresCompositingWhenDescendantsAreCompositing(layer->renderer())) { layer->setMustOverlapCompositedLayers(true); if (overlapMap) addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + willBeComposited = true; } + ASSERT(willBeComposited == needsToBeComposited(layer)); + if (layer->reflectionLayer()) + layer->reflectionLayer()->setMustOverlapCompositedLayers(willBeComposited); + // Subsequent layers in the parent stacking context also need to composite. if (childState.m_subtreeIsCompositing) compositingState.m_subtreeIsCompositing = true; - // If the layer is going into compositing mode, repaint its old location. - if (!layer->isComposited() && needsToBeComposited(layer)) - repaintOnCompositingChange(layer); - // Set the flag to say that this SC has compositing children. - // this can affect the answer to needsToBeComposited() when clipping, - // but that's ok here. layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing); + // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, + // so test that again. + if (!willBeComposited && clipsCompositingDescendants(layer)) { + if (overlapMap) + addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + willBeComposited = true; + } + + // If we're back at the root, and no other layers need to be composited, and the root layer itself doesn't need + // to be composited, then we can drop out of compositing mode altogether. + if (layer->isRootLayer() && !childState.m_subtreeIsCompositing && !requiresCompositingLayer(layer)) { + m_compositing = false; + willBeComposited = false; + } + + // If the layer is going into compositing mode, repaint its old location. + ASSERT(willBeComposited == needsToBeComposited(layer)); + if (!layer->isComposited() && willBeComposited) + repaintOnCompositingChange(layer); + // Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree(). if (updateBacking(layer, CompositingChangeRepaintNow)) layersChanged = true; + + if (layer->reflectionLayer() && updateLayerCompositingState(layer->reflectionLayer(), CompositingChangeRepaintNow)) + layersChanged = true; } void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) @@ -577,39 +657,41 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) #if ENABLE(VIDEO) bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const { - // FIXME: ideally we need to look at all ancestors for mask or video. But for now, - // just bail on the obvious cases. - if (o->hasReflection() || !m_hasAcceleratedCompositing) + if (!m_hasAcceleratedCompositing) return false; return o->supportsAcceleratedRendering(); } #endif -void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& compositingState, bool updateHierarchy) +void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, const CompositingState& compositingState, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer) { // Make the layer compositing if necessary, and set up clipping and content layers. // Note that we can only do work here that is independent of whether the descendant layers // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. + RenderLayerBacking* layerBacking = layer->backing(); if (layerBacking) { // The compositing state of all our children has been updated already, so now // we can compute and cache the composited bounds for this layer. layerBacking->updateCompositedBounds(); + + if (RenderLayer* reflection = layer->reflectionLayer()) { + if (reflection->backing()) + reflection->backing()->updateCompositedBounds(); + } + layerBacking->updateGraphicsLayerConfiguration(); layerBacking->updateGraphicsLayerGeometry(); if (!layer->parent()) updateRootLayerPosition(); - - // FIXME: make this more incremental - if (updateHierarchy) - layerBacking->parentForSublayers()->removeAllChildren(); } - // host the document layer in the RenderView's root layer - if (updateHierarchy && layer->isRootLayer() && layer->isComposited()) - parentInRootLayer(layer); + // If this layer has backing, then we are collecting its children, otherwise appending + // to the compositing child list of an enclosing layer. + Vector<GraphicsLayer*> layerChildren; + Vector<GraphicsLayer*>& childList = layerBacking ? layerChildren : childLayersOfEnclosingLayer; CompositingState childState = compositingState; if (layer->isComposited()) @@ -630,19 +712,13 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); - if (updateHierarchy && curLayer->isComposited()) - setCompositingParent(curLayer, childState.m_compositingAncestor); + rebuildCompositingLayerTree(curLayer, childState, childList); } } - if (updateHierarchy && layerBacking && layerBacking->foregroundLayer()) { - layerBacking->foregroundLayer()->removeFromParent(); - - // The foreground layer has to be correctly sorted with child layers, so needs to become a child of the clipping layer. - GraphicsLayer* hostingLayer = layerBacking->parentForSublayers(); - hostingLayer->addChild(layerBacking->foregroundLayer()); - } + // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. + if (layerBacking && layerBacking->foregroundLayer()) + childList.append(layerBacking->foregroundLayer()); } ASSERT(!layer->m_normalFlowListDirty); @@ -650,9 +726,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); - if (updateHierarchy && curLayer->isComposited()) - setCompositingParent(curLayer, childState.m_compositingAncestor); + rebuildCompositingLayerTree(curLayer, childState, childList); } } @@ -661,14 +735,62 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); - if (updateHierarchy && curLayer->isComposited()) - setCompositingParent(curLayer, childState.m_compositingAncestor); + rebuildCompositingLayerTree(curLayer, childState, childList); } } } + + if (layerBacking) { + layerBacking->parentForSublayers()->setChildren(layerChildren); + childLayersOfEnclosingLayer.append(layerBacking->childForSuperlayers()); + } } +// This just updates layer geometry without changing the hierarchy. +void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) +{ + if (RenderLayerBacking* layerBacking = layer->backing()) { + // The compositing state of all our children has been updated already, so now + // we can compute and cache the composited bounds for this layer. + layerBacking->updateCompositedBounds(); + + if (RenderLayer* reflection = layer->reflectionLayer()) { + if (reflection->backing()) + reflection->backing()->updateCompositedBounds(); + } + + layerBacking->updateGraphicsLayerConfiguration(); + layerBacking->updateGraphicsLayerGeometry(); + + if (!layer->parent()) + updateRootLayerPosition(); + } + + if (layer->isStackingContext()) { + ASSERT(!layer->m_zOrderListsDirty); + + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) + updateLayerTreeGeometry(negZOrderList->at(i)); + } + } + + ASSERT(!layer->m_normalFlowListDirty); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) + updateLayerTreeGeometry(normalFlowList->at(i)); + } + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) + updateLayerTreeGeometry(posZOrderList->at(i)); + } + } +} // Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth updateDepth) @@ -676,12 +798,21 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com if (layer != compositingAncestor) { if (RenderLayerBacking* layerBacking = layer->backing()) { layerBacking->updateCompositedBounds(); + + if (RenderLayer* reflection = layer->reflectionLayer()) { + if (reflection->backing()) + reflection->backing()->updateCompositedBounds(); + } + layerBacking->updateGraphicsLayerGeometry(); if (updateDepth == RenderLayerBacking::CompositingChildren) return; } } + if (layer->reflectionLayer()) + updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), updateDepth); + if (!layer->hasCompositingDescendant()) return; @@ -716,6 +847,7 @@ void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& a void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect) { + // FIXME: This method does not work correctly with transforms. if (layer->isComposited()) layer->setBackingNeedsRepaintInRect(rect); @@ -724,7 +856,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - int x = 0, y = 0; + int x = 0; + int y = 0; curLayer->convertToLayerCoords(layer, x, y); IntRect childRect(rect); childRect.move(-x, -y); @@ -736,7 +869,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - int x = 0, y = 0; + int x = 0; + int y = 0; curLayer->convertToLayerCoords(layer, x, y); IntRect childRect(rect); childRect.move(-x, -y); @@ -748,7 +882,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - int x = 0, y = 0; + int x = 0; + int y = 0; curLayer->convertToLayerCoords(layer, x, y); IntRect childRect(rect); childRect.move(-x, -y); @@ -819,22 +954,28 @@ bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const if (!m_hasAcceleratedCompositing || !layer->isSelfPaintingLayer()) return false; - return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers(); + return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers() || (inCompositingMode() && layer->isRootLayer()); } // Note: this specifies whether the RL needs a compositing layer for intrinsic reasons. // Use needsToBeComposited() to determine if a RL actually needs a compositing layer. // static bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const -{ +{ + RenderObject* renderer = layer->renderer(); + // The compositing state of a reflection should match that of its reflected layer. + if (layer->isReflection()) { + renderer = renderer->parent(); // The RenderReplica's parent is the object being reflected. + layer = toRenderBoxModelObject(renderer)->layer(); + } // The root layer always has a compositing layer, but it may not have backing. - return (inCompositingMode() && layer->isRootLayer()) || - requiresCompositingForTransform(layer->renderer()) || - requiresCompositingForVideo(layer->renderer()) || - requiresCompositingForCanvas(layer->renderer()) || - layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden || - clipsCompositingDescendants(layer) || - requiresCompositingForAnimation(layer->renderer()); + return requiresCompositingForTransform(renderer) + || requiresCompositingForVideo(renderer) + || requiresCompositingForCanvas(renderer) + || requiresCompositingForPlugin(renderer) + || renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden + || clipsCompositingDescendants(layer) + || requiresCompositingForAnimation(renderer); } // Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips, @@ -897,6 +1038,8 @@ bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer) RenderVideo* video = toRenderVideo(renderer); return canAccelerateVideoRendering(video); } +#else + UNUSED_PARAM(renderer); #endif return false; } @@ -914,6 +1057,11 @@ bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer) return false; } +bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) const +{ + return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing(); +} + bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const { if (AnimationController* animController = renderer->animation()) { @@ -925,7 +1073,7 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render bool RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing(RenderObject* renderer) const { - return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask(); + return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection(); } // If an element has negative z-index children, those children render in front of the diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h index a809a7077a..5f1a178e21 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h @@ -38,6 +38,12 @@ class GraphicsLayer; class RenderVideo; #endif +enum CompositingUpdateType { + CompositingUpdateAfterLayoutOrStyleChange, + CompositingUpdateOnPaitingOrHitTest, + CompositingUpdateOnScroll +}; + // RenderLayerCompositor manages the hierarchy of // composited RenderLayers. It determines which RenderLayers // become compositing, and creates and maintains a hierarchy of @@ -47,7 +53,6 @@ class RenderVideo; class RenderLayerCompositor { public: - RenderLayerCompositor(RenderView*); ~RenderLayerCompositor(); @@ -61,8 +66,11 @@ public: // Returns true if the accelerated compositing is enabled bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; } - // Copy the acceleratedCompositingEnabledFlag from Settings - void cacheAcceleratedCompositingEnabledFlag(); + bool showDebugBorders() const { return m_showDebugBorders; } + bool showRepaintCounter() const { return m_showRepaintCounter; } + + // Copy the accelerated compositing related flags from Settings + void cacheAcceleratedCompositingFlags(); // Called when the layer hierarchy needs to be updated (compositing layers have been // created, destroyed or re-parented). @@ -77,7 +85,7 @@ public: void scheduleSync(); // Rebuild the tree of compositing layers - void updateCompositingLayers(RenderLayer* updateRoot = 0); + void updateCompositingLayers(CompositingUpdateType = CompositingUpdateAfterLayoutOrStyleChange, RenderLayer* updateRoot = 0); // Update the compositing state of the given layer. Returns true if that state changed. enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater }; @@ -147,8 +155,13 @@ private: // Returns true if any layer's compositing changed void computeCompositingRequirements(RenderLayer*, OverlapMap*, struct CompositingState&, bool& layersChanged); - void rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState&, bool updateHierarchy); + + // Recurses down the tree, parenting descendant compositing layers and collecting an array of child layers for the current compositing layer. + void rebuildCompositingLayerTree(RenderLayer* layer, const struct CompositingState&, Vector<GraphicsLayer*>& childGraphicsLayersOfEnclosingLayer); + // Recurses down the tree, updating layer geometry only. + void updateLayerTreeGeometry(RenderLayer*); + // Hook compositing layers together void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); void removeCompositedChildren(RenderLayer*); @@ -165,12 +178,15 @@ private: bool requiresCompositingForTransform(RenderObject*) const; bool requiresCompositingForVideo(RenderObject*) const; bool requiresCompositingForCanvas(RenderObject*) const; + bool requiresCompositingForPlugin(RenderObject*) const; bool requiresCompositingWhenDescendantsAreCompositing(RenderObject*) const; private: RenderView* m_renderView; OwnPtr<GraphicsLayer> m_rootPlatformLayer; bool m_hasAcceleratedCompositing; + bool m_showDebugBorders; + bool m_showRepaintCounter; bool m_compositingConsultsOverlap; bool m_compositing; bool m_rootLayerAttached; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp index 76a2e2f4ed..9736874983 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp @@ -67,7 +67,7 @@ void RenderLineBoxList::deleteLineBoxTree(RenderArena* arena) InlineFlowBox* line = m_firstLineBox; InlineFlowBox* nextLine; while (line) { - nextLine = line->nextFlowBox(); + nextLine = line->nextLineBox(); line->deleteLine(arena); line = nextLine; } @@ -78,13 +78,13 @@ void RenderLineBoxList::extractLineBox(InlineFlowBox* box) { checkConsistency(); - m_lastLineBox = box->prevFlowBox(); + m_lastLineBox = box->prevLineBox(); if (box == m_firstLineBox) m_firstLineBox = 0; if (box->prevLineBox()) box->prevLineBox()->setNextLineBox(0); box->setPreviousLineBox(0); - for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = box; curr; curr = curr->nextLineBox()) curr->setExtracted(); checkConsistency(); @@ -100,7 +100,7 @@ void RenderLineBoxList::attachLineBox(InlineFlowBox* box) } else m_firstLineBox = box; InlineFlowBox* last = box; - for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) { + for (InlineFlowBox* curr = box; curr; curr = curr->nextLineBox()) { curr->setExtracted(false); last = curr; } @@ -114,9 +114,9 @@ void RenderLineBoxList::removeLineBox(InlineFlowBox* box) checkConsistency(); if (box == m_firstLineBox) - m_firstLineBox = box->nextFlowBox(); + m_firstLineBox = box->nextLineBox(); if (box == m_lastLineBox) - m_lastLineBox = box->prevFlowBox(); + m_lastLineBox = box->prevLineBox(); if (box->nextLineBox()) box->nextLineBox()->setPreviousLineBox(box->prevLineBox()); if (box->prevLineBox()) @@ -128,8 +128,8 @@ void RenderLineBoxList::removeLineBox(InlineFlowBox* box) void RenderLineBoxList::deleteLineBoxes(RenderArena* arena) { if (m_firstLineBox) { - InlineRunBox* next; - for (InlineRunBox* curr = m_firstLineBox; curr; curr = next) { + InlineFlowBox* next; + for (InlineFlowBox* curr = m_firstLineBox; curr; curr = next) { next = curr->nextLineBox(); curr->destroy(arena); } @@ -140,7 +140,7 @@ void RenderLineBoxList::deleteLineBoxes(RenderArena* arena) void RenderLineBoxList::dirtyLineBoxes() { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) curr->dirtyLineBoxes(); } @@ -177,7 +177,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain // based off positions of our first line box or our last line box. RenderView* v = renderer->view(); bool usePrintRect = !v->printRect().isEmpty(); - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { if (usePrintRect) { // FIXME: This is a feeble effort to avoid splitting a line across two pages. // It is utterly inadequate, and this should not be done at paint time at all. @@ -199,6 +199,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain int bottom = curr->bottomVisibleOverflow() + renderer->maximalOutlineSize(info.phase); h = bottom - top; yPos = ty + top; + v->setMinimumColumnHeight(h); if (yPos < info.rect.bottom() && yPos + h > info.rect.y()) curr->paint(info, tx, ty); } @@ -235,7 +236,7 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq // See if our root lines contain the point. If so, then we hit test // them further. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. - for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) { + for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { if (y >= ty + curr->root()->topVisibleOverflow() && y < ty + curr->root()->bottomVisibleOverflow()) { bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty); if (inside) { @@ -280,9 +281,9 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend if (textBox) box = textBox->root(); } else if (curr->isRenderInline()) { - InlineRunBox* runBox = toRenderInline(curr)->lastLineBox(); - if (runBox) - box = runBox->root(); + InlineFlowBox* flowBox = toRenderInline(curr)->lastLineBox(); + if (flowBox) + box = flowBox->root(); } if (box) @@ -320,8 +321,8 @@ void RenderLineBoxList::checkConsistency() const { #ifdef CHECK_CONSISTENCY const InlineFlowBox* prev = 0; - for (const InlineFlowBox* child = m_firstLineBox; child != 0; child = child->nextFlowBox()) { - ASSERT(child->prevFlowBox() == prev); + for (const InlineFlowBox* child = m_firstLineBox; child != 0; child = child->nextLineBox()) { + ASSERT(child->prevLineBox() == prev); prev = child; } ASSERT(prev == m_lastLineBox); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp index 0edfdef31b..15c652ca32 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp @@ -321,7 +321,8 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in textColor = theme()->inactiveListBoxSelectionForegroundColor(); } - paintInfo.context->setFillColor(textColor); + ColorSpace colorSpace = itemStyle->colorSpace(); + paintInfo.context->setFillColor(textColor, colorSpace); Font itemFont = style()->font(); if (isOptionGroupElement(element)) { @@ -358,9 +359,10 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, in // Draw the background for this list box item if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) { + ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace(); IntRect itemRect = itemBoundingBoxRect(tx, ty, listIndex); itemRect.intersect(controlClipRect(tx, ty)); - paintInfo.context->fillRect(itemRect, backColor); + paintInfo.context->fillRect(itemRect, backColor, colorSpace); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp index e487c603e5..54a7dd2908 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp @@ -1,9 +1,7 @@ /** - * 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. + * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) * * This library is free software; you can redistribute it and/or @@ -53,8 +51,8 @@ void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* old { RenderBlock::styleDidChange(diff, oldStyle); - if (style()->listStyleType() != LNONE || - (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) { + if (style()->listStyleType() != NoneListStyle + || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); // The marker always inherits from the list item, regardless of where it might end // up (e.g., in some deeply nested line box). See CSS3 spec. @@ -77,11 +75,16 @@ void RenderListItem::destroy() RenderBlock::destroy(); } +static bool isList(Node* node) +{ + return (node->hasTagName(ulTag) || node->hasTagName(olTag)); +} + static Node* enclosingList(Node* node) { Node* parent = node->parentNode(); for (Node* n = parent; n; n = n->parentNode()) - if (n->hasTagName(ulTag) || n->hasTagName(olTag)) + if (isList(n)) return n; // If there's no actual <ul> or <ol> list element, then our parent acts as // our list for purposes of determining what other list items should be @@ -89,22 +92,38 @@ static Node* enclosingList(Node* node) return parent; } +static Node* enclosingList(const RenderObject* renderer) +{ + Node* node = renderer->node(); + if (node) + return enclosingList(node); + + renderer = renderer->parent(); + while (renderer && !renderer->node()) + renderer = renderer->parent(); + + node = renderer->node(); + if (isList(node)) + return node; + + return enclosingList(node); +} + static RenderListItem* previousListItem(Node* list, const RenderListItem* item) { - for (Node* node = item->node()->traversePreviousNode(); node != list; node = node->traversePreviousNode()) { - RenderObject* renderer = node->renderer(); - if (!renderer || !renderer->isListItem()) + for (RenderObject* renderer = item->previousInPreOrder(); renderer != list->renderer(); renderer = renderer->previousInPreOrder()) { + if (!renderer->isListItem()) continue; - Node* otherList = enclosingList(node); + Node* otherList = enclosingList(renderer); // This item is part of our current list, so it's what we're looking for. if (list == otherList) return toRenderListItem(renderer); // We found ourself inside another list; lets skip the rest of it. - // Use traverseNextNode() here because the other list itself may actually + // Use nextInPreOrder() here because the other list itself may actually // be a list item itself. We need to examine it, so we do this to counteract - // the traversePreviousNode() that will be done by the loop. + // the previousInPreOrder() that will be done by the loop. if (otherList) - node = otherList->traverseNextNode(); + renderer = otherList->renderer()->nextInPreOrder(); } return 0; } @@ -113,7 +132,7 @@ inline int RenderListItem::calcValue() const { if (m_hasExplicitValue) return m_explicitValue; - Node* list = enclosingList(node()); + Node* list = enclosingList(this); // FIXME: This recurses to a possible depth of the length of the list. // That's not good -- we need to change this to an iterative algorithm. if (RenderListItem* previousItem = previousListItem(list, this)) @@ -324,6 +343,8 @@ void RenderListItem::explicitValueChanged() void RenderListItem::setExplicitValue(int value) { + ASSERT(node()); + if (m_hasExplicitValue && m_explicitValue == value) return; m_explicitValue = value; @@ -334,6 +355,8 @@ void RenderListItem::setExplicitValue(int value) void RenderListItem::clearExplicitValue() { + ASSERT(node()); + if (!m_hasExplicitValue) return; m_hasExplicitValue = false; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp index 9627711780..d0353ee091 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp @@ -3,6 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) + * Copyright (C) 2010 Daniel Bates (dbates@intudata.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -40,6 +41,8 @@ namespace WebCore { const int cMarkerPadding = 7; +enum SequenceType { NumericSequence, AlphabeticSequence }; + static String toRoman(int number, bool upper) { // FIXME: CSS3 describes how to make this work for much larger numbers, @@ -48,7 +51,9 @@ static String toRoman(int number, bool upper) if (number < 1 || number > 3999) return String::number(number); - const int lettersSize = 12; // big enough for three each of I, X, C, and M + // Big enough to store largest roman number less than 3999 which + // is 3888 (MMMDCCCLXXXVIII) + const int lettersSize = 15; UChar letters[lettersSize]; int length = 0; @@ -75,26 +80,63 @@ static String toRoman(int number, bool upper) return String(&letters[lettersSize - length], length); } -static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize) +static inline String toAlphabeticOrNumeric(int number, const UChar* sequence, int sequenceSize, SequenceType type) { - ASSERT(alphabetSize >= 10); + ASSERT(sequenceSize >= 2); - if (number < 1) - return String::number(number); + const int lettersSize = sizeof(number) * 8 + 1; // Binary is the worst case; requires one character per bit plus a minus sign. - const int lettersSize = 10; // big enough for a 32-bit int, with a 10-letter alphabet UChar letters[lettersSize]; - --number; - letters[lettersSize - 1] = alphabet[number % alphabetSize]; + bool isNegativeNumber = false; + unsigned numberShadow = number; + if (type == AlphabeticSequence) { + ASSERT(number > 0); + --numberShadow; + } else if (number < 0) { + numberShadow = -number; + isNegativeNumber = true; + } + letters[lettersSize - 1] = sequence[numberShadow % sequenceSize]; int length = 1; - while ((number /= alphabetSize) > 0) - letters[lettersSize - ++length] = alphabet[number % alphabetSize - 1]; + + if (type == AlphabeticSequence) { + while ((numberShadow /= sequenceSize) > 0) + letters[lettersSize - ++length] = sequence[numberShadow % sequenceSize - 1]; + } else { + while ((numberShadow /= sequenceSize) > 0) + letters[lettersSize - ++length] = sequence[numberShadow % sequenceSize]; + } + if (isNegativeNumber) + letters[lettersSize - ++length] = hyphenMinus; ASSERT(length <= lettersSize); return String(&letters[lettersSize - length], length); } +static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize) +{ + if (number < 1) + return String::number(number); + + return toAlphabeticOrNumeric(number, alphabet, alphabetSize, AlphabeticSequence); +} + +static String toNumeric(int number, const UChar* numerals, int numeralsSize) +{ + return toAlphabeticOrNumeric(number, numerals, numeralsSize, NumericSequence); +} + +template <size_t size> static inline String toAlphabetic(int number, const UChar(&alphabet)[size]) +{ + return toAlphabetic(number, alphabet, size); +} + +template <size_t size> static inline String toNumeric(int number, const UChar(&alphabet)[size]) +{ + return toNumeric(number, alphabet, size); +} + static int toHebrewUnder1000(int number, UChar letters[5]) { // FIXME: CSS3 mentions various refinements not implemented here. @@ -335,58 +377,273 @@ static String toCJKIdeographic(int number, const UChar table[16]) return String(characters, length); } +static UChar listMarkerSuffix(EListStyleType type) +{ + // Note, the following switch statement has been explicitly + // grouped by list-style-type suffix. + switch (type) { + case NoneListStyle: + case Disc: + case Circle: + case Square: + ASSERT_NOT_REACHED(); + return ' '; + case Afar: + case Amharic: + case AmharicAbegede: + case Ethiopic: + case EthiopicAbegede: + case EthiopicAbegedeAmEt: + case EthiopicAbegedeGez: + case EthiopicAbegedeTiEr: + case EthiopicAbegedeTiEt: + case EthiopicHalehameAaEr: + case EthiopicHalehameAaEt: + case EthiopicHalehameAmEt: + case EthiopicHalehameGez: + case EthiopicHalehameOmEt: + case EthiopicHalehameSidEt: + case EthiopicHalehameSoEt: + case EthiopicHalehameTiEr: + case EthiopicHalehameTiEt: + case EthiopicHalehameTig: + case Oromo: + case Sidama: + case Somali: + case Tigre: + case TigrinyaEr: + case TigrinyaErAbegede: + case TigrinyaEt: + case TigrinyaEtAbegede: + return ethiopicPrefaceColon; + case Armenian: + case ArabicIndic: + case Bengali: + case BinaryListStyle: + case Cambodian: + case CJKIdeographic: + case CjkEarthlyBranch: + case CjkHeavenlyStem: + case DecimalLeadingZero: + case DecimalListStyle: + case Devanagari: + case Georgian: + case Gujarati: + case Gurmukhi: + case Hangul: + case HangulConsonant: + case Hebrew: + case Hiragana: + case HiraganaIroha: + case Kannada: + case Katakana: + case KatakanaIroha: + case Khmer: + case Lao: + case LowerAlpha: + case LowerGreek: + case LowerHexadecimal: + case LowerLatin: + case LowerNorwegian: + case LowerRoman: + case Malayalam: + case Mongolian: + case Myanmar: + case Octal: + case Oriya: + case Persian: + case Telugu: + case Thai: + case Tibetan: + case UpperAlpha: + case UpperGreek: + case UpperHexadecimal: + case UpperLatin: + case UpperNorwegian: + case UpperRoman: + case Urdu: + return '.'; + } + + ASSERT_NOT_REACHED(); + return '.'; +} + String listMarkerText(EListStyleType type, int value) { switch (type) { - case LNONE: + case NoneListStyle: return ""; // We use the same characters for text security. // See RenderText::setInternalString. - case CIRCLE: + case Circle: return String(&whiteBullet, 1); - case DISC: + case Disc: return String(&bullet, 1); - case SQUARE: + case Square: // The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE // instead, but I think this looks better. return String(&blackSquare, 1); - case LDECIMAL: + case DecimalListStyle: return String::number(value); - case DECIMAL_LEADING_ZERO: + case DecimalLeadingZero: if (value < -9 || value > 9) return String::number(value); if (value < 0) return "-0" + String::number(-value); // -01 to -09 return "0" + String::number(value); // 00 to 09 - case LOWER_ALPHA: - case LOWER_LATIN: { + case ArabicIndic: { + static const UChar arabicIndicNumerals[10] = { + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669 + }; + return toNumeric(value, arabicIndicNumerals); + } + case BinaryListStyle: { + static const UChar binaryNumerals[2] = { + '0', '1' + }; + return toNumeric(value, binaryNumerals); + } + case Bengali: { + static const UChar bengaliNumerals[10] = { + 0x09E6, 0x09E7, 0x09E8, 0x09E9, 0x09EA, 0x09EB, 0x09EC, 0x09ED, 0x09EE, 0x09EF + }; + return toNumeric(value, bengaliNumerals); + } + case Cambodian: + case Khmer: { + static const UChar khmerNumerals[10] = { + 0x17E0, 0x17E1, 0x17E2, 0x17E3, 0x17E4, 0x17E5, 0x17E6, 0x17E7, 0x17E8, 0x17E9 + }; + return toNumeric(value, khmerNumerals); + } + case Devanagari: { + static const UChar devanagariNumerals[10] = { + 0x0966, 0x0967, 0x0968, 0x0969, 0x096A, 0x096B, 0x096C, 0x096D, 0x096E, 0x096F + }; + return toNumeric(value, devanagariNumerals); + } + case Gujarati: { + static const UChar gujaratiNumerals[10] = { + 0x0AE6, 0x0AE7, 0x0AE8, 0x0AE9, 0x0AEA, 0x0AEB, 0x0AEC, 0x0AED, 0x0AEE, 0x0AEF + }; + return toNumeric(value, gujaratiNumerals); + } + case Gurmukhi: { + static const UChar gurmukhiNumerals[10] = { + 0x0A66, 0x0A67, 0x0A68, 0x0A69, 0x0A6A, 0x0A6B, 0x0A6C, 0x0A6D, 0x0A6E, 0x0A6F + }; + return toNumeric(value, gurmukhiNumerals); + } + case Kannada: { + static const UChar kannadaNumerals[10] = { + 0x0CE6, 0x0CE7, 0x0CE8, 0x0CE9, 0x0CEA, 0x0CEB, 0x0CEC, 0x0CED, 0x0CEE, 0x0CEF + }; + return toNumeric(value, kannadaNumerals); + } + case LowerHexadecimal: { + static const UChar lowerHexadecimalNumerals[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + return toNumeric(value, lowerHexadecimalNumerals); + } + case Lao: { + static const UChar laoNumerals[10] = { + 0x0ED0, 0x0ED1, 0x0ED2, 0x0ED3, 0x0ED4, 0x0ED5, 0x0ED6, 0x0ED7, 0x0ED8, 0x0ED9 + }; + return toNumeric(value, laoNumerals); + } + case Malayalam: { + static const UChar malayalamNumerals[10] = { + 0x0D66, 0x0D67, 0x0D68, 0x0D69, 0x0D6A, 0x0D6B, 0x0D6C, 0x0D6D, 0x0D6E, 0x0D6F + }; + return toNumeric(value, malayalamNumerals); + } + case Mongolian: { + static const UChar mongolianNumerals[10] = { + 0x1810, 0x1811, 0x1812, 0x1813, 0x1814, 0x1815, 0x1816, 0x1817, 0x1818, 0x1819 + }; + return toNumeric(value, mongolianNumerals); + } + case Myanmar: { + static const UChar myanmarNumerals[10] = { + 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049 + }; + return toNumeric(value, myanmarNumerals); + } + case Octal: { + static const UChar octalNumerals[8] = { + '0', '1', '2', '3', '4', '5', '6', '7' + }; + return toNumeric(value, octalNumerals); + } + case Oriya: { + static const UChar oriyaNumerals[10] = { + 0x0B66, 0x0B67, 0x0B68, 0x0B69, 0x0B6A, 0x0B6B, 0x0B6C, 0x0B6D, 0x0B6E, 0x0B6F + }; + return toNumeric(value, oriyaNumerals); + } + case Persian: + case Urdu: { + static const UChar urduNumerals[10] = { + 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4, 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9 + }; + return toNumeric(value, urduNumerals); + } + case Telugu: { + static const UChar teluguNumerals[10] = { + 0x0C66, 0x0C67, 0x0C68, 0x0C69, 0x0C6A, 0x0C6B, 0x0C6C, 0x0C6D, 0x0C6E, 0x0C6F + }; + return toNumeric(value, teluguNumerals); + } + case Tibetan: { + static const UChar tibetanNumerals[10] = { + 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24, 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29 + }; + return toNumeric(value, tibetanNumerals); + } + case Thai: { + static const UChar thaiNumerals[10] = { + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59 + }; + return toNumeric(value, thaiNumerals); + } + case UpperHexadecimal: { + static const UChar upperHexadecimalNumerals[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + return toNumeric(value, upperHexadecimalNumerals); + } + + case LowerAlpha: + case LowerLatin: { static const UChar lowerLatinAlphabet[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - return toAlphabetic(value, lowerLatinAlphabet, 26); + return toAlphabetic(value, lowerLatinAlphabet); } - case UPPER_ALPHA: - case UPPER_LATIN: { + case UpperAlpha: + case UpperLatin: { static const UChar upperLatinAlphabet[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - return toAlphabetic(value, upperLatinAlphabet, 26); + return toAlphabetic(value, upperLatinAlphabet); } - case LOWER_GREEK: { + case LowerGreek: { static const UChar lowerGreekAlphabet[24] = { 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9 }; - return toAlphabetic(value, lowerGreekAlphabet, 24); + return toAlphabetic(value, lowerGreekAlphabet); } - case HIRAGANA: { + case Hiragana: { // FIXME: This table comes from the CSS3 draft, and is probably // incorrect, given the comments in that draft. static const UChar hiraganaAlphabet[48] = { @@ -397,9 +654,9 @@ String listMarkerText(EListStyleType type, int value) 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093 }; - return toAlphabetic(value, hiraganaAlphabet, 48); + return toAlphabetic(value, hiraganaAlphabet); } - case HIRAGANA_IROHA: { + case HiraganaIroha: { // FIXME: This table comes from the CSS3 draft, and is probably // incorrect, given the comments in that draft. static const UChar hiraganaIrohaAlphabet[47] = { @@ -410,9 +667,9 @@ String listMarkerText(EListStyleType type, int value) 0x3053, 0x3048, 0x3066, 0x3042, 0x3055, 0x304D, 0x3086, 0x3081, 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, 0x305B, 0x3059 }; - return toAlphabetic(value, hiraganaIrohaAlphabet, 47); + return toAlphabetic(value, hiraganaIrohaAlphabet); } - case KATAKANA: { + case Katakana: { // FIXME: This table comes from the CSS3 draft, and is probably // incorrect, given the comments in that draft. static const UChar katakanaAlphabet[48] = { @@ -423,9 +680,9 @@ String listMarkerText(EListStyleType type, int value) 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3 }; - return toAlphabetic(value, katakanaAlphabet, 48); + return toAlphabetic(value, katakanaAlphabet); } - case KATAKANA_IROHA: { + case KatakanaIroha: { // FIXME: This table comes from the CSS3 draft, and is probably // incorrect, given the comments in that draft. static const UChar katakanaIrohaAlphabet[47] = { @@ -436,10 +693,187 @@ String listMarkerText(EListStyleType type, int value) 0x30B3, 0x30A8, 0x30C6, 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x30B9 }; - return toAlphabetic(value, katakanaIrohaAlphabet, 47); + return toAlphabetic(value, katakanaIrohaAlphabet); } - case CJK_IDEOGRAPHIC: { + case Afar: + case EthiopicHalehameAaEt: + case EthiopicHalehameAaEr: { + static const UChar ethiopicHalehameAaErAlphabet[18] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1260, 0x1270, 0x1290, + 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12E8, 0x12F0, 0x1308, 0x1338, 0x1348 + }; + return toAlphabetic(value, ethiopicHalehameAaErAlphabet); + } + case Amharic: + case EthiopicHalehameAmEt: { + static const UChar ethiopicHalehameAmEtAlphabet[33] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240, + 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8, + 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320, + 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350 + }; + return toAlphabetic(value, ethiopicHalehameAmEtAlphabet); + } + case AmharicAbegede: + case EthiopicAbegedeAmEt: { + static const UChar ethiopicAbegedeAmEtAlphabet[33] = { + 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0, + 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290, + 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1228, 0x1230, 0x1238, + 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350 + }; + return toAlphabetic(value, ethiopicAbegedeAmEtAlphabet); + } + case CjkEarthlyBranch: { + static const UChar cjkEarthlyBranchAlphabet[12] = { + 0x5B50, 0x4E11, 0x5BC5, 0x536F, 0x8FB0, 0x5DF3, 0x5348, 0x672A, 0x7533, + 0x9149, 0x620C, 0x4EA5 + }; + return toAlphabetic(value, cjkEarthlyBranchAlphabet); + } + case CjkHeavenlyStem: { + static const UChar cjkHeavenlyStemAlphabet[10] = { + 0x7532, 0x4E59, 0x4E19, 0x4E01, 0x620A, 0x5DF1, 0x5E9A, 0x8F9B, 0x58EC, + 0x7678 + }; + return toAlphabetic(value, cjkHeavenlyStemAlphabet); + } + case Ethiopic: + case EthiopicHalehameGez: { + static const UChar ethiopicHalehameGezAlphabet[26] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1240, 0x1260, + 0x1270, 0x1280, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8, + 0x12F0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350 + }; + return toAlphabetic(value, ethiopicHalehameGezAlphabet); + } + case EthiopicAbegede: + case EthiopicAbegedeGez: { + static const UChar ethiopicAbegedeGezAlphabet[26] = { + 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1200, 0x12C8, 0x12D8, 0x1210, 0x1320, + 0x12E8, 0x12A8, 0x1208, 0x1218, 0x1290, 0x1220, 0x12D0, 0x1348, 0x1338, + 0x1240, 0x1228, 0x1230, 0x1270, 0x1280, 0x1340, 0x1330, 0x1350 + }; + return toAlphabetic(value, ethiopicAbegedeGezAlphabet); + } + case HangulConsonant: { + static const UChar hangulConsonantAlphabet[14] = { + 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142, 0x3145, 0x3147, 0x3148, + 0x314A, 0x314B, 0x314C, 0x314D, 0x314E + }; + return toAlphabetic(value, hangulConsonantAlphabet); + } + case Hangul: { + static const UChar hangulAlphabet[14] = { + 0xAC00, 0xB098, 0xB2E4, 0xB77C, 0xB9C8, 0xBC14, 0xC0AC, 0xC544, 0xC790, + 0xCC28, 0xCE74, 0xD0C0, 0xD30C, 0xD558 + }; + return toAlphabetic(value, hangulAlphabet); + } + case Oromo: + case EthiopicHalehameOmEt: { + static const UChar ethiopicHalehameOmEtAlphabet[25] = { + 0x1200, 0x1208, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, 0x1270, + 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0, 0x12F8, + 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348 + }; + return toAlphabetic(value, ethiopicHalehameOmEtAlphabet); + } + case Sidama: + case EthiopicHalehameSidEt: { + static const UChar ethiopicHalehameSidEtAlphabet[26] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, + 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0, + 0x12F8, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348 + }; + return toAlphabetic(value, ethiopicHalehameSidEtAlphabet); + } + case Somali: + case EthiopicHalehameSoEt: { + static const UChar ethiopicHalehameSoEtAlphabet[22] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, + 0x1270, 0x1290, 0x12A0, 0x12A8, 0x12B8, 0x12C8, 0x12D0, 0x12E8, 0x12F0, + 0x1300, 0x1308, 0x1338, 0x1348 + }; + return toAlphabetic(value, ethiopicHalehameSoEtAlphabet); + } + case Tigre: + case EthiopicHalehameTig: { + static const UChar ethiopicHalehameTigAlphabet[27] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, + 0x1270, 0x1278, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8, + 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348, 0x1350 + }; + return toAlphabetic(value, ethiopicHalehameTigAlphabet); + } + case TigrinyaEr: + case EthiopicHalehameTiEr: { + static const UChar ethiopicHalehameTiErAlphabet[31] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1250, + 0x1260, 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8, 0x12C8, + 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328, + 0x1330, 0x1338, 0x1348, 0x1350 + }; + return toAlphabetic(value, ethiopicHalehameTiErAlphabet); + } + case TigrinyaErAbegede: + case EthiopicAbegedeTiEr: { + static const UChar ethiopicAbegedeTiErAlphabet[31] = { + 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0, + 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290, + 0x1298, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230, 0x1238, + 0x1270, 0x1278, 0x1330, 0x1350 + }; + return toAlphabetic(value, ethiopicAbegedeTiErAlphabet); + } + case TigrinyaEt: + case EthiopicHalehameTiEt: { + static const UChar ethiopicHalehameTiEtAlphabet[34] = { + 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240, + 0x1250, 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8, + 0x12B8, 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, + 0x1320, 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350 + }; + return toAlphabetic(value, ethiopicHalehameTiEtAlphabet); + } + case TigrinyaEtAbegede: + case EthiopicAbegedeTiEt: { + static const UChar ethiopicAbegedeTiEtAlphabet[34] = { + 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0, + 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290, + 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230, + 0x1238, 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350 + }; + return toAlphabetic(value, ethiopicAbegedeTiEtAlphabet); + } + case UpperGreek: { + static const UChar upperGreekAlphabet[24] = { + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, + 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9 + }; + return toAlphabetic(value, upperGreekAlphabet); + } + case LowerNorwegian: { + static const UChar lowerNorwegianAlphabet[29] = { + 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, + 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, + 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E6, + 0x00F8, 0x00E5 + }; + return toAlphabetic(value, lowerNorwegianAlphabet); + } + case UpperNorwegian: { + static const UChar upperNorwegianAlphabet[29] = { + 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, + 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, + 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00C6, + 0x00D8, 0x00C5 + }; + return toAlphabetic(value, upperNorwegianAlphabet); + } + case CJKIdeographic: { static const UChar traditionalChineseInformalTable[16] = { 0x842C, 0x5104, 0x5146, 0x5341, 0x767E, 0x5343, @@ -449,19 +883,19 @@ String listMarkerText(EListStyleType type, int value) return toCJKIdeographic(value, traditionalChineseInformalTable); } - case LOWER_ROMAN: + case LowerRoman: return toRoman(value, false); - case UPPER_ROMAN: + case UpperRoman: return toRoman(value, true); - case ARMENIAN: + case Armenian: // CSS3 says "armenian" means "lower-armenian". // But the CSS2.1 test suite contains uppercase test results for "armenian", // so we'll match the test suite. return toArmenian(value, true); - case GEORGIAN: + case Georgian: return toGeorgian(value); - case HEBREW: + case Hebrew: return toHebrew(value); } @@ -517,6 +951,15 @@ bool RenderListMarker::isImage() const return m_image && !m_image->errorOccurred(); } +IntRect RenderListMarker::localSelectionRect() +{ + InlineBox* box = inlineBoxWrapper(); + if (!box) + return IntRect(); + RootInlineBox* root = box->root(); + return IntRect(x(), root->selectionTop() - y(), width(), root->selectionHeight()); +} + void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) { if (paintInfo.phase != PaintPhaseForeground) @@ -543,10 +986,11 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(tx, ty, style()->highlight(), true); #endif - context->drawImage(m_image->image(this, marker.size()), marker.location()); + context->drawImage(m_image->image(this, marker.size()), style()->colorSpace(), marker.location()); if (selectionState() != SelectionNone) { - // FIXME: selectionRect() is in absolute, not painting coordinates. - context->fillRect(selectionRect(), selectionBackgroundColor()); + IntRect selRect = localSelectionRect(); + selRect.move(tx, ty); + context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace()); } return; } @@ -558,46 +1002,104 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) #endif if (selectionState() != SelectionNone) { - // FIXME: selectionRect() is in absolute, not painting coordinates. - context->fillRect(selectionRect(), selectionBackgroundColor()); + IntRect selRect = localSelectionRect(); + selRect.move(tx, ty); + context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace()); } const Color color(style()->color()); - context->setStrokeColor(color); + context->setStrokeColor(color, style()->colorSpace()); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); - context->setFillColor(color); + context->setFillColor(color, style()->colorSpace()); - switch (style()->listStyleType()) { - case DISC: + EListStyleType type = style()->listStyleType(); + switch (type) { + case Disc: context->drawEllipse(marker); return; - case CIRCLE: - context->setFillColor(Color::transparent); + case Circle: + context->setFillColor(Color::transparent, DeviceColorSpace); context->drawEllipse(marker); return; - case SQUARE: + case Square: context->drawRect(marker); return; - case LNONE: + case NoneListStyle: return; - case ARMENIAN: - case CJK_IDEOGRAPHIC: - case DECIMAL_LEADING_ZERO: - case GEORGIAN: - case HEBREW: - case HIRAGANA: - case HIRAGANA_IROHA: - case KATAKANA: - case KATAKANA_IROHA: - case LDECIMAL: - case LOWER_ALPHA: - case LOWER_GREEK: - case LOWER_LATIN: - case LOWER_ROMAN: - case UPPER_ALPHA: - case UPPER_LATIN: - case UPPER_ROMAN: + case Afar: + case Amharic: + case AmharicAbegede: + case ArabicIndic: + case Armenian: + case BinaryListStyle: + case Bengali: + case Cambodian: + case CJKIdeographic: + case CjkEarthlyBranch: + case CjkHeavenlyStem: + case DecimalLeadingZero: + case DecimalListStyle: + case Devanagari: + case Ethiopic: + case EthiopicAbegede: + case EthiopicAbegedeAmEt: + case EthiopicAbegedeGez: + case EthiopicAbegedeTiEr: + case EthiopicAbegedeTiEt: + case EthiopicHalehameAaEr: + case EthiopicHalehameAaEt: + case EthiopicHalehameAmEt: + case EthiopicHalehameGez: + case EthiopicHalehameOmEt: + case EthiopicHalehameSidEt: + case EthiopicHalehameSoEt: + case EthiopicHalehameTiEr: + case EthiopicHalehameTiEt: + case EthiopicHalehameTig: + case Georgian: + case Gujarati: + case Gurmukhi: + case Hangul: + case HangulConsonant: + case Hebrew: + case Hiragana: + case HiraganaIroha: + case Kannada: + case Katakana: + case KatakanaIroha: + case Khmer: + case Lao: + case LowerAlpha: + case LowerGreek: + case LowerHexadecimal: + case LowerLatin: + case LowerNorwegian: + case LowerRoman: + case Malayalam: + case Mongolian: + case Myanmar: + case Octal: + case Oriya: + case Oromo: + case Persian: + case Sidama: + case Somali: + case Telugu: + case Thai: + case Tibetan: + case Tigre: + case TigrinyaEr: + case TigrinyaErAbegede: + case TigrinyaEt: + case TigrinyaEtAbegede: + case UpperAlpha: + case UpperGreek: + case UpperHexadecimal: + case UpperLatin: + case UpperNorwegian: + case UpperRoman: + case Urdu: break; } if (m_text.isEmpty()) @@ -618,16 +1120,17 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) } const Font& font = style()->font(); + const UChar suffix = listMarkerSuffix(type); if (style()->direction() == LTR) { int width = font.width(textRun); context->drawText(style()->font(), textRun, marker.location()); - const UChar periodSpace[2] = { '.', ' ' }; - context->drawText(style()->font(), TextRun(periodSpace, 2), marker.location() + IntSize(width, 0)); + UChar suffixSpace[2] = { suffix, ' ' }; + context->drawText(style()->font(), TextRun(suffixSpace, 2), marker.location() + IntSize(width, 0)); } else { - const UChar spacePeriod[2] = { ' ', '.' }; - TextRun spacePeriodRun(spacePeriod, 2); - int width = font.width(spacePeriodRun); - context->drawText(style()->font(), spacePeriodRun, marker.location()); + UChar spaceSuffix[2] = { ' ', suffix }; + TextRun spaceSuffixRun(spaceSuffix, 2); + int width = font.width(spaceSuffixRun); + context->drawText(style()->font(), spaceSuffixRun, marker.location()); context->drawText(style()->font(), textRun, marker.location() + IntSize(width, 0)); } } @@ -691,39 +1194,95 @@ void RenderListMarker::calcPrefWidths() int width = 0; EListStyleType type = style()->listStyleType(); switch (type) { - case LNONE: + case NoneListStyle: break; - case CIRCLE: - case DISC: - case SQUARE: + case Circle: + case Disc: + case Square: m_text = listMarkerText(type, 0); // value is ignored for these types width = (font.ascent() * 2 / 3 + 1) / 2 + 2; break; - case ARMENIAN: - case CJK_IDEOGRAPHIC: - case DECIMAL_LEADING_ZERO: - case GEORGIAN: - case HEBREW: - case HIRAGANA: - case HIRAGANA_IROHA: - case KATAKANA: - case KATAKANA_IROHA: - case LDECIMAL: - case LOWER_ALPHA: - case LOWER_GREEK: - case LOWER_LATIN: - case LOWER_ROMAN: - case UPPER_ALPHA: - case UPPER_LATIN: - case UPPER_ROMAN: + case Afar: + case Amharic: + case AmharicAbegede: + case ArabicIndic: + case Armenian: + case BinaryListStyle: + case Bengali: + case Cambodian: + case CJKIdeographic: + case CjkEarthlyBranch: + case CjkHeavenlyStem: + case DecimalLeadingZero: + case DecimalListStyle: + case Devanagari: + case Ethiopic: + case EthiopicAbegede: + case EthiopicAbegedeAmEt: + case EthiopicAbegedeGez: + case EthiopicAbegedeTiEr: + case EthiopicAbegedeTiEt: + case EthiopicHalehameAaEr: + case EthiopicHalehameAaEt: + case EthiopicHalehameAmEt: + case EthiopicHalehameGez: + case EthiopicHalehameOmEt: + case EthiopicHalehameSidEt: + case EthiopicHalehameSoEt: + case EthiopicHalehameTiEr: + case EthiopicHalehameTiEt: + case EthiopicHalehameTig: + case Georgian: + case Gujarati: + case Gurmukhi: + case Hangul: + case HangulConsonant: + case Hebrew: + case Hiragana: + case HiraganaIroha: + case Kannada: + case Katakana: + case KatakanaIroha: + case Khmer: + case Lao: + case LowerAlpha: + case LowerGreek: + case LowerHexadecimal: + case LowerLatin: + case LowerNorwegian: + case LowerRoman: + case Malayalam: + case Mongolian: + case Myanmar: + case Octal: + case Oriya: + case Oromo: + case Persian: + case Sidama: + case Somali: + case Telugu: + case Thai: + case Tibetan: + case Tigre: + case TigrinyaEr: + case TigrinyaErAbegede: + case TigrinyaEt: + case TigrinyaEtAbegede: + case UpperAlpha: + case UpperGreek: + case UpperHexadecimal: + case UpperLatin: + case UpperNorwegian: + case UpperRoman: + case Urdu: m_text = listMarkerText(type, m_listItem->value()); if (m_text.isEmpty()) width = 0; else { int itemWidth = font.width(m_text); - const UChar periodSpace[2] = { '.', ' ' }; - int periodSpaceWidth = font.width(TextRun(periodSpace, 2)); - width = itemWidth + periodSpaceWidth; + UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' }; + int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2)); + width = itemWidth + suffixSpaceWidth; } break; } @@ -750,9 +1309,9 @@ void RenderListMarker::updateMargins() else marginLeft = cMarkerPadding; } else switch (style()->listStyleType()) { - case DISC: - case CIRCLE: - case SQUARE: + case Disc: + case Circle: + case Square: if (style()->direction() == LTR) { marginLeft = -1; marginRight = font.ascent() - minPrefWidth() + 1; @@ -771,12 +1330,12 @@ void RenderListMarker::updateMargins() else { int offset = font.ascent() * 2 / 3; switch (style()->listStyleType()) { - case DISC: - case CIRCLE: - case SQUARE: + case Disc: + case Circle: + case Square: marginLeft = -offset - cMarkerPadding - 1; break; - case LNONE: + case NoneListStyle: break; default: marginLeft = m_text.isEmpty() ? 0 : -minPrefWidth() - offset / 2; @@ -788,12 +1347,12 @@ void RenderListMarker::updateMargins() else { int offset = font.ascent() * 2 / 3; switch (style()->listStyleType()) { - case DISC: - case CIRCLE: - case SQUARE: + case Disc: + case Circle: + case Square: marginLeft = offset + cMarkerPadding + 1 - minPrefWidth(); break; - case LNONE: + case NoneListStyle: break; default: marginLeft = m_text.isEmpty() ? 0 : offset / 2; @@ -833,42 +1392,99 @@ IntRect RenderListMarker::getRelativeMarkerRect() if (isImage()) return IntRect(x(), y(), m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height()); - switch (style()->listStyleType()) { - case DISC: - case CIRCLE: - case SQUARE: { + EListStyleType type = style()->listStyleType(); + switch (type) { + case Disc: + case Circle: + case Square: { // FIXME: Are these particular rounding rules necessary? const Font& font = style()->font(); int ascent = font.ascent(); int bulletWidth = (ascent * 2 / 3 + 1) / 2; return IntRect(x() + 1, y() + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); } - case LNONE: + case NoneListStyle: return IntRect(); - case ARMENIAN: - case CJK_IDEOGRAPHIC: - case DECIMAL_LEADING_ZERO: - case GEORGIAN: - case HEBREW: - case HIRAGANA: - case HIRAGANA_IROHA: - case KATAKANA: - case KATAKANA_IROHA: - case LDECIMAL: - case LOWER_ALPHA: - case LOWER_GREEK: - case LOWER_LATIN: - case LOWER_ROMAN: - case UPPER_ALPHA: - case UPPER_LATIN: - case UPPER_ROMAN: + case Afar: + case Amharic: + case AmharicAbegede: + case ArabicIndic: + case Armenian: + case BinaryListStyle: + case Bengali: + case Cambodian: + case CJKIdeographic: + case CjkEarthlyBranch: + case CjkHeavenlyStem: + case DecimalLeadingZero: + case DecimalListStyle: + case Devanagari: + case Ethiopic: + case EthiopicAbegede: + case EthiopicAbegedeAmEt: + case EthiopicAbegedeGez: + case EthiopicAbegedeTiEr: + case EthiopicAbegedeTiEt: + case EthiopicHalehameAaEr: + case EthiopicHalehameAaEt: + case EthiopicHalehameAmEt: + case EthiopicHalehameGez: + case EthiopicHalehameOmEt: + case EthiopicHalehameSidEt: + case EthiopicHalehameSoEt: + case EthiopicHalehameTiEr: + case EthiopicHalehameTiEt: + case EthiopicHalehameTig: + case Georgian: + case Gujarati: + case Gurmukhi: + case Hangul: + case HangulConsonant: + case Hebrew: + case Hiragana: + case HiraganaIroha: + case Kannada: + case Katakana: + case KatakanaIroha: + case Khmer: + case Lao: + case LowerAlpha: + case LowerGreek: + case LowerHexadecimal: + case LowerLatin: + case LowerNorwegian: + case LowerRoman: + case Malayalam: + case Mongolian: + case Myanmar: + case Octal: + case Oriya: + case Oromo: + case Persian: + case Sidama: + case Somali: + case Telugu: + case Thai: + case Tibetan: + case Tigre: + case TigrinyaEr: + case TigrinyaErAbegede: + case TigrinyaEt: + case TigrinyaEtAbegede: + case UpperAlpha: + case UpperGreek: + case UpperHexadecimal: + case UpperLatin: + case UpperNorwegian: + case UpperRoman: + case Urdu: if (m_text.isEmpty()) return IntRect(); const Font& font = style()->font(); int itemWidth = font.width(m_text); - const UChar periodSpace[2] = { '.', ' ' }; - int periodSpaceWidth = font.width(TextRun(periodSpace, 2)); - return IntRect(x(), y() + font.ascent(), itemWidth + periodSpaceWidth, font.height()); + UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' }; + int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2)); + return IntRect(x(), y() + font.ascent(), itemWidth + suffixSpaceWidth, font.height()); } return IntRect(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h index 5b46278daa..971877b41f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h @@ -73,6 +73,7 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); IntRect getRelativeMarkerRect(); + IntRect localSelectionRect(); String m_text; RefPtr<StyleImage> m_image; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h index 886c3431b1..1651454df5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h @@ -53,7 +53,7 @@ namespace WebCore { class RenderLayer; // This class handles the auto-scrolling of layers with overflow: marquee. -class RenderMarquee { +class RenderMarquee : public Noncopyable { public: RenderMarquee(RenderLayer*); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp index 1d4da23381..7100435a96 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,32 +45,30 @@ using namespace HTMLNames; static const double cTimeUpdateRepeatDelay = 0.2; static const double cOpacityAnimationRepeatDelay = 0.05; -// FIXME get this from style -static const double cOpacityAnimationDurationFadeIn = 0.1; -static const double cOpacityAnimationDurationFadeOut = 0.3; RenderMedia::RenderMedia(HTMLMediaElement* video) - : RenderReplaced(video) + : RenderImage(video) , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) , m_mouseOver(false) , m_opacityAnimationStartTime(0) - , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn) + , m_opacityAnimationDuration(0) , m_opacityAnimationFrom(0) , m_opacityAnimationTo(1.0f) { } RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize) - : RenderReplaced(video, intrinsicSize) + : RenderImage(video) , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) , m_mouseOver(false) , m_opacityAnimationStartTime(0) - , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn) + , m_opacityAnimationDuration(0) , m_opacityAnimationFrom(0) , m_opacityAnimationTo(1.0f) { + setIntrinsicSize(intrinsicSize); } RenderMedia::~RenderMedia() @@ -89,7 +87,7 @@ void RenderMedia::destroy() m_controlsShadowRoot->detach(); m_controlsShadowRoot = 0; } - RenderReplaced::destroy(); + RenderImage::destroy(); } HTMLMediaElement* RenderMedia::mediaElement() const @@ -104,7 +102,7 @@ MediaPlayer* RenderMedia::player() const void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderReplaced::styleDidChange(diff, oldStyle); + RenderImage::styleDidChange(diff, oldStyle); if (m_controlsShadowRoot) { if (m_panel) @@ -121,6 +119,8 @@ void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldSty m_rewindButton->updateStyle(); if (m_returnToRealtimeButton) m_returnToRealtimeButton->updateStyle(); + if (m_toggleClosedCaptionsButton) + m_toggleClosedCaptionsButton->updateStyle(); if (m_statusDisplay) m_statusDisplay->updateStyle(); if (m_timelineContainer) @@ -144,7 +144,7 @@ void RenderMedia::layout() { IntSize oldSize = contentBoxRect().size(); - RenderReplaced::layout(); + RenderImage::layout(); RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0; if (!controlsRenderer) @@ -223,6 +223,13 @@ void RenderMedia::createReturnToRealtimeButton() m_returnToRealtimeButton->attachToParent(m_panel.get()); } +void RenderMedia::createToggleClosedCaptionsButton() +{ + ASSERT(!m_toggleClosedCaptionsButton); + m_toggleClosedCaptionsButton = new MediaControlToggleClosedCaptionsButtonElement(document(), mediaElement()); + m_toggleClosedCaptionsButton->attachToParent(m_panel.get()); +} + void RenderMedia::createStatusDisplay() { ASSERT(!m_statusDisplay); @@ -310,6 +317,7 @@ void RenderMedia::updateControls() m_volumeSliderContainer = 0; m_volumeSlider = 0; m_controlsShadowRoot = 0; + m_toggleClosedCaptionsButton = 0; } m_opacityAnimationTo = 1.0f; m_opacityAnimationTimer.stop(); @@ -333,6 +341,7 @@ void RenderMedia::updateControls() } createSeekBackButton(); createSeekForwardButton(); + createToggleClosedCaptionsButton(); createFullscreenButton(); createMuteButton(); createVolumeSliderContainer(); @@ -379,6 +388,8 @@ void RenderMedia::updateControls() m_rewindButton->update(); if (m_returnToRealtimeButton) m_returnToRealtimeButton->update(); + if (m_toggleClosedCaptionsButton) + m_toggleClosedCaptionsButton->update(); if (m_statusDisplay) m_statusDisplay->update(); if (m_fullscreenButton) @@ -401,10 +412,15 @@ void RenderMedia::updateTimeDisplay() { if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE) return; + float now = mediaElement()->currentTime(); float duration = mediaElement()->duration(); + // Allow the theme to format the time + ExceptionCode ec; + m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec); m_currentTimeDisplay->setCurrentValue(now); + m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec); m_timeRemainingDisplay->setCurrentValue(now - duration); } @@ -439,9 +455,9 @@ void RenderMedia::updateControlVisibility() } if (animateFrom < animateTo) - m_opacityAnimationDuration = cOpacityAnimationDurationFadeIn; + m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration(); else - m_opacityAnimationDuration = cOpacityAnimationDurationFadeOut; + m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration(); m_opacityAnimationFrom = animateFrom; m_opacityAnimationTo = animateTo; @@ -535,6 +551,9 @@ void RenderMedia::forwardEvent(Event* event) if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point)) m_returnToRealtimeButton->defaultEventHandler(event); + if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point)) + m_toggleClosedCaptionsButton->defaultEventHandler(event); + if (m_timeline && m_timeline->hitTest(point)) m_timeline->defaultEventHandler(event); @@ -557,7 +576,7 @@ void RenderMedia::forwardEvent(Event* event) int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { - int bottom = RenderReplaced::lowestPosition(includeOverflowInterior, includeSelf); + int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf); if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return bottom; @@ -566,7 +585,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int right = RenderReplaced::rightmostPosition(includeOverflowInterior, includeSelf); + int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf); if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return right; @@ -575,7 +594,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int left = RenderReplaced::leftmostPosition(includeOverflowInterior, includeSelf); + int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf); if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return left; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h index 602cd2648a..0d24c4c596 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,7 @@ #if ENABLE(VIDEO) -#include "RenderReplaced.h" +#include "RenderImage.h" #include "Timer.h" namespace WebCore { @@ -40,6 +40,7 @@ class MediaControlPlayButtonElement; class MediaControlSeekButtonElement; class MediaControlRewindButtonElement; class MediaControlReturnToRealtimeButtonElement; +class MediaControlToggleClosedCaptionsButtonElement; class MediaControlTimelineElement; class MediaControlVolumeSliderElement; class MediaControlFullscreenButtonElement; @@ -50,12 +51,12 @@ class MediaControlVolumeSliderContainerElement; class MediaControlElement; class MediaPlayer; -class RenderMedia : public RenderReplaced { +class RenderMedia : public RenderImage { public: RenderMedia(HTMLMediaElement*); RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize); virtual ~RenderMedia(); - + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -82,6 +83,7 @@ private: virtual const char* renderName() const { return "RenderMedia"; } virtual bool isMedia() const { return true; } + virtual bool isImage() const { return false; } virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; @@ -96,6 +98,7 @@ private: void createSeekForwardButton(); void createRewindButton(); void createReturnToRealtimeButton(); + void createToggleClosedCaptionsButton(); void createStatusDisplay(); void createTimelineContainer(); void createTimeline(); @@ -123,6 +126,7 @@ private: RefPtr<MediaControlSeekButtonElement> m_seekForwardButton; RefPtr<MediaControlRewindButtonElement> m_rewindButton; RefPtr<MediaControlReturnToRealtimeButtonElement> m_returnToRealtimeButton; + RefPtr<MediaControlToggleClosedCaptionsButtonElement> m_toggleClosedCaptionsButton; RefPtr<MediaControlTimelineElement> m_timeline; RefPtr<MediaControlVolumeSliderElement> m_volumeSlider; RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp index 9cc1493f52..17576ae06b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp @@ -90,6 +90,15 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R case MediaFullscreenButton: paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); break; + case MediaShowClosedCaptionsButton: + case MediaHideClosedCaptionsButton: +#if SAFARI_THEME_VERSION >= 4 + if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) { + bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton; + paintThemePart(captionsVisible ? SafariTheme::MediaHideClosedCaptionsButtonPart : SafariTheme::MediaShowClosedCaptionsButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + } +#endif + break; case MediaMuteButton: case MediaUnMuteButton: if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControlsChromium.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControlsChromium.cpp index 56fbec43c2..50feb4604e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -63,7 +63,7 @@ static bool hasSource(const HTMLMediaElement* mediaElement) static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image) { IntRect imageRect = image->rect(); - context->drawImage(image, rect); + context->drawImage(image, DeviceColorSpace, rect); return true; } @@ -114,9 +114,9 @@ static bool paintMediaSlider(RenderObject* object, const RenderObject::PaintInfo context->save(); context->setShouldAntialias(true); context->setStrokeStyle(SolidStroke); - context->setStrokeColor(style->borderLeftColor()); + context->setStrokeColor(style->borderLeftColor(), DeviceColorSpace); context->setStrokeThickness(style->borderLeftWidth()); - context->setFillColor(style->backgroundColor()); + context->setFillColor(style->backgroundColor(), DeviceColorSpace); context->drawRect(rect); context->restore(); @@ -172,13 +172,13 @@ static bool paintMediaVolumeSlider(RenderObject* object, const RenderObject::Pai GraphicsContext* context = paintInfo.context; Color originalColor = context->strokeColor(); if (originalColor != Color::white) - context->setStrokeColor(Color::white); + context->setStrokeColor(Color::white, DeviceColorSpace); int x = rect.x() + rect.width() / 2; context->drawLine(IntPoint(x, rect.y()), IntPoint(x, rect.y() + rect.height())); if (originalColor != Color::white) - context->setStrokeColor(originalColor); + context->setStrokeColor(originalColor, DeviceColorSpace); return true; } @@ -207,17 +207,17 @@ static bool paintMediaTimelineContainer(RenderObject* object, const RenderObject // Draw the left border using CSS defined width and color. context->setStrokeThickness(object->style()->borderLeftWidth()); - context->setStrokeColor(object->style()->borderLeftColor().rgb()); + context->setStrokeColor(object->style()->borderLeftColor().rgb(), DeviceColorSpace); context->drawLine(IntPoint(rect.x() + 1, rect.y()), IntPoint(rect.x() + 1, rect.y() + rect.height())); // Draw the right border using CSS defined width and color. context->setStrokeThickness(object->style()->borderRightWidth()); - context->setStrokeColor(object->style()->borderRightColor().rgb()); + context->setStrokeColor(object->style()->borderRightColor().rgb(), DeviceColorSpace); context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()), IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height())); - context->setStrokeColor(originalColor); + context->setStrokeColor(originalColor, DeviceColorSpace); context->setStrokeThickness(originalThickness); context->setStrokeStyle(originalStyle); } @@ -275,6 +275,8 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType case MediaRewindButton: case MediaReturnToRealtimeButton: case MediaStatusDisplay: + case MediaShowClosedCaptionsButton: + case MediaHideClosedCaptionsButton: ASSERT_NOT_REACHED(); break; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp index cbbc7cbad9..518925af56 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp @@ -1,7 +1,8 @@ /* * This file is part of the select element renderer in WebCore. * - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -24,6 +25,8 @@ #include "config.h" #include "RenderMenuList.h" +#include "AXObjectCache.h" +#include "AccessibilityObject.h" #include "CSSStyleSelector.h" #include "Frame.h" #include "FrameView.h" @@ -50,6 +53,7 @@ RenderMenuList::RenderMenuList(Element* element) , m_innerBlock(0) , m_optionsChanged(true) , m_optionsWidth(0) + , m_lastSelectedIndex(-1) , m_popup(0) , m_popupIsVisible(false) { @@ -306,10 +310,39 @@ void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange) select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange); } +#if ENABLE(NO_LISTBOX_RENDERING) +void RenderMenuList::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow) +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + select->listBoxSelectItem(select->listToOptionIndex(listIndex), allowMultiplySelections, shift, fireOnChangeNow); +} + +bool RenderMenuList::multiple() +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + return select->multiple(); +} +#endif + +void RenderMenuList::didSetSelectedIndex() +{ + int index = selectedIndex(); + if (m_lastSelectedIndex == index) + return; + + m_lastSelectedIndex = index; + + if (AXObjectCache::accessibilityEnabled()) + document()->axObjectCache()->postNotification(this, AXObjectCache::AXMenuListValueChanged, true, PostSynchronously); +} + String RenderMenuList::itemText(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return String(); + Element* element = listItems[listIndex]; if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) return optionGroupElement->groupLabelText(); else if (OptionElement* optionElement = toOptionElement(element)) @@ -317,17 +350,34 @@ String RenderMenuList::itemText(unsigned listIndex) const return String(); } +String RenderMenuList::itemAccessibilityText(unsigned listIndex) const +{ + // Allow the accessible name be changed if necessary. + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return String(); + + return AccessibilityObject::getAttribute(listItems[listIndex], aria_labelAttr); +} + String RenderMenuList::itemToolTip(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return String(); + Element* element = listItems[listIndex]; return element->title(); } bool RenderMenuList::itemIsEnabled(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return false; + Element* element = listItems[listIndex]; if (!isOptionElement(element)) return false; @@ -345,7 +395,18 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) { + // If we are making an out of bounds access, then we want to use the style + // of a different option element (index 0). However, if there isn't an option element + // before at index 0, we fall back to the menu's style. + if (!listIndex) + return menuStyle(); + + // Try to retrieve the style of an option element we know exists (index 0). + listIndex = 0; + } + Element* element = listItems[listIndex]; RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle(); return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->textIndent(), style->direction()) : menuStyle(); @@ -354,7 +415,10 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return style()->backgroundColor(); + Element* element = listItems[listIndex]; Color backgroundColor; if (element->renderStyle()) @@ -374,7 +438,6 @@ Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const PopupMenuStyle RenderMenuList::menuStyle() const { - RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style(); return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE, s->textIndent(), s->direction()); } @@ -410,8 +473,19 @@ int RenderMenuList::clientPaddingLeft() const return paddingLeft(); } +const int endOfLinePadding = 2; int RenderMenuList::clientPaddingRight() const { + if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) { + // For these appearance values, the theme applies padding to leave room for the + // drop-down button. But leaving room for the button inside the popup menu itself + // looks strange, so we return a small default padding to avoid having a large empty + // space appear on the side of the popup menu. + return endOfLinePadding; + } + + // If the appearance isn't MenulistPart, then the select is styled (non-native), so + // we want to return the user specified padding. return paddingRight(); } @@ -435,21 +509,30 @@ void RenderMenuList::popupDidHide() bool RenderMenuList::itemIsSeparator(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return false; + Element* element = listItems[listIndex]; return element->hasTagName(hrTag); } bool RenderMenuList::itemIsLabel(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return false; + Element* element = listItems[listIndex]; return isOptionGroupElement(element); } bool RenderMenuList::itemIsSelected(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); - Element* element = select->listItems()[listIndex]; + const Vector<Element*>& listItems = select->listItems(); + if (listIndex >= listItems.size()) + return false; + Element* element = listItems[listIndex]; if (OptionElement* optionElement = toOptionElement(element)) return optionElement->selected(); return false; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h index 2d617c115d..aeb62058b6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h @@ -1,7 +1,8 @@ /* * This file is part of the select element renderer in WebCore. * - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -37,7 +38,12 @@ namespace WebCore { class PopupMenu; class RenderText; +#if ENABLE(NO_LISTBOX_RENDERING) +class RenderMenuList : public RenderFlexibleBox, private ListPopupMenuClient { +#else class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient { +#endif + public: RenderMenuList(Element*); virtual ~RenderMenuList(); @@ -49,6 +55,8 @@ public: void setOptionsChanged(bool changed) { m_optionsChanged = changed; } + void didSetSelectedIndex(); + String text() const; private: @@ -73,6 +81,7 @@ private: // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; virtual String itemToolTip(unsigned listIndex) const; + virtual String itemAccessibilityText(unsigned listIndex) const; virtual bool itemIsEnabled(unsigned listIndex) const; virtual PopupMenuStyle itemStyle(unsigned listIndex) const; virtual PopupMenuStyle menuStyle() const; @@ -94,6 +103,11 @@ private: virtual HostWindow* hostWindow() const; virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); +#if ENABLE(NO_LISTBOX_RENDERING) + virtual void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true); + virtual bool multiple(); +#endif + virtual bool hasLineIfEmpty() const { return true; } Color itemBackgroundColor(unsigned listIndex) const; @@ -110,6 +124,8 @@ private: bool m_optionsChanged; int m_optionsWidth; + int m_lastSelectedIndex; + RefPtr<PopupMenu> m_popup; bool m_popupIsVisible; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp index 199de4a224..8212dcad32 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp @@ -4,6 +4,7 @@ * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -27,6 +28,7 @@ #include "RenderObject.h" #include "AXObjectCache.h" +#include "Chrome.h" #include "CSSStyleSelector.h" #include "FloatQuad.h" #include "Frame.h" @@ -41,6 +43,8 @@ #include "RenderImageGeneratedContent.h" #include "RenderInline.h" #include "RenderListItem.h" +#include "RenderRuby.h" +#include "RenderRubyText.h" #include "RenderTableCell.h" #include "RenderTableCol.h" #include "RenderTableRow.h" @@ -61,6 +65,11 @@ #include "WMLNames.h" #endif +#if ENABLE(SVG) +#include "RenderSVGResource.h" +#include "SVGRenderSupport.h" +#endif + using namespace std; namespace WebCore { @@ -103,46 +112,44 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) return image; } - RenderObject* o = 0; +#if ENABLE(RUBY) + if (node->hasTagName(rubyTag)) { + if (style->display() == INLINE) + return new (arena) RenderRubyAsInline(node); + else + return new (arena) RenderRubyAsBlock(node); + } + // treat <rt> as ruby text ONLY if it still has its default treatment of block + if (node->hasTagName(rtTag) && style->display() == BLOCK) + return new (arena) RenderRubyText(node); +#endif switch (style->display()) { case NONE: - break; + return 0; case INLINE: - o = new (arena) RenderInline(node); - break; + return new (arena) RenderInline(node); case BLOCK: - o = new (arena) RenderBlock(node); - break; case INLINE_BLOCK: - o = new (arena) RenderBlock(node); - break; - case LIST_ITEM: - o = new (arena) RenderListItem(node); - break; case RUN_IN: case COMPACT: - o = new (arena) RenderBlock(node); - break; + return new (arena) RenderBlock(node); + case LIST_ITEM: + return new (arena) RenderListItem(node); case TABLE: case INLINE_TABLE: - o = new (arena) RenderTable(node); - break; + return new (arena) RenderTable(node); case TABLE_ROW_GROUP: case TABLE_HEADER_GROUP: case TABLE_FOOTER_GROUP: - o = new (arena) RenderTableSection(node); - break; + return new (arena) RenderTableSection(node); case TABLE_ROW: - o = new (arena) RenderTableRow(node); - break; + return new (arena) RenderTableRow(node); case TABLE_COLUMN_GROUP: case TABLE_COLUMN: - o = new (arena) RenderTableCol(node); - break; + return new (arena) RenderTableCol(node); case TABLE_CELL: - o = new (arena) RenderTableCell(node); - break; + return new (arena) RenderTableCell(node); case TABLE_CAPTION: #if ENABLE(WCSS) // As per the section 17.1 of the spec WAP-239-WCSS-20011026-a.pdf, @@ -150,15 +157,13 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) // principal block box ([CSS2] section 9.2.1). case WAP_MARQUEE: #endif - o = new (arena) RenderBlock(node); - break; + return new (arena) RenderBlock(node); case BOX: case INLINE_BOX: - o = new (arena) RenderFlexibleBox(node); - break; + return new (arena) RenderFlexibleBox(node); } - return o; + return 0; } #ifndef NDEBUG @@ -307,7 +312,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) // Just add it... children->insertChildNode(this, newChild, beforeChild); } - + RenderCounter::rendererSubtreeAttached(newChild); if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); if (textToTransform) @@ -366,19 +371,14 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin if (this == stayWithin) return 0; - RenderObject* o; - if (!(o = nextSibling())) { - o = parent(); - while (o && !o->nextSibling()) { - if (o == stayWithin) - return 0; - o = o->parent(); - } - if (o) - o = o->nextSibling(); + const RenderObject* current = this; + RenderObject* next; + while (!(next = current->nextSibling())) { + current = current->parent(); + if (!current || current == stayWithin) + return 0; } - - return o; + return next; } RenderObject* RenderObject::previousInPreOrder() const @@ -643,7 +643,7 @@ RenderBlock* RenderObject::containingBlock() const } if (!o || !o->isRenderBlock()) - return 0; // Probably doesn't happen any more, but leave just in case. -dwh + return 0; // This can still happen in case of an orphaned tree return toRenderBlock(o); } @@ -719,7 +719,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, return; case DOTTED: case DASHED: - graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeColor(c, m_style->colorSpace()); graphicsContext->setStrokeThickness(width); graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke); @@ -740,7 +740,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, if (adjbw1 == 0 && adjbw2 == 0) { graphicsContext->setStrokeStyle(NoStroke); - graphicsContext->setFillColor(c); + graphicsContext->setFillColor(c, m_style->colorSpace()); switch (s) { case BSTop: case BSBottom: @@ -853,7 +853,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, // fall through case SOLID: { graphicsContext->setStrokeStyle(NoStroke); - graphicsContext->setFillColor(c); + graphicsContext->setFillColor(c, m_style->colorSpace()); ASSERT(x2 >= x1); ASSERT(y2 >= y1); if (!adjbw1 && !adjbw2) { @@ -913,7 +913,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in return; case DOTTED: case DASHED: - graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeColor(c, m_style->colorSpace()); graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); @@ -935,7 +935,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in } graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeColor(c, m_style->colorSpace()); graphicsContext->setStrokeThickness(third); graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan); graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird); @@ -954,13 +954,13 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in } graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeColor(c, m_style->colorSpace()); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); float halfThickness = (thickness + 1.0f) / 4.0f; int shiftForInner = static_cast<int>(halfThickness * 1.5f); - graphicsContext->setStrokeColor(c2); + graphicsContext->setStrokeColor(c2, m_style->colorSpace()); graphicsContext->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness); graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2, (radius.height() - shiftForInner) * 2), angleStart, angleSpan); @@ -974,7 +974,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in c = c.dark(); case SOLID: graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeColor(c, m_style->colorSpace()); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); break; @@ -1011,13 +1011,12 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) { if (!theme()->supportsFocusRing(style)) { // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. - graphicsContext->initFocusRing(ow, offset); - addFocusRingRects(graphicsContext, tx, ty); + Vector<IntRect> focusRingRects; + addFocusRingRects(focusRingRects, tx, ty); if (style->outlineStyleIsAuto()) - graphicsContext->drawFocusRing(oc); + graphicsContext->drawFocusRing(focusRingRects, ow, offset, oc); else - addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); - graphicsContext->clearFocusRing(); + addPDFURLRect(graphicsContext, unionRect(focusRingRects)); } } @@ -1075,6 +1074,23 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) return result; } +void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) +{ + Vector<IntRect> rects; + // FIXME: addFocusRingRects() needs to be passed this transform-unaware + // localToAbsolute() offset here because RenderInline::addFocusRingRects() + // implicitly assumes that. This doesn't work correctly with transformed + // descendants. + FloatPoint absolutePoint = localToAbsolute(); + addFocusRingRects(rects, absolutePoint.x(), absolutePoint.y()); + size_t count = rects.size(); + for (size_t i = 0; i < count; ++i) { + IntRect rect = rects[i]; + rect.move(-absolutePoint.x(), -absolutePoint.y()); + quads.append(localToAbsoluteQuad(FloatQuad(rect))); + } +} + void RenderObject::addAbsoluteRectForLayer(IntRect& result) { if (hasLayer()) @@ -1163,13 +1179,14 @@ void RenderObject::repaintRectangle(const IntRect& r, bool immediate) repaintUsingContainer(repaintContainer ? repaintContainer : view, dirtyRect, immediate); } -bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox) +bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox, const IntRect* newBoundsPtr, const IntRect* newOutlineBoxRectPtr) { RenderView* v = view(); if (v->printing()) return false; // Don't repaint if we're printing. - IntRect newBounds = clippedOverflowRectForRepaint(repaintContainer); + ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); + IntRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer); IntRect newOutlineBox; bool fullRepaint = selfNeedsLayout(); @@ -1177,7 +1194,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta if (!fullRepaint && style()->borderFit() == BorderFitLines) fullRepaint = true; if (!fullRepaint) { - newOutlineBox = outlineBoundsForRepaint(repaintContainer); + ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); + newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer); if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) fullRepaint = true; } @@ -1312,11 +1330,10 @@ void RenderObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, // anyway if its size does change. RenderBox* boxParent = toRenderBox(o); + IntRect repaintRect(rect); + repaintRect.move(-boxParent->layer()->scrolledContentOffset()); // For overflow:auto/scroll/hidden. + IntRect boxRect(0, 0, boxParent->layer()->width(), boxParent->layer()->height()); - int x = rect.x(); - int y = rect.y(); - boxParent->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. - IntRect repaintRect(x, y, rect.width(), rect.height()); rect = intersection(repaintRect, boxRect); if (rect.isEmpty()) return; @@ -1338,6 +1355,50 @@ void RenderObject::showTreeForThis() const node()->showTreeForThis(); } +void RenderObject::showRenderObject() const +{ + showRenderObject(0); +} + +void RenderObject::showRenderObject(int printedCharacters) const +{ + // As this function is intended to be used when debugging, the + // this pointer may be 0. + if (!this) { + fputs("(null)\n", stderr); + return; + } + + printedCharacters += fprintf(stderr, "%s %p", renderName(), this); + + if (node()) { + if (printedCharacters) + for (; printedCharacters < 39; printedCharacters++) + fputc(' ', stderr); + fputc('\t', stderr); + node()->showNode(); + } else + fputc('\n', stderr); +} + +void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const +{ + int printedCharacters = 0; + if (markedObject1 == this && markedLabel1) + printedCharacters += fprintf(stderr, "%s", markedLabel1); + if (markedObject2 == this && markedLabel2) + printedCharacters += fprintf(stderr, "%s", markedLabel2); + for (; printedCharacters < depth * 2; printedCharacters++) + fputc(' ', stderr); + + showRenderObject(printedCharacters); + if (!this) + return; + + for (const RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1); +} + #endif // NDEBUG Color RenderObject::selectionBackgroundColor() const @@ -1611,7 +1672,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS } } -void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*) +void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { if (s_affectsParentBlock) handleDynamicFloatPositionChange(); @@ -1619,9 +1680,19 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*) if (!m_parent) return; - if (diff == StyleDifferenceLayout) + if (diff == StyleDifferenceLayout) { + RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get()); + + // If the object already needs layout, then setNeedsLayout won't do + // any work. But if the containing block has changed, then we may need + // to mark the new containing blocks for layout. The change that can + // directly affect the containing block of this object is a change to + // the position style. + if (m_needsLayout && oldStyle->position() != m_style->position()) + markContainingBlocksForLayout(); + setNeedsLayoutAndPrefWidthsRecalc(); - else if (diff == StyleDifferenceLayoutPositionedMovementOnly) + } else if (diff == StyleDifferenceLayoutPositionedMovementOnly) setNeedsPositionedMovementLayout(); // Don't check for repaint here; we need to wait until the layer has been @@ -1688,6 +1759,11 @@ void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; + IntSize columnOffset; + o->adjustForColumns(columnOffset, roundedIntPoint(transformState.mappedPoint())); + if (!columnOffset.isZero()) + transformState.move(columnOffset); + if (o->hasOverflowClip()) transformState.move(-toRenderBox(o)->layer()->scrolledContentOffset()); @@ -1744,18 +1820,23 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderBoxModelObject* repaintContainer, bool fixed) const { - TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint(), &localQuad); + // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(), + // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks. + TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), &localQuad); mapLocalToContainer(repaintContainer, fixed, true, transformState); transformState.flatten(); return transformState.lastPlanarQuad(); } -IntSize RenderObject::offsetFromContainer(RenderObject* o) const +IntSize RenderObject::offsetFromContainer(RenderObject* o, const IntPoint& point) const { ASSERT(o == container()); IntSize offset; + + o->adjustForColumns(offset, point); + if (o->hasOverflowClip()) offset -= toRenderBox(o)->layer()->scrolledContentOffset(); @@ -1765,6 +1846,7 @@ IntSize RenderObject::offsetFromContainer(RenderObject* o) const IntSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const { IntSize offset; + IntPoint referencePoint; const RenderObject* currContainer = this; do { RenderObject* nextContainer = currContainer->container(); @@ -1772,7 +1854,9 @@ IntSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const if (!nextContainer) break; ASSERT(!currContainer->hasTransform()); - offset += currContainer->offsetFromContainer(nextContainer); + IntSize currentOffset = currContainer->offsetFromContainer(nextContainer, referencePoint); + offset += currentOffset; + referencePoint.move(currentOffset); currContainer = nextContainer; } while (currContainer != container); @@ -1875,7 +1959,7 @@ void RenderObject::destroy() // If this renderer is being autoscrolled, stop the autoscroll timer - // FIXME: RenderObject::destroy should not get called with a renderar whose document + // FIXME: RenderObject::destroy should not get called with a renderer whose document // has a null frame, so we assert this. However, we don't want release builds to crash which is why we // check that the frame is not null. ASSERT(document()->frame()); @@ -2376,9 +2460,20 @@ RenderBoxModelObject* RenderObject::offsetParent() const VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity) { - // If this is a non-anonymous renderer, then it's simple. - if (Node* node = this->node()) + // If this is a non-anonymous renderer in an editable area, then it's simple. + if (Node* node = this->node()) { + if (!node->isContentEditable()) { + // If it can be found, we prefer a visually equivalent position that is editable. + Position position(node, offset); + Position candidate = position.downstream(Position::CanCrossEditingBoundary); + if (candidate.node()->isContentEditable()) + return VisiblePosition(candidate, affinity); + candidate = position.upstream(Position::CanCrossEditingBoundary); + if (candidate.node()->isContentEditable()) + return VisiblePosition(candidate, affinity); + } return VisiblePosition(node, offset, affinity); + } // We don't want to cross the boundary between editable and non-editable // regions of the document, but that is either impossible or at least @@ -2426,6 +2521,17 @@ VisiblePosition RenderObject::createVisiblePosition(const Position& position) } #if ENABLE(SVG) +const SVGRenderBase* RenderObject::toSVGRenderBase() const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +RenderSVGResource* RenderObject::toRenderSVGResource() +{ + ASSERT_NOT_REACHED(); + return 0; +} FloatRect RenderObject::objectBoundingBox() const { @@ -2441,25 +2547,16 @@ FloatRect RenderObject::repaintRectInLocalCoordinates() const return FloatRect(); } -TransformationMatrix RenderObject::localTransform() const +AffineTransform RenderObject::localTransform() const { - return TransformationMatrix(); + static const AffineTransform identity; + return identity; } -TransformationMatrix RenderObject::localToParentTransform() const +const AffineTransform& RenderObject::localToParentTransform() const { - // FIXME: This double virtual call indirection is temporary until I can land the - // rest of the of the localToParentTransform() support for SVG. - return localTransform(); -} - -TransformationMatrix RenderObject::absoluteTransform() const -{ - // FIXME: This should use localToParentTransform(), but much of the SVG code - // depends on RenderBox::absoluteTransform() being the sum of the localTransform()s of all parent renderers. - if (parent()) - return localTransform() * parent()->absoluteTransform(); - return localTransform(); + static const AffineTransform identity; + return identity; } bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) @@ -2480,4 +2577,19 @@ void showTree(const WebCore::RenderObject* ro) ro->showTreeForThis(); } +void showRenderTree(const WebCore::RenderObject* object1) +{ + showRenderTree(object1, 0); +} + +void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2) +{ + if (object1) { + const WebCore::RenderObject* root = object1; + while (root->parent()) + root = root->parent(); + root->showRenderTreeAndMark(object1, "*", object2, "-", 0); + } +} + #endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h index e358c981ac..d928521d54 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h @@ -4,6 +4,7 @@ * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,6 +26,7 @@ #ifndef RenderObject_h #define RenderObject_h +#include "AffineTransform.h" #include "CachedResourceClient.h" #include "Document.h" #include "Element.h" @@ -51,6 +53,10 @@ class RenderLayer; class RenderTheme; class TransformState; class VisiblePosition; +#if ENABLE(SVG) +class RenderSVGResource; +class SVGRenderBase; +#endif /* * The painting of a layer occurs in three distinct phases. Each phase involves @@ -76,11 +82,13 @@ enum PaintPhase { PaintPhaseMask }; -enum PaintRestriction { - PaintRestrictionNone, - PaintRestrictionSelectionOnly, - PaintRestrictionSelectionOnlyBlackText +enum PaintBehaviorFlags { + PaintBehaviorNormal = 0, + PaintBehaviorSelectionOnly = 1 << 0, + PaintBehaviorForceBlackText = 1 << 1, + PaintBehaviorFlattenCompositingLayers = 1 << 2 }; +typedef unsigned PaintBehavior; enum HitTestFilter { HitTestAll, @@ -228,6 +236,12 @@ private: public: #ifndef NDEBUG void showTreeForThis() const; + + void showRenderObject() const; + // We don't make printedCharacters an optional parameter so that + // showRenderObject can be called from gdb easily. + void showRenderObject(int printedCharacters) const; + void showRenderTreeAndMark(const RenderObject* markedObject1 = 0, const char* markedLabel1 = 0, const RenderObject* markedObject2 = 0, const char* markedLabel2 = 0, int depth = 0) const; #endif static RenderObject* createObject(Node*, RenderStyle*); @@ -251,7 +265,9 @@ public: virtual bool isBlockFlow() const { return false; } virtual bool isBoxModelObject() const { return false; } virtual bool isCounter() const { return false; } + virtual bool isEmbeddedObject() const { return false; } virtual bool isFieldset() const { return false; } + virtual bool isFileUploadControl() const { return false; } virtual bool isFrame() const { return false; } virtual bool isFrameSet() const { return false; } virtual bool isImage() const { return false; } @@ -261,12 +277,22 @@ public: virtual bool isListMarker() const { return false; } virtual bool isMedia() const { return false; } virtual bool isMenuList() const { return false; } +#if ENABLE(PROGRESS_TAG) + virtual bool isProgress() const { return false; } +#endif virtual bool isRenderBlock() const { return false; } virtual bool isRenderButton() const { return false; } virtual bool isRenderImage() const { return false; } virtual bool isRenderInline() const { return false; } virtual bool isRenderPart() const { return false; } virtual bool isRenderView() const { return false; } + virtual bool isReplica() const { return false; } +#if ENABLE(RUBY) + virtual bool isRuby() const { return false; } + virtual bool isRubyBase() const { return false; } + virtual bool isRubyRun() const { return false; } + virtual bool isRubyText() const { return false; } +#endif virtual bool isSlider() const { return false; } virtual bool isTable() const { return false; } virtual bool isTableCell() const { return false; } @@ -296,6 +322,10 @@ public: bool cellWidthChanged() const { return m_cellWidthChanged; } void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; } +#if ENABLE(MATHML) + virtual bool isRenderMathMLBlock() const { return false; } +#endif // ENABLE(MATHML) + #if ENABLE(SVG) // FIXME: Until all SVG renders can be subclasses of RenderSVGModelObject we have // to add SVG renderer methods to RenderObject with an ASSERT_NOT_REACHED() default implementation. @@ -306,6 +336,10 @@ public: virtual bool isSVGText() const { return false; } virtual bool isSVGImage() const { return false; } virtual bool isSVGForeignObject() const { return false; } + virtual bool isSVGResource() const { return false; } + + virtual const SVGRenderBase* toSVGRenderBase() const; + virtual RenderSVGResource* toRenderSVGResource(); // Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width. // This is used for all computation of objectBoundingBox relative units and by SVGLocateable::getBBox(). @@ -322,16 +356,11 @@ public: // FIXME: This accessor is deprecated and mostly around for SVGRenderTreeAsText. // This only returns the transform="" value from the element // most callsites want localToParentTransform() instead. - virtual TransformationMatrix localTransform() const; + virtual AffineTransform localTransform() const; // Returns the full transform mapping from local coordinates to local coords for the parent SVG renderer // This includes any viewport transforms and x/y offsets as well as the transform="" value off the element. - virtual TransformationMatrix localToParentTransform() const; - - // Walks up the parent chain to create a transform which maps from local to document coords - // NOTE: This method is deprecated! It doesn't respect scroll offsets or repaint containers. - // FIXME: This is only virtual so that RenderSVGHiddenContainer can override it to match old LayoutTest results. - virtual TransformationMatrix absoluteTransform() const; + virtual const AffineTransform& localToParentTransform() const; // SVG uses FloatPoint precise hit testing, and passes the point in parent // coordinates instead of in repaint container coordinates. Eventually the @@ -486,10 +515,6 @@ public: /* This function performs a layout only if one is needed. */ void layoutIfNeeded() { if (needsLayout()) layout(); } - - // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted - // that just updates the object's position. If the size does change, the object remains dirty. - virtual void tryLayoutDoingPositionedMovementOnly() { } // used for element state updates that cannot be fixed with a // repaint and do not need a relayout @@ -539,8 +564,9 @@ public: // Convert a local quad into the coordinate system of container, taking transforms into account. FloatQuad localToContainerQuad(const FloatQuad&, RenderBoxModelObject* repaintContainer, bool fixed = false) const; - // Return the offset from the container() renderer (excluding transforms) - virtual IntSize offsetFromContainer(RenderObject*) const; + // Return the offset from the container() renderer (excluding transforms). In multi-column layout, + // different offsets apply at different points, so return the offset that applies to the given point. + virtual IntSize offsetFromContainer(RenderObject*, const IntPoint&) const; // Return the offset from an object up the container() chain. Asserts that none of the intermediate objects have transforms. IntSize offsetFromAncestorContainer(RenderObject*) const; @@ -551,6 +577,8 @@ public: // Build an array of quads in absolute coords for line boxes virtual void absoluteQuads(Vector<FloatQuad>&) { } + void absoluteFocusRingQuads(Vector<FloatQuad>&); + // the rect that will be painted if this object is passed as the paintingRoot IntRect paintingRootRect(IntRect& topLevelRect); @@ -587,8 +615,8 @@ public: // Repaint a specific subrectangle within a given object. The rect |r| is in the object's coordinate space. void repaintRectangle(const IntRect&, bool immediate = false); - // Repaint only if our old bounds and new bounds are different. - bool repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox); + // Repaint only if our old bounds and new bounds are different. The caller may pass in newBounds and newOutlineBox if they are known. + bool repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox, const IntRect* newBoundsPtr = 0, const IntRect* newOutlineBoxPtr = 0); // Repaint only if the object moved. virtual void repaintDuringLayoutIfMoved(const IntRect& rect); @@ -617,6 +645,10 @@ public: // that rect in the coordinate space of repaintContainer. virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + // If multiple-column layout results in applying an offset to the given point, add the same + // offset to the given size. + virtual void adjustForColumns(IntSize&, const IntPoint&) const { } + virtual unsigned int length() const { return 1; } bool isFloatingOrPositioned() const { return (isFloating() || isPositioned()); } @@ -736,7 +768,7 @@ public: bool shouldUseTransformFromContainer(const RenderObject* container) const; void getTransformFromContainer(const RenderObject* container, const IntSize& offsetInContainer, TransformationMatrix&) const; - virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { }; + virtual void addFocusRingRects(Vector<IntRect>&, int /*tx*/, int /*ty*/) { }; IntRect absoluteOutlineBounds() const { @@ -1028,6 +1060,10 @@ inline void adjustFloatQuadForAbsoluteZoom(FloatQuad& quad, RenderObject* render #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. void showTree(const WebCore::RenderObject*); +void showRenderTree(const WebCore::RenderObject* object1); +// We don't make object2 an optional parameter so that showRenderTree +// can be called from gdb easily. +void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2); #endif #endif // RenderObject_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp index 23ab98f277..d56a015f76 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp @@ -271,24 +271,29 @@ static RenderObject* findBeforeAfterParent(RenderObject* object) return beforeAfterParent; } -static void invalidateCountersInContainer(RenderObject* container) +static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier) { if (!container) return; container = findBeforeAfterParent(container); if (!container) return; + // Sometimes the counter is attached directly on the container. + if (container->isCounter()) { + toRenderCounter(container)->invalidate(identifier); + return; + } for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) { if (content->isCounter()) - toRenderCounter(content)->invalidate(); + toRenderCounter(content)->invalidate(identifier); } } -void RenderObjectChildList::invalidateCounters(RenderObject* owner) +void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier) { ASSERT(!owner->documentBeingDestroyed()); - invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE)); - invalidateCountersInContainer(beforeAfterContainer(owner, AFTER)); + invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier); + invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier); } void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject) @@ -369,9 +374,11 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo RefPtr<RenderStyle> style = RenderStyle::create(); style->inheritFrom(pseudoElementStyle); genChild->setStyle(style.release()); - } else - // Must be a first-letter container. updateFirstLetter() will take care of it. - ASSERT(genChild->style()->styleType() == FIRST_LETTER); + } else { + // RenderListItem may insert a list marker here. We do not need to care about this case. + // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it. + ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER); + } } } return; // We've updated the generated content. That's all we needed to do. diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h index bf8800a2d8..ba73c50cb4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h @@ -30,6 +30,7 @@ namespace WebCore { +class AtomicString; class RenderObject; class RenderObjectChildList { @@ -55,7 +56,7 @@ public: void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool fullInsert = true); void updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject = 0); - void invalidateCounters(RenderObject* owner); + void invalidateCounters(RenderObject* owner, const AtomicString& identifier); private: RenderObject* m_firstChild; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderOverflow.h b/src/3rdparty/webkit/WebCore/rendering/RenderOverflow.h index ed8976a5b7..253a672231 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderOverflow.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderOverflow.h @@ -37,7 +37,7 @@ namespace WebCore // Examples of visual overflow are shadows, text stroke (and eventually outline and border-image). // This object is allocated only when some of these fields have non-default values in the owning box. -class RenderOverflow { +class RenderOverflow : public Noncopyable { public: RenderOverflow(const IntRect& defaultRect = IntRect()) : m_topLayoutOverflow(defaultRect.y()) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp index cb56c0c310..74b467f238 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp @@ -24,13 +24,16 @@ #include "config.h" #include "RenderPart.h" +#include "RenderView.h" #include "Frame.h" #include "FrameView.h" +#include "HTMLFrameElementBase.h" namespace WebCore { RenderPart::RenderPart(Element* node) : RenderWidget(node) + , m_hasFallbackContent(false) { // init RenderObject attributes setInline(false); @@ -53,6 +56,60 @@ void RenderPart::setWidget(PassRefPtr<Widget> widget) viewCleared(); } +void RenderPart::layoutWithFlattening(bool fixedWidth, bool fixedHeight) +{ + FrameView* childFrameView = static_cast<FrameView*>(widget()); + RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0; + + // Do not expand frames which has zero width or height + if (!width() || !height() || !childRoot) { + updateWidgetPosition(); + if (childFrameView) + childFrameView->layout(); + setNeedsLayout(false); + return; + } + + // need to update to calculate min/max correctly + updateWidgetPosition(); + if (childRoot->prefWidthsDirty()) + childRoot->calcPrefWidths(); + + // if scrollbars are off, and the width or height are fixed + // we obey them and do not expand. With frame flattening + // no subframe much ever become scrollable. + + HTMLFrameElementBase* element = static_cast<HTMLFrameElementBase*>(node()); + bool isScrollable = element->scrollingMode() != ScrollbarAlwaysOff; + + // consider iframe inset border + int hBorder = borderLeft() + borderRight(); + int vBorder = borderTop() + borderBottom(); + + // make sure minimum preferred width is enforced + if (isScrollable || !fixedWidth) { + setWidth(max(width(), childRoot->minPrefWidth() + hBorder)); + // update again to pass the new width to the child frame + updateWidgetPosition(); + childFrameView->layout(); + } + + // expand the frame by setting frame height = content height + if (isScrollable || !fixedHeight || childRoot->isFrameSet()) + setHeight(max(height(), childFrameView->contentsHeight() + vBorder)); + if (isScrollable || !fixedWidth || childRoot->isFrameSet()) + setWidth(max(width(), childFrameView->contentsWidth() + hBorder)); + + updateWidgetPosition(); + + ASSERT(!childFrameView->layoutPending()); + ASSERT(!childRoot->needsLayout()); + ASSERT(!childRoot->firstChild() || !childRoot->firstChild()->firstChild() || !childRoot->firstChild()->firstChild()->needsLayout()); + + setNeedsLayout(false); +} + + void RenderPart::viewCleared() { } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.h b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h index 08abf99049..ef4b5e1b83 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPart.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h @@ -27,16 +27,22 @@ namespace WebCore { +// Renderer for frames via RenderPartObject, and plug-ins via RenderEmbeddedObject. + +// FIXME: This class is subclassed in RenderPartObject for iframes, which is in turn +// subclassed in RenderEmbeddedObject for object and embed. This class itself could be removed. class RenderPart : public RenderWidget { public: RenderPart(Element*); virtual ~RenderPart(); - + bool hasFallbackContent() const { return m_hasFallbackContent; } virtual void setWidget(PassRefPtr<Widget>); virtual void viewCleared(); + void layoutWithFlattening(bool fixedWidth, bool fixedHeight); + protected: bool m_hasFallbackContent; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp index e2c8e7d8af..c4c515ede4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp @@ -35,6 +35,7 @@ #include "Page.h" #include "RenderView.h" #include "RenderWidgetProtector.h" +#include "Settings.h" #include "Text.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) @@ -48,288 +49,72 @@ using namespace HTMLNames; RenderPartObject::RenderPartObject(Element* element) : RenderPart(element) { - // init RenderObject attributes - setInline(true); - m_hasFallbackContent = false; - - if (element->hasTagName(embedTag) || element->hasTagName(objectTag)) - view()->frameView()->setIsVisuallyNonEmpty(); } -RenderPartObject::~RenderPartObject() +bool RenderPartObject::flattenFrame() const { - if (frameView()) - frameView()->removeWidgetToUpdate(this); -} - -static bool isURLAllowed(Document* doc, const String& url) -{ - if (doc->frame()->page()->frameCount() >= 200) + if (!node() || !node()->hasTagName(iframeTag)) return false; - // We allow one level of self-reference because some sites depend on that. - // But we don't allow more than one. - KURL completeURL = doc->completeURL(url); - bool foundSelfReference = false; - for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) { - if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) { - if (foundSelfReference) - return false; - foundSelfReference = true; - } - } - return true; -} + HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node()); + bool isScrollable = frame->scrollingMode() != ScrollbarAlwaysOff; -typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap; + if (!isScrollable && style()->width().isFixed() + && style()->height().isFixed()) + return false; -static ClassIdToTypeMap* createClassIdToTypeMap() -{ - ClassIdToTypeMap* map = new ClassIdToTypeMap; - map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash"); - map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin"); - map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime"); - map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director"); - map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2"); - map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2"); - return map; + return frame->document()->frame() && frame->document()->frame()->settings()->frameFlatteningEnabled(); } -static String serviceTypeForClassId(const String& classId) +void RenderPartObject::calcHeight() { - // Return early if classId is empty (since we won't do anything below). - // Furthermore, if classId is null, calling get() below will crash. - if (classId.isEmpty()) - return String(); - - static ClassIdToTypeMap* map = createClassIdToTypeMap(); - return map->get(classId); -} + RenderPart::calcHeight(); + if (!flattenFrame()) + return; -static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues) -{ - // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP - // require "src" attribute). - int srcIndex = -1, dataIndex = -1; - for (unsigned int i = 0; i < paramNames->size(); ++i) { - if (equalIgnoringCase((*paramNames)[i], "src")) - srcIndex = i; - else if (equalIgnoringCase((*paramNames)[i], "data")) - dataIndex = i; - } + HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node()); + bool isScrollable = frame->scrollingMode() != ScrollbarAlwaysOff; - if (srcIndex == -1 && dataIndex != -1) { - paramNames->append("src"); - paramValues->append((*paramValues)[dataIndex]); + if (isScrollable || !style()->height().isFixed()) { + FrameView* view = static_cast<FrameView*>(widget()); + int border = borderTop() + borderBottom(); + setHeight(max(height(), view->contentsHeight() + border)); } } -void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) +void RenderPartObject::calcWidth() { - String url; - String serviceType; - Vector<String> paramNames; - Vector<String> paramValues; - Frame* frame = frameView()->frame(); - - // The calls to FrameLoader::requestObject within this function can result in a plug-in being initialized. - // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from - // the render tree and destroyed, causing a crash like <rdar://problem/6954546>. By extending our lifetime - // artifically to ensure that we remain alive for the duration of plug-in initialization. - RenderWidgetProtector protector(this); - - if (node()->hasTagName(objectTag)) { - HTMLObjectElement* o = static_cast<HTMLObjectElement*>(node()); - - o->setNeedWidgetUpdate(false); - if (!o->isFinishedParsingChildren()) - return; - - // Check for a child EMBED tag. - HTMLEmbedElement* embed = 0; - for (Node* child = o->firstChild(); child; ) { - if (child->hasTagName(embedTag)) { - embed = static_cast<HTMLEmbedElement*>(child); - break; - } else if (child->hasTagName(objectTag)) - child = child->nextSibling(); // Don't descend into nested OBJECT tags - else - child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags) - } - - // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. - HTMLElement *embedOrObject; - if (embed) { - embedOrObject = (HTMLElement *)embed; - url = embed->url(); - serviceType = embed->serviceType(); - } else - embedOrObject = (HTMLElement *)o; - - // If there was no URL or type defined in EMBED, try the OBJECT tag. - if (url.isEmpty()) - url = o->url(); - if (serviceType.isEmpty()) - serviceType = o->serviceType(); - - HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; - - // Scan the PARAM children. - // Get the URL and type from the params if we don't already have them. - // Get the attributes from the params if there is no EMBED tag. - Node *child = o->firstChild(); - while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { - if (child->hasTagName(paramTag)) { - HTMLParamElement* p = static_cast<HTMLParamElement*>(child); - String name = p->name(); - if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) - url = p->value(); - if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { - serviceType = p->value(); - int pos = serviceType.find(";"); - if (pos != -1) - serviceType = serviceType.left(pos); - } - if (!embed && !name.isEmpty()) { - uniqueParamNames.add(name.impl()); - paramNames.append(p->name()); - paramValues.append(p->value()); - } - } - child = child->nextSibling(); - } - - // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag - // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is - // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means - // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, - // else our Java plugin will misinterpret it. [4004531] - String codebase; - if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { - codebase = "codebase"; - uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already - } - - // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. - NamedNodeMap* attributes = embedOrObject->attributes(); - if (attributes) { - for (unsigned i = 0; i < attributes->length(); ++i) { - Attribute* it = attributes->attributeItem(i); - const AtomicString& name = it->name().localName(); - if (embed || !uniqueParamNames.contains(name.impl())) { - paramNames.append(name.string()); - paramValues.append(it->value().string()); - } - } - } + RenderPart::calcWidth(); + if (!flattenFrame()) + return; - mapDataParamToSrc(¶mNames, ¶mValues); + HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node()); + bool isScrollable = frame->scrollingMode() != ScrollbarAlwaysOff; - // If we still don't have a type, try to map from a specific CLASSID to a type. - if (serviceType.isEmpty()) - serviceType = serviceTypeForClassId(o->classId()); - - if (!isURLAllowed(document(), url)) - return; - - // Find out if we support fallback content. - m_hasFallbackContent = false; - for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { - if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param> - (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) - m_hasFallbackContent = true; - } - - if (onlyCreateNonNetscapePlugins) { - KURL completedURL; - if (!url.isEmpty()) - completedURL = frame->loader()->completeURL(url); - - if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) - return; - } - - bool success = o->dispatchBeforeLoadEvent(url) && - frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); - if (!success && m_hasFallbackContent) - o->renderFallbackContent(); - } else if (node()->hasTagName(embedTag)) { - HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(node()); - o->setNeedWidgetUpdate(false); - url = o->url(); - serviceType = o->serviceType(); - - if (url.isEmpty() && serviceType.isEmpty()) - return; - if (!isURLAllowed(document(), url)) - return; - - // add all attributes set on the embed object - NamedNodeMap* a = o->attributes(); - if (a) { - for (unsigned i = 0; i < a->length(); ++i) { - Attribute* it = a->attributeItem(i); - paramNames.append(it->name().localName().string()); - paramValues.append(it->value().string()); - } - } - - if (onlyCreateNonNetscapePlugins) { - KURL completedURL; - if (!url.isEmpty()) - completedURL = frame->loader()->completeURL(url); - - if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) - return; - - } - - if (o->dispatchBeforeLoadEvent(url)) - frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); - } -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) { - HTMLMediaElement* o = static_cast<HTMLMediaElement*>(node()); - - o->setNeedWidgetUpdate(false); - if (node()->hasTagName(videoTag)) { - HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node()); - String poster = vid->poster(); - if (!poster.isEmpty()) { - paramNames.append("_media_element_poster_"); - paramValues.append(poster); - } - } - - url = o->initialURL(); - if (!url.isEmpty()) { - paramNames.append("_media_element_src_"); - paramValues.append(url); - } - - serviceType = "application/x-media-element-proxy-plugin"; - - if (o->dispatchBeforeLoadEvent(url)) - frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues); + if (isScrollable || !style()->width().isFixed()) { + FrameView* view = static_cast<FrameView*>(widget()); + int border = borderLeft() + borderRight(); + setWidth(max(width(), view->contentsWidth() + border)); } -#endif } void RenderPartObject::layout() { ASSERT(needsLayout()); - calcWidth(); - calcHeight(); + RenderPart::calcWidth(); + RenderPart::calcHeight(); + + if (flattenFrame()) { + layoutWithFlattening(style()->width().isFixed(), style()->height().isFixed()); + return; + } RenderPart::layout(); m_overflow.clear(); addShadowOverflow(); - if (!widget() && frameView()) - frameView()->addWidgetToUpdate(this); - setNeedsLayout(false); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h index ad956bd1ea..5c7277e44e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h @@ -27,12 +27,13 @@ namespace WebCore { +// Renderer for iframes. Is subclassed in RenderEmbeddedObject for object and embed. class RenderPartObject : public RenderPart { public: RenderPartObject(Element*); - virtual ~RenderPartObject(); - void updateWidget(bool onlyCreateNonNetscapePlugins); + virtual void calcHeight(); + virtual void calcWidth(); private: virtual const char* renderName() const { return "RenderPartObject"; } @@ -40,6 +41,8 @@ private: virtual void layout(); virtual void viewCleared(); + + bool flattenFrame() const; }; inline RenderPartObject* toRenderPartObject(RenderObject* object) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp index 4a7662f23f..bcedd38088 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp @@ -3,6 +3,7 @@ 2004, 2005, 2008 Rob Buis <buis@kde.org> 2005, 2007 Eric Seidel <eric@webkit.org> 2009 Google, Inc. + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -33,9 +34,7 @@ #include "StrokeStyleApplier.h" #include "SVGPaintServer.h" #include "SVGRenderSupport.h" -#include "SVGResourceFilter.h" #include "SVGResourceMarker.h" -#include "SVGResourceMasker.h" #include "SVGStyledTransformableElement.h" #include "SVGTransformList.h" #include "SVGURIReference.h" @@ -68,12 +67,12 @@ RenderPath::RenderPath(SVGStyledTransformableElement* node) { } -TransformationMatrix RenderPath::localToParentTransform() const +const AffineTransform& RenderPath::localToParentTransform() const { return m_localTransform; } -TransformationMatrix RenderPath::localTransform() const +AffineTransform RenderPath::localTransform() const { return m_localTransform; } @@ -112,6 +111,34 @@ FloatRect RenderPath::objectBoundingBox() const return m_cachedLocalFillBBox; } +FloatRect RenderPath::strokeBoundingBox() const +{ + if (m_path.isEmpty()) + return FloatRect(); + + if (!m_cachedLocalStrokeBBox.isEmpty()) + return m_cachedLocalStrokeBBox; + + m_cachedLocalStrokeBBox = objectBoundingBox(); + if (style()->svgStyle()->hasStroke()) { + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle)); + } + + return m_cachedLocalStrokeBBox; +} + +FloatRect RenderPath::markerBoundingBox() const +{ + if (m_path.isEmpty()) + return FloatRect(); + + if (m_cachedLocalMarkerBBox.isEmpty()) + calculateMarkerBoundsIfNeeded(); + + return m_cachedLocalMarkerBBox; +} + FloatRect RenderPath::repaintRectInLocalCoordinates() const { if (m_path.isEmpty()) @@ -121,16 +148,25 @@ FloatRect RenderPath::repaintRectInLocalCoordinates() const if (!m_cachedLocalRepaintRect.isEmpty()) return m_cachedLocalRepaintRect; - if (!style()->svgStyle()->hasStroke()) - m_cachedLocalRepaintRect = objectBoundingBox(); + // FIXME: We need to be careful here. We assume that there is no filter, + // clipper, marker or masker if the rects are empty. + FloatRect rect = filterBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect = rect; else { - BoundingRectStrokeStyleApplier strokeStyle(this, style()); - m_cachedLocalRepaintRect = m_path.strokeBoundingRect(&strokeStyle); + m_cachedLocalRepaintRect = strokeBoundingBox(); + m_cachedLocalRepaintRect.unite(markerBoundingBox()); } - // Markers and filters can paint outside of the stroke path - m_cachedLocalRepaintRect.unite(m_markerBounds); - m_cachedLocalRepaintRect.unite(filterBoundingBoxForRenderer(this)); + rect = clipperBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect.intersect(rect); + + rect = maskerBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect.intersect(rect); + + style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect); return m_cachedLocalRepaintRect; } @@ -139,12 +175,9 @@ void RenderPath::setPath(const Path& newPath) { m_path = newPath; m_cachedLocalRepaintRect = FloatRect(); + m_cachedLocalStrokeBBox = FloatRect(); m_cachedLocalFillBBox = FloatRect(); -} - -const Path& RenderPath::path() const -{ - return m_path; + m_cachedLocalMarkerBBox = FloatRect(); } void RenderPath::layout() @@ -180,39 +213,48 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty()) return; - - paintInfo.context->save(); - paintInfo.context->concatCTM(localToParentTransform()); - - SVGResourceFilter* filter = 0; FloatRect boundingBox = repaintRectInLocalCoordinates(); - if (paintInfo.phase == PaintPhaseForeground) { - PaintInfo savedInfo(paintInfo); + FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox); + // FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage + // unfortunately fixing that problem is fairly complex unless we were willing to just futz the + // rect to something "close enough" + if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty()) + return; + + PaintInfo childPaintInfo(paintInfo); + childPaintInfo.context->save(); + applyTransformToPaintInfo(childPaintInfo, m_localTransform); + SVGResourceFilter* filter = 0; - prepareToRenderSVGContent(this, paintInfo, boundingBox, filter); - if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) - paintInfo.context->setShouldAntialias(false); - fillAndStrokePath(m_path, paintInfo.context, style(), this); + if (childPaintInfo.phase == PaintPhaseForeground) { + PaintInfo savedInfo(childPaintInfo); - if (static_cast<SVGStyledElement*>(node())->supportsMarkers()) - m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path); + if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) { + if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) + childPaintInfo.context->setShouldAntialias(false); + fillAndStrokePath(m_path, childPaintInfo.context, style(), this); - finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); + if (static_cast<SVGStyledElement*>(node())->supportsMarkers()) + m_markerLayoutInfo.drawMarkers(childPaintInfo); + } + finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context); } - if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) - paintOutline(paintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), + if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) + paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style()); - paintInfo.context->restore(); + childPaintInfo.context->restore(); } // This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords -void RenderPath::addFocusRingRects(GraphicsContext* graphicsContext, int, int) +void RenderPath::addFocusRingRects(Vector<IntRect>& rects, int, int) { - graphicsContext->addFocusRingRect(enclosingIntRect(repaintRectInLocalCoordinates())); + IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates()); + if (!rect.isEmpty()) + rects.append(rect); } bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) @@ -221,7 +263,7 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, if (hitTestAction != HitTestForeground) return false; - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents()); @@ -237,143 +279,27 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, return false; } -enum MarkerType { - Start, - Mid, - End -}; - -struct MarkerData { - FloatPoint origin; - FloatPoint subpathStart; - double strokeWidth; - FloatPoint inslopePoints[2]; - FloatPoint outslopePoints[2]; - MarkerType type; - SVGResourceMarker* marker; -}; - -struct DrawMarkersData { - DrawMarkersData(GraphicsContext*, SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, double strokeWidth); - GraphicsContext* context; - int elementIndex; - MarkerData previousMarkerData; - SVGResourceMarker* midMarker; -}; - -DrawMarkersData::DrawMarkersData(GraphicsContext* c, SVGResourceMarker *start, SVGResourceMarker *mid, double strokeWidth) - : context(c) - , elementIndex(0) - , midMarker(mid) -{ - previousMarkerData.origin = FloatPoint(); - previousMarkerData.subpathStart = FloatPoint(); - previousMarkerData.strokeWidth = strokeWidth; - previousMarkerData.marker = start; - previousMarkerData.type = Start; -} - -static void drawMarkerWithData(GraphicsContext* context, MarkerData &data) -{ - if (!data.marker) - return; - - FloatPoint inslopeChange = data.inslopePoints[1] - FloatSize(data.inslopePoints[0].x(), data.inslopePoints[0].y()); - FloatPoint outslopeChange = data.outslopePoints[1] - FloatSize(data.outslopePoints[0].x(), data.outslopePoints[0].y()); - - double inslope = rad2deg(atan2(inslopeChange.y(), inslopeChange.x())); - double outslope = rad2deg(atan2(outslopeChange.y(), outslopeChange.x())); - - double angle = 0.0; - switch (data.type) { - case Start: - angle = outslope; - break; - case Mid: - angle = (inslope + outslope) / 2; - break; - case End: - angle = inslope; - } - - data.marker->draw(context, FloatRect(), data.origin.x(), data.origin.y(), data.strokeWidth, angle); -} - -static inline void updateMarkerDataForElement(MarkerData& previousMarkerData, const PathElement* element) -{ - FloatPoint* points = element->points; - - switch (element->type) { - case PathElementAddQuadCurveToPoint: - // TODO - previousMarkerData.origin = points[1]; - break; - case PathElementAddCurveToPoint: - previousMarkerData.inslopePoints[0] = points[1]; - previousMarkerData.inslopePoints[1] = points[2]; - previousMarkerData.origin = points[2]; - break; - case PathElementMoveToPoint: - previousMarkerData.subpathStart = points[0]; - case PathElementAddLineToPoint: - previousMarkerData.inslopePoints[0] = previousMarkerData.origin; - previousMarkerData.inslopePoints[1] = points[0]; - previousMarkerData.origin = points[0]; - break; - case PathElementCloseSubpath: - previousMarkerData.inslopePoints[0] = previousMarkerData.origin; - previousMarkerData.inslopePoints[1] = points[0]; - previousMarkerData.origin = previousMarkerData.subpathStart; - previousMarkerData.subpathStart = FloatPoint(); - } -} - -static void drawStartAndMidMarkers(void* info, const PathElement* element) -{ - DrawMarkersData& data = *reinterpret_cast<DrawMarkersData*>(info); - - int elementIndex = data.elementIndex; - MarkerData& previousMarkerData = data.previousMarkerData; - - FloatPoint* points = element->points; - - // First update the outslope for the previous element - previousMarkerData.outslopePoints[0] = previousMarkerData.origin; - previousMarkerData.outslopePoints[1] = points[0]; - - // Draw the marker for the previous element - if (elementIndex != 0) - drawMarkerWithData(data.context, previousMarkerData); - - // Update our marker data for this element - updateMarkerDataForElement(previousMarkerData, element); - - if (elementIndex == 1) { - // After drawing the start marker, switch to drawing mid markers - previousMarkerData.marker = data.midMarker; - previousMarkerData.type = Mid; - } - - data.elementIndex++; -} - -FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect&, const Path& path) const +void RenderPath::calculateMarkerBoundsIfNeeded() const { Document* doc = document(); SVGElement* svgElement = static_cast<SVGElement*>(node()); - ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); + ASSERT(svgElement && svgElement->document()); + if (!svgElement->isStyled()) + return; SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); - const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (!styledElement->supportsMarkers()) + return; + const SVGRenderStyle* svgStyle = style()->svgStyle(); AtomicString startMarkerId(svgStyle->startMarker()); AtomicString midMarkerId(svgStyle->midMarker()); AtomicString endMarkerId(svgStyle->endMarker()); - SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId); - SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId); - SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId); + SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId, this); + SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId, this); + SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId, this); if (!startMarker && !startMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement); @@ -391,32 +317,10 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR endMarker->addClient(styledElement); if (!startMarker && !midMarker && !endMarker) - return FloatRect(); - - double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f); - DrawMarkersData data(context, startMarker, midMarker, strokeWidth); - - path.apply(&data, drawStartAndMidMarkers); - - data.previousMarkerData.marker = endMarker; - data.previousMarkerData.type = End; - drawMarkerWithData(context, data.previousMarkerData); - - // We know the marker boundaries, only after they're drawn! - // Otherwhise we'd need to do all the marker calculation twice - // once here (through paint()) and once in absoluteClippedOverflowRect(). - FloatRect bounds; - - if (startMarker) - bounds.unite(startMarker->cachedBounds()); - - if (midMarker) - bounds.unite(midMarker->cachedBounds()); - - if (endMarker) - bounds.unite(endMarker->cachedBounds()); + return; - return bounds; + float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f); + m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.h b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h index 2ff179e243..d530f3cdaa 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPath.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h @@ -25,10 +25,10 @@ #define RenderPath_h #if ENABLE(SVG) - +#include "AffineTransform.h" #include "FloatRect.h" #include "RenderSVGModelObject.h" -#include "TransformationMatrix.h" +#include "SVGMarkerLayoutInfo.h" namespace WebCore { @@ -40,7 +40,7 @@ class RenderPath : public RenderSVGModelObject { public: RenderPath(SVGStyledTransformableElement*); - const Path& path() const; + const Path& path() const { return m_path; } private: // Hit-detection seperated for the fill and the stroke @@ -48,9 +48,11 @@ private: bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; + virtual FloatRect markerBoundingBox() const; virtual FloatRect repaintRectInLocalCoordinates() const; - virtual TransformationMatrix localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const; void setPath(const Path&); @@ -59,20 +61,22 @@ private: virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const; + void calculateMarkerBoundsIfNeeded() const; private: - virtual TransformationMatrix localTransform() const; + virtual AffineTransform localTransform() const; mutable Path m_path; mutable FloatRect m_cachedLocalFillBBox; + mutable FloatRect m_cachedLocalStrokeBBox; mutable FloatRect m_cachedLocalRepaintRect; - FloatRect m_markerBounds; - TransformationMatrix m_localTransform; + mutable FloatRect m_cachedLocalMarkerBBox; + mutable SVGMarkerLayoutInfo m_markerLayoutInfo; + AffineTransform m_localTransform; }; inline RenderPath* toRenderPath(RenderObject* object) @@ -94,5 +98,3 @@ void toRenderPath(const RenderPath*); #endif // ENABLE(SVG) #endif - -// vim:ts=4:noet diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderProgress.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderProgress.cpp new file mode 100644 index 0000000000..8a57612f29 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderProgress.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#if ENABLE(PROGRESS_TAG) + +#include "RenderProgress.h" + +#include "HTMLProgressElement.h" +#include "RenderTheme.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +static const int defaultProgressWidth = 120; +static const int defaultProgressHeight = 20; + +RenderProgress::RenderProgress(HTMLProgressElement* element) + : RenderBlock(element) + , m_position(-1) +{ + setSize(IntSize(defaultProgressWidth, defaultProgressHeight)); + setReplaced(true); +} + +int RenderProgress::baselinePosition(bool, bool) const +{ + return height() + marginTop(); +} + +void RenderProgress::calcPrefWidths() +{ + m_minPrefWidth = 0; + m_maxPrefWidth = 0; + + if (style()->width().isFixed() && style()->width().value() > 0) + m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value()); + else + m_maxPrefWidth = defaultProgressWidth * style()->effectiveZoom(); + + if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { + m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value())); + m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value())); + } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) + m_minPrefWidth = 0; + else + m_minPrefWidth = m_maxPrefWidth; + + if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) { + m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); + m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); + } + + int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + m_minPrefWidth += toAdd; + m_maxPrefWidth += toAdd; + + setPrefWidthsDirty(false); +} + +void RenderProgress::layout() +{ + ASSERT(needsLayout()); + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + + calcWidth(); + calcHeight(); + + m_overflow.clear(); + + repainter.repaintAfterLayout(); + + setNeedsLayout(false); +} + +void RenderProgress::updateFromElement() +{ + HTMLProgressElement* element = static_cast<HTMLProgressElement*>(node()); + double position = element->position(); + int oldPosition = m_position; + bool canOptimize = theme()->getNumberOfPixelsForProgressPosition(position, m_position); + if (oldPosition == m_position) + return; + + IntRect paintRect = contentBoxRect(); + if (canOptimize) { + // FIXME: Need to handle indeterminate progress bar and RTL + int adjustedPosition = (m_position >= 0) ? m_position : 0; + int adjustedOldPosition = (oldPosition >= 0) ? oldPosition : 0; + paintRect.setX(std::min(adjustedPosition, adjustedOldPosition)); + paintRect.setWidth(std::max(adjustedPosition, adjustedOldPosition) - paintRect.x()); + } + repaintRectangle(paintRect); +} + +} // namespace WebCore +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderProgress.h b/src/3rdparty/webkit/WebCore/rendering/RenderProgress.h new file mode 100644 index 0000000000..0a90fde54a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderProgress.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderProgress_h +#define RenderProgress_h + +#if ENABLE(PROGRESS_TAG) +#include "RenderBlock.h" + +namespace WebCore { + +class HTMLProgressElement; + +class RenderProgress : public RenderBlock { +public: + RenderProgress(HTMLProgressElement*); + int position() { return m_position; } + +private: + virtual const char* renderName() const { return "RenderProgress"; } + virtual bool isProgress() const { return true; } + virtual int baselinePosition(bool, bool) const; + virtual void calcPrefWidths(); + virtual void layout(); + virtual void updateFromElement(); + int m_position; +}; + +inline RenderProgress* toRenderProgress(RenderObject* object) +{ + ASSERT(!object || object->isProgress()); + return static_cast<RenderProgress*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderProgress(const RenderProgress*); + +} // namespace WebCore + +#endif + +#endif // RenderProgress_h + diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp index 27d2e72af7..ba579dfcea 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp @@ -153,7 +153,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) if (drawSelectionTint) { IntRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.move(tx, ty); - paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor()); + paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor(), style()->colorSpace()); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h index 0ba6b8abc2..b5c61791b6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h @@ -46,8 +46,8 @@ protected: void setIntrinsicSize(const IntSize&); virtual void intrinsicSizeChanged(); + virtual void paint(PaintInfo&, int tx, int ty); bool shouldPaint(PaintInfo&, int& tx, int& ty); - void adjustOverflowForBoxShadowAndReflect(); IntRect localSelectionRect(bool checkWhetherSelected = true) const; private: @@ -62,7 +62,6 @@ private: virtual int minimumReplacedHeight() const { return 0; } - virtual void paint(PaintInfo&, int tx, int ty); virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { } virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp index 5fa3c620cc..1d589ae725 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp @@ -72,7 +72,7 @@ void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty) // computing using the wrong rootLayer layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), paintInfo.context, paintInfo.rect, - PaintRestrictionNone, 0, 0, + PaintBehaviorNormal, 0, 0, RenderLayer::PaintLayerHaveTransparency | RenderLayer::PaintLayerAppliedTransform | RenderLayer::PaintLayerTemporaryClipRects | RenderLayer::PaintLayerPaintingReflection); else if (paintInfo.phase == PaintPhaseMask) paintMask(paintInfo, tx, ty); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h index d5db3b742f..48c64e4aa5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h @@ -46,6 +46,10 @@ public: virtual void calcPrefWidths(); virtual void paint(PaintInfo&, int tx, int ty); + +private: + virtual bool isReplica() const { return true; } + }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRuby.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderRuby.cpp new file mode 100644 index 0000000000..4ab9d735e6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRuby.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(RUBY) +#include "RenderRuby.h" + +#include "RenderRubyRun.h" + +namespace WebCore { + +//=== generic helper functions to avoid excessive code duplication === + +static RenderRubyRun* lastRubyRun(const RenderObject* ruby) +{ + RenderObject* child = ruby->lastChild(); + if (child && ruby->isAfterContent(child)) + child = child->previousSibling(); + ASSERT(!child || child->isRubyRun()); + return static_cast<RenderRubyRun*>(child); +} + +static inline RenderRubyRun* findRubyRunParent(RenderObject* child) +{ + while (child && !child->isRubyRun()) + child = child->parent(); + return static_cast<RenderRubyRun*>(child); +} + +//=== ruby as inline object === + +RenderRubyAsInline::RenderRubyAsInline(Node* node) + : RenderInline(node) +{ +} + +RenderRubyAsInline::~RenderRubyAsInline() +{ +} + +bool RenderRubyAsInline::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isRubyText() + || child->isRubyRun() + || child->isInline(); +} + +void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild) +{ + // Note: ':after' content is handled implicitely below + + // if child is a ruby run, just add it normally + if (child->isRubyRun()) { + RenderInline::addChild(child, beforeChild); + return; + } + + if (beforeChild && !isAfterContent(beforeChild)) { + // insert child into run + ASSERT(!beforeChild->isRubyRun()); + RenderRubyRun* run = findRubyRunParent(beforeChild); + ASSERT(run); // beforeChild should always have a run as parent + if (run) { + run->addChild(child, beforeChild); + return; + } + ASSERT(false); // beforeChild should always have a run as parent! + // Emergency fallback: fall through and just append. + } + + // If the new child would be appended, try to add the child to the previous run + // if possible, or create a new run otherwise. + // (The RenderRubyRun object will handle the details) + RenderRubyRun* lastRun = lastRubyRun(this); + if (!lastRun || lastRun->hasRubyText()) { + lastRun = RenderRubyRun::staticCreateRubyRun(this); + RenderInline::addChild(lastRun); + } + lastRun->addChild(child); +} + +void RenderRubyAsInline::removeChild(RenderObject* child) +{ + // If the child's parent is *this, i.e. a ruby run or ':after' content, + // just use the normal remove method. + if (child->parent() == this) { + ASSERT(child->isRubyRun() || child->isAfterContent()); + RenderInline::removeChild(child); + return; + } + + // Find the containing run + RenderRubyRun* run = findRubyRunParent(child); + ASSERT(run); + run->removeChild(child); +} + + +//=== ruby as block object === + +RenderRubyAsBlock::RenderRubyAsBlock(Node* node) + : RenderBlock(node) +{ +} + +RenderRubyAsBlock::~RenderRubyAsBlock() +{ +} + +bool RenderRubyAsBlock::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isRubyText() + || child->isRubyRun() + || child->isInline(); +} + +void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) +{ + // Note: ':after' content is handled implicitely below + + // if child is a ruby run, just add it normally + if (child->isRubyRun()) { + RenderBlock::addChild(child, beforeChild); + return; + } + + if (beforeChild && !isAfterContent(beforeChild)) { + // insert child into run + ASSERT(!beforeChild->isRubyRun()); + RenderObject* run = beforeChild; + while (run && !run->isRubyRun()) + run = run->parent(); + if (run) { + run->addChild(child, beforeChild); + return; + } + ASSERT(false); // beforeChild should always have a run as parent! + // Emergency fallback: fall through and just append. + } + + // If the new child would be appended, try to add the child to the previous run + // if possible, or create a new run otherwise. + // (The RenderRubyRun object will handle the details) + RenderRubyRun* lastRun = lastRubyRun(this); + if (!lastRun || lastRun->hasRubyText()) { + lastRun = RenderRubyRun::staticCreateRubyRun(this); + RenderBlock::addChild(lastRun); + } + lastRun->addChild(child); +} + +void RenderRubyAsBlock::removeChild(RenderObject* child) +{ + // If the child's parent is *this, just use the normal remove method. + if (child->parent() == this) { + // This should happen only during destruction of the whole ruby element, though. + RenderBlock::removeChild(child); + return; + } + + // Find the containing run + RenderRubyRun* run = findRubyRunParent(child); + ASSERT(run); + run->removeChild(child); +} + +} // namespace WebCore + +#endif // ENABLE(RUBY) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRuby.h b/src/3rdparty/webkit/WebCore/rendering/RenderRuby.h new file mode 100644 index 0000000000..a5dafe981d --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRuby.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderRuby_h +#define RenderRuby_h + +#if ENABLE(RUBY) + +#include "RenderBlock.h" +#include "RenderInline.h" + +namespace WebCore { + +// Following the HTML 5 spec, the box object model for a <ruby> element allows several runs of ruby +// bases with their respective ruby texts looks as follows: +// +// 1 RenderRuby object, corresponding to the whole <ruby> HTML element +// 1+ RenderRubyRun (anonymous) +// 0 or 1 RenderRubyText - shuffled to the front in order to re-use existing block layouting +// 0-n inline object(s) +// 0 or 1 RenderRubyBase - contains the inline objects that make up the ruby base +// 1-n inline object(s) +// +// Note: <rp> elements are defined as having 'display:none' and thus normally are not assigned a renderer. + +// <ruby> when used as 'display:inline' +class RenderRubyAsInline : public RenderInline { +public: + RenderRubyAsInline(Node*); + virtual ~RenderRubyAsInline(); + + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject* child); + +private: + virtual bool isRuby() const { return true; } + virtual const char* renderName() const { return "RenderRuby (inline)"; } + virtual bool createsAnonymousWrapper() const { return true; } + virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); } +}; + +// <ruby> when used as 'display:block' or 'display:inline-block' +class RenderRubyAsBlock : public RenderBlock { +public: + RenderRubyAsBlock(Node*); + virtual ~RenderRubyAsBlock(); + + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject* child); + +private: + virtual bool isRuby() const { return true; } + virtual const char* renderName() const { return "RenderRuby (block)"; } + virtual bool createsAnonymousWrapper() const { return true; } + virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); } +}; + +} // namespace WebCore + +#endif + +#endif // RenderRuby_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.cpp new file mode 100644 index 0000000000..9b2dc9ef6f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(RUBY) +#include "RenderRubyBase.h" + +namespace WebCore { + +RenderRubyBase::RenderRubyBase(Node* node) + : RenderBlock(node) +{ + setInline(false); +} + +RenderRubyBase::~RenderRubyBase() +{ +} + +bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isInline(); +} + +bool RenderRubyBase::hasOnlyWrappedInlineChildren(RenderObject* beforeChild) const +{ + // Tests whether all children in the base before beforeChild are either floated/positioned, + // or inline objects wrapped in anonymous blocks. + // Note that beforeChild may be 0, in which case all children are looked at. + for (RenderObject* child = firstChild(); child != beforeChild; child = child->nextSibling()) { + if (!child->isFloatingOrPositioned() && !(child->isAnonymousBlock() && child->childrenInline())) + return false; + } + return true; +} + +void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) +{ + // This function removes all children that are before (!) beforeChild + // and appends them to toBase. + ASSERT(toBase); + + // First make sure that beforeChild (if set) is indeed a direct child of this. + // Inline children might be wrapped in an anonymous block if there's a continuation. + // Theoretically, in ruby bases, this can happen with only the first such a child, + // so it should be OK to just climb the tree. + while (fromBeforeChild && fromBeforeChild->parent() != this) + fromBeforeChild = fromBeforeChild->parent(); + + if (childrenInline()) + moveInlineChildren(toBase, fromBeforeChild); + else + moveBlockChildren(toBase, fromBeforeChild); + + setNeedsLayoutAndPrefWidthsRecalc(); + toBase->setNeedsLayoutAndPrefWidthsRecalc(); +} + +void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) +{ + RenderBlock* toBlock; + + if (toBase->childrenInline()) { + // The standard and easy case: move the children into the target base + toBlock = toBase; + } else { + // We need to wrap the inline objects into an anonymous block. + // If toBase has a suitable block, we re-use it, otherwise create a new one. + RenderObject* lastChild = toBase->lastChild(); + if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline()) + toBlock = toRenderBlock(lastChild); + else { + toBlock = toBase->createAnonymousBlock(); + toBase->children()->appendChildNode(toBase, toBlock); + } + } + // Move our inline children into the target block we determined above. + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) + moveChildTo(toBlock, toBlock->children(), child); +} + +void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) +{ + if (toBase->childrenInline()) { + // First check whether we move only wrapped inline objects. + if (hasOnlyWrappedInlineChildren(fromBeforeChild)) { + // The reason why the base is in block flow must be after beforeChild. + // We therefore can extract the inline objects and move them to toBase. + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) { + if (child->isAnonymousBlock()) { + RenderBlock* anonBlock = toRenderBlock(child); + ASSERT(anonBlock->childrenInline()); + ASSERT(!anonBlock->inlineContinuation()); + anonBlock->moveAllChildrenTo(toBase, toBase->children()); + anonBlock->deleteLineBoxTree(); + anonBlock->destroy(); + } else { + ASSERT(child->isFloatingOrPositioned()); + moveChildTo(toBase, toBase->children(), child); + } + } + } else { + // Moving block children -> have to set toBase as block flow + toBase->makeChildrenNonInline(); + // Move children, potentially collapsing anonymous block wrappers. + mergeBlockChildren(toBase, fromBeforeChild); + + // Now we need to check if the leftover children are all inline. + // If so, make this base inline again. + if (hasOnlyWrappedInlineChildren()) { + RenderObject* next = 0; + for (RenderObject* child = firstChild(); child; child = next) { + next = child->nextSibling(); + if (child->isFloatingOrPositioned()) + continue; + ASSERT(child->isAnonymousBlock()); + + RenderBlock* anonBlock = toRenderBlock(child); + ASSERT(anonBlock->childrenInline()); + ASSERT(!anonBlock->inlineContinuation()); + // Move inline children out of anonymous block. + anonBlock->moveAllChildrenTo(this, children(), anonBlock); + anonBlock->deleteLineBoxTree(); + anonBlock->destroy(); + } + setChildrenInline(true); + } + } + } else + mergeBlockChildren(toBase, fromBeforeChild); +} + +void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) +{ + // This function removes all children that are before fromBeforeChild and appends them to toBase. + ASSERT(!childrenInline()); + ASSERT(toBase); + ASSERT(!toBase->childrenInline()); + + // Quick check whether we have anything to do, to simplify the following code. + if (fromBeforeChild != firstChild()) + return; + + // If an anonymous block would be put next to another such block, then merge those. + RenderObject* firstChildHere = firstChild(); + RenderObject* lastChildThere = toBase->lastChild(); + if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline() + && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) { + RenderBlock* anonBlockHere = toRenderBlock(firstChildHere); + RenderBlock* anonBlockThere = toRenderBlock(lastChildThere); + anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children()); + anonBlockHere->deleteLineBoxTree(); + anonBlockHere->destroy(); + } + // Move all remaining children normally. + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) + moveChildTo(toBase, toBase->children(), child); +} + +} // namespace WebCore + +#endif // ENABLE(RUBY) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.h b/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.h new file mode 100644 index 0000000000..29c4858f57 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyBase.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderRubyBase_h +#define RenderRubyBase_h + +#if ENABLE(RUBY) + +#include "RenderBlock.h" + +namespace WebCore { + +class RenderRubyBase : public RenderBlock { +public: + RenderRubyBase(Node*); + virtual ~RenderRubyBase(); + + virtual const char* renderName() const { return "RenderRubyBase (anonymous)"; } + + virtual bool isRubyBase() const { return true; } + + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + +private: + bool hasOnlyWrappedInlineChildren(RenderObject* beforeChild = 0) const; + + void moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); + void moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); + void moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); + void mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); + + // Allow RenderRubyRun to manipulate the children within ruby bases. + friend class RenderRubyRun; +}; + +} // namespace WebCore + +#endif + +#endif // RenderRubyBase_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.cpp new file mode 100644 index 0000000000..d91c625eef --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(RUBY) +#include "RenderRubyRun.h" + +#include "RenderRubyBase.h" +#include "RenderRubyText.h" +#include "RenderView.h" + +using namespace std; + +namespace WebCore { + +RenderRubyRun::RenderRubyRun(Node* node) + : RenderBlock(node) + , m_beingDestroyed(false) +{ + setReplaced(true); + setInline(true); +} + +RenderRubyRun::~RenderRubyRun() +{ +} + +void RenderRubyRun::destroy() +{ + // Mark if the run is being destroyed to avoid trouble in removeChild(). + m_beingDestroyed = true; + RenderBlock::destroy(); +} + +bool RenderRubyRun::hasRubyText() const +{ + // The only place where a ruby text can be is in the first position + // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves. + return firstChild() && firstChild()->isRubyText(); +} + +bool RenderRubyRun::hasRubyBase() const +{ + // The only place where a ruby base can be is in the last position + // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves. + return lastChild() && lastChild()->isRubyBase(); +} + +bool RenderRubyRun::isEmpty() const +{ + return !hasRubyText() && !hasRubyBase(); +} + +RenderRubyText* RenderRubyRun::rubyText() const +{ + RenderObject* child = firstChild(); + return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0; +} + +RenderRubyBase* RenderRubyRun::rubyBase() const +{ + RenderObject* child = lastChild(); + return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0; +} + +RenderRubyBase* RenderRubyRun::rubyBaseSafe() +{ + RenderRubyBase* base = rubyBase(); + if (!base) { + base = createRubyBase(); + RenderBlock::addChild(base); + } + return base; +} + +RenderBlock* RenderRubyRun::firstLineBlock() const +{ + return 0; +} + +void RenderRubyRun::updateFirstLetter() +{ +} + +bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isRubyText() || child->isInline(); +} + +void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild) +{ + ASSERT(child); + + // If child is a ruby text + if (child->isRubyText()) { + if (!beforeChild) { + // RenderRuby has already ascertained that we can add the child here. + ASSERT(!hasRubyText()); + // prepend ruby texts as first child + RenderBlock::addChild(child, firstChild()); + } else if (beforeChild->isRubyText()) { + // New text is inserted just before another. + // In this case the new text takes the place of the old one, and + // the old text goes into a new run that is inserted as next sibling. + ASSERT(beforeChild->parent() == this); + RenderObject* ruby = parent(); + ASSERT(ruby->isRuby()); + RenderBlock* newRun = staticCreateRubyRun(ruby); + ruby->addChild(newRun, nextSibling()); + // Add the new ruby text and move the old one to the new run + // Note: Doing it in this order and not using RenderRubyRun's methods, + // in order to avoid automatic removal of the ruby run in case there is no + // other child besides the old ruby text. + RenderBlock::addChild(child, beforeChild); + RenderBlock::removeChild(beforeChild); + newRun->addChild(beforeChild); + } else { + ASSERT(hasRubyBase()); // Otherwise beforeChild would be borked. + // Insertion before a ruby base object. + // In this case we need insert a new run before the current one and split the base. + RenderObject* ruby = parent(); + RenderRubyRun* newRun = staticCreateRubyRun(ruby); + ruby->addChild(newRun, this); + newRun->addChild(child); + rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild); + } + } else { + // child is not a text -> insert it into the base + // (append it instead if beforeChild is the ruby text) + if (beforeChild && beforeChild->isRubyText()) + beforeChild = 0; + rubyBaseSafe()->addChild(child, beforeChild); + } +} + +void RenderRubyRun::removeChild(RenderObject* child) +{ + // If the child is a ruby text, then merge the ruby base with the base of + // the right sibling run, if possible. + if (!m_beingDestroyed && !documentBeingDestroyed() && child->isRubyText()) { + RenderRubyBase* base = rubyBase(); + RenderObject* rightNeighbour = nextSibling(); + if (base && rightNeighbour && rightNeighbour->isRubyRun()) { + // Ruby run without a base can happen only at the first run. + RenderRubyRun* rightRun = static_cast<RenderRubyRun*>(rightNeighbour); + ASSERT(rightRun->hasRubyBase()); + RenderRubyBase* rightBase = rightRun->rubyBaseSafe(); + // Collect all children in a single base, then swap the bases. + rightBase->moveChildren(base); + moveChildTo(rightRun, rightRun->children(), base); + rightRun->moveChildTo(this, children(), rightBase); + // The now empty ruby base will be removed below. + } + } + + RenderBlock::removeChild(child); + + if (!m_beingDestroyed && !documentBeingDestroyed()) { + // Check if our base (if any) is now empty. If so, destroy it. + RenderBlock* base = rubyBase(); + if (base && !base->firstChild()) { + RenderBlock::removeChild(base); + base->deleteLineBoxTree(); + base->destroy(); + } + + // If any of the above leaves the run empty, destroy it as well. + if (isEmpty()) { + parent()->removeChild(this); + deleteLineBoxTree(); + destroy(); + } + } +} + +RenderRubyBase* RenderRubyRun::createRubyBase() const +{ + RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */); + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(style()); + newStyle->setDisplay(BLOCK); + newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER? + rb->setStyle(newStyle.release()); + return rb; +} + +RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby) +{ + ASSERT(parentRuby && parentRuby->isRuby()); + RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */); + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(parentRuby->style()); + newStyle->setDisplay(INLINE_BLOCK); + rr->setStyle(newStyle.release()); + return rr; +} + +} // namespace WebCore + +#endif // ENABLE(RUBY) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.h b/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.h new file mode 100644 index 0000000000..acf359bb01 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyRun.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderRubyRun_h +#define RenderRubyRun_h + +#if ENABLE(RUBY) + +#include "RenderBlock.h" + +namespace WebCore { + +class RenderRubyBase; +class RenderRubyText; + +// RenderRubyRun are 'inline-block/table' like objects,and wrap a single pairing of a ruby base with its ruby text(s). +// See RenderRuby.h for further comments on the structure + +class RenderRubyRun : public RenderBlock { +public: + RenderRubyRun(Node*); + virtual ~RenderRubyRun(); + + virtual void destroy(); + + bool hasRubyText() const; + bool hasRubyBase() const; + bool isEmpty() const; + RenderRubyText* rubyText() const; + RenderRubyBase* rubyBase() const; + RenderRubyBase* rubyBaseSafe(); // creates the base if it doesn't already exist + + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject* child); + + virtual RenderBlock* firstLineBlock() const; + virtual void updateFirstLetter(); + + static RenderRubyRun* staticCreateRubyRun(const RenderObject* parentRuby); + +protected: + RenderRubyBase* createRubyBase() const; + +private: + virtual bool isRubyRun() const { return true; } + virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; } + virtual bool createsAnonymousWrapper() const { return true; } + virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } + + bool m_beingDestroyed; +}; + +} // namespace WebCore + +#endif + +#endif // RenderRubyRun_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.cpp new file mode 100644 index 0000000000..12e8feace3 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(RUBY) +#include "RenderRubyText.h" + +namespace WebCore { + +RenderRubyText::RenderRubyText(Node* node) + : RenderBlock(node) +{ +} + +RenderRubyText::~RenderRubyText() +{ +} + +bool RenderRubyText::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isInline(); +} + +} // namespace WebCore + +#endif // ENABLE(RUBY) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.h b/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.h new file mode 100644 index 0000000000..865d1798bd --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderRubyText.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderRubyText_h +#define RenderRubyText_h + +#if ENABLE(RUBY) + +#include "RenderBlock.h" + +namespace WebCore { + +class RenderRubyText : public RenderBlock { +public: + RenderRubyText(Node*); + virtual ~RenderRubyText(); + + virtual const char* renderName() const { return "RenderRubyText"; } + + virtual bool isRubyText() const { return true; } + + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; +}; + +} // namespace WebCore + +#endif + +#endif // RenderRubyText_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp index f065c44b07..99725d618c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp @@ -1,8 +1,7 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Apple Computer, Inc. - * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -40,9 +39,7 @@ void RenderSVGBlock::setStyle(PassRefPtr<RenderStyle> style) RefPtr<RenderStyle> useStyle = style; // SVG text layout code expects us to be a block-level style element. - if (useStyle->display() == NONE) - setChildrenInline(false); - else if (useStyle->isDisplayInlineType()) { + if (useStyle->isDisplayInlineType()) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(useStyle.get()); newStyle->setDisplay(BLOCK); @@ -50,14 +47,27 @@ void RenderSVGBlock::setStyle(PassRefPtr<RenderStyle> style) } RenderBlock::setStyle(useStyle.release()); - setReplaced(false); +} + +void RenderSVGBlock::updateBoxModelInfoFromStyle() +{ + RenderBlock::updateBoxModelInfoFromStyle(); - //FIXME: Once overflow rules are supported by SVG we should - //probably map the CSS overflow rules rather than just ignoring - //them + // RenderSVGlock, used by Render(SVGText|ForeignObject), is not allowed to call setHasOverflowClip(true). + // RenderBlock assumes a layer to be present when the overflow clip functionality is requested. Both + // Render(SVGText|ForeignObject) return 'false' on 'requiresLayer'. Fine for RenderSVGText. + // + // If we want to support overflow rules for <foreignObject> we can choose between two solutions: + // a) make RenderForeignObject require layers and SVG layer aware + // b) reactor overflow logic out of RenderLayer (as suggested by dhyatt), which is a large task + // + // Until this is resolved, disable overflow support. Opera/FF don't support it as well at the moment (Feb 2010). + // + // Note: This does NOT affect overflow handling on outer/inner <svg> elements - this is handled + // manually by RenderSVGRoot - which owns the documents enclosing root layer and thus works fine. setHasOverflowClip(false); } } -#endif // ENABLE(SVG) +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h index a4ececb3cd..19cac62720 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or @@ -22,8 +20,8 @@ #ifndef RenderSVGBlock_h #define RenderSVGBlock_h -#if ENABLE(SVG) +#if ENABLE(SVG) #include "RenderBlock.h" #include "SVGRenderSupport.h" @@ -35,10 +33,13 @@ class RenderSVGBlock : public RenderBlock, protected SVGRenderBase { public: RenderSVGBlock(SVGElement*); + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } + private: virtual void setStyle(PassRefPtr<RenderStyle>); + virtual void updateBoxModelInfoFromStyle(); }; } -#endif // ENABLE(SVG) -#endif // !RenderSVGBlock_h +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp index d7aec99dfe..6d1b965682 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp @@ -3,6 +3,7 @@ 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org> 2007 Eric Seidel <eric@webkit.org> Copyright (C) 2009 Google, Inc. All rights reserved. + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -25,14 +26,11 @@ #if ENABLE(SVG) #include "RenderSVGContainer.h" -#include "AXObjectCache.h" -#include "FloatQuad.h" #include "GraphicsContext.h" #include "RenderView.h" #include "SVGRenderSupport.h" #include "SVGResourceFilter.h" #include "SVGStyledElement.h" -#include "SVGURIReference.h" namespace WebCore { @@ -62,17 +60,7 @@ void RenderSVGContainer::layout() LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint()); calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - // Only force our kids to layout if we're being asked to relayout as a result of a parent changing - // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed - // that's a possible future optimization using LayoutState - // http://bugs.webkit.org/show_bug.cgi?id=15391 - if (selfNeedsLayout()) - child->setNeedsLayout(true); - - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - } + layoutChildren(this, selfNeedsLayout()); repainter.repaintAfterLayout(); setNeedsLayout(false); @@ -82,7 +70,7 @@ bool RenderSVGContainer::selfWillPaint() const { #if ENABLE(FILTERS) const SVGRenderStyle* svgStyle = style()->svgStyle(); - SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter()); + SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this); if (filter) return true; #endif @@ -94,7 +82,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) if (paintInfo.context->paintingDisabled() || !drawsContents()) return; - // Spec: groups w/o children still may render filter content. + // Spec: groups w/o children still may render filter content. if (!firstChild() && !selfWillPaint()) return; @@ -109,12 +97,16 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) SVGResourceFilter* filter = 0; FloatRect boundingBox = repaintRectInLocalCoordinates(); + + bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) - prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); + continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); - childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->paint(childPaintInfo, 0, 0); + if (continueRendering) { + childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo); + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->paint(childPaintInfo, 0, 0); + } if (paintInfo.phase == PaintPhaseForeground) finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); @@ -132,10 +124,11 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) } // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call -void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int) +void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int) { IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); - graphicsContext->addFocusRingRect(paintRectInParent); + if (!paintRectInParent.isEmpty()) + rects.append(paintRectInParent); } FloatRect RenderSVGContainer::objectBoundingBox() const @@ -143,14 +136,30 @@ FloatRect RenderSVGContainer::objectBoundingBox() const return computeContainerBoundingBox(this, false); } +FloatRect RenderSVGContainer::strokeBoundingBox() const +{ + return computeContainerBoundingBox(this, true); +} + // RenderSVGContainer is used for <g> elements which do not themselves have a // width or height, so we union all of our child rects as our repaint rect. FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const { FloatRect repaintRect = computeContainerBoundingBox(this, true); - // A filter on this container can paint outside of the union of the child repaint rects - repaintRect.unite(filterBoundingBoxForRenderer(this)); + FloatRect rect = filterBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect = rect; + + rect = clipperBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect.intersect(rect); + + rect = maskerBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect.intersect(rect); + + style()->svgStyle()->inflateForShadow(repaintRect); return repaintRect; } @@ -178,5 +187,3 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest } #endif // ENABLE(SVG) - -// vim:ts=4:noet diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h index f2195e3faf..f681e505f7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h @@ -42,10 +42,9 @@ public: void setDrawsContents(bool); bool drawsContents() const; -protected: virtual void paint(PaintInfo&, int parentX, int parentY); -private: +protected: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } @@ -54,9 +53,10 @@ private: virtual void layout(); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; virtual FloatRect repaintRectInLocalCoordinates() const; virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); @@ -71,6 +71,7 @@ private: bool selfWillPaint() const; +private: RenderObjectChildList m_children; bool m_drawsContents : 1; }; @@ -78,14 +79,14 @@ private: inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object) { // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. - ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")); + ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); return static_cast<RenderSVGContainer*>(object); } inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object) { // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. - ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")); + ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); return static_cast<const RenderSVGContainer*>(object); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp index b81e7f41ff..66391c82c6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp @@ -49,7 +49,7 @@ void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderSty // <stop> elements should only be allowed to make renderers under gradient elements // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient. if (SVGGradientElement* gradient = gradientElement()) { - if (SVGResource* resource = gradient->canvasResource()) + if (SVGResource* resource = gradient->canvasResource(this)) resource->invalidate(); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp index d4b39d3a74..bb0a15d344 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp @@ -38,17 +38,7 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element) void RenderSVGHiddenContainer::layout() { ASSERT(needsLayout()); - - // Layout our kids to prevent a kid from being marked as needing layout - // then never being asked to layout. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (selfNeedsLayout()) - child->setNeedsLayout(true); - - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - } - + layoutChildren(this, selfNeedsLayout()); setNeedsLayout(false); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h index 0ef0a430e7..fdbd2bcfa3 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h @@ -51,9 +51,6 @@ namespace WebCore { virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); - // FIXME: This override only exists to match existing LayoutTest results. - virtual TransformationMatrix absoluteTransform() const { return TransformationMatrix(); } - virtual FloatRect objectBoundingBox() const; virtual FloatRect repaintRectInLocalCoordinates() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp index 7e0b40d539..6fb9501674 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp @@ -4,6 +4,7 @@ Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org> Copyright (C) 2009, Google, Inc. + Copyright (C) 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -36,9 +37,6 @@ #include "SVGLength.h" #include "SVGPreserveAspectRatio.h" #include "SVGRenderSupport.h" -#include "SVGResourceClipper.h" -#include "SVGResourceFilter.h" -#include "SVGResourceMasker.h" namespace WebCore { @@ -47,81 +45,6 @@ RenderSVGImage::RenderSVGImage(SVGImageElement* impl) { } -void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio* aspectRatio) -{ - float origDestWidth = destRect.width(); - float origDestHeight = destRect.height(); - if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET) { - float widthToHeightMultiplier = srcRect.height() / srcRect.width(); - if (origDestHeight > (origDestWidth * widthToHeightMultiplier)) { - destRect.setHeight(origDestWidth * widthToHeightMultiplier); - switch (aspectRatio->align()) { - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: - destRect.setY(destRect.y() + origDestHeight / 2.0f - destRect.height() / 2.0f); - break; - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX: - destRect.setY(destRect.y() + origDestHeight - destRect.height()); - break; - } - } - if (origDestWidth > (origDestHeight / widthToHeightMultiplier)) { - destRect.setWidth(origDestHeight / widthToHeightMultiplier); - switch (aspectRatio->align()) { - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: - destRect.setX(destRect.x() + origDestWidth / 2.0f - destRect.width() / 2.0f); - break; - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX: - destRect.setX(destRect.x() + origDestWidth - destRect.width()); - break; - } - } - } else if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE) { - float widthToHeightMultiplier = srcRect.height() / srcRect.width(); - // if the destination height is less than the height of the image we'll be drawing - if (origDestHeight < (origDestWidth * widthToHeightMultiplier)) { - float destToSrcMultiplier = srcRect.width() / destRect.width(); - srcRect.setHeight(destRect.height() * destToSrcMultiplier); - switch (aspectRatio->align()) { - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: - srcRect.setY(destRect.y() + image()->height() / 2.0f - srcRect.height() / 2.0f); - break; - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX: - srcRect.setY(destRect.y() + image()->height() - srcRect.height()); - break; - } - } - // if the destination width is less than the width of the image we'll be drawing - if (origDestWidth < (origDestHeight / widthToHeightMultiplier)) { - float destToSrcMultiplier = srcRect.height() / destRect.height(); - srcRect.setWidth(destRect.width() * destToSrcMultiplier); - switch (aspectRatio->align()) { - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: - srcRect.setX(destRect.x() + image()->width() / 2.0f - srcRect.width() / 2.0f); - break; - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: - case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX: - srcRect.setX(destRect.x() + image()->width() - srcRect.width()); - break; - } - } - } -} - void RenderSVGImage::layout() { ASSERT(needsLayout()); @@ -138,6 +61,7 @@ void RenderSVGImage::layout() calcHeight(); m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); + m_cachedLocalRepaintRect = FloatRect(); repainter.repaintAfterLayout(); @@ -157,16 +81,16 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) PaintInfo savedInfo(paintInfo); - prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter); - - FloatRect destRect = m_localBounds; - FloatRect srcRect(0, 0, image()->width(), image()->height()); + if (prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) { + FloatRect destRect = m_localBounds; + FloatRect srcRect(0, 0, image()->width(), image()->height()); - SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); - if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) - adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio()); + SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); + if (imageElt->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) + imageElt->preserveAspectRatio().transformRect(destRect, srcRect); - paintInfo.context->drawImage(image(), destRect, srcRect); + paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect); + } finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); } @@ -176,6 +100,12 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) paintInfo.context->restore(); } +void RenderSVGImage::destroy() +{ + SVGRenderBase::deregisterFromResources(this); + RenderImage::destroy(); +} + bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // We only draw in the forground phase, so we only hit-test then. @@ -212,12 +142,29 @@ FloatRect RenderSVGImage::objectBoundingBox() const FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const { - FloatRect repaintRect = m_localBounds; + // If we already have a cached repaint rect, return that + if (!m_cachedLocalRepaintRect.isEmpty()) + return m_cachedLocalRepaintRect; + + m_cachedLocalRepaintRect = m_localBounds; + + // FIXME: We need to be careful here. We assume that there is no filter, + // clipper or masker if the rects are empty. + FloatRect rect = filterBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect = rect; + + rect = clipperBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect.intersect(rect); + + rect = maskerBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + m_cachedLocalRepaintRect.intersect(rect); - // Filters can paint outside the image content - repaintRect.unite(filterBoundingBoxForRenderer(this)); + style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect); - return repaintRect; + return m_cachedLocalRepaintRect; } void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) @@ -241,11 +188,12 @@ void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer, SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); } -void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int) +void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int) { // this is called from paint() after the localTransform has already been applied IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); - graphicsContext->addFocusRingRect(contentRect); + if (!contentRect.isEmpty()) + rects.append(contentRect); } void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h index ef117191d9..f48b9dd9f1 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h @@ -24,55 +24,58 @@ #define RenderSVGImage_h #if ENABLE(SVG) - -#include "TransformationMatrix.h" +#include "AffineTransform.h" #include "FloatRect.h" #include "RenderImage.h" +#include "SVGPreserveAspectRatio.h" #include "SVGRenderSupport.h" namespace WebCore { - class SVGImageElement; - class SVGPreserveAspectRatio; +class SVGImageElement; + +class RenderSVGImage : public RenderImage, protected SVGRenderBase { +public: + RenderSVGImage(SVGImageElement*); - class RenderSVGImage : public RenderImage, SVGRenderBase { - public: - RenderSVGImage(SVGImageElement*); +private: + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } + virtual const char* renderName() const { return "RenderSVGImage"; } + virtual bool isSVGImage() const { return true; } - private: - virtual const char* renderName() const { return "RenderSVGImage"; } - virtual bool isSVGImage() const { return true; } + virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual TransformationMatrix localToParentTransform() const { return m_localTransform; } + virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const { return m_localBounds; } + virtual FloatRect repaintRectInLocalCoordinates() const; - virtual FloatRect objectBoundingBox() const; - virtual FloatRect repaintRectInLocalCoordinates() const; + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); - virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); - virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); - virtual void absoluteQuads(Vector<FloatQuad>&); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + + virtual void layout(); + virtual void paint(PaintInfo&, int parentX, int parentY); - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - void adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio*); - - virtual void layout(); - virtual void paint(PaintInfo&, int parentX, int parentY); + virtual void destroy(); - virtual bool requiresLayer() const { return false; } + virtual bool requiresLayer() const { return false; } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual TransformationMatrix localTransform() const { return m_localTransform; } + virtual AffineTransform localTransform() const { return m_localTransform; } - TransformationMatrix m_localTransform; - FloatRect m_localBounds; - }; + AffineTransform m_localTransform; + FloatRect m_localBounds; + mutable FloatRect m_cachedLocalRepaintRect; +}; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp index cf97b52add..33459ce93c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp @@ -48,9 +48,9 @@ InlineFlowBox* RenderSVGInline::createInlineFlowBox() void RenderSVGInline::absoluteRects(Vector<IntRect>& rects, int, int) { - InlineRunBox* firstBox = firstLineBox(); + InlineFlowBox* firstBox = firstLineBox(); - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RootInlineBox* rootBox = firstBox ? firstBox->root() : 0; RenderBox* object = rootBox ? rootBox->block() : 0; if (!object) @@ -59,17 +59,45 @@ void RenderSVGInline::absoluteRects(Vector<IntRect>& rects, int, int) int xRef = object->x(); int yRef = object->y(); - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + for (InlineFlowBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height()); rects.append(enclosingIntRect(localToAbsoluteQuad(rect).boundingBox())); } } +FloatRect RenderSVGInline::objectBoundingBox() const +{ + if (const RenderObject* object = findTextRootObject(this)) + return object->objectBoundingBox(); + + return FloatRect(); +} + +FloatRect RenderSVGInline::strokeBoundingBox() const +{ + const RenderObject* object = findTextRootObject(this); + ASSERT(object); + + const SVGRenderBase* renderer = object->toSVGRenderBase(); + if (!renderer) + return FloatRect(); + + return renderer->strokeBoundingBox(); +} + +FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const +{ + if (const RenderObject* object = findTextRootObject(this)) + return object->repaintRectInLocalCoordinates(); + + return FloatRect(); +} + void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads) { - InlineRunBox* firstBox = firstLineBox(); + InlineFlowBox* firstBox = firstLineBox(); - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RootInlineBox* rootBox = firstBox ? firstBox->root() : 0; RenderBox* object = rootBox ? rootBox->block() : 0; if (!object) @@ -78,7 +106,7 @@ void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads) int xRef = object->x(); int yRef = object->y(); - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + for (InlineFlowBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height()); quads.append(localToAbsoluteQuad(rect)); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h index 9f9f3f5f2e..e57b93605d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h @@ -27,17 +27,31 @@ #if ENABLE(SVG) #include "RenderInline.h" +#include "SVGRenderSupport.h" + namespace WebCore { -class RenderSVGInline : public RenderInline { +class RenderSVGInline : public RenderInline, protected SVGRenderBase { public: RenderSVGInline(Node*); + + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } + virtual const char* renderName() const { return "RenderSVGInline"; } virtual bool requiresLayer() const { return false; } // These are shared between RenderSVGTSpan and RenderSVGTextPath virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); + + // Chapter 10.4 of the SVG Specification say that we should use the + // object bounding box of the parent text element. + // We search for the root text element and take it's bounding box. + // It is also necessary to take the stroke and repaint rect of + // this element, since we need it for filters. + virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; private: virtual InlineFlowBox* createInlineFlowBox(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h index e9c5d6e190..b475067909 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h @@ -39,6 +39,10 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle*); + // FIXME: We need objectBoundingBox for DRT results and filters at the moment. + // This should be fixed to give back the objectBoundingBox of the text root. + virtual FloatRect objectBoundingBox() const { return FloatRect(); } + virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp index 3fab5a6bab..c163dc6363 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp @@ -38,10 +38,6 @@ #include "RenderView.h" #include "SVGStyledElement.h" -#if ENABLE(FILTERS) -#include "SVGResourceFilter.h" -#endif - namespace WebCore { RenderSVGModelObject::RenderSVGModelObject(SVGStyledElement* node) @@ -86,6 +82,12 @@ void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads) quads.append(absoluteClippedOverflowRect()); } +void RenderSVGModelObject::destroy() +{ + deregisterFromResources(this); + RenderObject::destroy(); +} + bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h index 0aa13adc8f..c04c5900a2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h @@ -49,6 +49,8 @@ class RenderSVGModelObject : public RenderObject, protected SVGRenderBase { public: RenderSVGModelObject(SVGStyledElement*); + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } + virtual bool requiresLayer() const { return false; } virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); @@ -58,6 +60,8 @@ public: virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); + virtual void destroy(); + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; private: diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGResource.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResource.h new file mode 100644 index 0000000000..184ffe3954 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResource.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 RenderSVGResource_h +#define RenderSVGResource_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "RenderSVGHiddenContainer.h" + +namespace WebCore { + +enum RenderSVGResourceType { + MaskerResourceType, + ClipperResourceType +}; + +class RenderSVGResource : public RenderSVGHiddenContainer { +public: + RenderSVGResource(SVGStyledElement* node) : RenderSVGHiddenContainer(node) { } + + template<class Renderer> + Renderer* cast() + { + if (Renderer::s_resourceType == resourceType()) + return static_cast<Renderer*>(this); + + return 0; + } + + virtual RenderSVGResource* toRenderSVGResource() { return this; } + virtual bool isSVGResource() const { return true; } + virtual bool drawsContents() { return false; } + + virtual void invalidateClients() = 0; + virtual void invalidateClient(RenderObject*) = 0; + + virtual bool applyResource(RenderObject*, GraphicsContext*) = 0; + virtual FloatRect resourceBoundingBox(const FloatRect&) const = 0; + + virtual RenderSVGResourceType resourceType() const = 0; +}; + +template<typename Renderer> +Renderer* getRenderSVGResourceById(Document* document, const AtomicString& id) +{ + if (id.isEmpty()) + return 0; + + Element* element = document->getElementById(id); + if (!element || !element->isSVGElement()) + return 0; + + RenderObject* renderer = element->renderer(); + if (!renderer) + return 0; + + RenderSVGResource* renderResource = renderer->toRenderSVGResource(); + if (!renderResource) + return 0; + + return renderResource->cast<Renderer>(); +} + +} + +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.cpp new file mode 100644 index 0000000000..dfc4b1e9bb --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> + * Copyright (C) Research In Motion Limited 2009-2010. 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 "RenderSVGResourceClipper.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "RenderSVGResource.h" +#include "SVGClipPathElement.h" +#include "SVGElement.h" +#include "SVGRenderSupport.h" +#include "SVGStyledElement.h" +#include "SVGStyledTransformableElement.h" +#include "SVGUnitTypes.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType; + +RenderSVGResourceClipper::RenderSVGResourceClipper(SVGStyledElement* node) + : RenderSVGResource(node) +{ +} + +RenderSVGResourceClipper::~RenderSVGResourceClipper() +{ + m_clipper.clear(); +} + +void RenderSVGResourceClipper::invalidateClients() +{ + HashSet<RenderObject*>::const_iterator end = m_clipper.end(); + for (HashSet<RenderObject*>::const_iterator it = m_clipper.begin(); it != end; ++it) + (*it)->setNeedsLayout(true); + m_clipper.clear(); +} + +void RenderSVGResourceClipper::invalidateClient(RenderObject* object) +{ + ASSERT(object); + + // FIXME: The HashSet should always contain the object on calling invalidateClient. A race condition + // during the parsing can causes a call of invalidateClient right before the call of applyResource. + // We return earlier for the moment. This bug should be fixed in: + // https://bugs.webkit.org/show_bug.cgi?id=35181 + if (!m_clipper.contains(object)) + return; + + m_clipper.remove(object); +} + +bool RenderSVGResourceClipper::applyResource(RenderObject* object, GraphicsContext* context) +{ + ASSERT(object); + ASSERT(context); + + m_clipper.add(object); + + context->beginPath(); + + AffineTransform obbTransform; + FloatRect objectBoundingBox = object->objectBoundingBox(); + bool bbox = static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; + if (bbox) { + obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + } + + bool hasClipPath = false; + WindRule clipRule = RULE_EVENODD; + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable()) + continue; + SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode); + RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0; + if (!style || style->display() == NONE) + continue; + Path pathData = styled->toClipPath(); + if (pathData.isEmpty()) + continue; + if (bbox) + pathData.transform(obbTransform); + hasClipPath = true; + context->addPath(pathData); + clipRule = style->svgStyle()->clipRule(); + } + + if (!hasClipPath) { + Path clipPath; + clipPath.addRect(FloatRect()); + context->addPath(clipPath); + } + + // FIXME! + // We don't currently allow for heterogenous clip rules. + // we would have to detect such, draw to a mask, and then clip + // to that mask + context->clipPath(clipRule); + + return true; +} + +FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) const +{ + FloatRect clipRect; + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable()) + continue; + SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode); + RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0; + if (!style || style->display() == NONE || styled->toClipPath().isEmpty()) + continue; + clipRect.unite(styled->renderer()->objectBoundingBox()); + } + + if (clipRect.isEmpty()) + return FloatRect(); + + if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + AffineTransform obbTransform; + obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + return obbTransform.mapRect(clipRect); + } + + return clipRect; +} + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.h new file mode 100644 index 0000000000..0e1d2b5ce9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceClipper.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 RenderSVGResourceClipper_h +#define RenderSVGResourceClipper_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "RenderSVGResource.h" +#include "SVGClipPathElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashSet.h> + +namespace WebCore { + +class RenderSVGResourceClipper : public RenderSVGResource { + +public: + RenderSVGResourceClipper(SVGStyledElement*); + virtual ~RenderSVGResourceClipper(); + + virtual const char* renderName() const { return "RenderSVGResourceClipper"; } + + virtual void invalidateClients(); + virtual void invalidateClient(RenderObject*); + + virtual bool applyResource(RenderObject*, GraphicsContext*); + virtual FloatRect resourceBoundingBox(const FloatRect&) const; + + virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; } + + SVGUnitTypes::SVGUnitType clipPathUnits() const { return toUnitType(static_cast<SVGClipPathElement*>(node())->clipPathUnits()); } + + static RenderSVGResourceType s_resourceType; +private: + HashSet<RenderObject*> m_clipper; +}; + +} + +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.cpp new file mode 100644 index 0000000000..2923c6e2d1 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 "RenderSVGResourceMasker.h" + +#include "AffineTransform.h" +#include "CanvasPixelArray.h" +#include "Element.h" +#include "FloatPoint.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageBuffer.h" +#include "ImageData.h" +#include "IntRect.h" +#include "SVGElement.h" +#include "SVGMaskElement.h" +#include "SVGStyledElement.h" +#include "SVGUnitTypes.h" +#include <wtf/Vector.h> + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType; + +RenderSVGResourceMasker::RenderSVGResourceMasker(SVGStyledElement* node) + : RenderSVGResource(node) +{ +} + +RenderSVGResourceMasker::~RenderSVGResourceMasker() +{ + deleteAllValues(m_masker); + m_masker.clear(); +} + +void RenderSVGResourceMasker::invalidateClients() +{ + HashMap<RenderObject*, MaskerData*>::const_iterator end = m_masker.end(); + for (HashMap<RenderObject*, MaskerData*>::const_iterator it = m_masker.begin(); it != end; ++it) + it->first->setNeedsLayout(true); + deleteAllValues(m_masker); + m_masker.clear(); +} + +void RenderSVGResourceMasker::invalidateClient(RenderObject* object) +{ + ASSERT(object); + + // FIXME: The HashMap should always contain the object on calling invalidateClient. A race condition + // during the parsing can causes a call of invalidateClient right before the call of applyResource. + // We return earlier for the moment. This bug should be fixed in: + // https://bugs.webkit.org/show_bug.cgi?id=35181 + if (!m_masker.contains(object)) + return; + + delete m_masker.take(object); +} + +bool RenderSVGResourceMasker::applyResource(RenderObject* object, GraphicsContext* context) +{ + ASSERT(object); + ASSERT(context); + + if (!m_masker.contains(object)) + m_masker.set(object, new MaskerData); + + MaskerData* maskerData = m_masker.get(object); + if (!maskerData->maskImage && !maskerData->emptyMask) { + SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); + if (!maskElement) + return false; + + createMaskImage(maskerData, maskElement, object); + } + + if (!maskerData->maskImage) + return false; + + context->clipToImageBuffer(maskerData->maskRect, maskerData->maskImage.get()); + return true; +} + +FloatRect RenderSVGResourceMasker::resourceBoundingBox(const FloatRect& objectBoundingBox) const +{ + if (SVGMaskElement* element = static_cast<SVGMaskElement*>(node())) + return element->maskBoundingBox(objectBoundingBox); + + return FloatRect(); +} + +void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object) +{ + FloatRect objectBoundingBox = object->objectBoundingBox(); + + // Mask rect clipped with clippingBoundingBox and filterBoundingBox as long as they are present. + maskerData->maskRect = object->repaintRectInLocalCoordinates(); + if (maskerData->maskRect.isEmpty()) { + maskerData->emptyMask = true; + return; + } + + // Calculate the smallest rect for the mask ImageBuffer. + FloatRect repaintRect; + Vector<RenderObject*> rendererList; + for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { + RenderObject* renderer = node->renderer(); + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) + continue; + + rendererList.append(renderer); + repaintRect.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + } + + AffineTransform contextTransform; + // We need to scale repaintRect for objectBoundingBox to get the drawing area. + if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + contextTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + FloatPoint contextAdjustment = repaintRect.location(); + repaintRect = contextTransform.mapRect(repaintRect); + repaintRect.move(objectBoundingBox.x(), objectBoundingBox.y()); + contextTransform.translate(-contextAdjustment.x(), -contextAdjustment.y()); + } + repaintRect.intersect(maskerData->maskRect); + maskerData->maskRect = repaintRect; + IntRect maskImageRect = enclosingIntRect(maskerData->maskRect); + + maskImageRect.setLocation(IntPoint()); + + // Don't create ImageBuffers with image size of 0 + if (!maskImageRect.width() || !maskImageRect.height()) { + maskerData->emptyMask = true; + return; + } + + // FIXME: This changes color space to linearRGB, the default color space + // for masking operations in SVG. We need a switch for the other color-space + // attribute values sRGB, inherit and auto. + maskerData->maskImage = ImageBuffer::create(maskImageRect.size(), LinearRGB); + if (!maskerData->maskImage) + return; + + GraphicsContext* maskImageContext = maskerData->maskImage->context(); + ASSERT(maskImageContext); + + maskImageContext->save(); + + if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) + maskImageContext->translate(-maskerData->maskRect.x(), -maskerData->maskRect.y()); + maskImageContext->concatCTM(contextTransform); + + // draw the content into the ImageBuffer + Vector<RenderObject*>::iterator end = rendererList.end(); + for (Vector<RenderObject*>::iterator it = rendererList.begin(); it != end; it++) + renderSubtreeToImage(maskerData->maskImage.get(), *it); + + maskImageContext->restore(); + + // create the luminance mask + RefPtr<ImageData> imageData(maskerData->maskImage->getUnmultipliedImageData(maskImageRect)); + CanvasPixelArray* srcPixelArray(imageData->data()); + + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) { + unsigned char a = srcPixelArray->get(pixelOffset + 3); + if (!a) + continue; + unsigned char r = srcPixelArray->get(pixelOffset); + unsigned char g = srcPixelArray->get(pixelOffset + 1); + unsigned char b = srcPixelArray->get(pixelOffset + 2); + + double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0); + srcPixelArray->set(pixelOffset + 3, luma); + } + + maskerData->maskImage->putUnmultipliedImageData(imageData.get(), maskImageRect, IntPoint()); +} + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.h new file mode 100644 index 0000000000..6c73c84dc6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGResourceMasker.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 RenderSVGResourceMasker_h +#define RenderSVGResourceMasker_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "IntSize.h" +#include "RenderSVGResource.h" +#include "SVGMaskElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +struct MaskerData { + MaskerData(FloatRect rect = FloatRect(), bool emptyObject = false) + : maskRect(rect) + , emptyMask(emptyObject) + { + } + + OwnPtr<ImageBuffer> maskImage; + FloatRect maskRect; + bool emptyMask; +}; + +class RenderSVGResourceMasker : public RenderSVGResource { + +public: + RenderSVGResourceMasker(SVGStyledElement*); + virtual ~RenderSVGResourceMasker(); + + virtual const char* renderName() const { return "RenderSVGResourceMasker"; } + + virtual void invalidateClients(); + virtual void invalidateClient(RenderObject*); + + virtual bool applyResource(RenderObject*, GraphicsContext*); + virtual FloatRect resourceBoundingBox(const FloatRect&) const; + + SVGUnitTypes::SVGUnitType maskUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskUnits()); } + SVGUnitTypes::SVGUnitType maskContentUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskContentUnits()); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + void createMaskImage(MaskerData*, const SVGMaskElement*, RenderObject*); + + HashMap<RenderObject*, MaskerData*> m_masker; +}; + +} + +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp index 0a39bf4725..51bf3e733a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp @@ -77,6 +77,28 @@ void RenderSVGRoot::calcPrefWidths() setPrefWidthsDirty(false); } +int RenderSVGRoot::calcReplacedWidth(bool includeMaxWidth) const +{ + int replacedWidth = RenderBox::calcReplacedWidth(includeMaxWidth); + if (!style()->width().isPercent()) + return replacedWidth; + + // FIXME: Investigate in size rounding issues + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + return static_cast<int>(roundf(replacedWidth * svg->currentScale())); +} + +int RenderSVGRoot::calcReplacedHeight() const +{ + int replacedHeight = RenderBox::calcReplacedHeight(); + if (!style()->height().isPercent()) + return replacedHeight; + + // FIXME: Investigate in size rounding issues + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + return static_cast<int>(roundf(replacedHeight * svg->currentScale())); +} + void RenderSVGRoot::layout() { ASSERT(needsLayout()); @@ -84,25 +106,19 @@ void RenderSVGRoot::layout() // Arbitrary affine transforms are incompatible with LayoutState. view()->disableLayoutState(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); + bool needsLayout = selfNeedsLayout(); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); + IntSize oldSize(width(), height()); calcWidth(); calcHeight(); - SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); - setWidth(static_cast<int>(width() * svg->currentScale())); - setHeight(static_cast<int>(height() * svg->currentScale())); - calcViewport(); - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout - child->setNeedsLayout(true, false); - - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - } + // RenderSVGRoot needs to take special care to propagate window size changes to the children, + // if the outermost <svg> is using relative x/y/width/height values. Hence the additonal parameters. + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + layoutChildren(this, needsLayout || (svg->hasRelativeValues() && oldSize != size())); repainter.repaintAfterLayout(); view()->enableLayoutState(); @@ -113,7 +129,7 @@ bool RenderSVGRoot::selfWillPaint() const { #if ENABLE(FILTERS) const SVGRenderStyle* svgStyle = style()->svgStyle(); - SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter()); + SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this); if (filter) return true; #endif @@ -126,13 +142,13 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) return; IntPoint parentOriginInContainer(parentX, parentY); - IntPoint borderBoxOriginInContainer = parentOriginInContainer + IntSize(x(), y()); + IntPoint borderBoxOriginInContainer = parentOriginInContainer + parentOriginToBorderBox(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()); // An empty viewport disables rendering. FIXME: Should we still render filters? - if (viewportSize().isEmpty()) + if (m_viewportSize.isEmpty()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. @@ -143,9 +159,8 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) RenderObject::PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); - // SVG does not support independent x/y clipping - if (style()->overflowX() != OVISIBLE) - childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y())); + // Apply initial viewport clip - not affected by overflow handling + childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y())); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. @@ -153,10 +168,13 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) SVGResourceFilter* filter = 0; FloatRect boundingBox = repaintRectInLocalCoordinates(); + + bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) - prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); + continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); - RenderBox::paint(childPaintInfo, 0, 0); + if (continueRendering) + RenderBox::paint(childPaintInfo, 0, 0); if (childPaintInfo.phase == PaintPhaseForeground) finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); @@ -167,9 +185,10 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height(), style()); } -const FloatSize& RenderSVGRoot::viewportSize() const +void RenderSVGRoot::destroy() { - return m_viewportSize; + deregisterFromResources(this); + RenderBox::destroy(); } void RenderSVGRoot::calcViewport() @@ -183,28 +202,28 @@ void RenderSVGRoot::calcViewport() // In the normal case of <svg> being stand-alone or in a CSSBoxModel object we use // RenderBox::width()/height() (which pulls data from RenderStyle) m_viewportSize = FloatSize(width(), height()); - } else { - // In the SVGImage case grab the SVGLength values off of SVGSVGElement and use - // the special relativeWidthValue accessors which respect the specified containerSize - SVGLength width = svg->width(); - SVGLength height = svg->height(); - float viewportWidth = (width.unitType() == LengthTypePercentage) ? svg->relativeWidthValue() : width.value(svg); - float viewportHeight = (height.unitType() == LengthTypePercentage) ? svg->relativeHeightValue() : height.value(svg); - m_viewportSize = FloatSize(viewportWidth, viewportHeight); + return; } + + // In the SVGImage case grab the SVGLength values off of SVGSVGElement and use + // the special relativeWidthValue accessors which respect the specified containerSize + // FIXME: Check how SVGImage + zooming is supposed to be handled? + SVGLength width = svg->width(); + SVGLength height = svg->height(); + m_viewportSize = FloatSize(width.unitType() == LengthTypePercentage ? svg->relativeWidthValue() : width.value(svg), + height.unitType() == LengthTypePercentage ? svg->relativeHeightValue() : height.value(svg)); } // RenderBox methods will expect coordinates w/o any transforms in coordinates // relative to our borderBox origin. This method gives us exactly that. -TransformationMatrix RenderSVGRoot::localToBorderBoxTransform() const +AffineTransform RenderSVGRoot::localToBorderBoxTransform() const { - TransformationMatrix ctm; IntSize borderAndPadding = borderOriginToContentBox(); - ctm.translate(borderAndPadding.width(), borderAndPadding.height()); SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); - ctm.scale(svg->currentScale()); - ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y()); - return svg->viewBoxToViewTransform(width(), height()) * ctm; + float scale = svg->currentScale(); + FloatPoint translate = svg->currentTranslate(); + AffineTransform ctm(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()); + return svg->viewBoxToViewTransform(width() / scale, height() / scale) * ctm; } IntSize RenderSVGRoot::parentOriginToBorderBox() const @@ -217,28 +236,21 @@ IntSize RenderSVGRoot::borderOriginToContentBox() const return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop()); } -TransformationMatrix RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const +AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const { - TransformationMatrix parentToContainer; - parentToContainer.translate(parentOriginInContainer.x(), parentOriginInContainer.y()); - return localToParentTransform() * parentToContainer; + AffineTransform parentToContainer(localToParentTransform()); + return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y()); } -TransformationMatrix RenderSVGRoot::localToParentTransform() const +const AffineTransform& RenderSVGRoot::localToParentTransform() const { IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); - TransformationMatrix borderBoxOriginToParentOrigin; - borderBoxOriginToParentOrigin.translate(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); - - return localToBorderBoxTransform() * borderBoxOriginToParentOrigin; -} + AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform()); + borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); -// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed. -TransformationMatrix RenderSVGRoot::absoluteTransform() const -{ - // This would apply localTransform() twice if localTransform() were not the identity. - return localToParentTransform() * RenderBox::absoluteTransform(); + m_localToParentTransform = borderBoxOriginToParentOrigin; + return m_localToParentTransform; } FloatRect RenderSVGRoot::objectBoundingBox() const @@ -249,18 +261,26 @@ FloatRect RenderSVGRoot::objectBoundingBox() const FloatRect RenderSVGRoot::repaintRectInLocalCoordinates() const { // FIXME: This does not include the border but it should! - return computeContainerBoundingBox(this, true); + FloatRect repaintRect = computeContainerBoundingBox(this, true); + style()->svgStyle()->inflateForShadow(repaintRect); + return repaintRect; } -TransformationMatrix RenderSVGRoot::localTransform() const +AffineTransform RenderSVGRoot::localTransform() const { - return TransformationMatrix(); + return AffineTransform(); } void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) { - // Apply our local transforms (except for x/y translation) and call RenderBox's method to handle all the normal CSS Box model bits + // Apply our local transforms (except for x/y translation), then our shadow, + // and then call RenderBox's method to handle all the normal CSS Box model bits repaintRect = localToBorderBoxTransform().mapRect(repaintRect); + + // Apply initial viewport clip - not affected by overflow settings + repaintRect.intersect(enclosingIntRect(FloatRect(FloatPoint(), m_viewportSize))); + + style()->svgStyle()->inflateForShadow(repaintRect); RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed); } @@ -283,14 +303,9 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox(); // Note: For now, we're ignoring hits to border and padding for <svg> - - if (style()->overflowX() == OHIDDEN) { - // SVG doesn't support independent x/y overflow - ASSERT(style()->overflowY() == OHIDDEN); - IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox(); - if (!contentBoxRect().contains(pointInContentBox)) - return false; - } + IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox(); + if (!contentBoxRect().contains(pointInContentBox)) + return false; IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); @@ -310,5 +325,3 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } #endif // ENABLE(SVG) - -// vim:ts=4:noet diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h index 08c3058e70..53c1298c54 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h @@ -31,9 +31,9 @@ namespace WebCore { class SVGStyledElement; -class TransformationMatrix; +class AffineTransform; -class RenderSVGRoot : public RenderBox, SVGRenderBase { +class RenderSVGRoot : public RenderBox, protected SVGRenderBase { public: RenderSVGRoot(SVGStyledElement*); @@ -50,21 +50,24 @@ private: virtual int lineHeight(bool b, bool isRootLineBox = false) const; virtual int baselinePosition(bool b, bool isRootLineBox = false) const; virtual void calcPrefWidths(); - + virtual int calcReplacedWidth(bool includeMaxWidth = true) const; + virtual int calcReplacedHeight() const; virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual TransformationMatrix localToParentTransform() const; + virtual void destroy(); + + virtual const AffineTransform& localToParentTransform() const; bool fillContains(const FloatPoint&) const; bool strokeContains(const FloatPoint&) const; virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const { return computeContainerBoundingBox(this, true); } virtual FloatRect repaintRectInLocalCoordinates() const; - // FIXME: Both of these overrides should be removed. - virtual TransformationMatrix localTransform() const; - virtual TransformationMatrix absoluteTransform() const; + // FIXME: This override should be removed. + virtual AffineTransform localTransform() const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -73,17 +76,17 @@ private: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; void calcViewport(); - const FloatSize& viewportSize() const; bool selfWillPaint() const; IntSize parentOriginToBorderBox() const; IntSize borderOriginToContentBox() const; - TransformationMatrix localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const; - TransformationMatrix localToBorderBoxTransform() const; + AffineTransform localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const; + AffineTransform localToBorderBoxTransform() const; RenderObjectChildList m_children; FloatSize m_viewportSize; + mutable AffineTransform m_localToParentTransform; }; inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp new file mode 100644 index 0000000000..9d3d26f232 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp @@ -0,0 +1,101 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGShadowTreeRootContainer.h" + +#include "MouseEvent.h" +#include "SVGShadowTreeElements.h" +#include "SVGUseElement.h" + +namespace WebCore { + +RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer(SVGUseElement* node) + : RenderSVGTransformableContainer(node) + , m_recreateTree(false) +{ +} + +RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer() +{ + if (m_shadowRoot && m_shadowRoot->attached()) + m_shadowRoot->detach(); +} + +void RenderSVGShadowTreeRootContainer::updateStyle(Node::StyleChange change) +{ + if (m_shadowRoot && m_shadowRoot->attached()) + m_shadowRoot->recalcStyle(change); +} + +void RenderSVGShadowTreeRootContainer::updateFromElement() +{ + bool hadExistingTree = m_shadowRoot; + + SVGUseElement* useElement = static_cast<SVGUseElement*>(node()); + if (!m_shadowRoot) { + ASSERT(!m_recreateTree); + m_shadowRoot = new SVGShadowTreeRootElement(document(), useElement); + useElement->buildPendingResource(); + } + + ASSERT(m_shadowRoot->shadowParentNode() == useElement); + + bool shouldRecreateTree = m_recreateTree; + if (m_recreateTree) { + ASSERT(hadExistingTree); + + if (m_shadowRoot->attached()) + m_shadowRoot->detach(); + + m_shadowRoot->removeAllChildren(); + m_recreateTree = false; + } + + // Only rebuild the shadow tree, if we a) never had a tree or b) we were specifically asked to do so + // If the use element is a pending resource, and a) or b) is true, do nothing, and wait for the use + // element to be asked to buildPendingResource(), this will call us again, with m_recreateTrue=true. + if ((shouldRecreateTree || !hadExistingTree) && !useElement->isPendingResource()) { + useElement->buildShadowAndInstanceTree(m_shadowRoot.get()); + + // Attach shadow root element + m_shadowRoot->attachElement(style(), renderArena()); + + // Attach subtree, as if it was a regular non-shadow tree + for (Node* child = m_shadowRoot->firstChild(); child; child = child->nextSibling()) + child->attach(); + } + + ASSERT(!m_recreateTree); + RenderSVGTransformableContainer::updateFromElement(); +} + +void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderSVGTransformableContainer::styleDidChange(diff, oldStyle); + + if (RenderObject* shadowRootRenderer = m_shadowRoot ? m_shadowRoot->renderer() : 0) + shadowRootRenderer->setStyle(style()); +} + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.h new file mode 100644 index 0000000000..01cd4270c8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGShadowTreeRootContainer.h @@ -0,0 +1,50 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; 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 RenderSVGShadowTreeRootContainer_h +#define RenderSVGShadowTreeRootContainer_h + +#if ENABLE(SVG) +#include "RenderSVGTransformableContainer.h" + +namespace WebCore { + +class SVGUseElement; +class SVGShadowTreeRootElement; + +class RenderSVGShadowTreeRootContainer : public RenderSVGTransformableContainer { +public: + RenderSVGShadowTreeRootContainer(SVGUseElement*); + virtual ~RenderSVGShadowTreeRootContainer(); + + void markShadowTreeForRecreation() { m_recreateTree = true; } + void updateStyle(Node::StyleChange); + virtual void updateFromElement(); + +private: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + bool m_recreateTree; + RefPtr<SVGShadowTreeRootElement> m_shadowRoot; +}; + +} + +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h index 652c5e39ea..931bd8c432 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h @@ -31,12 +31,6 @@ class RenderSVGTSpan : public RenderSVGInline { public: RenderSVGTSpan(Node*); virtual const char* renderName() const { return "RenderSVGTSpan"; } - - // FIXME: These are incorrect, but have always behaved this way. - // These empty implementations prevent us from hitting RenderObject ASSERTS. - // tspan.getBBox() will be wrong, and repainting for tspans may not work correctly! - virtual FloatRect objectBoundingBox() const { return FloatRect(); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp index 3919d7fef6..76b8b86a56 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp @@ -6,6 +6,7 @@ * 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * 2007 Nikolas Zimmermann <zimmermann@kde.org> * 2008 Rob Buis <buis@kde.org> + * 2009 Dirk Schulze <krit@webkit.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -69,10 +70,6 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, void RenderSVGText::layout() { ASSERT(needsLayout()); - - // FIXME: This is a hack to avoid the RenderBlock::layout() partial repainting code which is not (yet) SVG aware - setNeedsLayout(true); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); // Best guess for a relative starting point @@ -111,6 +108,12 @@ bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResul return false; } +void RenderSVGText::destroy() +{ + deregisterFromResources(this); + RenderSVGBlock::destroy(); +} + bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); @@ -125,11 +128,8 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int) // Don't use objectBoundingBox here, as it's unites the selection rects. Makes it hard // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'. - for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) { - ASSERT(runBox->isInlineFlowBox()); - - InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); - for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) { + for (InlineFlowBox* flow = firstLineBox(); flow; flow = flow->nextLineBox()) { + for (InlineBox* box = flow->firstChild(); box; box = box->nextOnLine()) { FloatRect boxRect(box->x(), box->y(), box->width(), box->height()); // FIXME: crawling up the parent chain to map each rect is very inefficient // we should compute the absoluteTransform outside this loop first. @@ -146,11 +146,8 @@ void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads) // Don't use objectBoundingBox here, as it's unites the selection rects. Makes it hard // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'. - for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) { - ASSERT(runBox->isInlineFlowBox()); - - InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); - for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) { + for (InlineFlowBox* flow = firstLineBox(); flow; flow = flow->nextLineBox()) { + for (InlineBox* box = flow->firstChild(); box; box = box->nextOnLine()) { FloatRect boxRect(box->x(), box->y(), box->width(), box->height()); // FIXME: crawling up the parent chain to map each quad is very inefficient // we should compute the absoluteTransform outside this loop first. @@ -172,11 +169,8 @@ FloatRect RenderSVGText::objectBoundingBox() const { FloatRect boundingBox; - for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) { - ASSERT(runBox->isInlineFlowBox()); - - InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); - for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) + for (InlineFlowBox* flow = firstLineBox(); flow; flow = flow->nextLineBox()) { + for (InlineBox* box = flow->firstChild(); box; box = box->nextOnLine()) boundingBox.unite(FloatRect(box->x(), box->y(), box->width(), box->height())); } @@ -184,13 +178,13 @@ FloatRect RenderSVGText::objectBoundingBox() const return boundingBox; } -FloatRect RenderSVGText::repaintRectInLocalCoordinates() const +FloatRect RenderSVGText::strokeBoundingBox() const { FloatRect repaintRect = objectBoundingBox(); // SVG needs to include the strokeWidth(), not the textStrokeWidth(). if (style()->svgStyle()->hasStroke()) { - float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 0.0f); + float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 1.0f); #if ENABLE(SVG_FONTS) const Font& font = style()->font(); @@ -205,7 +199,28 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const repaintRect.inflate(strokeWidth); } - repaintRect.unite(filterBoundingBoxForRenderer(this)); + return repaintRect; +} + +FloatRect RenderSVGText::repaintRectInLocalCoordinates() const +{ + FloatRect repaintRect = strokeBoundingBox(); + + // FIXME: We need to be careful here. We assume that there is no filter, + // clipper or masker if the rects are empty. + FloatRect rect = filterBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect = rect; + + rect = clipperBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect.intersect(rect); + + rect = maskerBoundingBoxForRenderer(this); + if (!rect.isEmpty()) + repaintRect.intersect(rect); + + style()->svgStyle()->inflateForShadow(repaintRect); return repaintRect; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h index 9a2770ba3c..ab4b09b5c8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h @@ -26,7 +26,7 @@ #if ENABLE(SVG) -#include "TransformationMatrix.h" +#include "AffineTransform.h" #include "RenderSVGBlock.h" namespace WebCore { @@ -40,9 +40,11 @@ public: private: virtual const char* renderName() const { return "RenderSVGText"; } + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } + virtual bool isSVGText() const { return true; } - virtual TransformationMatrix localToParentTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } virtual void paint(PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -51,6 +53,8 @@ private: virtual bool requiresLayer() const { return false; } virtual void layout(); + virtual void destroy(); + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); @@ -60,14 +64,15 @@ private: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; virtual FloatRect repaintRectInLocalCoordinates() const; // FIXME: This can be removed when localTransform() is removed from RenderObject - virtual TransformationMatrix localTransform() const { return m_localTransform; } + virtual AffineTransform localTransform() const { return m_localTransform; } virtual RootInlineBox* createRootInlineBox(); - TransformationMatrix m_localTransform; + AffineTransform m_localTransform; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp index 2324eee4f0..4bec7a7918 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> + Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2006 Rob Buis <buis@kde.org> 2009 Google, Inc. @@ -20,12 +20,12 @@ */ #include "config.h" -#if ENABLE(SVG) +#if ENABLE(SVG) #include "RenderSVGTransformableContainer.h" +#include "SVGShadowTreeElements.h" #include "SVGStyledTransformableElement.h" -#include "SVGTransformList.h" namespace WebCore { @@ -34,12 +34,12 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf { } -TransformationMatrix RenderSVGTransformableContainer::localToParentTransform() const +const AffineTransform& RenderSVGTransformableContainer::localToParentTransform() const { return m_localTransform; } -TransformationMatrix RenderSVGTransformableContainer::localTransform() const +AffineTransform RenderSVGTransformableContainer::localTransform() const { return m_localTransform; } @@ -47,6 +47,14 @@ TransformationMatrix RenderSVGTransformableContainer::localTransform() const void RenderSVGTransformableContainer::calculateLocalTransform() { m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform(); + if (!node()->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(node())->isShadowTreeContainerElement()) + return; + + FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(node())->containerTranslation(); + if (translation.width() == 0 && translation.height() == 0) + return; + + m_localTransform.translate(translation.width(), translation.height()); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h index c929761f16..1de0b195c6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h @@ -31,14 +31,14 @@ namespace WebCore { public: RenderSVGTransformableContainer(SVGStyledTransformableElement*); - virtual TransformationMatrix localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const; private: virtual void calculateLocalTransform(); // FIXME: This can be made non-virtual once SVGRenderTreeAsText stops using localTransform() - virtual TransformationMatrix localTransform() const; + virtual AffineTransform localTransform() const; - TransformationMatrix m_localTransform; + AffineTransform m_localTransform; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp index a432ef3b76..103d9d2f26 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp @@ -38,23 +38,33 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node) { } -void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) +FloatRect RenderSVGViewportContainer::markerBoundaries(const AffineTransform& markerTransformation) const { - // FIXME: The if statement here evaluates to false. isEmpty() is exactly the same - // as what is on the right side, so it's basically !isEmpty && isEmpty. So this - // function does nothing. + FloatRect coordinates = repaintRectInLocalCoordinates(); - // A value of zero disables rendering of the element. - if (!m_viewport.isEmpty() && (m_viewport.width() <= 0. || m_viewport.height() <= 0.)) - return; + // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated + coordinates = localToParentTransform().mapRect(coordinates); - RenderSVGContainer::paint(paintInfo, parentX, parentY); + return markerTransformation.mapRect(coordinates); +} + +AffineTransform RenderSVGViewportContainer::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const +{ + // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker + FloatPoint mappedOrigin = viewportTransform().mapPoint(origin); + + AffineTransform transformation = contentTransformation; + if (strokeWidth != -1) + transformation.scaleNonUniform(strokeWidth, strokeWidth); + + transformation.translate(-mappedOrigin.x(), -mappedOrigin.y()); + return transformation; } void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) { - if (style()->overflowX() != OVISIBLE) - paintInfo.context->clip(enclosingIntRect(m_viewport)); // FIXME: Eventually we'll want float-precision clipping + if (SVGRenderBase::isOverflowHidden(this)) + paintInfo.context->clip(m_viewport); } void RenderSVGViewportContainer::calcViewport() @@ -82,7 +92,7 @@ void RenderSVGViewportContainer::calcViewport() } } -TransformationMatrix RenderSVGViewportContainer::viewportTransform() const +AffineTransform RenderSVGViewportContainer::viewportTransform() const { if (node()->hasTagName(SVGNames::svgTag)) { SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); @@ -92,38 +102,27 @@ TransformationMatrix RenderSVGViewportContainer::viewportTransform() const return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } - return TransformationMatrix(); + return AffineTransform(); } -TransformationMatrix RenderSVGViewportContainer::localToParentTransform() const +const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const { - TransformationMatrix viewportTranslation; - viewportTranslation.translate(m_viewport.x(), m_viewport.y()); - return viewportTransform() * viewportTranslation; + AffineTransform viewportTranslation(viewportTransform()); + m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + return m_localToParentTransform; // If this class were ever given a localTransform(), then the above would read: // return viewportTransform() * localTransform() * viewportTranslation; } -// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed. -TransformationMatrix RenderSVGViewportContainer::absoluteTransform() const -{ - // This would apply localTransform() twice if localTransform() were not the identity. - return localToParentTransform() * RenderSVGContainer::absoluteTransform(); -} - bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent) { - // Respect the viewport clip (which is in parent coords). SVG does not support separate x/y overflow rules. - if (style()->overflowX() == OHIDDEN) { - ASSERT(style()->overflowY() == OHIDDEN); - if (!m_viewport.contains(pointInParent)) - return false; - } - return true; + // Respect the viewport clip (which is in parent coords) + if (!SVGRenderBase::isOverflowHidden(this)) + return true; + + return m_viewport.contains(pointInParent); } } #endif // ENABLE(SVG) - -// vim:ts=4:noet diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h index b8b30b5506..c4043ec946 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h @@ -24,7 +24,6 @@ #define RenderSVGViewportContainer_h #if ENABLE(SVG) - #include "RenderSVGContainer.h" namespace WebCore { @@ -35,19 +34,19 @@ class RenderSVGViewportContainer : public RenderSVGContainer { public: RenderSVGViewportContainer(SVGStyledElement*); - // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed. - TransformationMatrix viewportTransform() const; + // Calculates marker boundaries, mapped to the target element's coordinate space + FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; - virtual void paint(PaintInfo&, int parentX, int parentY); + // Generates a transformation matrix usable to render marker content. Handles scaling the marker content + // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in. + AffineTransform markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth = -1) const; private: virtual bool isSVGContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGViewportContainer"; } - virtual TransformationMatrix localToParentTransform() const; - - // FIXME: This override should be removed once callers of RenderBox::absoluteTransform() can be removed. - virtual TransformationMatrix absoluteTransform() const; + AffineTransform viewportTransform() const; + virtual const AffineTransform& localToParentTransform() const; virtual void calcViewport(); @@ -55,6 +54,7 @@ private: virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); FloatRect m_viewport; + mutable AffineTransform m_localToParentTransform; }; inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object) @@ -70,5 +70,3 @@ void toRenderSVGViewportContainer(const RenderSVGViewportContainer*); #endif // ENABLE(SVG) #endif // RenderSVGViewportContainer_h - -// vim:ts=4:noet diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp index 06ca32ad9c..19143ccc40 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp @@ -109,7 +109,7 @@ IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollb void RenderScrollbarTheme::paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect) { // FIXME: Implement. - context->fillRect(cornerRect, Color::white); + context->fillRect(cornerRect, Color::white, DeviceColorSpace); } void RenderScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h b/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h index e7b7b7893f..c06a9ae476 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h @@ -30,7 +30,7 @@ namespace WebCore { -class RenderSelectionInfoBase { +class RenderSelectionInfoBase : public Noncopyable { public: RenderSelectionInfoBase() : m_object(0) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp index 442af39401..729fd1522b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -35,6 +35,7 @@ #include "RenderLayer.h" #include "RenderTheme.h" #include "RenderView.h" +#include "StepRange.h" #include <wtf/MathExtras.h> using std::min; @@ -45,70 +46,10 @@ using namespace HTMLNames; static const int defaultTrackLength = 129; -// FIXME: The SliderRange class and functions are entirely based on the DOM, -// and could be put with HTMLInputElement (possibly with a new name) instead of here. -struct SliderRange { - bool isIntegral; - double minimum; - double maximum; // maximum must be >= minimum. - - explicit SliderRange(HTMLInputElement*); - double clampValue(double value); - - // Map value into 0-1 range - double proportionFromValue(double value) - { - if (minimum == maximum) - return 0; - - return (value - minimum) / (maximum - minimum); - } - - // Map from 0-1 range to value - double valueFromProportion(double proportion) - { - return minimum + proportion * (maximum - minimum); - } - - double valueFromElement(HTMLInputElement*, bool* wasClamped = 0); -}; - -SliderRange::SliderRange(HTMLInputElement* element) -{ - // FIXME: What's the right way to handle an integral range with non-integral minimum and maximum? - // Currently values are guaranteed to be integral but could be outside the range in that case. - - isIntegral = !equalIgnoringCase(element->getAttribute(precisionAttr), "float"); - - maximum = element->rangeMaximum(); - minimum = element->rangeMinimum(); -} - -double SliderRange::clampValue(double value) -{ - double clampedValue = max(minimum, min(value, maximum)); - return isIntegral ? round(clampedValue) : clampedValue; -} - -double SliderRange::valueFromElement(HTMLInputElement* element, bool* wasClamped) -{ - double oldValue; - bool parseSuccess = HTMLInputElement::formStringToDouble(element->value(), &oldValue); - if (!parseSuccess) - oldValue = (minimum + maximum) / 2; - double newValue = clampValue(oldValue); - - if (wasClamped) - *wasClamped = !parseSuccess || newValue != oldValue; - - return newValue; -} - // Returns a value between 0 and 1. -// As with SliderRange, this could be on HTMLInputElement instead of here. static double sliderPosition(HTMLInputElement* element) { - SliderRange range(element); + StepRange range(element); return range.proportionFromValue(range.valueFromElement(element)); } @@ -352,10 +293,9 @@ void RenderSlider::layout() thumb->repaintDuringLayoutIfMoved(oldThumbRect); statePusher.pop(); + addOverflowFromChild(thumb); } - addOverflowFromChild(thumb); - repainter.repaintAfterLayout(); setNeedsLayout(false); @@ -363,15 +303,6 @@ void RenderSlider::layout() void RenderSlider::updateFromElement() { - HTMLInputElement* element = static_cast<HTMLInputElement*>(node()); - - // Send the value back to the element if the range changes it. - SliderRange range(element); - bool clamped; - double value = range.valueFromElement(element, &clamped); - if (clamped) - element->setValueFromRenderer(String::number(value)); - // Layout will take care of the thumb's size and position. if (!m_thumb) { m_thumb = new SliderThumbElement(document(), node()); @@ -421,12 +352,12 @@ void RenderSlider::setValueForPosition(int position) HTMLInputElement* element = static_cast<HTMLInputElement*>(node()); // Calculate the new value based on the position, and send it to the element. - SliderRange range(element); + StepRange range(element); double fraction = static_cast<double>(position) / trackSize(); if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart) fraction = 1 - fraction; double value = range.clampValue(range.valueFromProportion(fraction)); - element->setValueFromRenderer(String::number(value)); + element->setValueFromRenderer(HTMLInputElement::serializeForNumberType(value)); // Also update the position if appropriate. if (position != currentPosition()) { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp index 73f365410d..e0fbebef2f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp @@ -485,6 +485,9 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { + if (!shouldPaintWithinRoot(paintInfo)) + return; + int w = width(); int h = height(); @@ -578,6 +581,25 @@ void RenderTable::appendColumn(int span) setNeedsLayoutAndPrefWidthsRecalc(); } +RenderTableCol* RenderTable::nextColElement(RenderTableCol* current) const +{ + RenderObject* next = current->firstChild(); + if (!next) + next = current->nextSibling(); + if (!next && current->parent()->isTableCol()) + next = current->parent()->nextSibling(); + + while (next) { + if (next->isTableCol()) + return toRenderTableCol(next); + if (next != m_caption) + return 0; + next = next->nextSibling(); + } + + return 0; +} + RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const { if (!m_hasColElements) @@ -586,32 +608,31 @@ RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) int cCol = 0; while (child) { - if (child->isTableCol()) { - RenderTableCol* colElem = toRenderTableCol(child); - int span = colElem->span(); - if (!colElem->firstChild()) { - int startCol = cCol; - int endCol = cCol + span - 1; - cCol += span; - if (cCol > col) { - if (startEdge) - *startEdge = startCol == col; - if (endEdge) - *endEdge = endCol == col; - return colElem; - } - } - - RenderObject* next = child->firstChild(); - if (!next) - next = child->nextSibling(); - if (!next && child->parent()->isTableCol()) - next = child->parent()->nextSibling(); - child = next; - } else if (child == m_caption) - child = child->nextSibling(); - else + if (child->isTableCol()) break; + if (child != m_caption) + return 0; + child = child->nextSibling(); + } + if (!child) + return 0; + + RenderTableCol* colElem = toRenderTableCol(child); + while (colElem) { + int span = colElem->span(); + if (!colElem->firstChild()) { + int startCol = cCol; + int endCol = cCol + span - 1; + cCol += span; + if (cCol > col) { + if (startEdge) + *startEdge = startCol == col; + if (endEdge) + *endEdge = endCol == col; + return colElem; + } + } + colElem = nextColElement(colElem); } return 0; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.h b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h index e75d644d3c..5978c0b066 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTable.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h @@ -113,6 +113,7 @@ public: } RenderTableCol* colElement(int col, bool* startEdge = 0, bool* endEdge = 0) const; + RenderTableCol* nextColElement(RenderTableCol* current) const; bool needsSectionRecalc() const { return m_needsSectionRecalc; } void setNeedsSectionRecalc() diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp index 8dc9145b4d..7309ace5b7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp @@ -83,18 +83,42 @@ void RenderTableCell::updateFromElement() Length RenderTableCell::styleOrColWidth() const { Length w = style()->width(); - if (colSpan() > 1 || !w.isAuto()) + if (!w.isAuto()) return w; + RenderTableCol* tableCol = table()->colElement(col()); + if (tableCol) { - w = tableCol->style()->width(); - + int colSpanCount = colSpan(); + + Length colWidthSum = Length(0, Fixed); + for (int i = 1; i <= colSpanCount; i++) { + Length colWidth = tableCol->style()->width(); + + // Percentage value should be returned only for colSpan == 1. + // Otherwise we return original width for the cell. + if (!colWidth.isFixed()) { + if (colSpanCount > 1) + return w; + return colWidth; + } + + colWidthSum = Length(colWidthSum.value() + colWidth.value(), Fixed); + + tableCol = table()->nextColElement(tableCol); + // If no next <col> tag found for the span we just return what we have for now. + if (!tableCol) + break; + } + // Column widths specified on <col> apply to the border box of the cell. // Percentages don't need to be handled since they're always treated this way (even when specified on the cells). // See Bugzilla bug 8126 for details. - if (w.isFixed() && w.value() > 0) - w = Length(max(0, w.value() - borderLeft() - borderRight() - paddingLeft() - paddingRight()), Fixed); + if (colWidthSum.isFixed() && colWidthSum.value() > 0) + colWidthSum = Length(max(0, colWidthSum.value() - borderLeft() - borderRight() - paddingLeft() - paddingRight()), Fixed); + return colWidthSum; } + return w; } @@ -154,6 +178,17 @@ void RenderTableCell::setOverrideSize(int size) RenderBlock::setOverrideSize(size); } +IntSize RenderTableCell::offsetFromContainer(RenderObject* o, const IntPoint& point) const +{ + ASSERT(o == container()); + + IntSize offset = RenderBlock::offsetFromContainer(o, point); + if (parent()) + offset.expand(-parentBox()->x(), -parentBox()->y()); + + return offset; +} + IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { // If the table grid is dirty, we cannot get reliable information about adjoining cells, @@ -212,35 +247,11 @@ void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContain return; r.setY(r.y()); RenderView* v = view(); - if ((!v || !v->layoutStateEnabled()) && parent()) + if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent()) r.move(-parentBox()->x(), -parentBox()->y()); // Rows are in the same coordinate space, so don't add their offset in. RenderBlock::computeRectForRepaint(repaintContainer, r, fixed); } -void RenderTableCell::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const -{ - if (repaintContainer == this) - return; - - RenderView* v = view(); - if ((!v || !v->layoutStateEnabled()) && parent()) { - // Rows are in the same coordinate space, so don't add their offset in. - // FIXME: this is wrong with transforms - transformState.move(-parentBox()->x(), -parentBox()->y()); - } - RenderBlock::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); -} - -void RenderTableCell::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const -{ - RenderBlock::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); - if (parent()) { - // Rows are in the same coordinate space, so add their offset back in. - // FIXME: this is wrong with transforms - transformState.move(parentBox()->x(), parentBox()->y()); - } -} - int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const { if (isRootLineBox) @@ -642,6 +653,9 @@ int RenderTableCell::borderHalfBottom(bool outer) const void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty) { if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) { + if (!shouldPaintWithinRoot(paintInfo)) + return; + tx += x(); ty += y(); int os = 2 * maximalOutlineSize(paintInfo.phase); @@ -800,6 +814,9 @@ void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject) { + if (!shouldPaintWithinRoot(paintInfo)) + return; + if (!backgroundObject) return; @@ -831,7 +848,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i paintInfo.context->save(); paintInfo.context->clip(clipRect); } - paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h); + paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h, CompositeSourceOver, backgroundObject); if (shouldClip) paintInfo.context->restore(); } @@ -839,6 +856,9 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { + if (!shouldPaintWithinRoot(paintInfo)) + return; + RenderTable* tableElt = table(); if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild()) return; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h index 8855dff9cb..b6622f4f74 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h @@ -99,13 +99,12 @@ public: virtual void setOverrideSize(int); + bool hasVisibleOverflow() const { return m_overflow; } + protected: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; - virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; - private: virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; } @@ -120,6 +119,7 @@ private: virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo&, int tx, int ty); + virtual IntSize offsetFromContainer(RenderObject*, const IntPoint&) const; virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp index bafadfc460..a11a14ba85 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp @@ -1,6 +1,4 @@ /** - * 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) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp index b8ac497b78..34c854bd5e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp @@ -42,6 +42,14 @@ namespace WebCore { using namespace HTMLNames; +static inline void setRowHeightToRowStyleHeightIfNotRelative(RenderTableSection::RowStruct* row) +{ + ASSERT(row && row->rowRenderer); + row->height = row->rowRenderer->style()->height(); + if (row->height.isRelative()) + row->height = Length(); +} + RenderTableSection::RenderTableSection(Node* node) : RenderBox(node) , m_gridRows(0) @@ -122,11 +130,8 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild m_grid[m_cRow].rowRenderer = toRenderTableRow(child); - if (!beforeChild) { - m_grid[m_cRow].height = child->style()->height(); - if (m_grid[m_cRow].height.isRelative()) - m_grid[m_cRow].height = Length(); - } + if (!beforeChild) + setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]); // If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that. while (beforeChild && beforeChild->parent() != this) @@ -641,12 +646,11 @@ int RenderTableSection::layoutRows(int toAdd) if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell) continue; addOverflowFromChild(cell); + m_hasOverflowingCell |= cell->hasVisibleOverflow(); } } - m_hasOverflowingCell = m_overflow; - - statePusher.pop(); + statePusher.pop(); return height(); } @@ -1083,6 +1087,7 @@ void RenderTableSection::recalcCells() RenderTableRow* tableRow = toRenderTableRow(row); m_grid[m_cRow].rowRenderer = tableRow; + setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]); for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp index 88a05e5f5f..aa919e0fb5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp @@ -25,7 +25,9 @@ #include "config.h" #include "RenderText.h" +#include "AXObjectCache.h" #include "CharacterNames.h" +#include "EllipsisBox.h" #include "FloatQuad.h" #include "FrameView.h" #include "InlineTextBox.h" @@ -46,12 +48,6 @@ using namespace Unicode; namespace WebCore { -// FIXME: Move to StringImpl.h eventually. -static inline bool charactersAreAllASCII(StringImpl* text) -{ - return charactersAreAllASCII(text->characters(), text->length()); -} - RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) : RenderObject(node) , m_minWidth(-1) @@ -64,7 +60,7 @@ RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) , m_hasTab(false) , m_linesDirty(false) , m_containsReversedText(false) - , m_isAllASCII(charactersAreAllASCII(m_text.get())) + , m_isAllASCII(m_text.containsOnlyASCII()) , m_knownNotToUseFallbackFonts(false) { ASSERT(m_text); @@ -148,9 +144,9 @@ void RenderText::extractTextBox(InlineTextBox* box) if (box == m_firstTextBox) m_firstTextBox = 0; if (box->prevTextBox()) - box->prevTextBox()->setNextLineBox(0); - box->setPreviousLineBox(0); - for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox()) + box->prevTextBox()->setNextTextBox(0); + box->setPreviousTextBox(0); + for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) curr->setExtracted(); checkConsistency(); @@ -161,8 +157,8 @@ void RenderText::attachTextBox(InlineTextBox* box) checkConsistency(); if (m_lastTextBox) { - m_lastTextBox->setNextLineBox(box); - box->setPreviousLineBox(m_lastTextBox); + m_lastTextBox->setNextTextBox(box); + box->setPreviousTextBox(m_lastTextBox); } else m_firstTextBox = box; InlineTextBox* last = box; @@ -184,9 +180,9 @@ void RenderText::removeTextBox(InlineTextBox* box) if (box == m_lastTextBox) m_lastTextBox = box->prevTextBox(); if (box->nextTextBox()) - box->nextTextBox()->setPreviousLineBox(box->prevTextBox()); + box->nextTextBox()->setPreviousTextBox(box->prevTextBox()); if (box->prevTextBox()) - box->prevTextBox()->setNextLineBox(box->nextTextBox()); + box->prevTextBox()->setNextTextBox(box->nextTextBox()); checkConsistency(); } @@ -228,27 +224,32 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u start = min(start, static_cast<unsigned>(INT_MAX)); end = min(end, static_cast<unsigned>(INT_MAX)); - FloatPoint absPos = localToAbsolute(FloatPoint()); - for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { // Note: box->end() returns the index of the last character, not the index past it if (start <= box->start() && box->end() < end) { - IntRect r = IntRect(absPos.x() + box->x(), absPos.y() + box->y(), box->width(), box->height()); + IntRect r = IntRect(box->x(), box->y(), box->width(), box->height()); if (useSelectionHeight) { - IntRect selectionRect = box->selectionRect(absPos.x(), absPos.y(), start, end); + IntRect selectionRect = box->selectionRect(0, 0, start, end); r.setHeight(selectionRect.height()); r.setY(selectionRect.y()); } + FloatPoint origin = localToAbsolute(r.location()); + r.setX(origin.x()); + r.setY(origin.y()); rects.append(r); } else { unsigned realEnd = min(box->end() + 1, end); - IntRect r = box->selectionRect(absPos.x(), absPos.y(), start, realEnd); + IntRect r = box->selectionRect(0, 0, start, realEnd); if (!r.isEmpty()) { if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values r.setHeight(box->height()); - r.setY(absPos.y() + box->y()); + r.setY(box->y()); } + FloatPoint origin = localToAbsolute(r.location()); + localToAbsolute(origin); + r.setX(origin.x()); + r.setY(origin.y()); rects.append(r); } } @@ -286,7 +287,7 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, } else { unsigned realEnd = min(box->end() + 1, end); IntRect r = box->selectionRect(0, 0, start, realEnd); - if (!r.isEmpty()) { + if (r.height()) { if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values r.setHeight(box->height()); @@ -338,7 +339,7 @@ VisiblePosition RenderText::positionForPoint(const IntPoint& point) // at the y coordinate of the last line or below // and the x coordinate is to the right of the last text box right edge offset = lastTextBox()->offsetForPosition(point.x()); - return createVisiblePosition(offset + lastTextBox()->start(), DOWNSTREAM); + return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE); } InlineTextBox* lastBoxAbove = 0; @@ -435,8 +436,10 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int w = 0; bool isSpace; bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0. + ASSERT(m_text); + StringImpl& text = *m_text.impl(); for (int i = start; i < start + len; i++) { - char c = (*m_text)[i]; + char c = text[i]; if (c <= ' ') { if (c == ' ' || c == '\n') { w += monospaceCharacterWidth; @@ -479,7 +482,7 @@ void RenderText::trimmedPrefWidths(int leadWidth, int len = textLength(); - if (!len || (stripFrontSpaces && m_text->containsOnlyWhitespace())) { + if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) { beginMinW = 0; endMinW = 0; beginMaxW = 0; @@ -499,7 +502,9 @@ void RenderText::trimmedPrefWidths(int leadWidth, hasBreakableChar = m_hasBreakableChar; hasBreak = m_hasBreak; - if ((*m_text)[0] == ' ' || ((*m_text)[0] == '\n' && !style()->preserveNewline()) || (*m_text)[0] == '\t') { + ASSERT(m_text); + StringImpl& text = *m_text.impl(); + if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') { const Font& f = style()->font(); // FIXME: This ignores first-line. if (stripFrontSpaces) { const UChar space = ' '; @@ -522,7 +527,7 @@ void RenderText::trimmedPrefWidths(int leadWidth, endMaxW = maxW; for (int i = 0; i < len; i++) { int linelen = 0; - while (i + linelen < len && (*m_text)[i + linelen] != '\n') + while (i + linelen < len && text[i + linelen] != '\n') linelen++; if (linelen) { @@ -757,11 +762,24 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f setPrefWidthsDirty(false); } +bool RenderText::isAllCollapsibleWhitespace() +{ + int length = textLength(); + const UChar* text = characters(); + for (int i = 0; i < length; i++) { + if (!style()->isCollapsibleWhiteSpace(text[i])) + return false; + } + return true; +} + bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const { + ASSERT(m_text); + StringImpl& text = *m_text.impl(); unsigned currPos; for (currPos = from; - currPos < from + len && ((*m_text)[currPos] == '\n' || (*m_text)[currPos] == ' ' || (*m_text)[currPos] == '\t'); + currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t'); currPos++) { } return currPos >= (from + len); } @@ -813,7 +831,9 @@ void RenderText::setSelectionState(SelectionState state) } } - containingBlock()->setSelectionState(state); + // The returned value can be null in case of an orphaned tree. + if (RenderBlock* cb = containingBlock()) + cb->setSelectionState(state); } void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force) @@ -932,7 +952,7 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) // characters into space characters. Then, it will draw all space characters, including // leading, trailing and multiple contiguous space characters. - m_text = m_text->replace('\n', ' '); + m_text.replace('\n', ' '); // If xml:space="preserve" is set, white-space is set to "pre", which // preserves leading, trailing & contiguous space character for us. @@ -943,13 +963,13 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) // Then, it will strip off all leading and trailing space characters. // Then, all contiguous space characters will be consolidated. - m_text = m_text->replace('\n', StringImpl::empty()); + m_text.replace('\n', StringImpl::empty()); // If xml:space="default" is set, white-space is set to "nowrap", which handles // leading, trailing & contiguous space character removal for us. } - m_text = m_text->replace('\t', ' '); + m_text.replace('\t', ' '); } #endif @@ -957,15 +977,14 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) switch (style()->textTransform()) { case TTNONE: break; - case CAPITALIZE: { - m_text = m_text->capitalize(previousCharacter()); + case CAPITALIZE: + m_text.makeCapitalized(previousCharacter()); break; - } case UPPERCASE: - m_text = m_text->upper(); + m_text.makeUpper(); break; case LOWERCASE: - m_text = m_text->lower(); + m_text.makeLower(); break; } @@ -975,32 +994,36 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) case TSNONE: break; case TSCIRCLE: - m_text = m_text->secure(whiteBullet); + m_text.makeSecure(whiteBullet); break; case TSDISC: - m_text = m_text->secure(bullet); + m_text.makeSecure(bullet); break; case TSSQUARE: - m_text = m_text->secure(blackSquare); + m_text.makeSecure(blackSquare); } } ASSERT(m_text); - ASSERT(!isBR() || (textLength() == 1 && (*m_text)[0] == '\n')); + ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n')); - m_isAllASCII = charactersAreAllASCII(m_text.get()); + m_isAllASCII = m_text.containsOnlyASCII(); } void RenderText::setText(PassRefPtr<StringImpl> text, bool force) { ASSERT(text); - if (!force && equal(m_text.get(), text.get())) + if (!force && equal(m_text.impl(), text.get())) return; setTextInternal(text); setNeedsLayoutAndPrefWidthsRecalc(); m_knownNotToUseFallbackFonts = false; + + AXObjectCache* axObjectCache = document()->axObjectCache(); + if (axObjectCache->accessibilityEnabled()) + axObjectCache->contentChanged(this); } int RenderText::lineHeight(bool firstLine, bool) const @@ -1031,8 +1054,8 @@ InlineTextBox* RenderText::createInlineTextBox() if (!m_firstTextBox) m_firstTextBox = m_lastTextBox = textBox; else { - m_lastTextBox->setNextLineBox(textBox); - textBox->setPreviousLineBox(m_lastTextBox); + m_lastTextBox->setNextTextBox(textBox); + textBox->setPreviousTextBox(m_lastTextBox); m_lastTextBox = textBox; } textBox->setIsText(true); @@ -1050,11 +1073,11 @@ void RenderText::positionLineBox(InlineBox* box) if (m_firstTextBox == s) m_firstTextBox = s->nextTextBox(); else - s->prevTextBox()->setNextLineBox(s->nextTextBox()); + s->prevTextBox()->setNextTextBox(s->nextTextBox()); if (m_lastTextBox == s) m_lastTextBox = s->prevTextBox(); else - s->nextTextBox()->setPreviousLineBox(s->prevTextBox()); + s->nextTextBox()->setPreviousTextBox(s->prevTextBox()); s->destroy(renderArena()); return; } @@ -1158,9 +1181,25 @@ IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContain return IntRect(); IntRect rect; - for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) + for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { rect.unite(box->selectionRect(0, 0, startPos, endPos)); + // Check if there are ellipsis which fall within the selection. + unsigned short truncation = box->truncation(); + if (truncation != cNoTruncation) { + if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) { + int ePos = min<int>(endPos - box->start(), box->len()); + int sPos = max<int>(startPos - box->start(), 0); + // The ellipsis should be considered to be selected if the end of + // the selection is past the beginning of the truncation and the + // beginning of the selection is before or at the beginning of the + // truncation. + if (ePos >= truncation && sPos <= truncation) + rect.unite(ellipsis->selectionRect(0, 0)); + } + } + } + if (clipToVisibleContent) computeRectForRepaint(repaintContainer, rect); else { @@ -1205,7 +1244,7 @@ unsigned RenderText::caretMaxRenderedOffset() const int RenderText::previousOffset(int current) const { - StringImpl* si = m_text.get(); + StringImpl* si = m_text.impl(); TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current - 1; @@ -1253,14 +1292,16 @@ inline bool isHangulLVT(UChar32 character) int RenderText::previousOffsetForBackwardDeletion(int current) const { #if PLATFORM(MAC) + ASSERT(m_text); + StringImpl& text = *m_text.impl(); UChar32 character; while (current > 0) { - if (U16_IS_TRAIL((*m_text)[--current])) + if (U16_IS_TRAIL(text[--current])) --current; if (current < 0) break; - UChar32 character = m_text->characterStartingAt(current); + UChar32 character = text.characterStartingAt(current); // We don't combine characters in Armenian ... Limbu range for backward deletion. if ((character >= 0x0530) && (character < 0x1950)) @@ -1274,7 +1315,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const return current; // Hangul - character = m_text->characterStartingAt(current); + character = text.characterStartingAt(current); if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) { HangulState state; HangulState initialState; @@ -1290,7 +1331,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const initialState = state; - while (current > 0 && ((character = m_text->characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) { + while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) { switch (state) { case HangulStateV: if (character <= HANGUL_CHOSEONG_END) @@ -1328,7 +1369,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const int RenderText::nextOffset(int current) const { - StringImpl* si = m_text.get(); + StringImpl* si = m_text.impl(); TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current + 1; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.h b/src/3rdparty/webkit/WebCore/rendering/RenderText.h index 915ff40acb..e9ed147a4d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.h @@ -50,7 +50,7 @@ public: virtual void destroy(); - StringImpl* text() const { return m_text.get(); } + StringImpl* text() const { return m_text.impl(); } InlineTextBox* createInlineTextBox(); void dirtyLineBoxes(bool fullLayout); @@ -63,8 +63,8 @@ public: virtual VisiblePosition positionForPoint(const IntPoint&); - const UChar* characters() const { return m_text->characters(); } - unsigned textLength() const { return m_text->length(); } // non virtual implementation of length() + const UChar* characters() const { return m_text.characters(); } + unsigned textLength() const { return m_text.length(); } // non virtual implementation of length() void positionLineBox(InlineBox*); virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; @@ -121,7 +121,8 @@ public: void checkConsistency() const; virtual void calcPrefWidths(int leadWidth); - + bool isAllCollapsibleWhitespace(); + protected: virtual void styleWillChange(StyleDifference, const RenderStyle*) { } virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -150,7 +151,7 @@ private: int m_minWidth; // here to minimize padding in 64-bit. - RefPtr<StringImpl> m_text; + String m_text; InlineTextBox* m_firstTextBox; InlineTextBox* m_lastTextBox; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp index f430399568..b98900a223 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp @@ -70,8 +70,8 @@ static Color disabledTextColor(const Color& textColor, const Color& backgroundCo RenderTextControl::RenderTextControl(Node* node, bool placeholderVisible) : RenderBlock(node) , m_placeholderVisible(placeholderVisible) - , m_edited(false) - , m_userEdited(false) + , m_wasChangedSinceLastChangeEvent(false) + , m_lastChangeWasUserEdit(false) { } @@ -195,17 +195,17 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue) ASSERT(!ec); } - m_edited = false; - m_userEdited = false; + // We set m_lastChangeWasUserEdit to false since this change was not explicitly made by the user (say, via typing on the keyboard), see <rdar://problem/5359921>. + m_lastChangeWasUserEdit = false; } static_cast<Element*>(node())->setFormControlValueMatchesRenderer(true); } -void RenderTextControl::setUserEdited(bool isUserEdited) +void RenderTextControl::setLastChangeWasUserEdit(bool lastChangeWasUserEdit) { - m_userEdited = isUserEdited; - document()->setIgnoreAutofocus(isUserEdited); + m_lastChangeWasUserEdit = lastChangeWasUserEdit; + document()->setIgnoreAutofocus(lastChangeWasUserEdit); } int RenderTextControl::selectionStart() @@ -266,11 +266,6 @@ void RenderTextControl::setSelectionRange(int start, int end) if (Frame* frame = document()->frame()) frame->selection()->setSelection(newSelection); - - // FIXME: Granularity is stored separately on the frame, but also in the selection controller. - // The granularity in the selection controller should be used, and then this line of code would not be needed. - if (Frame* frame = document()->frame()) - frame->setSelectionGranularity(CharacterGranularity); } VisibleSelection RenderTextControl::selection(int start, int end) const @@ -312,8 +307,8 @@ int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos) void RenderTextControl::subtreeHasChanged() { - m_edited = true; - m_userEdited = true; + m_wasChangedSinceLastChangeEvent = true; + m_lastChangeWasUserEdit = true; } String RenderTextControl::finishText(Vector<UChar>& result) const @@ -459,6 +454,78 @@ IntRect RenderTextControl::controlClipRect(int tx, int ty) const return clipRect; } +static const char* fontFamiliesWithInvalidCharWidth[] = { + "American Typewriter", + "Arial Hebrew", + "Chalkboard", + "Cochin", + "Corsiva Hebrew", + "Courier", + "Euphemia UCAS", + "Geneva", + "Gill Sans", + "Hei", + "Helvetica", + "Hoefler Text", + "InaiMathi", + "Kai", + "Lucida Grande", + "Marker Felt", + "Monaco", + "Mshtakan", + "New Peninim MT", + "Osaka", + "Raanana", + "STHeiti", + "Symbol", + "Times", + "Apple Braille", + "Apple LiGothic", + "Apple LiSung", + "Apple Symbols", + "AppleGothic", + "AppleMyungjo", + "#GungSeo", + "#HeadLineA", + "#PCMyungjo", + "#PilGi", +}; + +// For font families where any of the fonts don't have a valid entry in the OS/2 table +// for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCharWidth +// from the width of a '0'. This only seems to apply to a fixed number of Mac fonts, +// but, in order to get similar rendering across platforms, we do this check for +// all platforms. +bool RenderTextControl::hasValidAvgCharWidth(AtomicString family) +{ + static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0; + + if (!fontFamiliesWithInvalidCharWidthMap) { + fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>; + + for (unsigned i = 0; i < sizeof(fontFamiliesWithInvalidCharWidth) / sizeof(fontFamiliesWithInvalidCharWidth[0]); i++) + fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i])); + } + + return !fontFamiliesWithInvalidCharWidthMap->contains(family); +} + +float RenderTextControl::getAvgCharWidth(AtomicString family) +{ + if (hasValidAvgCharWidth(family)) + return roundf(style()->font().primaryFont()->avgCharWidth()); + + const UChar ch = '0'; + return style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false)); +} + +float RenderTextControl::scaleEmToUnits(int x) const +{ + // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the "head" font table. + float unitsPerEm = 2048.0f; + return roundf(style()->font().size() * x / unitsPerEm); +} + void RenderTextControl::calcPrefWidths() { ASSERT(prefWidthsDirty()); @@ -470,8 +537,8 @@ void RenderTextControl::calcPrefWidths() m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value()); else { // Use average character width. Matches IE. - float charWidth = style()->font().primaryFont()->avgCharWidth(); - m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight(); + AtomicString family = style()->font().family().family(); + m_maxPrefWidth = preferredContentWidth(getAvgCharWidth(family)) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight(); } if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { @@ -505,9 +572,10 @@ void RenderTextControl::selectionChanged(bool userTriggered) } } -void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); + if (width() && height()) + rects.append(IntRect(tx, ty, width(), height())); } HTMLElement* RenderTextControl::innerTextElement() const diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h index cdd8716d63..2fc8edca47 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h @@ -34,11 +34,11 @@ class RenderTextControl : public RenderBlock { public: virtual ~RenderTextControl(); - bool isEdited() const { return m_edited; } - void setEdited(bool isEdited) { m_edited = isEdited; } + bool wasChangedSinceLastChangeEvent() const { return m_wasChangedSinceLastChangeEvent; } + void setChangedSinceLastChangeEvent(bool wasChangedSinceLastChangeEvent) { m_wasChangedSinceLastChangeEvent = wasChangedSinceLastChangeEvent; } - bool isUserEdited() const { return m_userEdited; } - void setUserEdited(bool isUserEdited); + bool lastChangeWasUserEdit() const { return m_lastChangeWasUserEdit; } + void setLastChangeWasUserEdit(bool lastChangeWasUserEdit); int selectionStart(); int selectionEnd(); @@ -74,6 +74,10 @@ protected: int textBlockWidth() const; int textBlockHeight() const; + float scaleEmToUnits(int x) const; + + static bool hasValidAvgCharWidth(AtomicString family); + virtual float getAvgCharWidth(AtomicString family); virtual int preferredContentWidth(float charWidth) const = 0; virtual void adjustControlHeightBasedOnLineHeight(int lineHeight) = 0; virtual void cacheSelection(int start, int end) = 0; @@ -99,14 +103,14 @@ private: virtual bool avoidsFloats() const { return true; } void setInnerTextStyle(PassRefPtr<RenderStyle>); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); virtual bool canBeProgramaticallyScrolled(bool) const { return true; } String finishText(Vector<UChar>&) const; - bool m_edited; - bool m_userEdited; + bool m_wasChangedSinceLastChangeEvent; + bool m_lastChangeWasUserEdit; RefPtr<TextControlInnerTextElement> m_innerText; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp index a49e092b1b..af422538ac 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -47,7 +47,7 @@ void RenderTextControlMultiLine::subtreeHasChanged() RenderTextControl::subtreeHasChanged(); HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); textArea->setFormControlValueMatchesRenderer(false); - textArea->updateValidity(); + textArea->setNeedsValidityCheck(); if (!node()->focused()) return; @@ -64,8 +64,8 @@ bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitT return false; bool resultIsTextValueOrPlaceholder - = !m_placeholderVisible && result.innerNode() == innerTextElement() - || m_placeholderVisible && result.innerNode()->isDescendantOf(innerTextElement()); + = (!m_placeholderVisible && result.innerNode() == innerTextElement()) + || (m_placeholderVisible && result.innerNode()->isDescendantOf(innerTextElement())); if (result.innerNode() == node() || resultIsTextValueOrPlaceholder) hitInnerTextElement(result, x, y, tx, ty); @@ -77,6 +77,17 @@ void RenderTextControlMultiLine::forwardEvent(Event* event) RenderTextControl::forwardEvent(event); } +float RenderTextControlMultiLine::getAvgCharWidth(AtomicString family) +{ + // Since Lucida Grande is the default font, we want this to match the width + // of Courier New, the default font for textareas in IE, Firefox and Safari Win. + // 1229 is the avgCharWidth value in the OS/2 table for Courier New. + if (family == AtomicString("Lucida Grande")) + return scaleEmToUnits(1229); + + return RenderTextControl::getAvgCharWidth(family); +} + int RenderTextControlMultiLine::preferredContentWidth(float charWidth) const { int factor = static_cast<HTMLTextAreaElement*>(node())->cols(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h index 3371a8f1a0..fbca308145 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h @@ -40,6 +40,7 @@ private: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + virtual float getAvgCharWidth(AtomicString family); virtual int preferredContentWidth(float charWidth) const; virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); virtual int baselinePosition(bool firstLine, bool isRootLineBox) const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp index be800a7310..a762ac5499 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -150,7 +150,7 @@ void RenderTextControlSingleLine::hidePopup() void RenderTextControlSingleLine::subtreeHasChanged() { - bool wasEdited = isEdited(); + bool wasChanged = wasChangedSinceLastChangeEvent(); RenderTextControl::subtreeHasChanged(); InputElement* input = inputElement(); @@ -167,7 +167,7 @@ void RenderTextControlSingleLine::subtreeHasChanged() if (input->searchEventsShouldBeDispatched()) startSearchEventTimer(); - if (!wasEdited && node()->focused()) { + if (!wasChanged && node()->focused()) { if (Frame* frame = document()->frame()) frame->textFieldDidBeginEditing(static_cast<Element*>(node())); } @@ -374,7 +374,19 @@ int RenderTextControlSingleLine::textBlockWidth() const return width; } + +float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family) +{ + // Since Lucida Grande is the default font, we want this to match the width + // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and + // IE for some encodings (in IE, the default font is encoding specific). + // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg. + if (family == AtomicString("Lucida Grande")) + return scaleEmToUnits(901); + return RenderTextControl::getAvgCharWidth(family); +} + int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const { int factor = inputElement()->size(); @@ -383,8 +395,20 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const int result = static_cast<int>(ceilf(charWidth * factor)); + float maxCharWidth = 0.f; + AtomicString family = style()->font().family().family(); + // Since Lucida Grande is the default font, we want this to match the width + // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and + // IE for some encodings (in IE, the default font is encoding specific). + // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg. + if (family == AtomicString("Lucida Grande")) + maxCharWidth = scaleEmToUnits(4027); + else if (hasValidAvgCharWidth(family)) + maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth()); + // For text inputs, IE adds some extra width. - result += style()->font().primaryFont()->maxCharWidth() - charWidth; + if (maxCharWidth > 0.f) + result += maxCharWidth - charWidth; if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() + @@ -461,8 +485,12 @@ void RenderTextControlSingleLine::updateFromElement() ExceptionCode ec = 0; innerTextElement()->setInnerText(static_cast<Element*>(node())->getAttribute(placeholderAttr), ec); ASSERT(!ec); - } else - setInnerTextValue(inputElement()->value()); + } else { + if (!inputElement()->suggestedValue().isNull()) + setInnerTextValue(inputElement()->suggestedValue()); + else + setInnerTextValue(inputElement()->value()); + } if (m_searchPopupIsVisible) m_searchPopup->updateFromElement(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h index e30ff0d3d1..e1bcc84568 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h @@ -75,6 +75,7 @@ private: virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f, Node** stopNode = 0); int textBlockWidth() const; + virtual float getAvgCharWidth(AtomicString family); virtual int preferredContentWidth(float charWidth) const; virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); @@ -100,6 +101,7 @@ private: virtual void valueChanged(unsigned listIndex, bool fireEvents = true); virtual String itemText(unsigned listIndex) const; virtual String itemToolTip(unsigned) const { return String(); } + virtual String itemAccessibilityText(unsigned) const { return String(); } virtual bool itemIsEnabled(unsigned listIndex) const; virtual PopupMenuStyle itemStyle(unsigned listIndex) const; virtual PopupMenuStyle menuStyle() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp index 9ff110649e..f3398a3e35 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp @@ -69,6 +69,10 @@ void RenderTextFragment::setTextInternal(PassRefPtr<StringImpl> text) m_firstLetter = 0; m_start = 0; m_end = textLength(); + if (Node* t = node()) { + ASSERT(!t->renderer()); + t->setRenderer(this); + } } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp index 5ee01e445a..7c284a6ced 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp @@ -1,7 +1,7 @@ /** * This file is part of the theme implementation for form controls in WebCore. * - * Copyright (C) 2005, 2006, 2007, 2008 Apple Computer, Inc. + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -87,6 +87,8 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El switch (part) { case ListButtonPart: case CheckboxPart: + case InnerSpinButtonPart: + case OuterSpinButtonPart: case RadioPart: case PushButtonPart: case SquareButtonPart: @@ -176,6 +178,10 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El case DefaultButtonPart: case ButtonPart: return adjustButtonStyle(selector, style, e); + case InnerSpinButtonPart: + return adjustInnerSpinButtonStyle(selector, style, e); + case OuterSpinButtonPart: + return adjustOuterSpinButtonStyle(selector, style, e); #endif case TextFieldPart: return adjustTextFieldStyle(selector, style, e); @@ -203,6 +209,10 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El return adjustSearchFieldResultsDecorationStyle(selector, style, e); case SearchFieldResultsButtonPart: return adjustSearchFieldResultsButtonStyle(selector, style, e); +#if ENABLE(PROGRESS_TAG) + case ProgressBarPart: + return adjustProgressBarStyle(selector, style, e); +#endif default: break; } @@ -232,6 +242,8 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf case ListButtonPart: case DefaultButtonPart: case ButtonPart: + case InnerSpinButtonPart: + case OuterSpinButtonPart: m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView()); return false; default: @@ -252,9 +264,17 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf case DefaultButtonPart: case ButtonPart: return paintButton(o, paintInfo, r); + case InnerSpinButtonPart: + return paintInnerSpinButton(o, paintInfo, r); + case OuterSpinButtonPart: + return paintOuterSpinButton(o, paintInfo, r); #endif case MenulistPart: return paintMenuList(o, paintInfo, r); +#if ENABLE(PROGRESS_TAG) + case ProgressBarPart: + return paintProgressBar(o, paintInfo, r); +#endif case SliderHorizontalPart: case SliderVerticalPart: return paintSliderTrack(o, paintInfo, r); @@ -278,6 +298,8 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf return paintMediaRewindButton(o, paintInfo, r); case MediaReturnToRealtimeButtonPart: return paintMediaReturnToRealtimeButton(o, paintInfo, r); + case MediaToggleClosedCaptionsButtonPart: + return paintMediaToggleClosedCaptionsButton(o, paintInfo, r); case MediaSliderPart: return paintMediaSliderTrack(o, paintInfo, r); case MediaSliderThumbPart: @@ -343,6 +365,9 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo case DefaultButtonPart: case ButtonPart: case MenulistPart: +#if ENABLE(PROGRESS_TAG) + case ProgressBarPart: +#endif case SliderHorizontalPart: case SliderVerticalPart: case SliderThumbHorizontalPart: @@ -378,6 +403,9 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf case DefaultButtonPart: case ButtonPart: case MenulistPart: +#if ENABLE(PROGRESS_TAG) + case ProgressBarPart: +#endif case SliderHorizontalPart: case SliderVerticalPart: case SliderThumbHorizontalPart: @@ -416,10 +444,41 @@ bool RenderTheme::shouldRenderMediaControlPart(ControlPart part, Element* e) return mediaElement->movieLoadType() == MediaPlayer::LiveStream; case MediaFullscreenButtonPart: return mediaElement->supportsFullscreen(); + case MediaToggleClosedCaptionsButtonPart: + return mediaElement->hasClosedCaptions(); default: return true; } } + +String RenderTheme::formatMediaControlsTime(float time) const +{ + if (!isfinite(time)) + time = 0; + int seconds = (int)fabsf(time); + int hours = seconds / (60 * 60); + int minutes = (seconds / 60) % 60; + seconds %= 60; + if (hours) { + if (hours > 9) + return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + + return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + } + + return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds); +} + +String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const +{ + return formatMediaControlsTime(currentTime); +} + +String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float duration) const +{ + return formatMediaControlsTime(currentTime - duration); +} + #endif Color RenderTheme::activeSelectionBackgroundColor() const @@ -581,7 +640,7 @@ bool RenderTheme::supportsFocusRing(const RenderStyle* style) const bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const { - // Default implementation assumes the controls dont respond to changes in :hover state + // Default implementation assumes the controls don't respond to changes in :hover state if (state == HoverState && !supportsHover(o->style())) return false; @@ -701,6 +760,10 @@ bool RenderTheme::isHovered(const RenderObject* o) const bool RenderTheme::isDefault(const RenderObject* o) const { + // A button should only have the default appearance if the page is active + if (!isActive(o)) + return false; + if (!o->document()) return false; @@ -754,6 +817,14 @@ void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Eleme setButtonSize(style); } +void RenderTheme::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +void RenderTheme::adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + #endif void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const @@ -768,6 +839,18 @@ void RenderTheme::adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) { } +#if ENABLE(PROGRESS_TAG) +bool RenderTheme::getNumberOfPixelsForProgressPosition(double , int& progressSize) const +{ + progressSize = 0; + return false; +} + +void RenderTheme::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} +#endif + void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h index 1b6a7e44e5..fbdf91030d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h @@ -169,10 +169,22 @@ public: // Method for painting the caps lock indicator virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return 0; }; +#if ENABLE(PROGRESS_TAG) + // Helper method for optimizing the paint area of the progress bar. + // If supported, it returns number of pixels needed to draw the progress bar up to the progress position. + // progressSize is the value that is passed back to RenderTheme during drawing. + virtual bool getNumberOfPixelsForProgressPosition(double position, int& progressSize) const; +#endif + #if ENABLE(VIDEO) // Media controls virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual double mediaControlsFadeInDuration() { return 0.1; } + virtual double mediaControlsFadeOutDuration() { return 0.3; } + virtual String formatMediaControlsTime(float time) const; + virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; + virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; #endif protected: @@ -203,6 +215,11 @@ protected: virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual void setButtonSize(RenderStyle*) const { } + + virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintInnerSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual void adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintOuterSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } #endif virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -217,6 +234,11 @@ protected: virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } +#if ENABLE(PROGRESS_TAG) + virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintProgressBar(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } +#endif + virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } @@ -250,6 +272,7 @@ protected: virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp index 9048ce38e2..13c9cd62ad 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -25,13 +25,27 @@ #include "config.h" #include "RenderThemeChromiumLinux.h" -#include "Color.h" #include "CSSValueKeywords.h" +#include "Color.h" #include "RenderObject.h" #include "UserAgentStyleSheets.h" namespace WebCore { +unsigned RenderThemeChromiumLinux::m_thumbInactiveColor = 0xf0ebe5; +unsigned RenderThemeChromiumLinux::m_thumbActiveColor = 0xfaf8f5; +unsigned RenderThemeChromiumLinux::m_trackColor = 0xe3ddd8; +unsigned RenderThemeChromiumLinux::m_activeSelectionBackgroundColor = + 0xff1e90ff; +unsigned RenderThemeChromiumLinux::m_activeSelectionForegroundColor = + Color::black; +unsigned RenderThemeChromiumLinux::m_inactiveSelectionBackgroundColor = + 0xffc8c8c8; +unsigned RenderThemeChromiumLinux::m_inactiveSelectionForegroundColor = + 0xff323232; + +double RenderThemeChromiumLinux::m_caretBlinkInterval; + PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create() { return adoptRef(new RenderThemeChromiumLinux()); @@ -92,6 +106,26 @@ Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const return Color(0x32, 0x32, 0x32); } +Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const +{ + return m_activeSelectionBackgroundColor; +} + +Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const +{ + return m_inactiveSelectionBackgroundColor; +} + +Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const +{ + return m_activeSelectionForegroundColor; +} + +Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const +{ + return m_inactiveSelectionForegroundColor; +} + void RenderThemeChromiumLinux::adjustSliderThumbSize(RenderObject* o) const { // These sizes match the sizes in Chromium Win. @@ -122,4 +156,24 @@ double RenderThemeChromiumLinux::caretBlinkIntervalInternal() const return m_caretBlinkInterval; } +void RenderThemeChromiumLinux::setSelectionColors( + unsigned activeBackgroundColor, + unsigned activeForegroundColor, + unsigned inactiveBackgroundColor, + unsigned inactiveForegroundColor) +{ + m_activeSelectionBackgroundColor = activeBackgroundColor; + m_activeSelectionForegroundColor = activeForegroundColor; + m_inactiveSelectionBackgroundColor = inactiveBackgroundColor; + m_inactiveSelectionForegroundColor = inactiveForegroundColor; +} + +void RenderThemeChromiumLinux::setScrollbarColors( + SkColor inactiveColor, SkColor activeColor, SkColor trackColor) +{ + m_thumbInactiveColor = inactiveColor; + m_thumbActiveColor = activeColor; + m_trackColor = trackColor; +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h index e137ad598e..c60dec3266 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h @@ -49,11 +49,28 @@ namespace WebCore { virtual Color inactiveListBoxSelectionBackgroundColor() const; virtual Color inactiveListBoxSelectionForegroundColor() const; + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual void adjustSliderThumbSize(RenderObject*) const; - void setCaretBlinkInterval(double interval); + static void setCaretBlinkInterval(double interval); virtual double caretBlinkIntervalInternal() const; + static void setSelectionColors(unsigned activeBackgroundColor, + unsigned activeForegroundColor, + unsigned inactiveBackgroundColor, + unsigned inactiveForegroundColor); + + static void setScrollbarColors(unsigned inactive_color, + unsigned active_color, + unsigned track_color); + static unsigned thumbInactiveColor() { return m_thumbInactiveColor; } + static unsigned thumbActiveColor() { return m_thumbActiveColor; } + static unsigned trackColor() { return m_trackColor; } + private: RenderThemeChromiumLinux(); virtual ~RenderThemeChromiumLinux(); @@ -61,7 +78,16 @@ namespace WebCore { // A general method asking if any control tinting is supported at all. virtual bool supportsControlTints() const; - double m_caretBlinkInterval; + static double m_caretBlinkInterval; + + static unsigned m_activeSelectionBackgroundColor; + static unsigned m_activeSelectionForegroundColor; + static unsigned m_inactiveSelectionBackgroundColor; + static unsigned m_inactiveSelectionForegroundColor; + + static unsigned m_thumbInactiveColor; + static unsigned m_thumbActiveColor; + static unsigned m_trackColor; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h index 61b5e8f39c..81010382fb 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h @@ -191,7 +191,6 @@ private: mutable HashMap<int, RGBA32> m_systemColorCache; RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; - bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm index bcfcd577c6..03aab1cb5b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm @@ -41,7 +41,7 @@ #import "RenderSlider.h" #import "RenderView.h" #import "SharedBuffer.h" -#import "UserAgentStyleSheets.h" +#import "TimeRanges.h" #import "WebCoreSystemInterface.h" #import "UserAgentStyleSheets.h" #import <Carbon/Carbon.h> @@ -78,7 +78,7 @@ using std::min; // The methods in this file are specific to the Mac OS X platform. -// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. +// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. @interface WebCoreRenderThemeNotificationObserver : NSObject { @@ -96,7 +96,7 @@ using std::min; { [super init]; _theme = theme; - + return self; } @@ -322,7 +322,7 @@ static RGBA32 convertNSColorToColor(NSColor *color) static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); } - // This conversion above can fail if the NSColor in question is an NSPatternColor + // This conversion above can fail if the NSColor in question is an NSPatternColor // (as many system colors are). These colors are actually a repeating pattern // not just a solid color. To work around this we simply draw a 1x1 image of // the color and use that pixel's color. It might be better to use an average of @@ -390,7 +390,7 @@ Color RenderThemeChromiumMac::systemColor(int cssValueId) const { if (m_systemColorCache.contains(cssValueId)) return m_systemColorCache.get(cssValueId); - + Color color; switch (cssValueId) { case CSSValueActiveborder: @@ -504,7 +504,7 @@ bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const Bor { if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) return style->border() != border; - + // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming @@ -518,13 +518,14 @@ bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const Bor void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r) { ControlPart part = o->style()->appearance(); - + #if USE(NEW_THEME) switch (part) { case CheckboxPart: case RadioPart: case PushButtonPart: case SquareButtonPart: + case ListButtonPart: case DefaultButtonPart: case ButtonPart: return RenderTheme::adjustRepaintRect(o, r); @@ -565,13 +566,13 @@ IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& siz FloatRect RenderThemeChromiumMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const { FloatRect partRect(inputRect); - + // Compute an offset between the part renderer and the input renderer FloatSize offsetFromInputRenderer; const RenderObject* renderer = partRenderer; while (renderer && renderer != inputRenderer) { RenderObject* containingRenderer = renderer->container(); - offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer); + offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer, IntPoint()); renderer = containingRenderer; } // If the input renderer was not a container, something went wrong @@ -760,7 +761,7 @@ bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject*, const RenderO LocalCurrentGraphicsContext localContext(paintInfo.context); wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r); - + return false; } @@ -820,7 +821,7 @@ bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject:: inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); paintInfo.context->save(); - + #ifndef BUILDING_ON_TIGER // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect paintInfo.context->clip(inflatedRect); @@ -980,10 +981,10 @@ bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderOb if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) return false; - + paintInfo.context->save(); - paintInfo.context->setFillColor(o->style()->color()); + paintInfo.context->setFillColor(o->style()->color(), o->style()->colorSpace()); paintInfo.context->setStrokeStyle(NoStroke); FloatPoint arrow1[3]; @@ -1012,11 +1013,11 @@ bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderOb // Draw the separator to the left of the arrows paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. paintInfo.context->setStrokeStyle(SolidStroke); - paintInfo.context->setStrokeColor(leftSeparatorColor); + paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), IntPoint(leftEdgeOfSeparator, bounds.bottom())); - paintInfo.context->setStrokeColor(rightSeparatorColor); + paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); @@ -1036,7 +1037,7 @@ void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, Ren style->resetBorder(); style->resetPadding(); - + // Height is locked to auto. style->setHeight(Length(Auto)); @@ -1106,7 +1107,7 @@ void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector*, Render const int minHeight = 15; style->setMinHeight(Length(minHeight, Fixed)); - + style->setLineHeight(RenderStyle::initialLineHeight()); } @@ -1136,6 +1137,9 @@ int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const return sizeForSystemFont(style, menuListSizes()).width(); } +const int trackWidth = 5; +const int trackRadius = 2; + void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { style->setBoxShadow(0); @@ -1143,9 +1147,6 @@ void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderSty bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - static const int trackWidth = 5; - static const int trackRadius = 2; - IntRect bounds = r; float zoomLevel = o->style()->effectiveZoom(); float zoomedTrackWidth = trackWidth * zoomLevel; @@ -1179,7 +1180,7 @@ bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObjec radius, radius); CGContextDrawShading(context, mainShading.get()); paintInfo.context->restore(); - + return false; } @@ -1201,7 +1202,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec LocalCurrentGraphicsContext localContext(paintInfo.context); // Update the various states we respond to. - updateActiveState(sliderThumbCell, o); + updateActiveState(sliderThumbCell, o->parent()); updateEnabledState(sliderThumbCell, o->parent()); updateFocusedState(sliderThumbCell, o->parent()); @@ -1233,7 +1234,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec paintInfo.context->save(); float zoomLevel = o->style()->effectiveZoom(); - + FloatRect unzoomedRect = bounds; if (zoomLevel != 1.0f) { unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); @@ -1251,22 +1252,6 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec return false; } -void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const -{ - static const int sliderThumbWidth = 15; - static const int sliderThumbHeight = 15; - - float zoomLevel = o->style()->effectiveZoom(); - if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { - o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); - o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); - } - -#if ENABLE(VIDEO) - RenderMediaControlsChromium::adjustMediaSliderThumbSize(o); -#endif -} - bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { NSSearchFieldCell* search = this->search(); @@ -1279,7 +1264,7 @@ bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObjec float zoomLevel = o->style()->effectiveZoom(); IntRect unzoomedRect = r; - + if (zoomLevel != 1.0f) { unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); @@ -1328,7 +1313,7 @@ void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const // If the width and height are both specified, then we have nothing to do. if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) return; - + // Use the font size to determine the intrinsic width of the control. setSizeFromFont(style, searchFieldSizes()); } @@ -1345,19 +1330,19 @@ void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, style->setBorderBottomWidth(borderWidth); style->setBorderBottomStyle(INSET); style->setBorderTopWidth(borderWidth); - style->setBorderTopStyle(INSET); - + style->setBorderTopStyle(INSET); + // Override height. style->setHeight(Length(Auto)); setSearchFieldSize(style); - + // Override padding size to match AppKit text positioning. const int padding = 1 * style->effectiveZoom(); style->setPaddingLeft(Length(padding, Fixed)); style->setPaddingRight(Length(padding, Fixed)); style->setPaddingTop(Length(padding, Fixed)); style->setPaddingBottom(Length(padding, Fixed)); - + NSControlSize controlSize = controlSizeForFont(style); setFontFromControlSize(selector, style, controlSize); @@ -1495,7 +1480,7 @@ bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, cons FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - + IntRect unzoomedRect(localBounds); if (zoomLevel != 1.0f) { unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); @@ -1507,12 +1492,28 @@ bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, cons [[search searchButtonCell] drawWithFrame:unzoomedRect inView:FlippedView()]; [[search searchButtonCell] setControlView:nil]; - + paintInfo.context->restore(); return false; } +const int sliderThumbWidth = 15; +const int sliderThumbHeight = 15; + +void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const +{ + float zoomLevel = o->style()->effectiveZoom(); + if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { + o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); + o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); + } + +#if ENABLE(VIDEO) + RenderMediaControlsChromium::adjustMediaSliderThumbSize(o); +#endif +} + #if ENABLE(VIDEO) bool RenderThemeChromiumMac::shouldRenderMediaControlPart(ControlPart part, Element* e) { @@ -1553,7 +1554,7 @@ bool RenderThemeChromiumMac::paintMediaControlsBackground(RenderObject* object, { return RenderMediaControlsChromium::paintMediaControlsPart(MediaTimelineContainer, object, paintInfo, rect); } - + String RenderThemeChromiumMac::extraMediaControlsStyleSheet() { return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); @@ -1568,7 +1569,7 @@ NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const [m_popupButton.get() setUsesItemFromMenu:NO]; [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; } - + return m_popupButton.get(); } @@ -1602,7 +1603,7 @@ NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; } - + return m_sliderThumbHorizontal.get(); } @@ -1615,7 +1616,7 @@ NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; } - + return m_sliderThumbVertical.get(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp index fb42bb7af5..8b3b388ca9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -217,6 +217,22 @@ int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const return 0; } +// These are the default dimensions of radio buttons and checkboxes. +static const int widgetStandardWidth = 13; +static const int widgetStandardHeight = 13; + +// Return a rectangle that has the same center point as |original|, but with a +// size capped at |width| by |height|. +IntRect center(const IntRect& original, int width, int height) +{ + width = std::min(original.width(), width); + height = std::min(original.height(), height); + int x = original.x() + (original.width() - width) / 2; + int y = original.y() + (original.height() - height) / 2; + + return IntRect(x, y, width, height); +} + bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) { static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef(); @@ -231,7 +247,7 @@ bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject: else image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage; - i.context->drawImage(image, rect); + i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth)); return false; } @@ -246,7 +262,7 @@ void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const // querying the theme gives you a larger size that accounts for the higher // DPI. Until our entire engine honors a DPI setting other than 96, we // can't rely on the theme's metrics. - const IntSize size(13, 13); + const IntSize size(widgetStandardHeight, widgetStandardWidth); setSizeIfAuto(style, size); } @@ -263,7 +279,7 @@ bool RenderThemeChromiumSkia::paintRadio(RenderObject* o, const RenderObject::Pa else image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage; - i.context->drawImage(image, rect); + i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth)); return false; } @@ -348,6 +364,15 @@ bool RenderThemeChromiumSkia::paintButton(RenderObject* o, const RenderObject::P return false; } +void RenderThemeChromiumSkia::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + if (style->appearance() == PushButtonPart) { + // Ignore line-height. + style->setLineHeight(RenderStyle::initialLineHeight()); + } +} + + bool RenderThemeChromiumSkia::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) { return true; @@ -358,6 +383,12 @@ bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const RenderObject: return paintTextField(o, i, r); } +void RenderThemeChromiumSkia::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Ignore line-height. + style->setLineHeight(RenderStyle::initialLineHeight()); +} + bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); @@ -372,28 +403,41 @@ void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelecto style->setHeight(Length(cancelButtonSize, Fixed)); } -bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const { - IntRect bounds = r; - ASSERT(o->parent()); - if (!o->parent() || !o->parent()->isBox()) - return false; - - RenderBox* parentRenderBox = toRenderBox(o->parent()); + // Compute an offset between the part renderer and the input renderer. + IntSize offsetFromInputRenderer = -(partRenderer->offsetFromAncestorContainer(inputRenderer)); + // Move the rect into partRenderer's coords. + partRect.move(offsetFromInputRenderer); + // Account for the local drawing offset. + partRect.move(localOffset.x(), localOffset.y()); - IntRect parentBox = parentRenderBox->absoluteContentBox(); + return partRect; +} - // Make sure the scaled button stays square and will fit in its parent's box - bounds.setHeight(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height()))); - bounds.setWidth(bounds.height()); +bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + // Get the renderer of <input> element. + Node* input = cancelButtonObject->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) + return false; + RenderBox* inputRenderBox = toRenderBox(input->renderer()); + IntRect inputContentBox = inputRenderBox->contentBoxRect(); + // Make sure the scaled button stays square and will fit in its parent's box. + int cancelButtonSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), r.height())); + // Calculate cancel button's coordinates relative to the input element. // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will // be one pixel closer to the bottom of the field. This tends to look better with the text. - bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); + IntRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(), + inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2, + cancelButtonSize, cancelButtonSize); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r); static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef(); static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef(); - i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); + paintInfo.context->drawImage(isPressed(cancelButtonObject) ? cancelPressedImage : cancelImage, + cancelButtonObject->style()->colorSpace(), paintingRect); return false; } @@ -414,26 +458,27 @@ void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(CSSStyleSe style->setHeight(Length(magnifierSize, Fixed)); } -bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - IntRect bounds = r; - ASSERT(o->parent()); - if (!o->parent() || !o->parent()->isBox()) + // Get the renderer of <input> element. + Node* input = magnifierObject->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) return false; + RenderBox* inputRenderBox = toRenderBox(input->renderer()); + IntRect inputContentBox = inputRenderBox->contentBoxRect(); - RenderBox* parentRenderBox = toRenderBox(o->parent()); - IntRect parentBox = parentRenderBox->absoluteContentBox(); - - // Make sure the scaled decoration stays square and will fit in its parent's box - bounds.setHeight(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height()))); - bounds.setWidth(bounds.height()); - + // Make sure the scaled decoration stays square and will fit in its parent's box. + int magnifierSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), r.height())); + // Calculate decoration's coordinates relative to the input element. // Center the decoration vertically. Round up though, so if it has to be one pixel off-center, it will // be one pixel closer to the bottom of the field. This tends to look better with the text. - bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); + IntRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(), + inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2, + magnifierSize, magnifierSize); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); - i.context->drawImage(magnifierImage, bounds); + paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect); return false; } @@ -448,28 +493,25 @@ void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(CSSStyleSelect style->setHeight(Length(magnifierHeight, Fixed)); } -bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* magnifierObject, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - IntRect bounds = r; - ASSERT(o->parent()); - if (!o->parent()) - return false; - if (!o->parent() || !o->parent()->isBox()) + // Get the renderer of <input> element. + Node* input = magnifierObject->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) return false; + RenderBox* inputRenderBox = toRenderBox(input->renderer()); + IntRect inputContentBox = inputRenderBox->contentBoxRect(); - RenderBox* parentRenderBox = toRenderBox(o->parent()); - IntRect parentBox = parentRenderBox->absoluteContentBox(); - - // Make sure the scaled decoration will fit in its parent's box - bounds.setHeight(std::min(parentBox.height(), bounds.height())); - bounds.setWidth(std::min(parentBox.width(), static_cast<int>(bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize))); - - // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will - // be one pixel closer to the bottom of the field. This tends to look better with the text. - bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); + // Make sure the scaled decoration will fit in its parent's box. + int magnifierHeight = std::min(inputContentBox.height(), r.height()); + int magnifierWidth = std::min(inputContentBox.width(), static_cast<int>(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize)); + IntRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(), + inputContentBox.y() + (inputContentBox.height() - magnifierHeight + 1) / 2, + magnifierWidth, magnifierHeight); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef(); - i.context->drawImage(magnifierImage, bounds); + paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect); return false; } @@ -690,26 +732,6 @@ int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) cons return menuListInternalPadding(style, BottomPadding); } -int RenderThemeChromiumSkia::buttonInternalPaddingLeft() const -{ - return 3; -} - -int RenderThemeChromiumSkia::buttonInternalPaddingRight() const -{ - return 3; -} - -int RenderThemeChromiumSkia::buttonInternalPaddingTop() const -{ - return 1; -} - -int RenderThemeChromiumSkia::buttonInternalPaddingBottom() const -{ - return 1; -} - #if ENABLE(VIDEO) bool RenderThemeChromiumSkia::shouldRenderMediaControlPart(ControlPart part, Element* e) { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h index 98e3a35571..dc920b1cf2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h @@ -71,11 +71,13 @@ namespace WebCore { virtual void setRadioSize(RenderStyle*) const; virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -121,11 +123,6 @@ namespace WebCore { virtual int popupInternalPaddingTop(RenderStyle*) const; virtual int popupInternalPaddingBottom(RenderStyle*) const; - virtual int buttonInternalPaddingLeft() const; - virtual int buttonInternalPaddingRight() const; - virtual int buttonInternalPaddingTop() const; - virtual int buttonInternalPaddingBottom() const; - #if ENABLE(VIDEO) // Media controls virtual bool shouldRenderMediaControlPart(ControlPart, Element*); @@ -151,6 +148,7 @@ namespace WebCore { private: int menuListInternalPadding(RenderStyle*, int paddingType) const; bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); + IntRect convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp index 4b38d53e74..db31825a0f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -86,7 +86,7 @@ private: return transformMode == KeepTransform ? NoLayer : OpaqueCompositeLayer; } - static TransformMode getTransformMode(const TransformationMatrix& matrix) + static TransformMode getTransformMode(const AffineTransform& matrix) { if (matrix.b() != 0 || matrix.c() != 0) // Skew. return Untransform; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h index 1d68c630c9..48c6c42c20 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h @@ -126,6 +126,7 @@ protected: virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp index 2ea3b8beaf..9e97079386 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp @@ -830,8 +830,8 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject: paintInfo.context->save(); - paintInfo.context->setFillColor(o->style()->color()); - paintInfo.context->setStrokeColor(NoStroke); + paintInfo.context->setFillColor(o->style()->color(), DeviceColorSpace); + paintInfo.context->setStrokeColor(NoStroke, DeviceColorSpace); FloatPoint arrow[3]; arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f); @@ -851,11 +851,11 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject: // Draw the separator to the left of the arrows paintInfo.context->setStrokeThickness(1.0f); paintInfo.context->setStrokeStyle(SolidStroke); - paintInfo.context->setStrokeColor(leftSeparatorColor); + paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), IntPoint(leftEdgeOfSeparator, bounds.bottom())); - paintInfo.context->setStrokeColor(rightSeparatorColor); + paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp index 92bfd03587..52afbd6c05 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp @@ -819,7 +819,7 @@ bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderO static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef(); static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef(); - paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); + paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, o->style()->colorSpace(), bounds); return false; } @@ -868,7 +868,7 @@ bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const Re bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); - paintInfo.context->drawImage(magnifierImage, bounds); + paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds); return false; } @@ -904,7 +904,7 @@ bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const Render bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef(); - paintInfo.context->drawImage(magnifierImage, bounds); + paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds); return false; } @@ -955,6 +955,23 @@ Color RenderThemeWin::systemColor(int cssValueId) const } #if ENABLE(VIDEO) + +bool RenderThemeWin::shouldRenderMediaControlPart(ControlPart part, Element* element) +{ + if (part == MediaToggleClosedCaptionsButtonPart) { + // We rely on QuickTime to render captions so only enable the button for a video element. +#if SAFARI_THEME_VERSION >= 4 + if (!element->hasTagName(videoTag)) + return false; +#else + return false; +#endif + } + + return RenderTheme::shouldRenderMediaControlPart(part, element); +} + + bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); @@ -989,6 +1006,12 @@ bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const RenderObject:: { return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r); } + +bool RenderThemeWin::paintMediaToggleClosedCaptionsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r); +} + #endif } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h index 99c200417c..a9fa5e66ac 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h @@ -125,6 +125,7 @@ public: virtual bool supportsFocusRing(const RenderStyle*) const; #if ENABLE(VIDEO) + virtual bool shouldRenderMediaControlPart(ControlPart, Element*); virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); @@ -132,6 +133,7 @@ public: virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); #endif private: diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWince.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWince.cpp index fb89678b6c..c4aaaad878 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWince.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWince.cpp @@ -28,6 +28,7 @@ #include "CSSValueKeywords.h" #include "Document.h" #include "GraphicsContext.h" +#include "NotImplemented.h" #if ENABLE(VIDEO) #include "HTMLMediaElement.h" #endif @@ -377,12 +378,12 @@ bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const Rende IntRect cancelBounds(IntPoint(x, y), cancelSize); paintInfo.context->save(); paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius); - paintInfo.context->fillRect(cancelBounds, buttonColor); + paintInfo.context->fillRect(cancelBounds, buttonColor, DeviceColorSpace); // Draw the 'x' IntSize xSize(3, 3); IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize); - paintInfo.context->setStrokeColor(Color::white); + paintInfo.context->setStrokeColor(Color::white, DeviceColorSpace); paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size()); paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom())); @@ -489,11 +490,11 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai bool rc = RenderTheme::paintSliderTrack(o, i, r); IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2); i.context->save(); - i.context->setStrokeColor(Color::gray); - i.context->setFillColor(Color::gray); + i.context->setStrokeColor(Color::gray, DeviceColorSpace); + i.context->setFillColor(Color::gray, DeviceColorSpace); i.context->fillRect(r); #if ENABLE(VIDEO) - HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); if (mediaElement) { i.context->setStrokeColor(Color(0, 0xff, 0)); IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.right() - r.x() - 4), (r.y() + r.bottom()) / 2); @@ -501,7 +502,7 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai left = right; } #endif - i.context->setStrokeColor(Color::black); + i.context->setStrokeColor(Color::black, DeviceColorSpace); i.context->drawLine(left, IntPoint(r.right() - 2, left.y())); i.context->restore(); return rc; @@ -511,10 +512,10 @@ bool RenderThemeWince::paintSliderThumb(RenderObject* o, const RenderObject::Pai { bool rc = RenderTheme::paintSliderThumb(o, i, r); i.context->save(); - i.context->setStrokeColor(Color::black); - i.context->setFillColor(Color::black); + i.context->setStrokeColor(Color::black, DeviceColorSpace); + i.context->setFillColor(Color::black, DeviceColorSpace); #if ENABLE(VIDEO) - HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); if (mediaElement) { float pt = (mediaElement->currentTime() - mediaElement->startTime()) / mediaElement->duration(); FloatRect intRect = r; @@ -574,7 +575,7 @@ bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const RenderO bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { bool rc = paintButton(o, paintInfo, r); - HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); bool muted = !mediaElement || mediaElement->muted(); FloatRect imRect = r; imRect.inflate(-2); @@ -604,7 +605,7 @@ bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const RenderObject: paintInfo.context->save(); paintInfo.context->setStrokeColor(Color::black); paintInfo.context->setFillColor(Color::black); - HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); bool paused = !mediaElement || mediaElement->paused(); if (paused) { float width = imRect.width(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp index b7ab191d7d..164a6560ad 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp @@ -36,13 +36,16 @@ #include "HTMLNames.h" #include "InlineTextBox.h" #include "RenderBR.h" +#include "RenderFileUploadControl.h" #include "RenderInline.h" #include "RenderListMarker.h" +#include "RenderPart.h" #include "RenderTableCell.h" #include "RenderView.h" #include "RenderWidget.h" #include "SelectionController.h" #include "TextStream.h" +#include <wtf/UnusedParam.h> #include <wtf/Vector.h> #if ENABLE(SVG) @@ -55,11 +58,19 @@ #include "SVGRenderTreeAsText.h" #endif +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerBacking.h" +#endif + +#if PLATFORM(QT) +#include <QWidget> +#endif + namespace WebCore { using namespace HTMLNames; -static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0); +static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal); #if !ENABLE(SVG) static TextStream &operator<<(TextStream& ts, const IntRect& r) @@ -217,6 +228,9 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) ts << " " << r; if (!(o.isText() && !o.isBR())) { + if (o.isFileUploadControl()) { + ts << " " << quoteAndEscapeNonPrintables(toRenderFileUploadControl(&o)->fileTextValue()); + } if (o.parent() && (o.parent()->style()->color() != o.style()->color())) ts << " [color=" << o.style()->color().name() << "]"; @@ -336,6 +350,24 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) } } +#if PLATFORM(QT) + // Print attributes of embedded QWidgets. E.g. when the WebCore::Widget + // is invisible the QWidget should be invisible too. + if (o.isRenderPart()) { + const RenderPart* part = toRenderPart(const_cast<RenderObject*>(&o)); + if (part->widget() && part->widget()->platformWidget()) { + QWidget* wid = part->widget()->platformWidget(); + + ts << " [QT: "; + ts << "geometry: {" << wid->geometry() << "} "; + ts << "isHidden: " << wid->isHidden() << " "; + ts << "isSelfVisible: " << part->widget()->isSelfVisible() << " "; + ts << "isParentVisible: " << part->widget()->isParentVisible() << " "; + ts << "mask: {" << wid->mask().boundingRect() << "} ] "; + } + } +#endif + return ts; } @@ -363,6 +395,10 @@ void write(TextStream& ts, const RenderObject& o, int indent) write(ts, *toRenderPath(&o), indent); return; } + if (o.isSVGResource()) { + writeSVGResource(ts, o, indent); + return; + } if (o.isSVGContainer()) { writeSVGContainer(ts, o, indent); return; @@ -417,9 +453,15 @@ void write(TextStream& ts, const RenderObject& o, int indent) } } +enum LayerPaintPhase { + LayerPaintPhaseAll = 0, + LayerPaintPhaseBackground = -1, + LayerPaintPhaseForeground = 1 +}; + static void write(TextStream& ts, RenderLayer& l, const IntRect& layerBounds, const IntRect& backgroundClipRect, const IntRect& clipRect, const IntRect& outlineClipRect, - int layerType = 0, int indent = 0) + LayerPaintPhase paintPhase = LayerPaintPhaseAll, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal) { writeIndent(ts, indent); @@ -445,19 +487,28 @@ static void write(TextStream& ts, RenderLayer& l, ts << " scrollHeight " << l.scrollHeight(); } - if (layerType == -1) + if (paintPhase == LayerPaintPhaseBackground) ts << " layerType: background only"; - else if (layerType == 1) + else if (paintPhase == LayerPaintPhaseForeground) ts << " layerType: foreground only"; - + +#if USE(ACCELERATED_COMPOSITING) + if (behavior & RenderAsTextShowCompositedLayers) { + if (l.isComposited()) + ts << " (composited, bounds " << l.backing()->compositedBounds() << ")"; + } +#else + UNUSED_PARAM(behavior); +#endif + ts << "\n"; - if (layerType != -1) + if (paintPhase != LayerPaintPhaseBackground) write(ts, *l.renderer(), indent + 1); } static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l, - const IntRect& paintDirtyRect, int indent) + const IntRect& paintDirtyRect, int indent, RenderAsTextBehavior behavior) { // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; @@ -467,29 +518,46 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye l->updateZOrderLists(); l->updateNormalFlowList(); - bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect, rootLayer); + bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : l->intersectsDamageRect(layerBounds, damageRect, rootLayer); Vector<RenderLayer*>* negList = l->negZOrderList(); - if (shouldPaint && negList && negList->size() > 0) - write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, -1, indent); + bool paintsBackgroundSeparately = negList && negList->size() > 0; + if (shouldPaint && paintsBackgroundSeparately) + write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, LayerPaintPhaseBackground, indent, behavior); if (negList) { + int currIndent = indent; + if (behavior & RenderAsTextShowLayerNesting) { + writeIndent(ts, indent); + ts << " negative z-order list(" << negList->size() << ")\n"; + ++currIndent; + } for (unsigned i = 0; i != negList->size(); ++i) - writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent); + writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, currIndent, behavior); } if (shouldPaint) - write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, negList && negList->size() > 0, indent); - - Vector<RenderLayer*>* normalFlowList = l->normalFlowList(); - if (normalFlowList) { + write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, paintsBackgroundSeparately ? LayerPaintPhaseForeground : LayerPaintPhaseAll, indent, behavior); + + if (Vector<RenderLayer*>* normalFlowList = l->normalFlowList()) { + int currIndent = indent; + if (behavior & RenderAsTextShowLayerNesting) { + writeIndent(ts, indent); + ts << " normal flow list(" << normalFlowList->size() << ")\n"; + ++currIndent; + } for (unsigned i = 0; i != normalFlowList->size(); ++i) - writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, indent); + writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, currIndent, behavior); } - Vector<RenderLayer*>* posList = l->posZOrderList(); - if (posList) { + if (Vector<RenderLayer*>* posList = l->posZOrderList()) { + int currIndent = indent; + if (behavior & RenderAsTextShowLayerNesting) { + writeIndent(ts, indent); + ts << " positive z-order list(" << posList->size() << ")\n"; + ++currIndent; + } for (unsigned i = 0; i != posList->size(); ++i) - writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent); + writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, currIndent, behavior); } } @@ -535,8 +603,11 @@ static void writeSelection(TextStream& ts, const RenderObject* o) << "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().node()) << "\n"; } -String externalRepresentation(RenderObject* o) +String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) { + frame->document()->updateLayout(); + + RenderObject* o = frame->contentRenderer(); if (!o) return String(); @@ -544,20 +615,21 @@ String externalRepresentation(RenderObject* o) #if ENABLE(SVG) writeRenderResources(ts, o->document()); #endif - if (o->view()->frameView()) - o->view()->frameView()->layout(); if (o->hasLayer()) { RenderLayer* l = toRenderBox(o)->layer(); - writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height())); + writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), 0, behavior); writeSelection(ts, o); } return ts.release(); } -static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* parent) +static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* parent, bool& isFirstCounter) { for (RenderObject* child = parent->firstChild(); child; child = child->nextSibling()) { if (child->isCounter()) { + if (!isFirstCounter) + stream << " "; + isFirstCounter = false; String str(toRenderText(child)->text()); stream << str; } @@ -570,12 +642,13 @@ String counterValueForElement(Element* element) RefPtr<Element> elementRef(element); element->document()->updateLayout(); TextStream stream; + bool isFirstCounter = true; // The counter renderers should be children of anonymous children // (i.e., :before or :after pseudo-elements). if (RenderObject* renderer = element->renderer()) { for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { if (child->isAnonymous()) - writeCounterValuesFromChildren(stream, child); + writeCounterValuesFromChildren(stream, child, isFirstCounter); } } return stream.release(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h index 325f109478..13525e7d77 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h @@ -29,11 +29,20 @@ namespace WebCore { class Element; +class Frame; class RenderObject; class String; class TextStream; -String externalRepresentation(RenderObject*); +enum RenderAsTextBehaviorFlags { + RenderAsTextBehaviorNormal = 0, + RenderAsTextShowAllLayers = 1 << 0, // Dump all layers, not just those that would paint. + RenderAsTextShowLayerNesting = 1 << 1, // Annotate the layer lists. + RenderAsTextShowCompositedLayers = 1 << 2 // Show which layers are composited. +}; +typedef unsigned RenderAsTextBehavior; + +String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); void write(TextStream&, const RenderObject&, int indent = 0); // Helper function shared with SVGRenderTreeAsText diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp index 246d0c0b7e..13d6f60d61 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ #include "HTMLNames.h" #include "HTMLVideoElement.h" #include "MediaPlayer.h" +#include "RenderView.h" #if USE(ACCELERATED_COMPOSITING) #include "RenderLayer.h" @@ -49,18 +50,25 @@ using namespace HTMLNames; static const int cDefaultWidth = 300; static const int cDefaultHeight = 150; -RenderVideo::RenderVideo(HTMLMediaElement* video) +RenderVideo::RenderVideo(HTMLVideoElement* video) : RenderMedia(video) { if (video->player()) setIntrinsicSize(video->player()->naturalSize()); else { - // Video in standalone media documents should not use the default 300x150 - // size since they also have audio thrown at them. By setting the intrinsic - // size to 300x1 the video will resize itself in these cases, and audio will - // have the correct height (it needs to be > 0 for controls to render properly). - if (video->ownerDocument() && video->ownerDocument()->isMediaDocument()) + // When the natural size of the video is unavailable, we use the provided + // width and height attributes of the video element as the intrinsic size until + // better values become available. If these attributes are not set, we fall back + // to a default video size (300x150). + if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr)) + setIntrinsicSize(IntSize(video->width(), video->height())); + else if (video->ownerDocument() && video->ownerDocument()->isMediaDocument()) { + // Video in standalone media documents should not use the default 300x150 + // size since they also have audio thrown at them. By setting the intrinsic + // size to 300x1 the video will resize itself in these cases, and audio will + // have the correct height (it needs to be > 0 for controls to render properly). setIntrinsicSize(IntSize(cDefaultWidth, 1)); + } else setIntrinsicSize(IntSize(cDefaultWidth, cDefaultHeight)); } @@ -73,7 +81,15 @@ RenderVideo::~RenderVideo() p->setFrameView(0); } } - + +void RenderVideo::intrinsicSizeChanged() +{ + if (videoElement()->shouldDisplayPosterImage()) + RenderMedia::intrinsicSizeChanged(); + videoSizeChanged(); +} + + void RenderVideo::videoSizeChanged() { if (!player()) @@ -86,41 +102,72 @@ void RenderVideo::videoSizeChanged() } } -IntRect RenderVideo::videoBox() const +void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect) { + RenderMedia::imageChanged(newImage, rect); + + // Cache the image intrinsic size so we can continue to use it to draw the image correctly + // even after we know the video intrisic size but aren't able to draw video frames yet + // (we don't want to scale the poster to the video size). + if (videoElement()->shouldDisplayPosterImage()) + m_cachedImageSize = intrinsicSize(); +} + +IntRect RenderVideo::videoBox() const +{ + if (m_cachedImageSize.isEmpty() && videoElement()->shouldDisplayPosterImage()) + return IntRect(); + + IntSize elementSize; + if (videoElement()->shouldDisplayPosterImage()) + elementSize = m_cachedImageSize; + else + elementSize = intrinsicSize(); + IntRect contentRect = contentBoxRect(); - - if (intrinsicSize().isEmpty() || contentRect.isEmpty()) + if (elementSize.isEmpty() || contentRect.isEmpty()) return IntRect(); - IntRect resultRect = contentRect; - int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width(); + IntRect renderBox = contentRect; + int ratio = renderBox.width() * elementSize.height() - renderBox.height() * elementSize.width(); if (ratio > 0) { - int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().height(); + int newWidth = renderBox.height() * elementSize.width() / elementSize.height(); // Just fill the whole area if the difference is one pixel or less (in both sides) - if (resultRect.width() - newWidth > 2) - resultRect.setWidth(newWidth); - resultRect.move((contentRect.width() - resultRect.width()) / 2, 0); + if (renderBox.width() - newWidth > 2) + renderBox.setWidth(newWidth); + renderBox.move((contentRect.width() - renderBox.width()) / 2, 0); } else if (ratio < 0) { - int newHeight = contentRect.width() * intrinsicSize().height() / intrinsicSize().width(); - if (resultRect.height() - newHeight > 2) - resultRect.setHeight(newHeight); - resultRect.move(0, (contentRect.height() - resultRect.height()) / 2); + int newHeight = renderBox.width() * elementSize.height() / elementSize.width(); + if (renderBox.height() - newHeight > 2) + renderBox.setHeight(newHeight); + renderBox.move(0, (contentRect.height() - renderBox.height()) / 2); } - return resultRect; + + return renderBox; } void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty) { MediaPlayer* mediaPlayer = player(); - if (!mediaPlayer) + bool displayingPoster = videoElement()->shouldDisplayPosterImage(); + + if (displayingPoster && document()->printing() && !view()->printImages()) return; - updatePlayer(); + + if (!displayingPoster) { + if (!mediaPlayer) + return; + updatePlayer(); + } + IntRect rect = videoBox(); if (rect.isEmpty()) return; rect.move(tx, ty); - mediaPlayer->paint(paintInfo.context, rect); + if (displayingPoster) + paintIntoRect(paintInfo.context, rect); + else + mediaPlayer->paint(paintInfo.context, rect); } void RenderVideo::layout() @@ -129,6 +176,12 @@ void RenderVideo::layout() updatePlayer(); } +HTMLVideoElement* RenderVideo::videoElement() const +{ + ASSERT(node()->hasTagName(videoTag)); + return static_cast<HTMLVideoElement*>(node()); +} + void RenderVideo::updateFromElement() { RenderMedia::updateFromElement(); @@ -140,7 +193,7 @@ void RenderVideo::updatePlayer() MediaPlayer* mediaPlayer = player(); if (!mediaPlayer) return; - if (!mediaElement()->inActiveDocument()) { + if (!videoElement()->inActiveDocument()) { mediaPlayer->setVisible(false); return; } @@ -155,40 +208,6 @@ void RenderVideo::updatePlayer() mediaPlayer->setVisible(true); } -bool RenderVideo::isWidthSpecified() const -{ - switch (style()->width().type()) { - case Fixed: - case Percent: - return true; - case Auto: - case Relative: // FIXME: Shouldn't this case return true? It doesn't for images. - case Static: - case Intrinsic: - case MinIntrinsic: - return false; - } - ASSERT(false); - return false; -} - -bool RenderVideo::isHeightSpecified() const -{ - switch (style()->height().type()) { - case Fixed: - case Percent: - return true; - case Auto: - case Relative: // FIXME: Shouldn't this case return true? It doesn't for images. - case Static: - case Intrinsic: - case MinIntrinsic: - return false; - } - ASSERT(false); - return false; -} - int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const { int width; @@ -235,24 +254,9 @@ int RenderVideo::calcAspectRatioHeight() const return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth; } -void RenderVideo::calcPrefWidths() +int RenderVideo::minimumReplacedHeight() const { - ASSERT(prefWidthsDirty()); - - int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight(); - m_maxPrefWidth = calcReplacedWidth(false) + paddingAndBorders; - - if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) - m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0)); - - if (style()->width().isPercent() || style()->height().isPercent() || - style()->maxWidth().isPercent() || style()->maxHeight().isPercent() || - style()->minWidth().isPercent() || style()->minHeight().isPercent()) - m_minPrefWidth = 0; - else - m_minPrefWidth = m_maxPrefWidth; - - setPrefWidthsDirty(false); + return 0; } #if USE(ACCELERATED_COMPOSITING) @@ -271,14 +275,6 @@ void RenderVideo::acceleratedRenderingStateChanged() if (p) p->acceleratedRenderingStateChanged(); } - -GraphicsLayer* RenderVideo::videoGraphicsLayer() const -{ - if (hasLayer() && layer()->isComposited()) - return layer()->backing()->graphicsLayer(); - - return 0; -} #endif // USE(ACCELERATED_COMPOSITING) } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h index 79e5b4e3c4..16c846d290 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,13 +33,11 @@ namespace WebCore { class HTMLMediaElement; -#if USE(ACCELERATED_COMPOSITING) -class GraphicsLayer; -#endif +class HTMLVideoElement; class RenderVideo : public RenderMedia { public: - RenderVideo(HTMLMediaElement*); + RenderVideo(HTMLVideoElement*); virtual ~RenderVideo(); void videoSizeChanged(); @@ -48,13 +46,14 @@ public: #if USE(ACCELERATED_COMPOSITING) bool supportsAcceleratedRendering() const; void acceleratedRenderingStateChanged(); - GraphicsLayer* videoGraphicsLayer() const; #endif private: virtual void updateFromElement(); + inline HTMLVideoElement* videoElement() const; - virtual void intrinsicSizeChanged() { videoSizeChanged(); } + virtual void intrinsicSizeChanged(); + virtual void imageChanged(WrappedImagePtr, const IntRect*); virtual const char* renderName() const { return "RenderVideo"; } @@ -67,16 +66,14 @@ private: virtual int calcReplacedWidth(bool includeMaxWidth = true) const; virtual int calcReplacedHeight() const; - - virtual void calcPrefWidths(); + virtual int minimumReplacedHeight() const; int calcAspectRatioWidth() const; int calcAspectRatioHeight() const; - bool isWidthSpecified() const; - bool isHeightSpecified() const; - void updatePlayer(); + + IntSize m_cachedImageSize; }; inline RenderVideo* toRenderVideo(RenderObject* object) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp index e2b4b045f1..4f76e8010b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp @@ -198,7 +198,7 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int) if (baseColor.alpha() > 0) { paintInfo.context->save(); paintInfo.context->setCompositeOperation(CompositeCopy); - paintInfo.context->fillRect(paintInfo.rect, baseColor); + paintInfo.context->fillRect(paintInfo.rect, baseColor, style()->colorSpace()); paintInfo.context->restore(); } else paintInfo.context->clearRect(paintInfo.rect); @@ -326,7 +326,13 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { RenderSelectionInfo* info = i->second; - selRect.unite(info->rect()); + // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. + IntRect currRect = info->rect(); + if (RenderBoxModelObject* repaintContainer = info->repaintContainer()) { + FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); + currRect = absQuad.enclosingBoundingBox(); + } + selRect.unite(currRect); delete info; } return selRect; @@ -425,7 +431,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e o = o->nextInPreOrder(); } - m_cachedSelectionBounds = IntRect(); + m_layer->clearBlockSelectionGapsBounds(); // Now that the selection state has been updated for the new objects, walk them again and // put them in the new objects list. @@ -438,9 +444,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e RenderBlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb); if (blockInfo) break; - blockInfo = new RenderBlockSelectionInfo(cb); - newSelectedBlocks.set(cb, blockInfo); - m_cachedSelectionBounds.unite(blockInfo->rects()); + newSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); cb = cb->containingBlock(); } } @@ -517,7 +521,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e void RenderView::clearSelection() { - repaintViewRectangle(m_cachedSelectionBounds); + m_layer->repaintBlockSelectionGaps(); setSelection(0, -1, 0, -1, RepaintNewMinusOld); } @@ -537,6 +541,8 @@ void RenderView::updateWidgetPositions() RenderWidgetSet::iterator end = m_widgets.end(); for (RenderWidgetSet::iterator it = m_widgets.begin(); it != end; ++it) (*it)->updateWidgetPosition(); + for (RenderWidgetSet::iterator it = m_widgets.begin(); it != end; ++it) + (*it)->widgetPositionsUpdated(); } void RenderView::addWidget(RenderWidget* o) @@ -648,6 +654,17 @@ void RenderView::pushLayoutState(RenderObject* root) m_layoutState = new (renderArena()) LayoutState(root); } +bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const +{ + RenderObject* o = renderer; + while (o) { + if (o->hasColumns() || o->hasTransform() || o->hasReflection()) + return true; + o = o->container(); + } + return false; +} + void RenderView::updateHitTestResult(HitTestResult& result, const IntPoint& point) { if (result.innerNode()) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.h b/src/3rdparty/webkit/WebCore/rendering/RenderView.h index bc5db9e643..1e007e8af9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderView.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML widget for KDE. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2006 Apple Computer, Inc. * @@ -77,9 +75,11 @@ public: bool printing() const; void setPrintImages(bool enable) { m_printImages = enable; } bool printImages() const { return m_printImages; } - void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_forcedPageBreak = false; } + void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_minimumColumnHeight = 0; m_forcedPageBreak = false; } void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false); + void setMinimumColumnHeight(int height) { m_minimumColumnHeight = height; } int bestTruncatedAt() const { return m_bestTruncatedAt; } + int minimumColumnHeight() const { return m_minimumColumnHeight; } int truncatedAt() const { return m_truncatedAt; } @@ -140,6 +140,8 @@ public: state->destroy(renderArena()); } + bool shouldDisableLayoutStateForSubtree(RenderObject*) const; + // Returns true if layoutState should be used for its cached offset and clip. bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; } LayoutState* layoutState() const { return m_layoutState; } @@ -193,10 +195,9 @@ protected: RenderWidgetSet m_widgets; private: - IntRect m_cachedSelectionBounds; - int m_bestTruncatedAt; int m_truncatorWidth; + int m_minimumColumnHeight; bool m_forcedPageBreak; LayoutState* m_layoutState; unsigned m_layoutStateDisableCount; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp index 9af7137faf..561bead868 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp @@ -23,8 +23,8 @@ #include "config.h" #include "RenderWidget.h" -#include "AnimationController.h" #include "AXObjectCache.h" +#include "AnimationController.h" #include "GraphicsContext.h" #include "HitTestResult.h" #include "RenderView.h" @@ -40,18 +40,65 @@ static HashMap<const Widget*, RenderWidget*>& widgetRendererMap() return *staticWidgetRendererMap; } +static size_t widgetHierarchyUpdateSuspendCount; + +typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap; + +static WidgetToParentMap& widgetNewParentMap() +{ + DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ()); + return map; +} + +void RenderWidget::suspendWidgetHierarchyUpdates() +{ + widgetHierarchyUpdateSuspendCount++; +} + +void RenderWidget::resumeWidgetHierarchyUpdates() +{ + ASSERT(widgetHierarchyUpdateSuspendCount); + if (widgetHierarchyUpdateSuspendCount == 1) { + WidgetToParentMap map = widgetNewParentMap(); + widgetNewParentMap().clear(); + WidgetToParentMap::iterator end = map.end(); + for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) { + Widget* child = it->first.get(); + ScrollView* currentParent = child->parent(); + FrameView* newParent = it->second; + if (newParent != currentParent) { + if (currentParent) + currentParent->removeChild(child); + if (newParent) + newParent->addChild(child); + } + } + } + widgetHierarchyUpdateSuspendCount--; +} + +static void moveWidgetToParentSoon(Widget* child, FrameView* parent) +{ + if (!widgetHierarchyUpdateSuspendCount) { + if (parent) + parent->addChild(child); + else + child->removeFromParent(); + return; + } + widgetNewParentMap().set(child, parent); +} + RenderWidget::RenderWidget(Node* node) : RenderReplaced(node) , m_widget(0) , m_frameView(node->document()->view()) - , m_refCount(0) -{ - view()->addWidget(this); - // Reference counting is used to prevent the widget from being // destroyed while inside the Widget code, which might not be // able to handle that. - ref(); + , m_refCount(1) +{ + view()->addWidget(this); } void RenderWidget::destroy() @@ -62,14 +109,6 @@ void RenderWidget::destroy() // both RenderBox::destroy() and RenderObject::destroy(). // Fix originally made for <rdar://problem/4228818>. - // <rdar://problem/6937089> suggests that node() can be null by the time we call renderArena() - // in the end of this function. One way this might happen is if this function was invoked twice - // in a row, so bail out and turn a crash into an assertion failure in debug builds and a leak - // in release builds. - ASSERT(node()); - if (!node()) - return; - animation()->cancelAnimations(this); if (RenderView* v = view()) @@ -81,12 +120,8 @@ void RenderWidget::destroy() } remove(); - if (m_widget) { - if (m_frameView) - m_frameView->removeChild(m_widget.get()); - widgetRendererMap().remove(m_widget.get()); - } - + setWidget(0); + // removes from override size map if (hasOverrideSize()) setOverrideSize(-1); @@ -100,14 +135,6 @@ void RenderWidget::destroy() destroyLayer(); } - // <rdar://problem/6937089> suggests that node() can be null here. One way this might happen is - // if this function was re-entered (and therefore the null check at the beginning did not fail), - // so bail out and turn a crash into an assertion failure in debug builds and a leak in release - // builds. - ASSERT(node()); - if (!node()) - return; - // Grab the arena from node()->document()->renderArena() before clearing the node pointer. // Clear the node before deref-ing, as this may be deleted when deref is called. RenderArena* arena = renderArena(); @@ -121,39 +148,52 @@ RenderWidget::~RenderWidget() clearWidget(); } -void RenderWidget::setWidgetGeometry(const IntRect& frame) +bool RenderWidget::setWidgetGeometry(const IntRect& frame) { - if (node() && m_widget->frameRect() != frame) { - RenderWidgetProtector protector(this); - RefPtr<Node> protectedNode(node()); - m_widget->setFrameRect(frame); - } + ASSERT(!widgetHierarchyUpdateSuspendCount); + if (!node()) + return false; + + IntRect windowClipRect = m_frameView ? m_frameView->windowClipRectForLayer(enclosingLayer(), true) : IntRect(); + bool clipChanged = m_windowClipRect != windowClipRect; + bool boundsChanged = m_widget->frameRect() != frame; + + if (!boundsChanged && !clipChanged) + return false; + + m_windowClipRect = windowClipRect; + + RenderWidgetProtector protector(this); + RefPtr<Node> protectedNode(node()); + m_widget->setFrameRect(frame); + return boundsChanged; } void RenderWidget::setWidget(PassRefPtr<Widget> widget) { - if (widget != m_widget) { - if (m_widget) { - m_widget->removeFromParent(); - widgetRendererMap().remove(m_widget.get()); - clearWidget(); - } - m_widget = widget; - if (m_widget) { - widgetRendererMap().add(m_widget.get(), this); - // if we've already received a layout, apply the calculated space to the - // widget immediately, but we have to have really been full constructed (with a non-null - // style pointer). - if (style()) { - if (!needsLayout()) - setWidgetGeometry(absoluteContentBox()); - if (style()->visibility() != VISIBLE) - m_widget->hide(); - else - m_widget->show(); - } - m_frameView->addChild(m_widget.get()); + if (widget == m_widget) + return; + + if (m_widget) { + moveWidgetToParentSoon(m_widget.get(), 0); + widgetRendererMap().remove(m_widget.get()); + clearWidget(); + } + m_widget = widget; + if (m_widget) { + widgetRendererMap().add(m_widget.get(), this); + // If we've already received a layout, apply the calculated space to the + // widget immediately, but we have to have really been fully constructed (with a non-null + // style pointer). + if (style()) { + if (!needsLayout()) + setWidgetGeometry(absoluteContentBox()); + if (style()->visibility() != VISIBLE) + m_widget->hide(); + else + m_widget->show(); } + moveWidgetToParentSoon(m_widget.get(), m_frameView); } } @@ -221,19 +261,28 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) } if (m_widget) { - // Move the widget if necessary. We normally move and resize widgets during layout, but sometimes - // widgets can move without layout occurring (most notably when you scroll a document that - // contains fixed positioned elements). - m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop()); - // Tell the widget to paint now. This is the only time the widget is allowed // to paint itself. That way it will composite properly with z-indexed layers. if (m_substituteImage) - paintInfo.context->drawImage(m_substituteImage.get(), m_widget->frameRect()); - else - m_widget->paint(paintInfo.context, paintInfo.rect); + paintInfo.context->drawImage(m_substituteImage.get(), style()->colorSpace(), m_widget->frameRect()); + else { + IntPoint widgetLocation = m_widget->frameRect().location(); + IntPoint paintLocation(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop()); + IntRect paintRect = paintInfo.rect; + + IntSize paintOffset = paintLocation - widgetLocation; + // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer, + // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing. + if (!paintOffset.isZero()) { + paintInfo.context->translate(paintOffset); + paintRect.move(-paintOffset); + } + m_widget->paint(paintInfo.context, paintRect); - if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaints()) { + if (!paintOffset.isZero()) + paintInfo.context->translate(-paintOffset); + } + if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaintsIfNotOverlapped()) { ASSERT(!paintInfo.overlapTestRequests->contains(this)); paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); } @@ -245,7 +294,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) // Paint a partially transparent wash over selected widgets. if (isSelected() && !document()->printing()) { // FIXME: selectionRect() is in absolute, not painting coordinates. - paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor()); + paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor(), style()->colorSpace()); } } @@ -274,15 +323,8 @@ void RenderWidget::updateWidgetPosition() int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); - IntRect newBounds(absPos.x(), absPos.y(), w, h); - IntRect oldBounds(m_widget->frameRect()); - bool boundsChanged = newBounds != oldBounds; - if (boundsChanged) { - RenderWidgetProtector protector(this); - RefPtr<Node> protectedNode(node()); - m_widget->setFrameRect(newBounds); - } - + bool boundsChanged = setWidgetGeometry(IntRect(absPos.x(), absPos.y(), w, h)); + // if the frame bounds got changed, or if view needs layout (possibly indicating // content size is wrong) we have to do a layout to set the right widget size if (m_widget->isFrameView()) { @@ -292,6 +334,13 @@ void RenderWidget::updateWidgetPosition() } } +void RenderWidget::widgetPositionsUpdated() +{ + if (!m_widget) + return; + m_widget->widgetPositionsUpdated(); +} + void RenderWidget::setSelectionState(SelectionState state) { if (selectionState() != state) { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h index 78537fdfa5..e57955600b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h @@ -39,9 +39,14 @@ public: static RenderWidget* find(const Widget*); void updateWidgetPosition(); + void widgetPositionsUpdated(); + IntRect windowClipRect() const { return m_windowClipRect; } void showSubstituteImage(PassRefPtr<Image>); + static void suspendWidgetHierarchyUpdates(); + static void resumeWidgetHierarchyUpdates(); + protected: RenderWidget(Node*); @@ -51,17 +56,17 @@ protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void layout(); + virtual void paint(PaintInfo&, int x, int y); private: virtual bool isWidget() const { return true; } - virtual void paint(PaintInfo&, int x, int y); virtual void destroy(); virtual void setSelectionState(SelectionState); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual void setOverlapTestResult(bool); - void setWidgetGeometry(const IntRect&); + bool setWidgetGeometry(const IntRect&); friend class RenderWidgetProtector; RenderArena* ref() { ++m_refCount; return renderArena(); } @@ -70,6 +75,7 @@ private: RefPtr<Widget> m_widget; RefPtr<Image> m_substituteImage; FrameView* m_frameView; + IntRect m_windowClipRect; int m_refCount; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp index c8e072ea79..23316f7104 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp @@ -21,6 +21,7 @@ #include "RootInlineBox.h" #include "BidiResolver.h" +#include "Chrome.h" #include "ChromeClient.h" #include "Document.h" #include "EllipsisBox.h" diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h index b0b0e15daa..fae0cba0e0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h @@ -1,6 +1,4 @@ /* - * This file is part of the line box implementation for KDE. - * * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -51,8 +49,8 @@ public: void detachEllipsisBox(RenderArena*); - RootInlineBox* nextRootBox() const { return static_cast<RootInlineBox*>(m_nextLine); } - RootInlineBox* prevRootBox() const { return static_cast<RootInlineBox*>(m_prevLine); } + RootInlineBox* nextRootBox() const { return static_cast<RootInlineBox*>(m_nextLineBox); } + RootInlineBox* prevRootBox() const { return static_cast<RootInlineBox*>(m_prevLineBox); } virtual void adjustPosition(int dx, int dy); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp index 900e0baed0..7e856725a5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp @@ -512,9 +512,9 @@ bool SVGChar::isHidden() const return pathData && pathData->hidden; } -TransformationMatrix SVGChar::characterTransform() const +AffineTransform SVGChar::characterTransform() const { - TransformationMatrix ctm; + AffineTransform ctm; // Rotate character around angle, and possibly scale. ctm.translate(x, y); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h index b5b4f3e00d..f0d1fa4b26 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h @@ -24,15 +24,15 @@ #define SVGCharacterLayoutInfo_h #if ENABLE(SVG) +#include "AffineTransform.h" +#include "SVGRenderStyle.h" +#include "SVGTextContentElement.h" + #include <wtf/Assertions.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> -#include <wtf/Vector.h> - -#include "TransformationMatrix.h" #include <wtf/RefCounted.h> -#include "SVGRenderStyle.h" -#include "SVGTextContentElement.h" +#include <wtf/Vector.h> namespace WebCore { @@ -234,7 +234,7 @@ struct SVGChar { // Helper methods bool isHidden() const; - TransformationMatrix characterTransform() const; + AffineTransform characterTransform() const; }; struct SVGInlineBoxCharacterRange { @@ -275,7 +275,7 @@ struct SVGTextChunk { // textLength & lengthAdjust support float textLength; ELengthAdjust lengthAdjust; - TransformationMatrix ctm; + AffineTransform ctm; // status flags bool isVerticalText : 1; @@ -291,15 +291,12 @@ struct SVGTextChunk { struct SVGTextChunkWalkerBase { virtual ~SVGTextChunkWalkerBase() { } - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; // Followings methods are only used for painting text chunks virtual void start(InlineBox*) = 0; virtual void end(InlineBox*) = 0; - - virtual bool setupFill(InlineBox*) = 0; - virtual bool setupStroke(InlineBox*) = 0; }; template<typename CallbackClass> @@ -307,7 +304,7 @@ struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { public: typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, int startOffset, - const TransformationMatrix& chunkCtm, + const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end); @@ -315,27 +312,20 @@ public: typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box); typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box); - typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box); - typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box); - - SVGTextChunkWalker(CallbackClass* object, + SVGTextChunkWalker(CallbackClass* object, SVGTextChunkWalkerCallback walker, SVGTextChunkStartCallback start = 0, - SVGTextChunkEndCallback end = 0, - SVGTextChunkSetupFillCallback fill = 0, - SVGTextChunkSetupStrokeCallback stroke = 0) + SVGTextChunkEndCallback end = 0) : m_object(object) , m_walkerCallback(walker) , m_startCallback(start) , m_endCallback(end) - , m_setupFillCallback(fill) - , m_setupStrokeCallback(stroke) { ASSERT(object); ASSERT(walker); } - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); @@ -358,31 +348,11 @@ public: ASSERT_NOT_REACHED(); } - virtual bool setupFill(InlineBox* box) - { - if (m_setupFillCallback) - return (*m_object.*m_setupFillCallback)(box); - - ASSERT_NOT_REACHED(); - return false; - } - - virtual bool setupStroke(InlineBox* box) - { - if (m_setupStrokeCallback) - return (*m_object.*m_setupStrokeCallback)(box); - - ASSERT_NOT_REACHED(); - return false; - } - private: CallbackClass* m_object; SVGTextChunkWalkerCallback m_walkerCallback; SVGTextChunkStartCallback m_startCallback; SVGTextChunkEndCallback m_endCallback; - SVGTextChunkSetupFillCallback m_setupFillCallback; - SVGTextChunkSetupStrokeCallback m_setupStrokeCallback; }; struct SVGTextChunkLayoutInfo { diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp index d0fa9ae0ca..65aa5a14e1 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp @@ -1,6 +1,4 @@ /** - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2007 Rob Buis <buis@kde.org> * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * @@ -110,9 +108,7 @@ FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int off FloatRect glyphRect(x1, y1, x2 - x1, y2 - y1); // Take per-character transformations into account - TransformationMatrix ctm = svgChar.characterTransform(); - if (!ctm.isIdentity()) - glyphRect = ctm.mapRect(glyphRect); + glyphRect = svgChar.characterTransform().mapRect(glyphRect); return glyphRect; } @@ -128,7 +124,7 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker { { } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { RenderStyle* style = textBox->textRenderer()->style(); @@ -195,7 +191,7 @@ struct SVGInlineTextBoxSelectionRectWalker { { } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { RenderStyle* style = textBox->textRenderer()->style(); @@ -326,7 +322,33 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos) return enclosingIntRect(walkerCallback.selectionRect()); } -void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGPaintServer* activePaintServer) +bool SVGInlineTextBox::chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd) +{ + // NOTE: We ignore SVGInlineTextBox::m_start here because it is always 0. + // Curently SVG doesn't use HTML block-level layout, in which m_start would be set. + + int chunkStart = chunk - textRenderer()->characters(); + ASSERT(0 <= chunkStart); + + selectionStartEnd(selectionStart, selectionEnd); + if (selectionEnd <= chunkStart) + return false; + if (chunkStart + chunkLength <= selectionStart) + return false; + + // Map indices from view-global to chunk-local. + selectionStart -= chunkStart; + selectionEnd -= chunkStart; + // Then clamp with chunk range + if (selectionStart < 0) + selectionStart = 0; + if (chunkLength < selectionEnd) + selectionEnd = chunkLength; + + return selectionStart < selectionEnd; +} + +void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGTextPaintInfo& textPaintInfo) { if (renderer()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline) return; @@ -352,13 +374,13 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t RenderStyle* styleToUse = text->style(isFirstLineStyle()); const Font& font = styleToUse->font(); - TransformationMatrix ctm = svgChar.characterTransform(); + AffineTransform ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) paintInfo.context->concatCTM(ctm); // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection // and marked text. - if (paintInfo.phase != PaintPhaseSelection && !isPrinting) { + if (paintInfo.phase != PaintPhaseSelection && !isPrinting && textPaintInfo.subphase == SVGTextPaintSubphaseBackground) { #if PLATFORM(MAC) // Custom highlighters go behind everything else. if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) @@ -378,28 +400,52 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t } } - // Set a text shadow if we have one. - // FIXME: Support multiple shadow effects. Need more from the CG API before - // we can do this. - bool setShadow = false; - if (styleToUse->textShadow()) { - paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y), - styleToUse->textShadow()->blur, styleToUse->textShadow()->color); - setShadow = true; - } + bool isGlyphPhase = textPaintInfo.subphase == SVGTextPaintSubphaseGlyphFill || textPaintInfo.subphase == SVGTextPaintSubphaseGlyphStroke; + bool isSelectionGlyphPhase = textPaintInfo.subphase == SVGTextPaintSubphaseGlyphFillSelection || textPaintInfo.subphase == SVGTextPaintSubphaseGlyphStrokeSelection; + + if (isGlyphPhase || isSelectionGlyphPhase) { + // Set a text shadow if we have one. + // FIXME: Support multiple shadow effects. Need more from the CG API before + // we can do this. + bool setShadow = false; + if (styleToUse->textShadow()) { + paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y), + styleToUse->textShadow()->blur, styleToUse->textShadow()->color, + styleToUse->colorSpace()); + setShadow = true; + } - IntPoint origin((int) svgChar.x, (int) svgChar.y); - TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x); + IntPoint origin((int) svgChar.x, (int) svgChar.y); + TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x); #if ENABLE(SVG_FONTS) - // SVG Fonts need access to the paint server used to draw the current text chunk. - // They need to be able to call renderPath() on a SVGPaintServer object. - run.setActivePaintServer(activePaintServer); + // SVG Fonts need access to the paint server used to draw the current text chunk. + // They need to be able to call renderPath() on a SVGPaintServer object. + ASSERT(textPaintInfo.activePaintServer); + run.setActivePaintServer(textPaintInfo.activePaintServer); #endif - paintInfo.context->drawText(font, run, origin); + int selectionStart = 0; + int selectionEnd = 0; + bool haveSelectedRange = haveSelection && chunkSelectionStartEnd(chars, length, selectionStart, selectionEnd); + + if (isGlyphPhase) { + if (haveSelectedRange) { + paintInfo.context->drawText(font, run, origin, 0, selectionStart); + paintInfo.context->drawText(font, run, origin, selectionEnd, run.length()); + } else + paintInfo.context->drawText(font, run, origin); + } else { + ASSERT(isSelectionGlyphPhase); + if (haveSelectedRange) + paintInfo.context->drawText(font, run, origin, selectionStart, selectionEnd); + } + + if (setShadow) + paintInfo.context->clearShadow(); + } - if (paintInfo.phase != PaintPhaseSelection) { + if (paintInfo.phase != PaintPhaseSelection && textPaintInfo.subphase == SVGTextPaintSubphaseForeground) { paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false); if (useCustomUnderlines) { @@ -429,9 +475,6 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t } - if (setShadow) - paintInfo.context->clearShadow(); - if (!ctm.isIdentity()) paintInfo.context->concatCTM(ctm.inverse()); } @@ -477,7 +520,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar int adjust = startPos >= boxStartOffset ? boxStartOffset : 0; p->drawHighlightForText(font, svgTextRunForInlineTextBox(textRenderer()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), IntPoint((int) svgChar.x, (int) svgChar.y - font.ascent()), - font.ascent() + font.descent(), color, startPos - adjust, endPos - adjust); + font.ascent() + font.descent(), color, style->colorSpace(), startPos - adjust, endPos - adjust); p->restore(); } @@ -521,7 +564,7 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte context->save(); context->beginPath(); - TransformationMatrix ctm = svgChar.characterTransform(); + AffineTransform ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) context->concatCTM(ctm); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h index 76837ccdfa..596fdf325b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2007 Rob Buis <buis@kde.org> * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * @@ -34,6 +32,22 @@ namespace WebCore { struct SVGChar; struct SVGTextDecorationInfo; + enum SVGTextPaintSubphase { + SVGTextPaintSubphaseBackground, + SVGTextPaintSubphaseGlyphFill, + SVGTextPaintSubphaseGlyphFillSelection, + SVGTextPaintSubphaseGlyphStroke, + SVGTextPaintSubphaseGlyphStrokeSelection, + SVGTextPaintSubphaseForeground + }; + + struct SVGTextPaintInfo { + SVGTextPaintInfo() : activePaintServer(0), subphase(SVGTextPaintSubphaseBackground) {} + + SVGPaintServer* activePaintServer; + SVGTextPaintSubphase subphase; + }; + class SVGInlineTextBox : public InlineTextBox { public: SVGInlineTextBox(RenderObject* obj); @@ -51,7 +65,7 @@ namespace WebCore { virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); // SVGs custom paint text method - void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGPaintServer*); + void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGTextPaintInfo&); // SVGs custom paint selection method void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&); @@ -71,6 +85,7 @@ namespace WebCore { private: friend class RenderSVGInlineText; bool svgCharacterHitsPosition(int x, int y, int& offset) const; + bool chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd); int m_height; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGMarkerData.h b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerData.h new file mode 100644 index 0000000000..5ff29939cc --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerData.h @@ -0,0 +1,134 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; 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 SVGMarkerData_h +#define SVGMarkerData_h + +#if ENABLE(SVG) +#include "FloatConversion.h" +#include "Path.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +class SVGResourceMarker; + +class SVGMarkerData { +public: + enum Type { + Unknown = 0, + Start, + Mid, + End + }; + + SVGMarkerData(const Type& type = Unknown, SVGResourceMarker* marker = 0) + : m_type(type) + , m_marker(marker) + { + } + + FloatPoint origin() const { return m_origin; } + SVGResourceMarker* marker() const { return m_marker; } + + float currentAngle() const + { + FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0]; + FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0]; + + double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width())); + double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width())); + + double angle = 0; + switch (m_type) { + case Start: + angle = outslope; + break; + case Mid: + angle = (inslope + outslope) / 2; + break; + case End: + angle = inslope; + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + return narrowPrecisionToFloat(angle); + } + + void updateTypeAndMarker(const Type& type, SVGResourceMarker* marker) + { + m_type = type; + m_marker = marker; + } + + void updateOutslope(const FloatPoint& point) + { + m_outslopePoints[0] = m_origin; + m_outslopePoints[1] = point; + } + + void updateMarkerDataForPathElement(const PathElement* element) + { + FloatPoint* points = element->points; + + switch (element->type) { + case PathElementAddQuadCurveToPoint: + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) + m_origin = points[1]; + break; + case PathElementAddCurveToPoint: + m_inslopePoints[0] = points[1]; + m_inslopePoints[1] = points[2]; + m_origin = points[2]; + break; + case PathElementMoveToPoint: + m_subpathStart = points[0]; + case PathElementAddLineToPoint: + updateInslope(points[0]); + m_origin = points[0]; + break; + case PathElementCloseSubpath: + updateInslope(points[0]); + m_origin = m_subpathStart; + m_subpathStart = FloatPoint(); + } + } + +private: + void updateInslope(const FloatPoint& point) + { + m_inslopePoints[0] = m_origin; + m_inslopePoints[1] = point; + } + + Type m_type; + SVGResourceMarker* m_marker; + FloatPoint m_origin; + FloatPoint m_subpathStart; + FloatPoint m_inslopePoints[2]; + FloatPoint m_outslopePoints[2]; +}; + +} + +#endif // ENABLE(SVG) +#endif // SVGMarkerData_h diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.cpp new file mode 100644 index 0000000000..3fe513f527 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.cpp @@ -0,0 +1,124 @@ +/* + Copyright (C) Research In Motion Limited 2010. All rights reserved. + 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005, 2008 Rob Buis <buis@kde.org> + 2005, 2007 Eric Seidel <eric@webkit.org> + 2009 Google, 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 + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGMarkerLayoutInfo.h" + +#include "RenderSVGViewportContainer.h" +#include "SVGResourceMarker.h" + +namespace WebCore { + +SVGMarkerLayoutInfo::SVGMarkerLayoutInfo() + : m_midMarker(0) + , m_elementIndex(0) + , m_strokeWidth(0) +{ +} + +SVGMarkerLayoutInfo::~SVGMarkerLayoutInfo() +{ +} + +static inline void processStartAndMidMarkers(void* infoPtr, const PathElement* element) +{ + SVGMarkerLayoutInfo& info = *reinterpret_cast<SVGMarkerLayoutInfo*>(infoPtr); + SVGMarkerData& markerData = info.markerData(); + int& elementIndex = info.elementIndex(); + + // First update the outslope for the previous element + markerData.updateOutslope(element->points[0]); + + // Draw the marker for the previous element + SVGResourceMarker* marker = markerData.marker(); + if (elementIndex > 0 && marker) + info.addLayoutedMarker(marker, markerData.origin(), markerData.currentAngle()); + + // Update our marker data for this element + markerData.updateMarkerDataForPathElement(element); + + // After drawing the start marker, switch to drawing mid markers + if (elementIndex == 1) + markerData.updateTypeAndMarker(SVGMarkerData::Mid, info.midMarker()); + + ++elementIndex; +} + +FloatRect SVGMarkerLayoutInfo::calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path& path) +{ + m_layout.clear(); + m_midMarker = midMarker; + m_strokeWidth = strokeWidth; + m_elementIndex = 0; + m_markerData = SVGMarkerData(SVGMarkerData::Start, startMarker); + path.apply(this, processStartAndMidMarkers); + + if (endMarker) { + m_markerData.updateTypeAndMarker(SVGMarkerData::End, endMarker); + addLayoutedMarker(endMarker, m_markerData.origin(), m_markerData.currentAngle()); + } + + if (m_layout.isEmpty()) + return FloatRect(); + + Vector<MarkerLayout>::iterator it = m_layout.begin(); + Vector<MarkerLayout>::iterator end = m_layout.end(); + + FloatRect bounds; + for (; it != end; ++it) { + MarkerLayout& layout = *it; + + RenderSVGViewportContainer* markerContent = layout.marker->renderer(); + ASSERT(markerContent); + + bounds.unite(markerContent->markerBoundaries(layout.matrix)); + } + + return bounds; +} + +void SVGMarkerLayoutInfo::drawMarkers(RenderObject::PaintInfo& paintInfo) +{ + if (m_layout.isEmpty()) + return; + + Vector<MarkerLayout>::iterator it = m_layout.begin(); + Vector<MarkerLayout>::iterator end = m_layout.end(); + + for (; it != end; ++it) { + MarkerLayout& layout = *it; + layout.marker->draw(paintInfo, layout.matrix); + } +} + +void SVGMarkerLayoutInfo::addLayoutedMarker(SVGResourceMarker* marker, const FloatPoint& origin, float angle) +{ + ASSERT(marker); + m_layout.append(MarkerLayout(marker, marker->markerTransformation(origin, angle, m_strokeWidth))); +} + +} + +#endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.h b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.h new file mode 100644 index 0000000000..517c993eb6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/SVGMarkerLayoutInfo.h @@ -0,0 +1,74 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; 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 SVGMarkerLayoutInfo_h +#define SVGMarkerLayoutInfo_h + +#if ENABLE(SVG) +#include "RenderObject.h" +#include "SVGMarkerData.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class Path; +class SVGResourceMarker; + +struct MarkerLayout { + MarkerLayout(SVGResourceMarker* markerObj = 0, AffineTransform matrixObj = AffineTransform()) + : marker(markerObj) + , matrix(matrixObj) + { + ASSERT(marker); + } + + SVGResourceMarker* marker; + AffineTransform matrix; +}; + +class SVGMarkerLayoutInfo : public Noncopyable { +public: + SVGMarkerLayoutInfo(); + ~SVGMarkerLayoutInfo(); + + FloatRect calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path&); + void drawMarkers(RenderObject::PaintInfo&); + + // Used by static inline helper functions in SVGMarkerLayoutInfo.cpp + SVGMarkerData& markerData() { return m_markerData; } + SVGResourceMarker* midMarker() const { return m_midMarker; } + int& elementIndex() { return m_elementIndex; } + void addLayoutedMarker(SVGResourceMarker*, const FloatPoint& origin, float angle); + +private: + SVGResourceMarker* m_midMarker; + + // Used while layouting markers + int m_elementIndex; + SVGMarkerData m_markerData; + float m_strokeWidth; + + // Holds the final computed result + Vector<MarkerLayout> m_layout; +}; + +} + +#endif // ENABLE(SVG) +#endif // SVGMarkerLayoutInfo_h diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp index ea087f9031..284a9da7d0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp @@ -2,7 +2,9 @@ * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * (C) 2007 Eric Seidel <eric@webkit.org> - * Copyright (C) 2009 Google, Inc. All rights reserved. + * (C) 2009 Google, Inc. All rights reserved. + * (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2009-2010. 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 @@ -26,21 +28,27 @@ #if ENABLE(SVG) #include "SVGRenderSupport.h" +#include "AffineTransform.h" +#include "Document.h" #include "ImageBuffer.h" #include "RenderObject.h" #include "RenderSVGContainer.h" +#include "RenderSVGResource.h" +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceMasker.h" #include "RenderView.h" -#include "SVGResourceClipper.h" #include "SVGResourceFilter.h" -#include "SVGResourceMasker.h" #include "SVGStyledElement.h" #include "SVGURIReference.h" #include "TransformState.h" -#include "TransformationMatrix.h" #include <wtf/UnusedParam.h> namespace WebCore { +SVGRenderBase::~SVGRenderBase() +{ +} + IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer) { // Return early for any cases where we don't actually paint @@ -56,6 +64,8 @@ IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, Rende void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) { + object->style()->svgStyle()->inflateForShadow(repaintRect); + // Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent repaintRect = object->localToParentTransform().mapRect(repaintRect); object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed); @@ -64,12 +74,12 @@ void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelOb void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) { ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree. - ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. + ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless. transformState.applyTransform(object->localToParentTransform()); object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); } -void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter) +bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter) { #if !ENABLE(FILTERS) UNUSED_PARAM(filter); @@ -90,12 +100,15 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject // Setup transparency layers before setting up filters! float opacity = style->opacity(); if (opacity < 1.0f) { - paintInfo.context->clip(enclosingIntRect(boundingBox)); + paintInfo.context->clip(repaintRect); paintInfo.context->beginTransparencyLayer(opacity); } - if (ShadowData* shadow = svgStyle->shadow()) - paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color); + if (ShadowData* shadow = svgStyle->shadow()) { + paintInfo.context->clip(repaintRect); + paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color, style->colorSpace()); + paintInfo.context->beginTransparencyLayer(1.0f); + } #if ENABLE(FILTERS) AtomicString filterId(svgStyle->filter()); @@ -107,7 +120,7 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject Document* document = object->document(); #if ENABLE(FILTERS) - SVGResourceFilter* newFilter = getFilterById(document, filterId); + SVGResourceFilter* newFilter = getFilterById(document, filterId, object); if (newFilter == rootFilter) { // Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>. // The filter is NOT meant to be applied twice in that case! @@ -117,28 +130,27 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject filter = newFilter; #endif - SVGResourceClipper* clipper = getClipperById(document, clipperId); - SVGResourceMasker* masker = getMaskerById(document, maskerId); + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, maskerId)) { + if (!masker->applyResource(object, paintInfo.context)) + return false; + } else if (!maskerId.isEmpty()) + svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); + + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, clipperId)) + clipper->applyResource(object, paintInfo.context); + else if (!clipperId.isEmpty()) + svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement); #if ENABLE(FILTERS) if (filter) { filter->addClient(styledElement); - filter->prepareFilter(paintInfo.context, object); + if (!filter->prepareFilter(paintInfo.context, object)) + return false; } else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif - if (clipper) { - clipper->addClient(styledElement); - clipper->applyClip(paintInfo.context, boundingBox); - } else if (!clipperId.isEmpty()) - svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement); - - if (masker) { - masker->addClient(styledElement); - masker->applyMask(paintInfo.context, boundingBox); - } else if (!maskerId.isEmpty()) - svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); + return true; } void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext) @@ -163,6 +175,11 @@ void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::P float opacity = style->opacity(); if (opacity < 1.0f) paintInfo.context->endTransparencyLayer(); + + // This needs to be done separately from opacity, because if both properties are set, + // then the transparency layers are nested. + if (style->svgStyle()->shadow()) + paintInfo.context->endTransparencyLayer(); } void renderSubtreeToImage(ImageBuffer* image, RenderObject* item) @@ -218,19 +235,81 @@ FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* contain return boundingBox; } -FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) +void SVGRenderBase::layoutChildren(RenderObject* start, bool selfNeedsLayout) +{ + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + // Only force our kids to layout if we're being asked to relayout as a result of a parent changing + // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed + // that's a possible future optimization using LayoutState + // http://bugs.webkit.org/show_bug.cgi?id=15391 + bool needsLayout = selfNeedsLayout; + if (!needsLayout) { + if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) { + if (element->isStyled()) + needsLayout = static_cast<SVGStyledElement*>(element)->hasRelativeValues(); + } + } + + if (needsLayout) + child->setNeedsLayout(true, false); + + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); + } +} + +bool SVGRenderBase::isOverflowHidden(const RenderObject* object) +{ + // SVG doesn't support independent x/y overflow + ASSERT(object->style()->overflowX() == object->style()->overflowY()); + + // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle + ASSERT(object->style()->overflowX() != OSCROLL); + + // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. + ASSERT(!object->isRoot()); + + return object->style()->overflowX() == OHIDDEN; +} + +FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) const { #if ENABLE(FILTERS) - SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter()); + SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter(), object); if (filter) - return filter->filterBoundingBox(); + return filter->filterBoundingBox(object->objectBoundingBox()); #else UNUSED_PARAM(object); #endif return FloatRect(); } -void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform) +FloatRect SVGRenderBase::clipperBoundingBoxForRenderer(const RenderObject* object) const +{ + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object->document(), object->style()->svgStyle()->clipPath())) + return clipper->resourceBoundingBox(object->objectBoundingBox()); + + return FloatRect(); +} + +FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object) const +{ + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object->document(), object->style()->svgStyle()->maskElement())) + return masker->resourceBoundingBox(object->objectBoundingBox()); + + return FloatRect(); +} + +void SVGRenderBase::deregisterFromResources(RenderObject* object) +{ + // We only have the renderer for masker and clipper at the moment. + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object->document(), object->style()->svgStyle()->maskElement())) + masker->invalidateClient(object); + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object->document(), object->style()->svgStyle()->clipPath())) + clipper->invalidateClient(object); +} + +void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const AffineTransform& localToAncestorTransform) { if (localToAncestorTransform.isIdentity()) return; @@ -239,6 +318,16 @@ void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const Transfo paintInfo.rect = localToAncestorTransform.inverse().mapRect(paintInfo.rect); } -} // namespace WebCore +const RenderObject* findTextRootObject(const RenderObject* start) +{ + while (start && !start->isSVGText()) + start = start->parent(); + ASSERT(start); + ASSERT(start->isSVGText()); -#endif // ENABLE(SVG) + return start; +} + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h index da2bf5910c..7170855e37 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h @@ -26,46 +26,67 @@ #if ENABLE(SVG) #include "RenderObject.h" +#include "SVGElement.h" +#include "SVGStyledElement.h" namespace WebCore { - class SVGResourceFilter; - class ImageBuffer; +class SVGResourceFilter; +class ImageBuffer; - // SVGRendererBase is an abstract base class which all SVG renderers inherit - // from in order to share SVG renderer code. - // FIXME: This code can all move into RenderSVGModelObject once - // all SVG renderers inherit from RenderSVGModelObject. - class SVGRenderBase { - public: - // FIXME: These are only public for SVGRootInlineBox. - // It's unclear if these should be exposed or not. SVGRootInlineBox may - // pass the wrong RenderObject* and boundingBox to these functions. - static void prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0); - static void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, SVGResourceFilter*&, GraphicsContext* savedContext); +// SVGRendererBase is an abstract base class which all SVG renderers inherit +// from in order to share SVG renderer code. +// FIXME: This code can all move into RenderSVGModelObject once +// all SVG renderers inherit from RenderSVGModelObject. +class SVGRenderBase { +public: + virtual ~SVGRenderBase(); - protected: - static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer); - static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed); + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } - static void mapLocalToContainer(const RenderObject*, RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&); + // FIXME: These are only public for SVGRootInlineBox. + // It's unclear if these should be exposed or not. SVGRootInlineBox may + // pass the wrong RenderObject* and boundingBox to these functions. + static bool prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0); + static void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, SVGResourceFilter*&, GraphicsContext* savedContext); - // Used to share the "walk all the children" logic between objectBoundingBox - // and repaintRectInLocalCoordinates in RenderSVGRoot and RenderSVGContainer - static FloatRect computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent); + // Layout all children of the passed render object + static void layoutChildren(RenderObject*, bool selfNeedsLayout); - // returns the filter bounding box (or the empty rect if no filter) in local coordinates - static FloatRect filterBoundingBoxForRenderer(const RenderObject*); - }; + // Helper function determining wheter overflow is hidden + static bool isOverflowHidden(const RenderObject*); - // FIXME: This should move to RenderObject or PaintInfo - // Used for transforming the GraphicsContext and damage rect before passing PaintInfo to child renderers. - void applyTransformToPaintInfo(RenderObject::PaintInfo&, const TransformationMatrix& localToChildTransform); + virtual FloatRect strokeBoundingBox() const { return FloatRect(); } + virtual FloatRect markerBoundingBox() const { return FloatRect(); } - // This offers a way to render parts of a WebKit rendering tree into a ImageBuffer. - void renderSubtreeToImage(ImageBuffer*, RenderObject*); + // returns the bounding box of filter, clipper, marker and masker (or the empty rect if no filter) in local coordinates + FloatRect filterBoundingBoxForRenderer(const RenderObject*) const; + FloatRect clipperBoundingBoxForRenderer(const RenderObject*) const; + FloatRect maskerBoundingBoxForRenderer(const RenderObject*) const; - void clampImageBufferSizeToViewport(FrameView*, IntSize& imageBufferSize); +protected: + static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer); + static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed); + + static void mapLocalToContainer(const RenderObject*, RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&); + + // Used to share the "walk all the children" logic between objectBoundingBox + // and repaintRectInLocalCoordinates in RenderSVGRoot and RenderSVGContainer + static FloatRect computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent); + + static void deregisterFromResources(RenderObject*); +}; + +// FIXME: This should move to RenderObject or PaintInfo +// Used for transforming the GraphicsContext and damage rect before passing PaintInfo to child renderers. +void applyTransformToPaintInfo(RenderObject::PaintInfo&, const AffineTransform& localToChildTransform); + +// This offers a way to render parts of a WebKit rendering tree into a ImageBuffer. +void renderSubtreeToImage(ImageBuffer*, RenderObject*); + +void clampImageBufferSizeToViewport(FrameView*, IntSize& imageBufferSize); + +const RenderObject* findTextRootObject(const RenderObject* start); } // namespace WebCore #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp index 28e506ad90..5d70505f57 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -34,10 +34,13 @@ #include "HTMLNames.h" #include "InlineTextBox.h" #include "NodeRenderStyle.h" +#include "Path.h" #include "RenderImage.h" #include "RenderPath.h" #include "RenderSVGContainer.h" #include "RenderSVGInlineText.h" +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceMasker.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" #include "RenderTreeAsText.h" @@ -46,7 +49,6 @@ #include "SVGPaintServerGradient.h" #include "SVGPaintServerPattern.h" #include "SVGPaintServerSolid.h" -#include "SVGResourceClipper.h" #include "SVGRootInlineBox.h" #include "SVGStyledElement.h" #include <math.h> @@ -179,7 +181,7 @@ TextStream& operator<<(TextStream& ts, const FloatSize& s) return ts; } -TextStream& operator<<(TextStream& ts, const TransformationMatrix& transform) +TextStream& operator<<(TextStream& ts, const AffineTransform& transform) { if (transform.isIdentity()) ts << "identity"; @@ -195,6 +197,37 @@ TextStream& operator<<(TextStream& ts, const TransformationMatrix& transform) return ts; } +static TextStream& operator<<(TextStream& ts, const WindRule rule) +{ + switch (rule) { + case RULE_NONZERO: + ts << "NON-ZERO"; + break; + case RULE_EVENODD: + ts << "EVEN-ODD"; + break; + } + + return ts; +} + +static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType) +{ + switch (unitType) { + case SVGUnitTypes::SVG_UNIT_TYPE_UNKNOWN: + ts << "unknown"; + break; + case SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE: + ts << "userSpaceOnUse"; + break; + case SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX: + ts << "objectBoundingBox"; + break; + } + + return ts; +} + TextStream& operator<<(TextStream& ts, const Color& c) { return ts << c.name(); @@ -298,10 +331,9 @@ static void writeStyle(TextStream& ts, const RenderObject& object) writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO); ts << "}]"; } + writeIfNotDefault(ts, "clip rule", svgStyle->clipRule(), RULE_NONZERO); } - if (!svgStyle->clipPath().isEmpty()) - writeNameAndQuotedValue(ts, "clip path", svgStyle->clipPath()); writeIfNotEmpty(ts, "start marker", svgStyle->startMarker()); writeIfNotEmpty(ts, "middle marker", svgStyle->midMarker()); writeIfNotEmpty(ts, "end marker", svgStyle->endMarker()); @@ -310,7 +342,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object) static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object) { - ts << " " << object.absoluteTransform().mapRect(object.repaintRectInLocalCoordinates()); + ts << " " << const_cast<RenderObject&>(object).absoluteClippedOverflowRect(); writeStyle(ts, object); return ts; } @@ -464,11 +496,37 @@ static void writeChildren(TextStream& ts, const RenderObject& object, int indent write(ts, *child, indent + 1); } +void writeSVGResource(TextStream& ts, const RenderObject& object, int indent) +{ + writeStandardPrefix(ts, object, indent); + + Element* element = static_cast<Element*>(object.node()); + const AtomicString& id = element->getIDAttribute(); + writeNameAndQuotedValue(ts, "id", id); + + RenderSVGResource* resource = const_cast<RenderObject&>(object).toRenderSVGResource(); + if (resource->resourceType() == MaskerResourceType) { + RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource); + ASSERT(masker); + writeNameValuePair(ts, "maskUnits", masker->maskUnits()); + writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits()); + } else if (resource->resourceType() == ClipperResourceType) { + RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource); + ASSERT(clipper); + writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits()); + } + + // FIXME: Handle other RenderSVGResource* classes here, after converting them from SVGResource*. + ts << "\n"; + writeChildren(ts, object, indent); +} + void writeSVGContainer(TextStream& ts, const RenderObject& container, int indent) { writeStandardPrefix(ts, container, indent); writePositionAndStyle(ts, container); ts << "\n"; + writeResources(ts, container, indent); writeChildren(ts, container, indent); } @@ -484,6 +542,7 @@ void writeSVGText(TextStream& ts, const RenderBlock& text, int indent) writeStandardPrefix(ts, text, indent); writeRenderSVGTextBox(ts, text); ts << "\n"; + writeResources(ts, text, indent); writeChildren(ts, text, indent); } @@ -493,20 +552,51 @@ void writeSVGInlineText(TextStream& ts, const RenderText& text, int indent) // Why not just linesBoundingBox()? ts << " " << FloatRect(text.firstRunOrigin(), text.linesBoundingBox().size()) << "\n"; + writeResources(ts, text, indent); writeSVGInlineTextBoxes(ts, text, indent); } +void writeSVGImage(TextStream& ts, const RenderImage& image, int indent) +{ + writeStandardPrefix(ts, image, indent); + writePositionAndStyle(ts, image); + ts << "\n"; + writeResources(ts, image, indent); +} + void write(TextStream& ts, const RenderPath& path, int indent) { writeStandardPrefix(ts, path, indent); ts << path << "\n"; + writeResources(ts, path, indent); } -void writeSVGImage(TextStream& ts, const RenderImage& image, int indent) +void writeResources(TextStream& ts, const RenderObject& object, int indent) { - writeStandardPrefix(ts, image, indent); - writePositionAndStyle(ts, image); - ts << "\n"; + const RenderStyle* style = object.style(); + const SVGRenderStyle* svgStyle = style->svgStyle(); + + if (!svgStyle->maskElement().isEmpty()) { + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object.document(), svgStyle->maskElement())) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "masker", svgStyle->maskElement()); + ts << " "; + writeStandardPrefix(ts, *masker, 0); + ts << " " << masker->resourceBoundingBox(object.objectBoundingBox()) << "\n"; + } + } + if (!svgStyle->clipPath().isEmpty()) { + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object.document(), svgStyle->clipPath())) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "clipPath", svgStyle->clipPath()); + ts << " "; + writeStandardPrefix(ts, *clipper, 0); + ts << " " << clipper->resourceBoundingBox(object.objectBoundingBox()) << "\n"; + } + } + // FIXME: Handle other RenderSVGResource* classes here, after converting them from SVGResource*. } void writeRenderResources(TextStream& ts, Node* parent) @@ -521,11 +611,11 @@ void writeRenderResources(TextStream& ts, Node* parent) continue; SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement); - RefPtr<SVGResource> resource(styled->canvasResource()); + RefPtr<SVGResource> resource(styled->canvasResource(node->renderer())); if (!resource) continue; - String elementId = svgElement->getAttribute(HTMLNames::idAttr); + String elementId = svgElement->getAttribute(svgElement->idAttributeName()); // FIXME: These names are lies! if (resource->isPaintServer()) { RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h index bee4f36fbe..905652b279 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h @@ -45,20 +45,23 @@ namespace WebCore { class RenderPath; class RenderSVGRoot; class RenderText; - class TransformationMatrix; + class AffineTransform; + class SVGUnitTypes; // functions used by the main RenderTreeAsText code void write(TextStream&, const RenderPath&, int indent); void write(TextStream&, const RenderSVGRoot&, int indent); +void writeSVGResource(TextStream&, const RenderObject&, int indent); void writeSVGContainer(TextStream&, const RenderObject&, int indent); void writeSVGImage(TextStream&, const RenderImage&, int indent); void writeSVGInlineText(TextStream&, const RenderText&, int indent); void writeSVGText(TextStream&, const RenderBlock&, int indent); +void writeResources(TextStream&, const RenderObject&, int indent); void writeRenderResources(TextStream&, Node* parent); // helper operators defined used in various classes to dump the render tree. -TextStream& operator<<(TextStream&, const TransformationMatrix&); +TextStream& operator<<(TextStream&, const AffineTransform&); TextStream& operator<<(TextStream&, const IntRect&); TextStream& operator<<(TextStream&, const Color&); TextStream& operator<<(TextStream&, const IntPoint&); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp index 58297428da..03b9db4a7a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp @@ -363,6 +363,13 @@ struct SVGRootInlineBoxPaintWalker { ASSERT(!m_chunkStarted); } + bool mayHaveSelection(SVGInlineTextBox* box) const + { + int selectionStart = 0, selectionEnd = 0; + box->selectionStartEnd(selectionStart, selectionEnd); + return selectionStart < selectionEnd; + } + void teardownFillPaintServer() { if (!m_fillPaintServer) @@ -429,7 +436,13 @@ struct SVGRootInlineBoxPaintWalker { m_paintInfo.rect = m_savedInfo.rect; } - bool chunkSetupFillCallback(InlineBox* box) + bool setupBackground(SVGInlineTextBox* /*box*/) + { + m_textPaintInfo.subphase = SVGTextPaintSubphaseBackground; + return true; + } + + bool setupFill(SVGInlineTextBox* box) { InlineFlowBox* flowBox = box->parent(); @@ -440,6 +453,7 @@ struct SVGRootInlineBoxPaintWalker { ASSERT(!m_strokePaintServer); teardownFillPaintServer(); + m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFill; m_fillPaintServer = SVGPaintServer::fillPaintServer(object->style(), object); if (m_fillPaintServer) { m_fillPaintServer->setup(m_paintInfo.context, object, ApplyToFillTargetType, true); @@ -450,7 +464,35 @@ struct SVGRootInlineBoxPaintWalker { return false; } - bool chunkSetupStrokeCallback(InlineBox* box) + bool setupFillSelection(SVGInlineTextBox* box) + { + InlineFlowBox* flowBox = box->parent(); + + // Setup fill paint server + RenderObject* object = flowBox->renderer(); + ASSERT(object); + RenderStyle* style = object->getCachedPseudoStyle(SELECTION); + if (!style) + style = object->style(); + + ASSERT(!m_strokePaintServer); + teardownFillPaintServer(); + + if (!mayHaveSelection(box)) + return false; + + m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFillSelection; + m_fillPaintServer = SVGPaintServer::fillPaintServer(style, object); + if (m_fillPaintServer) { + m_fillPaintServer->setup(m_paintInfo.context, object, style, ApplyToFillTargetType, true); + m_fillPaintServerObject = object; + return true; + } + + return false; + } + + bool setupStroke(SVGInlineTextBox* box) { InlineFlowBox* flowBox = box->parent(); @@ -462,6 +504,7 @@ struct SVGRootInlineBoxPaintWalker { teardownFillPaintServer(); teardownStrokePaintServer(); + m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStroke; m_strokePaintServer = SVGPaintServer::strokePaintServer(object->style(), object); if (m_strokePaintServer) { @@ -473,9 +516,88 @@ struct SVGRootInlineBoxPaintWalker { return false; } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, + bool setupStrokeSelection(SVGInlineTextBox* box) + { + InlineFlowBox* flowBox = box->parent(); + + // Setup stroke paint server + RenderObject* object = flowBox->renderer(); + ASSERT(object); + RenderStyle* style = object->getCachedPseudoStyle(SELECTION); + if (!style) + style = object->style(); + + // If we're both stroked & filled, teardown fill paint server before stroking. + teardownFillPaintServer(); + teardownStrokePaintServer(); + + if (!mayHaveSelection(box)) + return false; + + m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStrokeSelection; + m_strokePaintServer = SVGPaintServer::strokePaintServer(style, object); + if (m_strokePaintServer) { + m_strokePaintServer->setup(m_paintInfo.context, object, style, ApplyToStrokeTargetType, true); + m_strokePaintServerObject = object; + return true; + } + + return false; + } + + bool setupForeground(SVGInlineTextBox* /*box*/) + { + teardownFillPaintServer(); + teardownStrokePaintServer(); + + m_textPaintInfo.subphase = SVGTextPaintSubphaseForeground; + + return true; + } + + SVGPaintServer* activePaintServer() const + { + switch (m_textPaintInfo.subphase) { + case SVGTextPaintSubphaseGlyphFill: + case SVGTextPaintSubphaseGlyphFillSelection: + ASSERT(m_fillPaintServer); + return m_fillPaintServer; + case SVGTextPaintSubphaseGlyphStroke: + case SVGTextPaintSubphaseGlyphStrokeSelection: + ASSERT(m_strokePaintServer); + return m_strokePaintServer; + case SVGTextPaintSubphaseBackground: + case SVGTextPaintSubphaseForeground: + default: + return 0; + } + } + + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { + if (setupBackground(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + + if (setupFill(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + + if (setupFillSelection(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + + if (setupStroke(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + + if (setupStrokeSelection(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + + if (setupForeground(textBox)) + paintChunk(textBox, startOffset, chunkCtm, start, end); + } + + void paintChunk(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) + { RenderText* text = textBox->textRenderer(); ASSERT(text); @@ -523,12 +645,8 @@ struct SVGRootInlineBoxPaintWalker { textBox->paintDecoration(OVERLINE, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info); // Paint text - SVGPaintServer* activePaintServer = m_fillPaintServer; - if (!activePaintServer) - activePaintServer = m_strokePaintServer; - - ASSERT(activePaintServer); - textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, activePaintServer); + m_textPaintInfo.activePaintServer = activePaintServer(); + textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, m_textPaintInfo); // Paint decorations, that have to be drawn afterwards if (textDecorations & LINE_THROUGH && textWidth != 0.0f) @@ -561,6 +679,8 @@ private: int m_tx; int m_ty; + + SVGTextPaintInfo m_textPaintInfo; }; void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) @@ -575,18 +695,16 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) FloatRect boundingBox(tx + x(), ty + y(), width(), height()); // Initialize text rendering - SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter); - - // Render text, chunk-by-chunk - SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty); - SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback, - &SVGRootInlineBoxPaintWalker::chunkPortionCallback, - &SVGRootInlineBoxPaintWalker::chunkStartCallback, - &SVGRootInlineBoxPaintWalker::chunkEndCallback, - &SVGRootInlineBoxPaintWalker::chunkSetupFillCallback, - &SVGRootInlineBoxPaintWalker::chunkSetupStrokeCallback); - - walkTextChunks(&walker); + if (SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter)) { + // Render text, chunk-by-chunk + SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty); + SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback, + &SVGRootInlineBoxPaintWalker::chunkPortionCallback, + &SVGRootInlineBoxPaintWalker::chunkStartCallback, + &SVGRootInlineBoxPaintWalker::chunkEndCallback); + + walkTextChunks(&walker); + } // Finalize text rendering SVGRenderBase::finishRenderSVGContent(renderer(), paintInfo, filter, savedInfo.context); @@ -831,9 +949,8 @@ static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk) SVGChar& firstChar = *(chunk.start); // Assure we apply the chunk scaling in the right origin - TransformationMatrix newChunkCtm; - newChunkCtm.translate(firstChar.x, firstChar.y); - newChunkCtm = chunk.ctm * newChunkCtm; + AffineTransform newChunkCtm(chunk.ctm); + newChunkCtm.translateRight(firstChar.x, firstChar.y); newChunkCtm.translate(-firstChar.x, -firstChar.y); chunk.ctm = newChunkCtm; @@ -944,7 +1061,6 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter Vector<SVGTextChunk>::iterator it = tempChunks.begin(); Vector<SVGTextChunk>::iterator end = tempChunks.end(); - TransformationMatrix ctm; float computedLength = 0.0f; for (; it != end; ++it) { @@ -1388,7 +1504,7 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* } else ASSERT(!info.chunk.boxes.isEmpty()); - // Walk string to find out new chunk positions, if existant + // Walk string to find out new chunk positions, if existent for (unsigned i = 0; i < length; ++i) { ASSERT(info.it != svgChars.end()); @@ -1677,15 +1793,7 @@ void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGI ASSERT(itCharEnd <= curChunk.end); // Process this chunk portion - if (textBox) - (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); - else { - if (walker->setupFill(range.box)) - (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); - - if (walker->setupStroke(range.box)) - (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); - } + (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd); chunkOffset += length; diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h index 65bade04fb..7b1dcc44d0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h @@ -28,6 +28,7 @@ #if ENABLE(SVG) #include "RootInlineBox.h" #include "SVGCharacterLayoutInfo.h" +#include "SVGRenderSupport.h" namespace WebCore { @@ -43,13 +44,14 @@ struct LastGlyphInfo { bool isValid; }; -class SVGRootInlineBox : public RootInlineBox { +class SVGRootInlineBox : public RootInlineBox, protected SVGRenderBase { public: SVGRootInlineBox(RenderObject* obj) : RootInlineBox(obj) , m_height(0) { } + virtual const SVGRenderBase* toSVGRenderBase() const { return this; } virtual bool isSVGRootInlineBox() { return true; } @@ -63,6 +65,9 @@ public: virtual void computePerCharacterLayoutInformation(); + virtual FloatRect objectBoundingBox() const { return FloatRect(); } + virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } + // Used by SVGInlineTextBox const Vector<SVGTextChunk>& svgTextChunks() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.cpp new file mode 100644 index 0000000000..d9ce640028 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.cpp @@ -0,0 +1,80 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGShadowTreeElements.h" + +#include "Document.h" +#include "FloatSize.h" +#include "RenderObject.h" +#include "SVGNames.h" + +namespace WebCore { + +// SVGShadowTreeContainerElement +SVGShadowTreeContainerElement::SVGShadowTreeContainerElement(Document* document) + : SVGGElement(SVGNames::gTag, document) +{ +} + +SVGShadowTreeContainerElement::~SVGShadowTreeContainerElement() +{ +} + +FloatSize SVGShadowTreeContainerElement::containerTranslation() const +{ + return FloatSize(m_xOffset.value(this), m_yOffset.value(this)); +} + +// SVGShadowTreeRootElement +SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, Node* shadowParent) + : SVGShadowTreeContainerElement(document) + , m_shadowParent(shadowParent) +{ + setInDocument(true); +} + +SVGShadowTreeRootElement::~SVGShadowTreeRootElement() +{ +} + +void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena) +{ + ASSERT(m_shadowParent); + + // Create the renderer with the specified style + RenderObject* renderer = createRenderer(arena, style.get()); + if (renderer) { + setRenderer(renderer); + renderer->setStyle(style); + } + + // Set these explicitly since this normally happens during an attach() + setAttached(); + + // Add the renderer to the render tree + if (renderer) + m_shadowParent->renderer()->addChild(renderer); +} + +} + +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.h b/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.h new file mode 100644 index 0000000000..ed42e89740 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/SVGShadowTreeElements.h @@ -0,0 +1,67 @@ +/* + Copyright (C) Research In Motion Limited 2010. 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 + aint with this library; 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 SVGShadowTreeElements_h +#define SVGShadowTreeElements_h + +#if ENABLE(SVG) +#include "SVGGElement.h" +#include "SVGLength.h" + +namespace WebCore { + +class FloatSize; + +class SVGShadowTreeContainerElement : public SVGGElement { +public: + SVGShadowTreeContainerElement(Document*); + virtual ~SVGShadowTreeContainerElement(); + + virtual bool isShadowTreeContainerElement() const { return true; } + + FloatSize containerTranslation() const; + void setContainerOffset(const SVGLength& x, const SVGLength& y) + { + m_xOffset = x; + m_yOffset = y; + } + +private: + SVGLength m_xOffset; + SVGLength m_yOffset; +}; + +class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement { +public: + SVGShadowTreeRootElement(Document*, Node* shadowParent); + virtual ~SVGShadowTreeRootElement(); + + virtual bool isShadowNode() const { return m_shadowParent; } + virtual Node* shadowParentNode() { return m_shadowParent; } + + void attachElement(PassRefPtr<RenderStyle>, RenderArena*); + +private: + Node* m_shadowParent; +}; + +} + +#endif +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/TableLayout.h b/src/3rdparty/webkit/WebCore/rendering/TableLayout.h index 8ae0ce781e..10d6e260d2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/TableLayout.h +++ b/src/3rdparty/webkit/WebCore/rendering/TableLayout.h @@ -1,6 +1,4 @@ /* - * This file is part of the HTML rendering engine for KDE. - * * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) * @@ -23,11 +21,13 @@ #ifndef TableLayout_h #define TableLayout_h +#include <wtf/Noncopyable.h> + namespace WebCore { class RenderTable; -class TableLayout { +class TableLayout : public Noncopyable { public: TableLayout(RenderTable* table) : m_table(table) diff --git a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp index fc7f7f0e0c..4cd55c5fc9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp @@ -63,18 +63,17 @@ bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, Hit VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) { - int contentsX = point.x(); - int contentsY = point.y(); + IntPoint contentsPoint(point); // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that // into account here. if (m_multiLine) { RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); if (renderer->hasOverflowClip()) - renderer->layer()->addScrolledContentOffset(contentsX, contentsY); + contentsPoint += renderer->layer()->scrolledContentOffset(); } - return RenderBlock::positionForPoint(IntPoint(contentsX, contentsY)); + return RenderBlock::positionForPoint(contentsPoint); } TextControlInnerElement::TextControlInnerElement(Document* doc, Node* shadowParent) diff --git a/src/3rdparty/webkit/WebCore/rendering/TrailingFloatsRootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/TrailingFloatsRootInlineBox.h new file mode 100644 index 0000000000..68bf637bab --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/TrailingFloatsRootInlineBox.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TrailingFloatsRootInlineBox_h +#define TrailingFloatsRootInlineBox_h + +#include "RootInlineBox.h" + +namespace WebCore { + +class TrailingFloatsRootInlineBox : public RootInlineBox { +public: + TrailingFloatsRootInlineBox(RenderObject* object) : RootInlineBox(object) + { +#if ENABLE(SVG) + setHasVirtualHeight(); +#endif + } + +private: + virtual int virtualHeight() const { return 0; } +}; + +} // namespace WebCore + +#endif // TrailingFloatsRootInlineBox_h diff --git a/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp b/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp index a9e68f4b1a..ecc614e0e4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp @@ -49,6 +49,12 @@ void TransformState::move(int x, int y, TransformAccumulation accumulate) m_accumulatingTransform = accumulate == AccumulateTransform; } +// FIXME: We transform AffineTransform to TransformationMatrix. This is rather inefficient. +void TransformState::applyTransform(const AffineTransform& transformFromContainer, TransformAccumulation accumulate) +{ + applyTransform(transformFromContainer.toTransformationMatrix(), accumulate); +} + void TransformState::applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate) { // If we have an accumulated transform from last time, multiply in this transform @@ -115,7 +121,7 @@ void TransformState::flattenWithTransform(const TransformationMatrix& t) } // We could throw away m_accumulatedTransform if we wanted to here, but that - // would cause thrash when traversing hierarachies with alternating + // would cause thrash when traversing hierarchies with alternating // preserve-3d and flat elements. if (m_accumulatedTransform) m_accumulatedTransform->makeIdentity(); diff --git a/src/3rdparty/webkit/WebCore/rendering/TransformState.h b/src/3rdparty/webkit/WebCore/rendering/TransformState.h index d2c962a90c..0b4ca46b23 100644 --- a/src/3rdparty/webkit/WebCore/rendering/TransformState.h +++ b/src/3rdparty/webkit/WebCore/rendering/TransformState.h @@ -26,6 +26,7 @@ #ifndef TransformState_h #define TransformState_h +#include "AffineTransform.h" #include "FloatPoint.h" #include "FloatQuad.h" #include "IntSize.h" @@ -59,6 +60,7 @@ public: } void move(int x, int y, TransformAccumulation = FlattenTransform); + void applyTransform(const AffineTransform& transformFromContainer, TransformAccumulation = FlattenTransform); void applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation = FlattenTransform); void flatten(); diff --git a/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp index 9b46cd2e34..1cc6fd1efe 100644 --- a/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp @@ -1,21 +1,26 @@ /* - * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2007, 2010 Apple Inc. All rights reserved. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -44,13 +49,30 @@ static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak) } } -static inline bool shouldBreakAfter(UChar ch) +// This differs from the Unicode algorithm only in that Unicode does not break +// between a question mark and a vertical line (U+007C). +static const unsigned char internetExplorerLineBreaksAfterQuestionMarkTable[0x80] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // \t + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, // ! " ' ) , . / + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, // : ; ? + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // ] + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 // } +}; + +static const size_t internetExplorerLineBreaksAfterQuestionMarkTableSize = sizeof(internetExplorerLineBreaksAfterQuestionMarkTable) / sizeof(*internetExplorerLineBreaksAfterQuestionMarkTable); + +static inline bool shouldBreakAfter(UChar ch, UChar nextCh) { - // Match WinIE's breaking strategy, which is to always allow breaks after hyphens and question marks. - // FIXME: it appears that IE behavior is more complex, see <http://bugs.webkit.org/show_bug.cgi?id=17475>. switch (ch) { - case '-': + // For a question mark preceding a non-ASCII characters, defer to the Unicode algorithm by returning false. + // For ASCII characters, use a lookup table for enhanced speed and for compatibility with Internet Explorer. case '?': + return nextCh < internetExplorerLineBreaksAfterQuestionMarkTableSize && internetExplorerLineBreaksAfterQuestionMarkTable[nextCh]; + // Internet Explorer always allows breaking after a hyphen. + case '-': case softHyphen: // FIXME: cases for ideographicComma and ideographicFullStop are a workaround for an issue in Unicode 5.0 // which is likely to be resolved in Unicode 5.1 <http://bugs.webkit.org/show_bug.cgi?id=17411>. @@ -88,7 +110,7 @@ int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakS for (int i = pos; i < len; i++) { UChar ch = str[i]; - if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh)) + if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh, ch)) return i; if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { diff --git a/src/3rdparty/webkit/WebCore/rendering/break_lines.h b/src/3rdparty/webkit/WebCore/rendering/break_lines.h index 14f740fe87..4d6b8dcd7d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/break_lines.h +++ b/src/3rdparty/webkit/WebCore/rendering/break_lines.h @@ -1,6 +1,4 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 2005 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h index 24d5f86f95..2c261f84be 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h @@ -25,15 +25,15 @@ #ifndef ContentData_h #define ContentData_h -#include "PlatformString.h" #include "RenderStyleConstants.h" -#include "StringImpl.h" -#include "StyleImage.h" #include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> namespace WebCore { class CounterContent; +class StringImpl; +class StyleImage; struct ContentData : Noncopyable { public: diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h index cf118132ee..702d9c2395 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h @@ -30,7 +30,7 @@ namespace WebCore { -class CounterContent { +class CounterContent : public FastAllocBase { public: CounterContent(const AtomicString& identifier, EListStyleType style, const AtomicString& separator) : m_identifier(identifier) diff --git a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp index ec910c9cfa..597e919656 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp @@ -270,4 +270,15 @@ bool FillLayer::containsImage(StyleImage* s) const return false; } +bool FillLayer::imagesAreLoaded() const +{ + const FillLayer* curr; + for (curr = this; curr; curr = curr->next()) { + if (curr->m_image && !curr->m_image->isLoaded()) + return false; + } + + return true; +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h index fb928b6596..cef6b19beb 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h @@ -59,7 +59,7 @@ struct FillSize { LengthSize size; }; -struct FillLayer { +struct FillLayer : FastAllocBase { public: FillLayer(EFillLayerType); ~FillLayer(); @@ -126,6 +126,7 @@ public: } bool containsImage(StyleImage*) const; + bool imagesAreLoaded() const; bool hasImage() const { diff --git a/src/3rdparty/webkit/WebCore/rendering/style/LineClampValue.h b/src/3rdparty/webkit/WebCore/rendering/style/LineClampValue.h new file mode 100644 index 0000000000..2119ca2916 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/style/LineClampValue.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LineClampValue_h +#define LineClampValue_h + +#include "RenderStyleConstants.h" + +namespace WebCore { + +class LineClampValue { +public: + LineClampValue() + : m_type(LineClampLineCount) + , m_value(-1) + { + } + + LineClampValue(int value, ELineClampType type) + : m_type(type) + , m_value(value) + { + } + + int value() const { return m_value; } + + bool isPercentage() const { return m_type == LineClampPercentage; } + + bool isNone() const { return m_value == -1; } + + bool operator==(const LineClampValue& o) const + { + return value() == o.value() && isPercentage() == o.isPercentage(); + } + + bool operator!=(const LineClampValue& o) const + { + return !(*this == o); + } + +private: + ELineClampType m_type; + int m_value; +}; + +} // namespace WebCore + +#endif // LineClampValue_h diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp index a861fea314..712344fdd2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp @@ -192,6 +192,11 @@ static inline int pseudoBit(PseudoId pseudo) return 1 << (pseudo - 1); } +bool RenderStyle::hasAnyPublicPseudoStyles() const +{ + return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits; +} + bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const { ASSERT(pseudo > NOPSEUDO); @@ -454,8 +459,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon if (inherited->m_effectiveZoom != other->inherited->m_effectiveZoom) return StyleDifferenceLayout; - if (rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1 || - rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1) { + if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) || + (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) { // FIXME: We should add an optimized form of layout that just recomputes visual overflow. return StyleDifferenceLayout; } @@ -702,7 +707,7 @@ void RenderStyle::addBindingURI(StringImpl* uri) void RenderStyle::setTextShadow(ShadowData* val, bool add) { - ASSERT(!val || !val->spread && val->style == Normal); + ASSERT(!val || (!val->spread && val->style == Normal)); StyleRareInheritedData* rareData = rareInheritedData.access(); if (!add) { diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h index 2e8fb0acda..6ec05343c5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h @@ -37,6 +37,7 @@ #include "CachedImage.h" #include "CollapsedBorderValue.h" #include "Color.h" +#include "ColorSpace.h" #include "ContentData.h" #include "CounterDirectives.h" #include "CursorList.h" @@ -49,6 +50,7 @@ #include "Length.h" #include "LengthBox.h" #include "LengthSize.h" +#include "LineClampValue.h" #include "NinePieceImage.h" #include "OutlineValue.h" #include "Pair.h" @@ -87,8 +89,8 @@ #include "BindingURI.h" #endif -#ifdef __WINS__ -#define compareEqual(t, u) ((t) == (u)) +#if COMPILER(WINSCW) +#define compareEqual(t, u) ((t) == (u)) #else template<typename T, typename U> inline bool compareEqual(const T& t, const U& u) { return t == static_cast<T>(u); } #endif @@ -181,7 +183,7 @@ protected: unsigned _empty_cells : 1; // EEmptyCell unsigned _caption_side : 2; // ECaptionSide - unsigned _list_style_type : 5 ; // EListStyleType + unsigned _list_style_type : 7; // EListStyleType unsigned _list_style_position : 1; // EListStylePosition unsigned _visibility : 2; // EVisibility unsigned _text_align : 3; // ETextAlign @@ -192,37 +194,38 @@ protected: bool _border_collapse : 1 ; unsigned _white_space : 3; // EWhiteSpace unsigned _box_direction : 1; // EBoxDirection (CSS3 box_direction property, flexible box layout module) - // 32 bits + // 34 bits // non CSS2 inherited bool _visuallyOrdered : 1; bool _htmlHacks : 1; bool _force_backgrounds_to_white : 1; unsigned _pointerEvents : 4; // EPointerEvents - // 39 bits + // 41 bits } inherited_flags; // don't inherit struct NonInheritedFlags { bool operator==(const NonInheritedFlags& other) const { - return (_effectiveDisplay == other._effectiveDisplay) && - (_originalDisplay == other._originalDisplay) && - (_overflowX == other._overflowX) && - (_overflowY == other._overflowY) && - (_vertical_align == other._vertical_align) && - (_clear == other._clear) && - (_position == other._position) && - (_floating == other._floating) && - (_table_layout == other._table_layout) && - (_page_break_before == other._page_break_before) && - (_page_break_after == other._page_break_after) && - (_styleType == other._styleType) && - (_affectedByHover == other._affectedByHover) && - (_affectedByActive == other._affectedByActive) && - (_affectedByDrag == other._affectedByDrag) && - (_pseudoBits == other._pseudoBits) && - (_unicodeBidi == other._unicodeBidi); + return _effectiveDisplay == other._effectiveDisplay + && _originalDisplay == other._originalDisplay + && _overflowX == other._overflowX + && _overflowY == other._overflowY + && _vertical_align == other._vertical_align + && _clear == other._clear + && _position == other._position + && _floating == other._floating + && _table_layout == other._table_layout + && _page_break_before == other._page_break_before + && _page_break_after == other._page_break_after + && _page_break_inside == other._page_break_inside + && _styleType == other._styleType + && _affectedByHover == other._affectedByHover + && _affectedByActive == other._affectedByActive + && _affectedByDrag == other._affectedByDrag + && _pseudoBits == other._pseudoBits + && _unicodeBidi == other._unicodeBidi; } bool operator!=(const NonInheritedFlags& other) const { return !(*this == other); } @@ -239,6 +242,7 @@ protected: unsigned _page_break_before : 2; // EPageBreak unsigned _page_break_after : 2; // EPageBreak + unsigned _page_break_inside : 2; // EPageBreak unsigned _styleType : 5; // PseudoId bool _affectedByHover : 1; @@ -246,7 +250,7 @@ protected: bool _affectedByDrag : 1; unsigned _pseudoBits : 7; unsigned _unicodeBidi : 2; // EUnicodeBidi - // 48 bits + // 50 bits } noninherited_flags; // !END SYNC! @@ -282,6 +286,7 @@ protected: noninherited_flags._table_layout = initialTableLayout(); noninherited_flags._page_break_before = initialPageBreak(); noninherited_flags._page_break_after = initialPageBreak(); + noninherited_flags._page_break_inside = initialPageBreak(); noninherited_flags._styleType = NOPSEUDO; noninherited_flags._affectedByHover = false; noninherited_flags._affectedByActive = false; @@ -345,6 +350,7 @@ public: bool isStyleAvailable() const; + bool hasAnyPublicPseudoStyles() const; bool hasPseudoStyle(PseudoId pseudo) const; void setHasPseudoStyle(PseudoId pseudo); @@ -462,7 +468,7 @@ public: return font().lineSpacing(); if (lh.isPercent()) - return lh.calcMinValue(fontSize(), true); + return lh.calcMinValue(fontSize()); return lh.value(); } @@ -583,7 +589,7 @@ public: short widows() const { return inherited->widows; } short orphans() const { return inherited->orphans; } - EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(inherited->page_break_inside); } + EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(noninherited_flags._page_break_inside); } EPageBreak pageBreakBefore() const { return static_cast<EPageBreak>(noninherited_flags._page_break_before); } EPageBreak pageBreakAfter() const { return static_cast<EPageBreak>(noninherited_flags._page_break_after); } @@ -603,6 +609,7 @@ public: const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; } float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; } const Color& textFillColor() const { return rareInheritedData->textFillColor; } + ColorSpace colorSpace() const { return static_cast<ColorSpace>(rareInheritedData->colorSpace); } float opacity() const { return rareNonInheritedData->opacity; } ControlPart appearance() const { return static_cast<ControlPart>(rareNonInheritedData->m_appearance); } EBoxAlignment boxAlign() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->align); } @@ -697,7 +704,7 @@ public: bool isRunningAcceleratedAnimation() const { return rareNonInheritedData->m_runningAcceleratedAnimation; } #endif - int lineClamp() const { return rareNonInheritedData->lineClamp; } + const LineClampValue& lineClamp() const { return rareNonInheritedData->lineClamp; } bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; } ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); } @@ -918,7 +925,7 @@ public: void setWidows(short w) { SET_VAR(inherited, widows, w); } void setOrphans(short o) { SET_VAR(inherited, orphans, o); } - void setPageBreakInside(EPageBreak b) { SET_VAR(inherited, page_break_inside, b); } + void setPageBreakInside(EPageBreak b) { noninherited_flags._page_break_inside = b; } void setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; } void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; } @@ -934,6 +941,7 @@ public: void setTextStrokeColor(const Color& c) { SET_VAR(rareInheritedData, textStrokeColor, c) } void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w) } void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c) } + void setColorSpace(ColorSpace space) { SET_VAR(rareInheritedData, colorSpace, space) } void setOpacity(float f) { SET_VAR(rareNonInheritedData, opacity, f); } void setAppearance(ControlPart a) { SET_VAR(rareNonInheritedData, m_appearance, a); } void setBoxAlign(EBoxAlignment a) { SET_VAR(rareNonInheritedData.access()->flexibleBox, align, a); } @@ -1013,7 +1021,7 @@ public: void setIsRunningAcceleratedAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_runningAcceleratedAnimation, b); } #endif - void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); } + void setLineClamp(LineClampValue c) { SET_VAR(rareNonInheritedData, lineClamp, c); } void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); } void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); } @@ -1106,7 +1114,7 @@ public: static EEmptyCell initialEmptyCells() { return SHOW; } static EFloat initialFloating() { return FNONE; } static EListStylePosition initialListStylePosition() { return OUTSIDE; } - static EListStyleType initialListStyleType() { return DISC; } + static EListStyleType initialListStyleType() { return Disc; } static EOverflow initialOverflowX() { return OVISIBLE; } static EOverflow initialOverflowY() { return OVISIBLE; } static EPageBreak initialPageBreak() { return PBAUTO; } @@ -1185,7 +1193,7 @@ public: static Color initialBackgroundColor() { return Color::transparent; } // Keep these at the end. - static int initialLineClamp() { return -1; } + static LineClampValue initialLineClamp() { return LineClampValue(); } static bool initialTextSizeAdjust() { return true; } static ETextSecurity initialTextSecurity() { return TSNONE; } #if ENABLE(DASHBOARD_SUPPORT) diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h index 3010947ad7..29412c67b5 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * @@ -66,15 +66,19 @@ enum StyleDifferenceContextSensitiveProperty { // Static pseudo styles. Dynamic ones are produced on the fly. enum PseudoId { + // The order must be NOP ID, public IDs, and then internal IDs. NOPSEUDO, FIRST_LINE, FIRST_LETTER, BEFORE, AFTER, SELECTION, FIRST_LINE_INHERITED, SCROLLBAR, FILE_UPLOAD_BUTTON, INPUT_PLACEHOLDER, SLIDER_THUMB, SEARCH_CANCEL_BUTTON, SEARCH_DECORATION, SEARCH_RESULTS_DECORATION, SEARCH_RESULTS_BUTTON, MEDIA_CONTROLS_PANEL, MEDIA_CONTROLS_PLAY_BUTTON, MEDIA_CONTROLS_MUTE_BUTTON, MEDIA_CONTROLS_TIMELINE, MEDIA_CONTROLS_TIMELINE_CONTAINER, - MEDIA_CONTROLS_VOLUME_SLIDER, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, MEDIA_CONTROLS_SEEK_BACK_BUTTON, - MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, + MEDIA_CONTROLS_VOLUME_SLIDER, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, + MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON, + MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, - INPUT_LIST_BUTTON, + INPUT_LIST_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, - FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON + FIRST_PUBLIC_PSEUDOID = FIRST_LINE, + FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON, + PUBLIC_PSEUDOID_MASK = ((1 << FIRST_INTERNAL_PSEUDOID) - 1) & ~((1 << FIRST_PUBLIC_PSEUDOID) - 1) }; // These have been defined in the order of their precedence for border-collapsing. Do @@ -202,12 +206,85 @@ enum EResize { RESIZE_NONE, RESIZE_BOTH, RESIZE_HORIZONTAL, RESIZE_VERTICAL }; +// The order of this enum must match the order of the list style types in CSSValueKeywords.in. enum EListStyleType { - DISC, CIRCLE, SQUARE, LDECIMAL, DECIMAL_LEADING_ZERO, - LOWER_ROMAN, UPPER_ROMAN, LOWER_GREEK, - LOWER_ALPHA, LOWER_LATIN, UPPER_ALPHA, UPPER_LATIN, - HEBREW, ARMENIAN, GEORGIAN, CJK_IDEOGRAPHIC, - HIRAGANA, KATAKANA, HIRAGANA_IROHA, KATAKANA_IROHA, LNONE + Disc, + Circle, + Square, + DecimalListStyle, + DecimalLeadingZero, + ArabicIndic, + BinaryListStyle, + Bengali, + Cambodian, + Khmer, + Devanagari, + Gujarati, + Gurmukhi, + Kannada, + LowerHexadecimal, + Lao, + Malayalam, + Mongolian, + Myanmar, + Octal, + Oriya, + Persian, + Urdu, + Telugu, + Tibetan, + Thai, + UpperHexadecimal, + LowerRoman, + UpperRoman, + LowerGreek, + LowerAlpha, + LowerLatin, + UpperAlpha, + UpperLatin, + Afar, + EthiopicHalehameAaEt, + EthiopicHalehameAaEr, + Amharic, + EthiopicHalehameAmEt, + AmharicAbegede, + EthiopicAbegedeAmEt, + CjkEarthlyBranch, + CjkHeavenlyStem, + Ethiopic, + EthiopicHalehameGez, + EthiopicAbegede, + EthiopicAbegedeGez, + HangulConsonant, + Hangul, + LowerNorwegian, + Oromo, + EthiopicHalehameOmEt, + Sidama, + EthiopicHalehameSidEt, + Somali, + EthiopicHalehameSoEt, + Tigre, + EthiopicHalehameTig, + TigrinyaEr, + EthiopicHalehameTiEr, + TigrinyaErAbegede, + EthiopicAbegedeTiEr, + TigrinyaEt, + EthiopicHalehameTiEt, + TigrinyaEtAbegede, + EthiopicAbegedeTiEt, + UpperGreek, + UpperNorwegian, + Hebrew, + Armenian, + Georgian, + CJKIdeographic, + Hiragana, + Katakana, + HiraganaIroha, + KatakanaIroha, + NoneListStyle }; enum StyleContentType { @@ -216,6 +293,8 @@ enum StyleContentType { enum EBorderFit { BorderFitBorder, BorderFitLines }; +enum EAnimationFillMode { AnimationFillModeNone, AnimationFillModeForwards, AnimationFillModeBackwards, AnimationFillModeBoth }; + enum EAnimPlayState { AnimPlayStatePlaying = 0x0, AnimPlayStatePaused = 0x1 @@ -321,6 +400,8 @@ enum ETransformStyle3D { enum EBackfaceVisibility { BackfaceVisibilityVisible, BackfaceVisibilityHidden }; + +enum ELineClampType { LineClampLineCount, LineClampPercentage }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp index e8827c4733..79580885bd 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp @@ -8,8 +8,6 @@ Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org) Copyright (C) 2002 Apple Computer, Inc. - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either @@ -32,11 +30,14 @@ #include "CSSPrimitiveValue.h" #include "CSSValueList.h" +#include "IntRect.h" #include "NodeRenderStyle.h" #include "RenderObject.h" #include "RenderStyle.h" #include "SVGStyledElement.h" +using namespace std; + namespace WebCore { SVGRenderStyle::SVGRenderStyle() @@ -143,6 +144,56 @@ float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* v return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style()), item->document()->documentElement()->renderStyle()); } + +static void getSVGShadowExtent(ShadowData* shadow, int& top, int& right, int& bottom, int& left) +{ + top = 0; + right = 0; + bottom = 0; + left = 0; + + int blurAndSpread = shadow->blur + shadow->spread; + + top = min(top, shadow->y - blurAndSpread); + right = max(right, shadow->x + blurAndSpread); + bottom = max(bottom, shadow->y + blurAndSpread); + left = min(left, shadow->x - blurAndSpread); +} + +void SVGRenderStyle::inflateForShadow(IntRect& repaintRect) const +{ + ShadowData* svgShadow = shadow(); + if (!svgShadow) + return; + + FloatRect repaintFloatRect = FloatRect(repaintRect); + inflateForShadow(repaintFloatRect); + repaintRect = enclosingIntRect(repaintFloatRect); +} + +void SVGRenderStyle::inflateForShadow(FloatRect& repaintRect) const +{ + ShadowData* svgShadow = shadow(); + if (!svgShadow) + return; + + int shadowTop; + int shadowRight; + int shadowBottom; + int shadowLeft; + getSVGShadowExtent(svgShadow, shadowTop, shadowRight, shadowBottom, shadowLeft); + + int overflowLeft = repaintRect.x() + shadowLeft; + int overflowRight = repaintRect.right() + shadowRight; + int overflowTop = repaintRect.y() + shadowTop; + int overflowBottom = repaintRect.bottom() + shadowBottom; + + repaintRect.setX(overflowLeft); + repaintRect.setY(overflowTop); + repaintRect.setWidth(overflowRight - overflowLeft); + repaintRect.setHeight(overflowBottom - overflowTop); +} + } #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h index 12477d771e..3f35a636b6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h @@ -3,8 +3,6 @@ 2004, 2005 Rob Buis <buis@kde.org> Copyright (C) 2005, 2006 Apple Computer, Inc. - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either @@ -32,180 +30,184 @@ #include "SVGRenderStyleDefs.h" #include "ShadowData.h" -#include <wtf/Platform.h> - namespace WebCore { - class RenderObject; - class RenderStyle; - - class SVGRenderStyle : public RefCounted<SVGRenderStyle> { - public: - static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); } - PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));} - ~SVGRenderStyle(); +class FloatRect; +class IntRect; +class RenderObject; +class RenderStyle; + +class SVGRenderStyle : public RefCounted<SVGRenderStyle> { +public: + static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); } + PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));} + ~SVGRenderStyle(); + + bool inheritedNotEqual(const SVGRenderStyle*) const; + void inheritFrom(const SVGRenderStyle*); + + // FIXME: These functions should move to ShadowData. + void inflateForShadow(IntRect&) const; + void inflateForShadow(FloatRect&) const; + + bool operator==(const SVGRenderStyle&) const; + bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); } + + // SVG CSS Properties + SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO) + SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO) + SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE) + + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG) + SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO) + + // SVG CSS Properties (using DataRef's) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill()) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0); + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0)) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String()) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String()) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0)) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255)) + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0) + + SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(ShadowData, shadowSVG, shadow, Shadow, shadow, 0) + + // convenience + bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } + bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } + + static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f); + +protected: + // inherit + struct InheritedFlags { + bool operator==(const InheritedFlags& other) const + { + return (_colorRendering == other._colorRendering) + && (_imageRendering == other._imageRendering) + && (_shapeRendering == other._shapeRendering) + && (_clipRule == other._clipRule) + && (_fillRule == other._fillRule) + && (_capStyle == other._capStyle) + && (_joinStyle == other._joinStyle) + && (_textAnchor == other._textAnchor) + && (_colorInterpolation == other._colorInterpolation) + && (_colorInterpolationFilters == other._colorInterpolationFilters) + && (_writingMode == other._writingMode) + && (_glyphOrientationHorizontal == other._glyphOrientationHorizontal) + && (_glyphOrientationVertical == other._glyphOrientationVertical); + } - bool inheritedNotEqual(const SVGRenderStyle*) const; - void inheritFrom(const SVGRenderStyle*); - - bool operator==(const SVGRenderStyle&) const; - bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); } - - // SVG CSS Properties - SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO) - SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO) - SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE) - - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO) - - // SVG CSS Properties (using DataRef's) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill()) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0); - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0)) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String()) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String()) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0)) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255)) - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0) - - SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(ShadowData, shadowSVG, shadow, Shadow, shadow, 0) - - // convenience - bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } - bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); } - - static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f); - - protected: - // inherit - struct InheritedFlags { - bool operator==(const InheritedFlags& other) const - { - return (_colorRendering == other._colorRendering) && - (_imageRendering == other._imageRendering) && - (_shapeRendering == other._shapeRendering) && - (_clipRule == other._clipRule) && - (_fillRule == other._fillRule) && - (_capStyle == other._capStyle) && - (_joinStyle == other._joinStyle) && - (_textAnchor == other._textAnchor) && - (_colorInterpolation == other._colorInterpolation) && - (_colorInterpolationFilters == other._colorInterpolationFilters) && - (_writingMode == other._writingMode) && - (_glyphOrientationHorizontal == other._glyphOrientationHorizontal) && - (_glyphOrientationVertical == other._glyphOrientationVertical); - } - - bool operator!=(const InheritedFlags& other) const - { - return !(*this == other); - } - - unsigned _colorRendering : 2; // EColorRendering - unsigned _imageRendering : 2; // EImageRendering - unsigned _shapeRendering : 2; // EShapeRendering - unsigned _clipRule : 1; // WindRule - unsigned _fillRule : 1; // WindRule - unsigned _capStyle : 2; // LineCap - unsigned _joinStyle : 2; // LineJoin - unsigned _textAnchor : 2; // ETextAnchor - unsigned _colorInterpolation : 2; // EColorInterpolation - unsigned _colorInterpolationFilters : 2; // EColorInterpolation - unsigned _writingMode : 3; // EWritingMode - unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation - unsigned _glyphOrientationVertical : 3; // EGlyphOrientation - } svg_inherited_flags; - - // don't inherit - struct NonInheritedFlags { - // 32 bit non-inherited, don't add to the struct, or the operator will break. - bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; } - bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; } - - union { - struct { - unsigned _alignmentBaseline : 4; // EAlignmentBaseline - unsigned _dominantBaseline : 4; // EDominantBaseline - unsigned _baselineShift : 2; // EBaselineShift - // 22 bits unused - } f; - uint32_t _niflags; - }; - } svg_noninherited_flags; - - // inherited attributes - DataRef<StyleFillData> fill; - DataRef<StyleStrokeData> stroke; - DataRef<StyleMarkerData> markers; - DataRef<StyleTextData> text; - - // non-inherited attributes - DataRef<StyleStopData> stops; - DataRef<StyleClipData> clip; - DataRef<StyleMaskData> mask; - DataRef<StyleMiscData> misc; - DataRef<StyleShadowSVGData> shadowSVG; - - private: - enum CreateDefaultType { CreateDefault }; - - SVGRenderStyle(); - SVGRenderStyle(const SVGRenderStyle&); - SVGRenderStyle(CreateDefaultType); // Used to create the default style. - - void setBitDefaults() + bool operator!=(const InheritedFlags& other) const { - svg_inherited_flags._clipRule = initialClipRule(); - svg_inherited_flags._colorRendering = initialColorRendering(); - svg_inherited_flags._fillRule = initialFillRule(); - svg_inherited_flags._imageRendering = initialImageRendering(); - svg_inherited_flags._shapeRendering = initialShapeRendering(); - svg_inherited_flags._textAnchor = initialTextAnchor(); - svg_inherited_flags._capStyle = initialCapStyle(); - svg_inherited_flags._joinStyle = initialJoinStyle(); - svg_inherited_flags._colorInterpolation = initialColorInterpolation(); - svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters(); - svg_inherited_flags._writingMode = initialWritingMode(); - svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal(); - svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical(); - - svg_noninherited_flags._niflags = 0; - svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline(); - svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline(); - svg_noninherited_flags.f._baselineShift = initialBaselineShift(); + return !(*this == other); } - }; + + unsigned _colorRendering : 2; // EColorRendering + unsigned _imageRendering : 2; // EImageRendering + unsigned _shapeRendering : 2; // EShapeRendering + unsigned _clipRule : 1; // WindRule + unsigned _fillRule : 1; // WindRule + unsigned _capStyle : 2; // LineCap + unsigned _joinStyle : 2; // LineJoin + unsigned _textAnchor : 2; // ETextAnchor + unsigned _colorInterpolation : 2; // EColorInterpolation + unsigned _colorInterpolationFilters : 2; // EColorInterpolation + unsigned _writingMode : 3; // EWritingMode + unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation + unsigned _glyphOrientationVertical : 3; // EGlyphOrientation + } svg_inherited_flags; + + // don't inherit + struct NonInheritedFlags { + // 32 bit non-inherited, don't add to the struct, or the operator will break. + bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; } + bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; } + + union { + struct { + unsigned _alignmentBaseline : 4; // EAlignmentBaseline + unsigned _dominantBaseline : 4; // EDominantBaseline + unsigned _baselineShift : 2; // EBaselineShift + // 22 bits unused + } f; + uint32_t _niflags; + }; + } svg_noninherited_flags; + + // inherited attributes + DataRef<StyleFillData> fill; + DataRef<StyleStrokeData> stroke; + DataRef<StyleMarkerData> markers; + DataRef<StyleTextData> text; + + // non-inherited attributes + DataRef<StyleStopData> stops; + DataRef<StyleClipData> clip; + DataRef<StyleMaskData> mask; + DataRef<StyleMiscData> misc; + DataRef<StyleShadowSVGData> shadowSVG; + +private: + enum CreateDefaultType { CreateDefault }; + + SVGRenderStyle(); + SVGRenderStyle(const SVGRenderStyle&); + SVGRenderStyle(CreateDefaultType); // Used to create the default style. + + void setBitDefaults() + { + svg_inherited_flags._clipRule = initialClipRule(); + svg_inherited_flags._colorRendering = initialColorRendering(); + svg_inherited_flags._fillRule = initialFillRule(); + svg_inherited_flags._imageRendering = initialImageRendering(); + svg_inherited_flags._shapeRendering = initialShapeRendering(); + svg_inherited_flags._textAnchor = initialTextAnchor(); + svg_inherited_flags._capStyle = initialCapStyle(); + svg_inherited_flags._joinStyle = initialJoinStyle(); + svg_inherited_flags._colorInterpolation = initialColorInterpolation(); + svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters(); + svg_inherited_flags._writingMode = initialWritingMode(); + svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal(); + svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical(); + + svg_noninherited_flags._niflags = 0; + svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline(); + svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline(); + svg_noninherited_flags.f._baselineShift = initialBaselineShift(); + } +}; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp index 2ed1d8fcc1..093f1f1fb6 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp @@ -8,8 +8,6 @@ Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org) Copyright (C) 2002 Apple Computer, Inc. - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h index f4cf9327a3..8f01d9f12d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h @@ -8,8 +8,6 @@ (C) 2000-2003 Dirk Mueller (mueller@kde.org) (C) 2002-2003 Apple Computer, Inc. - This file is part of the KDE project - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h index f4061f2e5e..089cf77599 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h @@ -26,6 +26,7 @@ #define ShadowData_h #include "Color.h" +#include <wtf/FastAllocBase.h> namespace WebCore { @@ -33,7 +34,7 @@ enum ShadowStyle { Normal, Inset }; // This struct holds information about shadows for the text-shadow and box-shadow properties. -struct ShadowData { +struct ShadowData : FastAllocBase { ShadowData() : x(0) , y(0) diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp index f59c0c2420..c73497f397 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp @@ -37,7 +37,6 @@ StyleInheritedData::StyleInheritedData() , vertical_border_spacing(RenderStyle::initialVerticalBorderSpacing()) , widows(RenderStyle::initialWidows()) , orphans(RenderStyle::initialOrphans()) - , page_break_inside(RenderStyle::initialPageBreak()) { } @@ -58,7 +57,6 @@ StyleInheritedData::StyleInheritedData(const StyleInheritedData& o) , vertical_border_spacing(o.vertical_border_spacing) , widows(o.widows) , orphans(o.orphans) - , page_break_inside(o.page_break_inside) { } @@ -84,8 +82,7 @@ bool StyleInheritedData::operator==(const StyleInheritedData& o) const horizontal_border_spacing == o.horizontal_border_spacing && vertical_border_spacing == o.vertical_border_spacing && widows == o.widows && - orphans == o.orphans && - page_break_inside == o.page_break_inside; + orphans == o.orphans; } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h index 548ca72364..3b30b8f64a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h @@ -68,7 +68,6 @@ public: // Paged media properties. short widows; short orphans; - unsigned page_break_inside : 2; // EPageBreak private: StyleInheritedData(); diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp index ce21720c5b..f731098f80 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -39,6 +39,7 @@ StyleRareInheritedData::StyleRareInheritedData() , textSizeAdjust(RenderStyle::initialTextSizeAdjust()) , resize(RenderStyle::initialResize()) , userSelect(RenderStyle::initialUserSelect()) + , colorSpace(DeviceColorSpace) { } @@ -58,6 +59,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , textSizeAdjust(o.textSizeAdjust) , resize(o.resize) , userSelect(o.userSelect) + , colorSpace(o.colorSpace) { } @@ -81,7 +83,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && khtmlLineBreak == o.khtmlLineBreak && textSizeAdjust == o.textSizeAdjust && resize == o.resize - && userSelect == o.userSelect; + && userSelect == o.userSelect + && colorSpace == o.colorSpace; } bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h index 06ad400480..2e87e6b97f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h @@ -65,6 +65,7 @@ public: bool textSizeAdjust : 1; // An Apple extension. unsigned resize : 2; // EResize unsigned userSelect : 1; // EUserSelect + unsigned colorSpace : 1; // ColorSpace private: StyleRareInheritedData(); diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h index 8dd22b39b1..452b273de2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -29,6 +29,7 @@ #include "CursorData.h" #include "DataRef.h" #include "FillLayer.h" +#include "LineClampValue.h" #include "NinePieceImage.h" #include "StyleTransformData.h" #include <wtf/OwnPtr.h> @@ -77,7 +78,7 @@ public: bool animationDataEquivalent(const StyleRareNonInheritedData&) const; bool transitionDataEquivalent(const StyleRareNonInheritedData&) const; - int lineClamp; // An Apple extension. + LineClampValue lineClamp; // An Apple extension. #if ENABLE(DASHBOARD_SUPPORT) Vector<StyleDashboardRegion> m_dashboardRegions; #endif |