diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering')
208 files changed, 21901 insertions, 11829 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp index 8f9feec..648e843 100644 --- a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp @@ -59,7 +59,9 @@ void AutoTableLayout::recalcColumn(int effCol) RenderTableCell* maxContributor = 0; while (child) { - if (child->isTableSection()) { + if (child->isTableCol()) + static_cast<RenderTableCol*>(child)->calcPrefWidths(); + else if (child->isTableSection()) { RenderTableSection* section = static_cast<RenderTableSection*>(child); int numRows = section->numRows(); RenderTableCell* last = 0; diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp index 0bd1d1a..db9a101 100644 --- a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp @@ -31,10 +31,7 @@ namespace WebCore { void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { GraphicsContext* context = paintInfo.context; - RenderStyle* style = m_object->style(m_firstLine); - if (style->font() != context->font()) - context->setFont(style->font()); - + RenderStyle* style = m_renderer->style(m_firstLine); Color textColor = style->color(); if (textColor != context->fillColor()) context->setFillColor(textColor); @@ -46,15 +43,15 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) } const String& str = m_str; - context->drawText(TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + m_baseline)); + 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())); if (setShadow) context->clearShadow(); if (m_markupBox) { // Paint the markup box - tx += m_x + m_width - m_markupBox->xPos(); - ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); + tx += m_x + m_width - m_markupBox->x(); + ty += m_y + style->font().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->font().ascent()); m_markupBox->paint(paintInfo, tx, ty); } } @@ -66,16 +63,17 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Hit test the markup box. if (m_markupBox) { - int mtx = tx + m_width - m_markupBox->xPos(); - int mty = ty + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); + RenderStyle* style = m_renderer->style(m_firstLine); + int mtx = tx + m_width - m_markupBox->x(); + int mty = ty + style->font().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->font().ascent()); if (m_markupBox->nodeAtPoint(request, result, x, y, mtx, mty)) { - object()->updateHitTestResult(result, IntPoint(x - mtx, y - mty)); + renderer()->updateHitTestResult(result, IntPoint(x - mtx, y - mty)); return true; } } if (visibleToHitTesting() && IntRect(tx, ty, m_width, m_height).contains(x, y)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h index dbb30cd..9dbd27f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h @@ -26,15 +26,15 @@ namespace WebCore { +class HitTestRequest; class HitTestResult; -struct HitTestRequest; - class EllipsisBox : public InlineBox { public: EllipsisBox(RenderObject* obj, const AtomicString& ellipsisStr, InlineFlowBox* parent, - int width, int y, int height, int baseline, bool firstLine, InlineBox* markupBox) - : InlineBox(obj, 0, y, width, height, baseline, firstLine, true, false, false, 0, 0, parent) + int width, int height, int y, bool firstLine, InlineBox* markupBox) + : InlineBox(obj, 0, y, width, firstLine, true, false, false, 0, 0, parent) + , m_height(height) , m_str(ellipsisStr) , m_markupBox(markupBox) { @@ -44,6 +44,9 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); private: + virtual int height() const { return m_height; } + + int m_height; AtomicString m_str; InlineBox* m_markupBox; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp index d7c1293..63a4f54 100644 --- a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp @@ -85,16 +85,15 @@ int FixedTableLayout::calcWidthArray(int) // iterate over all <col> elements RenderObject* child = m_table->firstChild(); - int cCol = 0; int nEffCols = m_table->numEffCols(); m_width.resize(nEffCols); m_width.fill(Length(Auto)); + int currentEffectiveColumn = 0; Length grpWidth; while (child) { if (child->isTableCol()) { - RenderTableCol *col = static_cast<RenderTableCol *>(child); - int span = col->span(); + RenderTableCol* col = static_cast<RenderTableCol*>(child); if (col->firstChild()) grpWidth = col->style()->width(); else { @@ -104,30 +103,36 @@ int FixedTableLayout::calcWidthArray(int) int effWidth = 0; if (w.isFixed() && w.value() > 0) effWidth = w.value(); - - int usedSpan = 0; - int i = 0; - while (usedSpan < span) { - if(cCol + i >= nEffCols) { - m_table->appendColumn(span - usedSpan); + + int span = col->span(); + while (span) { + int spanInCurrentEffectiveColumn; + if (currentEffectiveColumn >= nEffCols) { + m_table->appendColumn(span); nEffCols++; - m_width.resize(nEffCols); - m_width[nEffCols-1] = Length(); + m_width.append(Length()); + spanInCurrentEffectiveColumn = span; + } else { + if (span < m_table->spanOfEffCol(currentEffectiveColumn)) { + m_table->splitColumn(currentEffectiveColumn, span); + nEffCols++; + m_width.append(Length()); + } + spanInCurrentEffectiveColumn = m_table->spanOfEffCol(currentEffectiveColumn); } - int eSpan = m_table->spanOfEffCol(cCol+i); if ((w.isFixed() || w.isPercent()) && w.isPositive()) { - m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan); - usedWidth += effWidth * eSpan; + m_width[currentEffectiveColumn].setRawValue(w.type(), w.rawValue() * spanInCurrentEffectiveColumn); + usedWidth += effWidth * spanInCurrentEffectiveColumn; } - usedSpan += eSpan; - i++; + span -= spanInCurrentEffectiveColumn; + currentEffectiveColumn++; } - cCol += i; } + static_cast<RenderTableCol*>(child)->calcPrefWidths(); } else break; - RenderObject *next = child->firstChild(); + RenderObject* next = child->firstChild(); if (!next) next = child->nextSibling(); if (!next && child->parent()->isTableCol()) { @@ -146,7 +151,7 @@ int FixedTableLayout::calcWidthArray(int) if (section && !section->numRows()) section = m_table->sectionBelow(section, true); if (section) { - cCol = 0; + int cCol = 0; RenderObject* firstRow = section->firstChild(); child = firstRow->firstChild(); while (child) { diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h index 11dca4b..46dd7b8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h +++ b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h @@ -2,6 +2,7 @@ * 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/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,24 +20,35 @@ * Boston, MA 02110-1301, USA. * */ + #ifndef HitTestRequest_h #define HitTestRequest_h namespace WebCore { -struct HitTestRequest { - HitTestRequest(bool r, bool a, bool m = false, bool u = false) - : readonly(r) - , active(a) - , mouseMove(m) - , mouseUp(u) - { +class HitTestRequest { +public: + enum RequestType { + ReadOnly = 0x1, + Active = 0x2, + MouseMove = 0x4, + MouseUp = 0x8, + IgnoreClipping = 0x10 + }; + + HitTestRequest(int requestType) + : m_requestType(requestType) + { } - bool readonly; - bool active; - bool mouseMove; - bool mouseUp; + bool readOnly() const { return m_requestType & ReadOnly; } + bool active() const { return m_requestType & Active; } + bool mouseMove() const { return m_requestType & MouseMove; } + bool mouseUp() const { return m_requestType & MouseUp; } + bool ignoreClipping() const { return m_requestType & IgnoreClipping; } + +private: + int m_requestType; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp index 5a041ed..f2ed7db 100644 --- a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp @@ -159,6 +159,20 @@ String HitTestResult::spellingToolTip() const return marker->description; } +String HitTestResult::replacedString() const +{ + // Return the replaced string associated with this point, if any. This marker is created when a string is autocorrected, + // and is used for generating a contextual menu item that allows it to easily be changed back if desired. + if (!m_innerNonSharedNode) + return String(); + + DocumentMarker* marker = m_innerNonSharedNode->document()->markerContainingPoint(m_point, DocumentMarker::Replacement); + if (!marker) + return String(); + + return marker->description; +} + String HitTestResult::title() const { // Find the title in the nearest enclosing DOM node. @@ -177,9 +191,7 @@ String displayString(const String& string, const Node* node) { if (!node) return string; - String copy(string); - copy.replace('\\', node->document()->backslashAsCurrencySymbol()); - return copy; + return node->document()->displayStringModifiedByEncoding(string); } String HitTestResult::altDisplayString() const @@ -226,7 +238,7 @@ IntRect HitTestResult::imageRect() const { if (!image()) return IntRect(); - return m_innerNonSharedNode->renderer()->absoluteContentBox(); + return m_innerNonSharedNode->renderBox()->absoluteContentBox(); } KURL HitTestResult::absoluteImageURL() const diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h index 5ed9b34..4f0383f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h +++ b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h @@ -65,6 +65,7 @@ public: IntRect boundingBox() const; bool isSelected() const; String spellingToolTip() const; + String replacedString() const; String title() const; String altDisplayString() const; String titleDisplayString() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp index f5d0de5..2d956a8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp @@ -23,6 +23,7 @@ #include "HitTestResult.h" #include "InlineFlowBox.h" #include "RenderArena.h" +#include "RenderBox.h" #include "RootInlineBox.h" using namespace std; @@ -79,19 +80,47 @@ void InlineBox::operator delete(void* ptr, size_t sz) #ifndef NDEBUG void InlineBox::showTreeForThis() const { - if (m_object) - m_object->showTreeForThis(); + if (m_renderer) + m_renderer->showTreeForThis(); } #endif +int InlineBox::height() const +{ +#if ENABLE(SVG) + if (isSVG()) + return svgBoxHeight(); +#endif + + if (renderer()->isText()) + return m_isText ? renderer()->style(m_firstLine)->font().height() : 0; + if (renderer()->isBox() && parent()) + return toRenderBox(m_renderer)->height(); + + ASSERT(isInlineFlowBox()); + const InlineFlowBox* flowBox = static_cast<const InlineFlowBox*>(this); + RenderBoxModelObject* flowObject = boxModelObject(); + const Font& font = renderer()->style(m_firstLine)->font(); + int result = font.height(); + bool strictMode = renderer()->document()->inStrictMode(); + if (parent()) + result += flowObject->borderTop() + flowObject->paddingTop() + flowObject->borderBottom() + flowObject->paddingBottom(); + if (strictMode || flowBox->hasTextChildren() || flowObject->hasHorizontalBordersOrPadding()) + return result; + int bottom = root()->bottomOverflow(); + if (y() + result > bottom) + result = bottom - y(); + return result; +} + int InlineBox::caretMinOffset() const { - return m_object->caretMinOffset(); + return m_renderer->caretMinOffset(); } int InlineBox::caretMaxOffset() const { - return m_object->caretMaxOffset(); + return m_renderer->caretMaxOffset(); } unsigned InlineBox::caretMaxRenderedOffset() const @@ -108,34 +137,38 @@ void InlineBox::dirtyLineBoxes() void InlineBox::deleteLine(RenderArena* arena) { - if (!m_extracted) - m_object->setInlineBoxWrapper(0); + if (!m_extracted && m_renderer->isBox()) + toRenderBox(m_renderer)->setInlineBoxWrapper(0); destroy(arena); } void InlineBox::extractLine() { m_extracted = true; - m_object->setInlineBoxWrapper(0); + if (m_renderer->isBox()) + toRenderBox(m_renderer)->setInlineBoxWrapper(0); } void InlineBox::attachLine() { m_extracted = false; - m_object->setInlineBoxWrapper(this); + if (m_renderer->isBox()) + toRenderBox(m_renderer)->setInlineBoxWrapper(this); } void InlineBox::adjustPosition(int dx, int dy) { m_x += dx; m_y += dy; - if (m_object->isReplaced() || m_object->isBR()) - m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy); + if (m_renderer->isReplaced()) { + RenderBox* box = toRenderBox(m_renderer); + box->move(dx, dy); + } } void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { - if (!object()->shouldPaintWithinRoot(paintInfo) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) + if (!renderer()->shouldPaintWithinRoot(paintInfo) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; // Paint all phases of replaced elements atomically, as though the replaced element established its @@ -144,16 +177,16 @@ void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; RenderObject::PaintInfo info(paintInfo); info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - object()->paint(info, tx, ty); + renderer()->paint(info, tx, ty); if (!preservePhase) { info.phase = PaintPhaseChildBlockBackgrounds; - object()->paint(info, tx, ty); + renderer()->paint(info, tx, ty); info.phase = PaintPhaseFloat; - object()->paint(info, tx, ty); + renderer()->paint(info, tx, ty); info.phase = PaintPhaseForeground; - object()->paint(info, tx, ty); + renderer()->paint(info, tx, ty); info.phase = PaintPhaseOutline; - object()->paint(info, tx, ty); + renderer()->paint(info, tx, ty); } } @@ -162,7 +195,15 @@ bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result // Hit test all phases of replaced elements atomically, as though the replaced element established its // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 // specification.) - return object()->hitTest(request, result, IntPoint(x, y), tx, ty); + return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty); +} + +const RootInlineBox* InlineBox::root() const +{ + if (m_parent) + return m_parent->root(); + ASSERT(isRootInlineBox()); + return static_cast<const RootInlineBox*>(this); } RootInlineBox* InlineBox::root() @@ -225,13 +266,13 @@ InlineBox* InlineBox::prevLeafChild() RenderObject::SelectionState InlineBox::selectionState() { - return object()->selectionState(); + return renderer()->selectionState(); } bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) { // Non-replaced elements can always accommodate an ellipsis. - if (!m_object || !m_object->isReplaced()) + if (!m_renderer || !m_renderer->isReplaced()) return true; IntRect boxRect(m_x, 0, m_width, 10); @@ -239,7 +280,7 @@ bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidt return !(boxRect.intersects(ellipsisRect)); } -int InlineBox::placeEllipsisBox(bool, int, int, bool&) +int InlineBox::placeEllipsisBox(bool, int, int, int, bool&) { // Use -1 to mean "we didn't set the position." return -1; diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineBox.h index 41ad72a..9585278 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/InlineBox.h @@ -21,43 +21,41 @@ #ifndef InlineBox_h #define InlineBox_h -#include "RenderObject.h" // needed for RenderObject::PaintInfo +#include "RenderBoxModelObject.h" #include "TextDirection.h" namespace WebCore { +class HitTestRequest; class HitTestResult; class RootInlineBox; -struct HitTestRequest; // InlineBox represents a rectangle that occurs on a line. It corresponds to // some RenderObject (i.e., it represents a portion of that RenderObject). class InlineBox { public: InlineBox(RenderObject* obj) - : m_object(obj) + : m_next(0) + , m_prev(0) + , m_parent(0) + , m_renderer(obj) , m_x(0) , m_y(0) , m_width(0) - , m_height(0) - , m_baseline(0) - , m_next(0) - , m_prev(0) - , m_parent(0) , m_firstLine(false) , m_constructed(false) , m_bidiEmbeddingLevel(0) , m_dirty(false) , m_extracted(false) - , m_includeLeftEdge(false) - , m_includeRightEdge(false) - , m_hasTextChildren(true) +#if ENABLE(SVG) + , m_isSVG(false) +#endif , m_endsWithBreak(false) , m_hasSelectedChildren(false) , m_hasEllipsisBox(false) , m_dirOverride(false) - , m_treatAsText(true) + , m_isText(false) , m_determinedIfNextOnLineExists(false) , m_determinedIfPrevOnLineExists(false) , m_nextOnLineExists(false) @@ -69,30 +67,28 @@ public: { } - InlineBox(RenderObject* obj, int x, int y, int width, int height, int baseline, bool firstLine, bool constructed, + InlineBox(RenderObject* obj, int x, int y, int width, bool firstLine, bool constructed, bool dirty, bool extracted, InlineBox* next, InlineBox* prev, InlineFlowBox* parent) - : m_object(obj) + : m_next(next) + , m_prev(prev) + , m_parent(parent) + , m_renderer(obj) , m_x(x) , m_y(y) , m_width(width) - , m_height(height) - , m_baseline(baseline) - , m_next(next) - , m_prev(prev) - , m_parent(parent) , m_firstLine(firstLine) , m_constructed(constructed) , m_bidiEmbeddingLevel(0) , m_dirty(dirty) , m_extracted(extracted) - , m_includeLeftEdge(false) - , m_includeRightEdge(false) - , m_hasTextChildren(true) +#if ENABLE(SVG) + , m_isSVG(false) +#endif , m_endsWithBreak(false) , m_hasSelectedChildren(false) , m_hasEllipsisBox(false) , m_dirOverride(false) - , m_treatAsText(true) + , m_isText(false) , m_determinedIfNextOnLineExists(false) , m_determinedIfPrevOnLineExists(false) , m_nextOnLineExists(false) @@ -134,14 +130,16 @@ public: void showTreeForThis() const; #endif virtual bool isInlineBox() { return false; } - virtual bool isInlineFlowBox() { return false; } - virtual bool isContainer() { return false; } + virtual bool isInlineFlowBox() const { return false; } virtual bool isInlineTextBox() { return false; } - virtual bool isRootInlineBox() { return false; } + virtual bool isRootInlineBox() const { return false; } #if ENABLE(SVG) virtual bool isSVGRootInlineBox() { return false; } + bool isSVG() const { return m_isSVG; } + void setIsSVG(bool b) { m_isSVG = b; } #endif - virtual bool isText() const { return false; } + bool isText() const { return m_isText; } + void setIsText(bool b) { m_isText = b; } bool isConstructed() { return m_constructed; } virtual void setConstructed() @@ -178,7 +176,7 @@ public: InlineBox* nextLeafChild(); InlineBox* prevLeafChild(); - RenderObject* object() const { return m_object; } + RenderObject* renderer() const { return m_renderer; } InlineFlowBox* parent() const { @@ -187,29 +185,26 @@ public: } void setParent(InlineFlowBox* par) { m_parent = par; } + const RootInlineBox* root() const; RootInlineBox* root(); - + void setWidth(int w) { m_width = w; } int width() const { return m_width; } - void setXPos(int x) { m_x = x; } - int xPos() const { return m_x; } - - void setYPos(int y) { m_y = y; } - int yPos() const { return m_y; } + // x() is the left side of the box in the parent's coordinate system. + void setX(int x) { m_x = x; } + int x() const { return m_x; } - void setHeight(int h) { m_height = h; } - int height() const { return m_height; } - - void setBaseline(int b) { m_baseline = b; } - int baseline() const { return m_baseline; } + // y() is the top of the box in the parent's coordinate system. + void setY(int y) { m_y = y; } + int y() const { return m_y; } - bool hasTextChildren() const { return m_hasTextChildren; } + int height() const; - virtual int topOverflow() { return yPos(); } - virtual int bottomOverflow() { return yPos() + height(); } - virtual int leftOverflow() { return xPos(); } - virtual int rightOverflow() { return xPos() + width(); } + virtual int topOverflow() const { return y(); } + virtual int bottomOverflow() const { return y() + height(); } + virtual int leftOverflow() const { return x(); } + virtual int rightOverflow() const { return x() + width(); } virtual int caretMinOffset() const; virtual int caretMaxOffset() const; @@ -231,28 +226,40 @@ public: virtual RenderObject::SelectionState selectionState(); virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&); + // visibleLeftEdge, visibleRightEdge are in the parent's coordinate system. + virtual int placeEllipsisBox(bool ltr, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool&); void setHasBadParent(); int toAdd() const { return m_toAdd; } - bool visibleToHitTesting() const { return object()->style()->visibility() == VISIBLE && object()->style()->pointerEvents() != PE_NONE; } + bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; } -public: - RenderObject* m_object; + // Use with caution! The type is not checked! + RenderBoxModelObject* boxModelObject() const + { + if (!m_renderer->isText()) + return static_cast<RenderBoxModelObject*>(m_renderer); + return 0; + } - int m_x; - int m_y; - int m_width; - int m_height; - int m_baseline; +protected: +#if ENABLE(SVG) + virtual int svgBoxHeight() const { return 0; } +#endif private: InlineBox* m_next; // The next element on the same line as us. InlineBox* m_prev; // The previous element on the same line as us. InlineFlowBox* m_parent; // The box that contains us. + +public: + RenderObject* m_renderer; + + int m_x; + int m_y; + int m_width; // Some of these bits are actually for subclasses and moved here to compact the structures. @@ -266,10 +273,9 @@ protected: bool m_dirty : 1; bool m_extracted : 1; - // for InlineFlowBox - bool m_includeLeftEdge : 1; - bool m_includeRightEdge : 1; - bool m_hasTextChildren : 1; +#if ENABLE(SVG) + bool m_isSVG : 1; +#endif // for RootInlineBox bool m_endsWithBreak : 1; // Whether the line ends with a <br>. @@ -279,13 +285,13 @@ protected: // for InlineTextBox public: bool m_dirOverride : 1; - bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height. + bool m_isText : 1; // Whether or not this object represents text with a non-zero height. Includes non-image list markers, text boxes. protected: mutable bool m_determinedIfNextOnLineExists : 1; mutable bool m_determinedIfPrevOnLineExists : 1; mutable bool m_nextOnLineExists : 1; mutable bool m_prevOnLineExists : 1; - int m_toAdd : 13; // for justified text + int m_toAdd : 12; // for justified text #ifndef NDEBUG private: diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp index b4d240e..be6b966 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp @@ -28,7 +28,7 @@ #include "HitTestResult.h" #include "RootInlineBox.h" #include "RenderBlock.h" -#include "RenderFlow.h" +#include "RenderInline.h" #include "RenderListMarker.h" #include "RenderTableCell.h" #include "RootInlineBox.h" @@ -51,47 +51,6 @@ InlineFlowBox::~InlineFlowBox() #endif -RenderFlow* InlineFlowBox::flowObject() -{ - return static_cast<RenderFlow*>(m_object); -} - -int InlineFlowBox::marginLeft() -{ - if (!includeLeftEdge()) - return 0; - - Length margin = object()->style()->marginLeft(); - if (margin.isAuto()) - return 0; - if (margin.isFixed()) - return margin.value(); - return object()->marginLeft(); -} - -int InlineFlowBox::marginRight() -{ - if (!includeRightEdge()) - return 0; - - Length margin = object()->style()->marginRight(); - if (margin.isAuto()) - return 0; - if (margin.isFixed()) - return margin.value(); - return object()->marginRight(); -} - -int InlineFlowBox::marginBorderPaddingLeft() -{ - return marginLeft() + borderLeft() + paddingLeft(); -} - -int InlineFlowBox::marginBorderPaddingRight() -{ - return marginRight() + borderRight() + paddingRight(); -} - int InlineFlowBox::getFlowSpacingWidth() { int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight(); @@ -121,7 +80,7 @@ void InlineFlowBox::addToLine(InlineBox* child) child->setFirstLineStyleBit(m_firstLine); if (child->isText()) m_hasTextChildren = true; - if (child->object()->selectionState() != RenderObject::SelectionNone) + if (child->renderer()->selectionState() != RenderObject::SelectionNone) root()->setHasSelectedChildren(true); checkConsistency(); @@ -168,26 +127,41 @@ void InlineFlowBox::deleteLine(RenderArena* arena) m_lastChild = 0; #endif - static_cast<RenderFlow*>(m_object)->removeLineBox(this); + removeLineBoxFromRenderObject(); destroy(arena); } +void InlineFlowBox::removeLineBoxFromRenderObject() +{ + toRenderInline(renderer())->lineBoxes()->removeLineBox(this); +} + void InlineFlowBox::extractLine() { if (!m_extracted) - static_cast<RenderFlow*>(m_object)->extractLineBox(this); + extractLineBoxFromRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->extractLine(); } +void InlineFlowBox::extractLineBoxFromRenderObject() +{ + toRenderInline(renderer())->lineBoxes()->extractLineBox(this); +} + void InlineFlowBox::attachLine() { if (m_extracted) - static_cast<RenderFlow*>(m_object)->attachLineBox(this); + attachLineBoxToRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->attachLine(); } +void InlineFlowBox::attachLineBoxToRenderObject() +{ + toRenderInline(renderer())->lineBoxes()->attachLineBox(this); +} + void InlineFlowBox::adjustPosition(int dx, int dy) { InlineRunBox::adjustPosition(dx, dy); @@ -195,18 +169,23 @@ void InlineFlowBox::adjustPosition(int dx, int dy) child->adjustPosition(dx, dy); } +RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const +{ + return toRenderInline(renderer())->lineBoxes(); +} + bool InlineFlowBox::onEndChain(RenderObject* endObject) { if (!endObject) return false; - if (endObject == object()) + if (endObject == renderer()) return true; RenderObject* curr = endObject; RenderObject* parent = curr->parent(); while (parent && !parent->isRenderBlock()) { - if (parent->lastChild() != curr || parent == object()) + if (parent->lastChild() != curr || parent == renderer()) return false; curr = parent; @@ -223,19 +202,17 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en bool includeLeftEdge = false; bool includeRightEdge = false; - RenderFlow* flow = static_cast<RenderFlow*>(object()); - - if (!flow->firstChild()) - includeLeftEdge = includeRightEdge = true; // Empty inlines never split across lines. - else if (parent()) { // The root inline box never has borders/margins/padding. - bool ltr = flow->style()->direction() == LTR; - + // The root inline box never has borders/margins/padding. + if (parent()) { + bool ltr = renderer()->style()->direction() == LTR; + // Check to see if all initial lines are unconstructed. If so, then - // we know the inline began on this line. - if (!flow->firstLineBox()->isConstructed()) { - if (ltr && flow->firstLineBox() == this) + // we know the inline began on this line (unless we are a continuation). + RenderLineBoxList* lineBoxList = rendererLineBoxes(); + if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineContinuation()) { + if (ltr && lineBoxList->firstLineBox() == this) includeLeftEdge = true; - else if (!ltr && flow->lastLineBox() == this) + else if (!ltr && lineBoxList->lastLineBox() == this) includeRightEdge = true; } @@ -246,14 +223,15 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en // reverse for rtl), then the inline has closed. // (3) The line may end on the inline. If we are the last child (climbing up // the end object's chain), then we just closed as well. - if (!flow->lastLineBox()->isConstructed()) { + if (!lineBoxList->lastLineBox()->isConstructed()) { + RenderInline* inlineFlow = toRenderInline(renderer()); if (ltr) { if (!nextLineBox() && - ((lastLine && !object()->continuation()) || nextOnLineExists() || onEndChain(endObject))) + ((lastLine && !inlineFlow->continuation()) || nextOnLineExists() || onEndChain(endObject))) includeRightEdge = true; } else { if ((!prevLineBox() || prevLineBox()->isConstructed()) && - ((lastLine && !object()->continuation()) || prevOnLineExists() || onEndChain(endObject))) + ((lastLine && !inlineFlow->continuation()) || prevOnLineExists() || onEndChain(endObject))) includeLeftEdge = true; } } @@ -270,32 +248,32 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en } } -int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing) +int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& rightPosition, bool& needsWordSpacing) { // Set our x position. - setXPos(x); + setX(xPos); int boxShadowLeft = 0; int boxShadowRight = 0; - for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { boxShadowLeft = min(boxShadow->x - boxShadow->blur, boxShadowLeft); boxShadowRight = max(boxShadow->x + boxShadow->blur, boxShadowRight); } - leftPosition = min(x + boxShadowLeft, leftPosition); + leftPosition = min(xPos + boxShadowLeft, leftPosition); - int startX = x; - x += borderLeft() + paddingLeft(); + int startX = xPos; + xPos += borderLeft() + paddingLeft(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isText()) { + if (curr->renderer()->isText()) { InlineTextBox* text = static_cast<InlineTextBox*>(curr); - RenderText* rt = static_cast<RenderText*>(text->object()); + RenderText* rt = toRenderText(text->renderer()); if (rt->textLength()) { if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()])) - x += rt->style(m_firstLine)->font().wordSpacing(); + xPos += rt->style(m_firstLine)->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]); } - text->setXPos(x); + text->setX(xPos); int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f)); @@ -313,49 +291,44 @@ int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPo visualOverflowRight = max(visualOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow); } - leftPosition = min(x + visualOverflowLeft, leftPosition); - rightPosition = max(x + text->width() + visualOverflowRight, rightPosition); - m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), m_maxHorizontalVisualOverflow); - x += text->width(); + leftPosition = min(xPos + visualOverflowLeft, leftPosition); + rightPosition = max(xPos + text->width() + visualOverflowRight, rightPosition); + m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), (int)m_maxHorizontalVisualOverflow); + xPos += text->width(); } else { - if (curr->object()->isPositioned()) { - if (curr->object()->parent()->style()->direction() == LTR) - curr->setXPos(x); + if (curr->renderer()->isPositioned()) { + if (curr->renderer()->parent()->style()->direction() == LTR) + curr->setX(xPos); else // Our offset that we cache needs to be from the edge of the right border box and // not the left border box. We have to subtract |x| from the width of the block // (which can be obtained from the root line box). - curr->setXPos(root()->object()->width()-x); + curr->setX(root()->block()->width() - xPos); continue; // The positioned object has no effect on the width. } - if (curr->object()->isInlineFlow()) { + if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); - if (curr->object()->isCompact()) { - int ignoredX = x; - flow->placeBoxesHorizontally(ignoredX, leftPosition, rightPosition, needsWordSpacing); - } else { - x += flow->marginLeft(); - x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing); - x += flow->marginRight(); - } - } else if (!curr->object()->isCompact() && (!curr->object()->isListMarker() || static_cast<RenderListMarker*>(curr->object())->isInside())) { - x += curr->object()->marginLeft(); - curr->setXPos(x); - leftPosition = min(x + curr->object()->overflowLeft(false), leftPosition); - rightPosition = max(x + curr->object()->overflowWidth(false), rightPosition); - x += curr->width() + curr->object()->marginRight(); + xPos += flow->marginLeft(); + xPos = flow->placeBoxesHorizontally(xPos, leftPosition, rightPosition, needsWordSpacing); + xPos += flow->marginRight(); + } else if (!curr->renderer()->isListMarker() || static_cast<RenderListMarker*>(curr->renderer())->isInside()) { + xPos += curr->boxModelObject()->marginLeft(); + curr->setX(xPos); + leftPosition = min(xPos + toRenderBox(curr->renderer())->overflowLeft(false), leftPosition); + rightPosition = max(xPos + toRenderBox(curr->renderer())->overflowWidth(false), rightPosition); + xPos += curr->width() + curr->boxModelObject()->marginRight(); } } } - x += borderRight() + paddingRight(); - setWidth(x - startX); - rightPosition = max(xPos() + width() + boxShadowRight, rightPosition); + xPos += borderRight() + paddingRight(); + setWidth(xPos - startX); + rightPosition = max(x() + width() + boxShadowRight, rightPosition); - return x; + return xPos; } -void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) +int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock) { int maxPositionTop = 0; int maxPositionBottom = 0; @@ -364,8 +337,8 @@ void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) // Figure out if we're in strict mode. Note that we can't simply use !style()->htmlHacks(), // because that would match almost strict mode as well. - RenderObject* curr = object(); - while (curr && !curr->element()) + RenderObject* curr = renderer(); + while (curr && !curr->node()) curr = curr->container(); bool strictMode = (curr && curr->document()->inStrictMode()); @@ -383,12 +356,10 @@ void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) setVerticalOverflowPositions(topPosition, bottomPosition); setVerticalSelectionPositions(selectionTop, selectionBottom); - - // Shrink boxes with no text children in quirks and almost strict mode. - if (!strictMode) - shrinkBoxesWithNoTextChildren(topPosition, bottomPosition); heightOfBlock += maxHeight; + + return heightOfBlock; } void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, @@ -397,16 +368,17 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { // The computed lineheight needs to be extended for the // positioned elements - if (curr->object()->isPositioned()) + if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->yPos() == PositionTop || curr->yPos() == PositionBottom) { - if (curr->yPos() == PositionTop) { - if (maxAscent + maxDescent < curr->height()) - maxDescent = curr->height() - maxAscent; + if (curr->y() == PositionTop || curr->y() == PositionBottom) { + int lineHeight = curr->renderer()->lineHeight(m_firstLine); + if (curr->y() == PositionTop) { + if (maxAscent + maxDescent < lineHeight) + maxDescent = lineHeight - maxAscent; } else { - if (maxAscent + maxDescent < curr->height()) - maxAscent = curr->height() - maxDescent; + if (maxAscent + maxDescent < lineHeight) + maxAscent = lineHeight - maxDescent; } if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom)) @@ -418,47 +390,86 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, } } +static int verticalPositionForBox(InlineBox* curr, bool firstLine) +{ + if (curr->renderer()->isText()) + return curr->parent()->y(); + if (curr->renderer()->isBox()) + return toRenderBox(curr->renderer())->verticalPosition(firstLine); + return toRenderInline(curr->renderer())->verticalPositionFromCache(firstLine); +} + void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool strictMode) { if (isRootInlineBox()) { // Examine our root box. - setHeight(object()->lineHeight(m_firstLine, true)); - bool isTableCell = object()->isTableCell(); - if (isTableCell) { - RenderTableCell* tableCell = static_cast<RenderTableCell*>(object()); - setBaseline(tableCell->RenderBlock::baselinePosition(m_firstLine, true)); - } - else - setBaseline(object()->baselinePosition(m_firstLine, true)); + int lineHeight = renderer()->lineHeight(m_firstLine, true); + int baseline = renderer()->baselinePosition(m_firstLine, true); if (hasTextChildren() || strictMode) { - int ascent = baseline(); - int descent = height() - ascent; + int ascent = baseline; + int descent = lineHeight - ascent; if (maxAscent < ascent) maxAscent = ascent; if (maxDescent < descent) maxDescent = descent; } } - + for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) + if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. - curr->setHeight(curr->object()->lineHeight(m_firstLine)); - curr->setBaseline(curr->object()->baselinePosition(m_firstLine)); - curr->setYPos(curr->object()->verticalPositionHint(m_firstLine)); - if (curr->yPos() == PositionTop) { - if (maxPositionTop < curr->height()) - maxPositionTop = curr->height(); - } - else if (curr->yPos() == PositionBottom) { - if (maxPositionBottom < curr->height()) - maxPositionBottom = curr->height(); + bool isInlineFlow = curr->isInlineFlowBox(); + + int lineHeight; + int baseline; + Vector<const SimpleFontData*> usedFonts; + if (curr->isInlineTextBox()) + static_cast<InlineTextBox*>(curr)->takeFallbackFonts(usedFonts); + + if (!usedFonts.isEmpty()) { + usedFonts.append(curr->renderer()->style(m_firstLine)->font().primaryFont()); + Length parentLineHeight = curr->renderer()->parent()->style()->lineHeight(); + if (parentLineHeight.isNegative()) { + int baselineToBottom = 0; + baseline = 0; + for (size_t i = 0; i < usedFonts.size(); ++i) { + int halfLeading = (usedFonts[i]->lineSpacing() - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2; + baseline = max(baseline, halfLeading + usedFonts[i]->ascent()); + baselineToBottom = max(baselineToBottom, usedFonts[i]->lineSpacing() - usedFonts[i]->ascent() - usedFonts[i]->descent() - halfLeading); + } + lineHeight = baseline + baselineToBottom; + } else if (parentLineHeight.isPercent()) { + 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; + baseline = max(baseline, halfLeading + usedFonts[i]->ascent()); + } + } else { + lineHeight = parentLineHeight.value(); + baseline = 0; + for (size_t i = 0; i < usedFonts.size(); ++i) { + int halfLeading = (lineHeight - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2; + baseline = max(baseline, halfLeading + usedFonts[i]->ascent()); + } + } + } else { + lineHeight = curr->renderer()->lineHeight(m_firstLine); + baseline = curr->renderer()->baselinePosition(m_firstLine); } - else if (curr->hasTextChildren() || curr->object()->hasHorizontalBordersOrPadding() || strictMode) { - int ascent = curr->baseline() - curr->yPos(); - int descent = curr->height() - ascent; + + curr->setY(verticalPositionForBox(curr, m_firstLine)); + if (curr->y() == PositionTop) { + if (maxPositionTop < lineHeight) + maxPositionTop = lineHeight; + } else if (curr->y() == PositionBottom) { + if (maxPositionBottom < lineHeight) + maxPositionBottom = lineHeight; + } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasHorizontalBordersOrPadding() || strictMode) { + int ascent = baseline - curr->y(); + int descent = lineHeight - ascent; if (maxAscent < ascent) maxAscent = ascent; if (maxDescent < descent) @@ -470,135 +481,112 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi } } -void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, +void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode, int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom) { if (isRootInlineBox()) - setYPos(y + maxAscent - baseline());// Place our root box. + setY(yPos + max(0, maxAscent - renderer()->baselinePosition(m_firstLine, true))); // Place our root box. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) + if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. // Adjust boxes to use their real box y/height and not the logical height (as dictated by // line-height). - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); + bool isInlineFlow = curr->isInlineFlowBox(); + if (isInlineFlow) + static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); bool childAffectsTopBottomPos = true; - if (curr->yPos() == PositionTop) - curr->setYPos(y); - else if (curr->yPos() == PositionBottom) - curr->setYPos(y + maxHeight - curr->height()); + if (curr->y() == PositionTop) + curr->setY(yPos); + else if (curr->y() == PositionBottom) + curr->setY(yPos + maxHeight - curr->renderer()->lineHeight(m_firstLine)); else { - if (!curr->hasTextChildren() && !curr->object()->hasHorizontalBordersOrPadding() && !strictMode) + if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode) childAffectsTopBottomPos = false; - curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline()); + int posAdjust = maxAscent - curr->renderer()->baselinePosition(m_firstLine); + if (!childAffectsTopBottomPos) + posAdjust = max(0, posAdjust); + curr->setY(curr->y() + yPos + posAdjust); } - int newY = curr->yPos(); - int newHeight = curr->height(); - int newBaseline = curr->baseline(); + // FIXME: By only considering overflow as part of the root line box, we can't get an accurate picture regarding what the line + // actually needs to paint. A line box that is part of a self-painting layer technically shouldn't contribute to the overflow + // of the line, but in order to not do this and paint accurately, we have to track the overflow somewhere else (either by storing overflow + // in each InlineFlowBox up the chain or in the layer itself). Relative positioned objects on a line will cause scrollbars + // to appear when they shouldn't until we fix this issue. + int newY = curr->y(); int overflowTop = 0; int overflowBottom = 0; if (curr->isText() || curr->isInlineFlowBox()) { - const Font& font = curr->object()->style(m_firstLine)->font(); - newBaseline = font.ascent(); - newY += curr->baseline() - newBaseline; - newHeight = newBaseline + font.descent(); - for (ShadowData* shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) { + const Font& font = curr->renderer()->style(m_firstLine)->font(); + newY += curr->renderer()->baselinePosition(m_firstLine) - font.ascent(); + for (ShadowData* shadow = curr->renderer()->style()->textShadow(); shadow; shadow = shadow->next) { overflowTop = min(overflowTop, shadow->y - shadow->blur); overflowBottom = max(overflowBottom, shadow->y + shadow->blur); } - for (ShadowData* boxShadow = curr->object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + for (ShadowData* boxShadow = curr->renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur); overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur); } - for (ShadowData* textShadow = curr->object()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { + for (ShadowData* textShadow = curr->renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { overflowTop = min(overflowTop, textShadow->y - textShadow->blur); overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur); } - if (curr->object()->hasReflection()) { - overflowTop = min(overflowTop, curr->object()->reflectionBox().y()); - overflowBottom = max(overflowBottom, curr->object()->reflectionBox().bottom()); + if (curr->renderer()->hasReflection()) { + RenderBox* box = toRenderBox(curr->renderer()); + overflowTop = min(overflowTop, box->reflectionBox().y()); + overflowBottom = max(overflowBottom, box->reflectionBox().bottom()); } - if (curr->isInlineFlowBox()) { - newHeight += curr->object()->borderTop() + curr->object()->paddingTop() + - curr->object()->borderBottom() + curr->object()->paddingBottom(); - newY -= curr->object()->borderTop() + curr->object()->paddingTop(); - newBaseline += curr->object()->borderTop() + curr->object()->paddingTop(); - } - } else if (!curr->object()->isBR()) { - newY += curr->object()->marginTop(); - newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom()); - overflowTop = curr->object()->overflowTop(false); - overflowBottom = curr->object()->overflowHeight(false) - newHeight; + if (curr->isInlineFlowBox()) + newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop(); + } else if (!curr->renderer()->isBR()) { + RenderBox* box = toRenderBox(curr->renderer()); + newY += box->marginTop(); + overflowTop = box->overflowTop(false); + overflowBottom = box->overflowHeight(false) - box->height(); } - curr->setYPos(newY); - curr->setHeight(newHeight); - curr->setBaseline(newBaseline); + curr->setY(newY); if (childAffectsTopBottomPos) { + int boxHeight = curr->height(); selectionTop = min(selectionTop, newY); - selectionBottom = max(selectionBottom, newY + newHeight); + selectionBottom = max(selectionBottom, newY + boxHeight); topPosition = min(topPosition, newY + overflowTop); - bottomPosition = max(bottomPosition, newY + newHeight + overflowBottom); + bottomPosition = max(bottomPosition, newY + boxHeight + overflowBottom); } } if (isRootInlineBox()) { - const Font& font = object()->style(m_firstLine)->font(); - setHeight(font.ascent() + font.descent()); - setYPos(yPos() + baseline() - font.ascent()); - setBaseline(font.ascent()); + const Font& font = renderer()->style(m_firstLine)->font(); + setY(y() + renderer()->baselinePosition(m_firstLine, true) - font.ascent()); if (hasTextChildren() || strictMode) { - selectionTop = min(selectionTop, yPos()); - selectionBottom = max(selectionBottom, yPos() + height()); + selectionTop = min(selectionTop, y()); + selectionBottom = max(selectionBottom, y() + height()); } } } -void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos) -{ - // First shrink our kids. - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos); - } - - // See if we have text children. If not, then we need to shrink ourselves to fit on the line. - if (!hasTextChildren() && !object()->hasHorizontalBordersOrPadding()) { - if (yPos() < topPos) - setYPos(topPos); - if (yPos() + height() > bottomPos) - setHeight(bottomPos - yPos()); - if (baseline() > height()) - setBaseline(height()); - } -} - bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) { // Check children first. for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if (!curr->object()->hasLayer() && curr->nodeAtPoint(request, result, x, y, tx, ty)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) { + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } } // Now check ourselves. - IntRect rect(tx + m_x, ty + m_y, m_width, m_height); + IntRect rect(tx + m_x, ty + m_y, m_width, height()); if (visibleToHitTesting() && rect.contains(x, y)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space. + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space. return true; } @@ -607,15 +595,15 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { - int xPos = tx + m_x - object()->maximalOutlineSize(paintInfo.phase); - int w = width() + 2 * object()->maximalOutlineSize(paintInfo.phase); + int xPos = tx + m_x - renderer()->maximalOutlineSize(paintInfo.phase); + int w = width() + 2 * renderer()->maximalOutlineSize(paintInfo.phase); int shadowLeft = 0; int shadowRight = 0; - for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft); shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight); } - for (ShadowData* textShadow = object()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { + for (ShadowData* textShadow = renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft); shadowRight = max(textShadow->x + textShadow->blur, shadowRight); } @@ -627,14 +615,15 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) { // Add ourselves to the paint info struct's list of inlines that need to paint their // outlines. - if (object()->style()->visibility() == VISIBLE && object()->hasOutline() && !isRootInlineBox()) { - if ((object()->continuation() || object()->isInlineContinuation()) && !object()->hasLayer()) { + if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) { + RenderInline* inlineFlow = toRenderInline(renderer()); + if ((inlineFlow->continuation() || inlineFlow->isInlineContinuation()) && !boxModelObject()->hasSelfPaintingLayer()) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. - RenderBlock* block = object()->containingBlock()->containingBlock(); - block->addContinuationWithOutline(static_cast<RenderFlow*>(object()->element()->renderer())); - } else if (!object()->isInlineContinuation()) - paintInfo.outlineObjects->add(flowObject()); + RenderBlock* block = renderer()->containingBlock()->containingBlock(); + block->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer())); + } else if (!inlineFlow->isInlineContinuation()) + paintInfo.outlineObjects->add(inlineFlow); } } else if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, tx, ty); @@ -654,12 +643,12 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase; RenderObject::PaintInfo childInfo(paintInfo); childInfo.phase = paintPhase; - childInfo.paintingRoot = object()->paintingRootForChildren(paintInfo); + childInfo.paintingRoot = renderer()->paintingRootForChildren(paintInfo); // 3. Paint our children. if (paintPhase != PaintPhaseSelfOutline) { for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (!curr->object()->hasLayer()) + if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) curr->paint(childInfo, tx, ty); } } @@ -669,22 +658,20 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) paintTextDecorations(paintInfo, tx, ty, true); } -void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int my, int mh, int _tx, int _ty, int w, int h, CompositeOperator op) +void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int _tx, int _ty, int w, int h, CompositeOperator op) { if (!fillLayer) return; - paintFillLayers(paintInfo, c, fillLayer->next(), my, mh, _tx, _ty, w, h, op); - paintFillLayer(paintInfo, c, fillLayer, my, mh, _tx, _ty, w, h, op); + paintFillLayers(paintInfo, c, fillLayer->next(), _tx, _ty, w, h, op); + paintFillLayer(paintInfo, c, fillLayer, _tx, _ty, w, h, op); } -void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator op) +void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int w, int h, CompositeOperator op) { StyleImage* img = fillLayer->image(); - bool hasFillImage = img && img->canRender(object()->style()->effectiveZoom()); - if ((!hasFillImage && !object()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) - object()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, tx, ty, w, h, this, op); + bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom()); + if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, op); else { // We have a fill image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -703,7 +690,7 @@ void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, con totalWidth += curr->width(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); - object()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, startX, ty, totalWidth, h, this, op); + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, startX, ty, totalWidth, h, this, op); paintInfo.context->restore(); } } @@ -711,17 +698,17 @@ void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, con void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, int tx, int ty, int w, int h) { if ((!prevLineBox() && !nextLineBox()) || !parent()) - object()->paintBoxShadow(context, tx, ty, w, h, s); + boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s); else { // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines - object()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge()); + boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge()); } } void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty) { - if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) + if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; // Move x/y to our coordinates. @@ -731,30 +718,23 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - GraphicsContext* context = paintInfo.context; // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. - RenderStyle* styleToUse = object()->style(m_firstLine); - if ((!parent() && m_firstLine && styleToUse != object()->style()) || (parent() && object()->hasBoxDecorations())) { + RenderStyle* styleToUse = renderer()->style(m_firstLine); + if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) { // Shadow comes first and is behind the background and border. if (styleToUse->boxShadow()) paintBoxShadow(context, styleToUse, tx, ty, w, h); Color c = styleToUse->backgroundColor(); - paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h); // :first-line cannot be used to put borders on a line. Always paint borders with our // non-first-line style. - if (parent() && object()->style()->hasBorder()) { - StyleImage* borderImage = object()->style()->borderImage().image(); + if (parent() && renderer()->style()->hasBorder()) { + StyleImage* borderImage = renderer()->style()->borderImage().image(); bool hasBorderImage = borderImage && borderImage->canRender(styleToUse->effectiveZoom()); if (hasBorderImage && !borderImage->isLoaded()) return; // Don't paint anything while we wait for the image to load. @@ -762,7 +742,7 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int // The simple case is where we either have no border image or we are the only box for this object. In those // cases only a single call to draw is required. if (!hasBorderImage || (!prevLineBox() && !nextLineBox())) - object()->paintBorder(context, tx, ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge()); + boxModelObject()->paintBorder(context, tx, ty, w, h, renderer()->style(), includeLeftEdge(), includeRightEdge()); else { // We have a border image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -780,8 +760,8 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) totalWidth += curr->width(); context->save(); - context->clip(IntRect(tx, ty, width(), height())); - object()->paintBorder(context, startX, ty, totalWidth, h, object()->style()); + context->clip(IntRect(tx, ty, w, h)); + boxModelObject()->paintBorder(context, startX, ty, totalWidth, h, renderer()->style()); context->restore(); } } @@ -790,7 +770,7 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty) { - if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; // Move x/y to our coordinates. @@ -800,19 +780,11 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; - const NinePieceImage& maskNinePieceImage = object()->style()->maskBoxImage(); - StyleImage* maskBoxImage = object()->style()->maskBoxImage().image(); - if ((maskBoxImage && object()->style()->maskLayers()->hasImage()) || object()->style()->maskLayers()->next()) + const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage(); + StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image(); + if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next()) pushTransparencyLayer = true; CompositeOperator compositeOp = CompositeDestinationIn; @@ -822,16 +794,16 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty compositeOp = CompositeSourceOver; } - paintFillLayers(paintInfo, Color(), object()->style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp); + paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp); - bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(object()->style()->effectiveZoom()); + bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer()->style()->effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) return; // Don't paint anything while we wait for the image to load. // The simple case is where we are the only box for this object. In those // cases only a single call to draw is required. if (!prevLineBox() && !nextLineBox()) { - object()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, object()->style(), maskNinePieceImage, compositeOp); + boxModelObject()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, renderer()->style(), maskNinePieceImage, compositeOp); } else { // We have a mask image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -843,8 +815,8 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) totalWidth += curr->width(); paintInfo.context->save(); - paintInfo.context->clip(IntRect(tx, ty, width(), height())); - object()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, object()->style(), maskNinePieceImage, compositeOp); + paintInfo.context->clip(IntRect(tx, ty, w, h)); + boxModelObject()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, renderer()->style(), maskNinePieceImage, compositeOp); paintInfo.context->restore(); } @@ -855,12 +827,12 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty static bool shouldDrawTextDecoration(RenderObject* obj) { for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isInlineFlow()) + if (curr->isRenderInline()) return true; if (curr->isText() && !curr->isBR()) { if (!curr->style()->collapseWhiteSpace()) return true; - Node* currElement = curr->element(); + Node* currElement = curr->node(); if (!currElement) return true; if (!currElement->isTextNode()) @@ -876,8 +848,8 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int { // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in // almost-strict mode or strict mode). - if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(paintInfo) || - object()->style()->visibility() != VISIBLE) + if (renderer()->style()->htmlHacks() || !renderer()->shouldPaintWithinRoot(paintInfo) || + renderer()->style()->visibility() != VISIBLE) return; // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text. @@ -887,27 +859,46 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int GraphicsContext* context = paintInfo.context; tx += m_x; ty += m_y; - RenderStyle* styleToUse = object()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(m_firstLine); int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect(); if (deco != TDNONE && ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) && - shouldDrawTextDecoration(object())) { + shouldDrawTextDecoration(renderer())) { int x = m_x + borderLeft() + paddingLeft(); int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight()); RootInlineBox* rootLine = root(); if (rootLine->ellipsisBox()) { - int ellipsisX = rootLine->ellipsisBox()->xPos(); + int ellipsisX = m_x + rootLine->ellipsisBox()->x(); int ellipsisWidth = rootLine->ellipsisBox()->width(); - - // FIXME: Will need to work with RTL + bool ltr = renderer()->style()->direction() == LTR; if (rootLine == this) { - if (x + w >= ellipsisX + ellipsisWidth) - w -= (x + w - ellipsisX - ellipsisWidth); + // Trim w and x so that the underline isn't drawn underneath the ellipsis. + // ltr: is our right edge farther right than the right edge of the ellipsis. + // rtl: is the left edge of our box farther left than the left edge of the ellipsis. + bool ltrTruncation = ltr && (x + w >= ellipsisX + ellipsisWidth); + bool rtlTruncation = !ltr && (x <= ellipsisX + ellipsisWidth); + if (ltrTruncation) + w -= (x + w) - (ellipsisX + ellipsisWidth); + else if (rtlTruncation) { + int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth); + tx -= dx; + w += dx; + } } else { - if (x >= ellipsisX) + bool ltrPastEllipsis = ltr && x >= ellipsisX; + bool rtlPastEllipsis = !ltr && (x + w) <= (ellipsisX + ellipsisWidth); + if (ltrPastEllipsis || rtlPastEllipsis) return; - if (x + w >= ellipsisX) + + bool ltrTruncation = ltr && x + w >= ellipsisX; + bool rtlTruncation = !ltr && x <= ellipsisX; + if (ltrTruncation) w -= (x + w - ellipsisX); + else if (rtlTruncation) { + int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth); + tx -= dx; + w += dx; + } } } @@ -917,9 +908,9 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int Color underline, overline, linethrough; underline = overline = linethrough = styleToUse->color(); if (!parent()) - object()->getTextDecorationColors(deco, underline, overline, linethrough); + renderer()->getTextDecorationColors(deco, underline, overline, linethrough); - bool isPrinting = object()->document()->printing(); + bool isPrinting = renderer()->document()->printing(); context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1. bool paintUnderline = deco & UNDERLINE && !paintedChildren; @@ -928,13 +919,17 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255); + int baselinePos = renderer()->style(m_firstLine)->font().ascent(); + if (!isRootInlineBox()) + baselinePos += borderTop() + paddingTop(); + bool setClip = false; int extraOffset = 0; ShadowData* shadow = styleToUse->textShadow(); if (!linesAreOpaque && shadow && shadow->next) { - IntRect clipRect(tx, ty, w, m_baseline + 2); + IntRect clipRect(tx, ty, w, baselinePos + 2); for (ShadowData* s = shadow; s; s = s->next) { - IntRect shadowRect(tx, ty, w, m_baseline + 2); + IntRect shadowRect(tx, ty, w, baselinePos + 2); shadowRect.inflate(s->blur); shadowRect.move(s->x, s->y); clipRect.unite(shadowRect); @@ -942,7 +937,7 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int } context->save(); context->clip(clipRect); - extraOffset += m_baseline + 2; + extraOffset += baselinePos + 2; ty += extraOffset; setClip = true; } @@ -962,16 +957,19 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int if (paintUnderline) { context->setStrokeColor(underline); + context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. - context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), w, isPrinting); + context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting); } if (paintOverline) { context->setStrokeColor(overline); + context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), w, isPrinting); } if (paintLineThrough) { context->setStrokeColor(linethrough); - context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), w, isPrinting); + context->setStrokeStyle(SolidStroke); + context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting); } } while (shadow); @@ -1026,13 +1024,32 @@ bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsis return true; } -int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) +int InlineFlowBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox) { int result = -1; - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { - int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); + // We iterate over all children, the foundBox variable tells us when we've found the + // box containing the ellipsis. All boxes after that one in the flow are hidden. + // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate + // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis. + InlineBox *box = ltr ? firstChild() : lastChild(); + + // NOTE: these will cross after foundBox = true. + int visibleLeftEdge = blockLeftEdge; + int visibleRightEdge = blockRightEdge; + + while(box) { + int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, foundBox); if (currResult != -1 && result == -1) result = currResult; + + if (ltr) { + visibleLeftEdge += box->width(); + box = box->nextOnLine(); + } + else { + visibleRightEdge -= box->width(); + box = box->prevOnLine(); + } } return result; } diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h index 30dad38..ab1b6f2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h @@ -25,9 +25,9 @@ namespace WebCore { +class HitTestRequest; class HitTestResult; - -struct HitTestRequest; +class RenderLineBoxList; class InlineFlowBox : public InlineRunBox { public: @@ -36,6 +36,9 @@ public: , m_firstChild(0) , m_lastChild(0) , m_maxHorizontalVisualOverflow(0) + , m_includeLeftEdge(false) + , m_includeRightEdge(false) + , m_hasTextChildren(true) #ifndef NDEBUG , m_hasBadChildList(false) #endif @@ -52,10 +55,6 @@ public: virtual ~InlineFlowBox(); #endif - RenderFlow* flowObject(); - - virtual bool isInlineFlowBox() { return true; } - InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); } InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); } @@ -80,30 +79,38 @@ public: virtual void attachLine(); virtual void adjustPosition(int dx, int dy); + virtual void extractLineBoxFromRenderObject(); + virtual void attachLineBoxToRenderObject(); + virtual void removeLineBoxFromRenderObject(); + virtual void clearTruncation(); virtual void paintBoxDecorations(RenderObject::PaintInfo&, int tx, int ty); virtual void paintMask(RenderObject::PaintInfo&, int tx, int ty); - void paintFillLayers(const RenderObject::PaintInfo&, const Color&, const FillLayer*, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); - void paintFillLayer(const RenderObject::PaintInfo&, const Color&, const FillLayer*, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); + void paintFillLayers(const RenderObject::PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); + void paintFillLayer(const RenderObject::PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); void paintBoxShadow(GraphicsContext*, RenderStyle*, int tx, int ty, int w, int h); virtual void paintTextDecorations(RenderObject::PaintInfo&, int tx, int ty, bool paintedChildren = false); virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); - int marginBorderPaddingLeft(); - int marginBorderPaddingRight(); - int marginLeft(); - int marginRight(); - int borderLeft() { if (includeLeftEdge()) return object()->borderLeft(); return 0; } - int borderRight() { if (includeRightEdge()) return object()->borderRight(); return 0; } - int paddingLeft() { if (includeLeftEdge()) return object()->paddingLeft(); return 0; } - int paddingRight() { if (includeRightEdge()) return object()->paddingRight(); return 0; } - - bool includeLeftEdge() { return m_includeLeftEdge; } - bool includeRightEdge() { return m_includeRightEdge; } + virtual RenderLineBoxList* rendererLineBoxes() const; + + int marginBorderPaddingLeft() const { return marginLeft() + borderLeft() + paddingLeft(); } + int marginBorderPaddingRight() const { return marginRight() + borderRight() + paddingRight(); } + int marginLeft() const { if (includeLeftEdge()) return boxModelObject()->marginLeft(); return 0; } + int marginRight() const { if (includeRightEdge()) return boxModelObject()->marginRight(); return 0; } + int borderLeft() const { if (includeLeftEdge()) return renderer()->style()->borderLeftWidth(); return 0; } + int borderRight() const { if (includeRightEdge()) return renderer()->style()->borderRightWidth(); return 0; } + int borderTop() const { return renderer()->style()->borderTopWidth(); } + int borderBottom() const { return renderer()->style()->borderBottomWidth(); } + int paddingLeft() const { if (includeLeftEdge()) return boxModelObject()->paddingLeft(); return 0; } + int paddingRight() const { if (includeRightEdge()) return boxModelObject()->paddingRight(); return 0; } + int paddingTop() const { return boxModelObject()->paddingTop(); } + int paddingBottom() const { return boxModelObject()->paddingBottom(); } + + bool includeLeftEdge() const { return m_includeLeftEdge; } + bool includeRightEdge() const { return m_includeRightEdge; } void setEdges(bool includeLeft, bool includeRight) { m_includeLeftEdge = includeLeft; @@ -115,33 +122,40 @@ public: int getFlowSpacingWidth(); bool onEndChain(RenderObject* endObject); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool strictMode); void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom); void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom); - void shrinkBoxesWithNoTextChildren(int topPosition, int bottomPosition); virtual void setVerticalOverflowPositions(int /*top*/, int /*bottom*/) { } virtual void setVerticalSelectionPositions(int /*top*/, int /*bottom*/) { } - int maxHorizontalVisualOverflow() const { return m_maxHorizontalVisualOverflow; } + short maxHorizontalVisualOverflow() const { return m_maxHorizontalVisualOverflow; } void removeChild(InlineBox* child); virtual RenderObject::SelectionState selectionState(); virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&); + virtual int placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool&); + + bool hasTextChildren() const { return m_hasTextChildren; } void checkConsistency() const; void setHasBadChildList(); private: + virtual bool isInlineFlowBox() const { return true; } + InlineBox* m_firstChild; InlineBox* m_lastChild; - int m_maxHorizontalVisualOverflow; + short m_maxHorizontalVisualOverflow; + + bool m_includeLeftEdge : 1; + bool m_includeRightEdge : 1; + bool m_hasTextChildren : 1; #ifndef NDEBUG bool m_hasBadChildList; @@ -165,7 +179,7 @@ inline void InlineFlowBox::setHasBadChildList() #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. -void showTree(const WebCore::InlineBox*); +void showTree(const WebCore::InlineFlowBox*); #endif #endif // InlineFlowBox_h diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp index a5857e0..53646f9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp @@ -60,10 +60,10 @@ bool InlineTextBox::isSelected(int startPos, int endPos) const RenderObject::SelectionState InlineTextBox::selectionState() { - RenderObject::SelectionState state = object()->selectionState(); + RenderObject::SelectionState state = renderer()->selectionState(); if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) { int startPos, endPos; - object()->selectionStartEnd(startPos, endPos); + renderer()->selectionStartEnd(startPos, endPos); // The position after a hard line break is considered to be past its end. int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0); @@ -92,7 +92,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos) if (sPos >= ePos) return IntRect(); - RenderText* textObj = textObject(); + RenderText* textObj = textRenderer(); int selTop = selectionTop(); int selHeight = selectionHeight(); const Font& f = textObj->style(m_firstLine)->font(); @@ -108,7 +108,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos) void InlineTextBox::deleteLine(RenderArena* arena) { - static_cast<RenderText*>(m_object)->removeTextBox(this); + toRenderText(renderer())->removeTextBox(this); destroy(arena); } @@ -117,7 +117,7 @@ void InlineTextBox::extractLine() if (m_extracted) return; - static_cast<RenderText*>(m_object)->extractTextBox(this); + toRenderText(renderer())->extractTextBox(this); } void InlineTextBox::attachLine() @@ -125,48 +125,70 @@ void InlineTextBox::attachLine() if (!m_extracted) return; - static_cast<RenderText*>(m_object)->attachTextBox(this); + toRenderText(renderer())->attachTextBox(this); } -int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) +int InlineTextBox::placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool& foundBox) { if (foundBox) { m_truncation = cFullTruncation; return -1; } - int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + ellipsisWidth; + // For LTR this is the left edge of the box, for RTL, the right edge in parent coordinates. + int ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth; - // For LTR, if the left edge of the ellipsis is to the left of our text run, then we are the run that will get truncated. - if (ltr) { - if (ellipsisX <= m_x) { - // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box. + // Criteria for full truncation: + // LTR: the left edge of the ellipsis is to the left of our text run. + // RTL: the right edge of the ellipsis is to the right of our text run. + bool ltrFullTruncation = flowIsLTR && ellipsisX <= m_x; + bool rtlFullTruncation = !flowIsLTR && ellipsisX >= (m_x + m_width); + if (ltrFullTruncation || rtlFullTruncation) { + // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box. + m_truncation = cFullTruncation; + foundBox = true; + return -1; + } + + bool ltrEllipsisWithinBox = flowIsLTR && (ellipsisX < m_x + m_width); + bool rtlEllipsisWithinBox = !flowIsLTR && (ellipsisX > m_x); + if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) { + foundBox = true; + + // The inline box may have different directionality than it's parent. Since truncation + // behavior depends both on both the parent and the inline block's directionality, we + // must keep track of these separately. + bool ltr = direction() == LTR; + if (ltr != flowIsLTR) { + // Width in pixels of the visible portion of the box, excluding the ellipsis. + int visibleBoxWidth = visibleRightEdge - visibleLeftEdge - ellipsisWidth; + ellipsisX = ltr ? m_x + visibleBoxWidth : m_x + m_width - visibleBoxWidth; + } + + int offset = offsetForPosition(ellipsisX, false); + if (offset == 0) { + // No characters should be rendered. Set ourselves to full truncation and place the ellipsis at the min of our start + // and the ellipsis edge. m_truncation = cFullTruncation; - foundBox = true; - return -1; + return min(ellipsisX, m_x); } - if (ellipsisX < m_x + m_width) { - if (direction() == RTL) - return -1; // FIXME: Support LTR truncation when the last run is RTL someday. + // Set the truncation index on the text run. + m_truncation = offset; - foundBox = true; + // If we got here that means that we were only partially truncated and we need to return the pixel offset at which + // to place the ellipsis. + int widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine); - int offset = offsetForPosition(ellipsisX, false); - if (offset == 0) { - // No characters should be rendered. Set ourselves to full truncation and place the ellipsis at the min of our start - // and the ellipsis edge. - m_truncation = cFullTruncation; - return min(ellipsisX, m_x); - } - - // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character. - m_truncation = offset; - return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, textPos(), m_firstLine); - } - } - else { - // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR) + // The ellipsis needs to be placed just after the last visible character. + // Where "after" is defined by the flow directionality, not the inline + // box directionality. + // e.g. In the case of an LTR inline box truncated in an RTL flow then we can + // have a situation such as |Hello| -> |...He| + if (flowIsLTR) + return m_x + widthOfVisibleText; + else + return (m_x + m_width) - widthOfVisibleText - ellipsisWidth; } return -1; } @@ -216,7 +238,7 @@ void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, con bool InlineTextBox::isLineBreak() const { - return object()->isBR() || (object()->style()->preserveNewline() && len() == 1 && (*textObject()->text())[start()] == '\n'); + return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text())[start()] == '\n'); } bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty) @@ -224,15 +246,15 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in if (isLineBreak()) return false; - IntRect rect(tx + m_x, ty + m_y, m_width, m_height); + IntRect rect(tx + m_x, ty + m_y, m_width, height()); if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.contains(x, y)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } return false; } -static void paintTextWithShadows(GraphicsContext* context, 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, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) { do { IntSize extraOffset; @@ -256,12 +278,12 @@ static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRu } if (startOffset <= endOffset) - context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset); + context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) - context->drawText(textRun, textOrigin + extraOffset, 0, endOffset); + context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset); if (startOffset < textRun.length()) - context->drawText(textRun, textOrigin + extraOffset, startOffset); + context->drawText(font, textRun, textOrigin + extraOffset, startOffset); } if (!shadow) @@ -278,10 +300,10 @@ static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRu void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { - if (isLineBreak() || !object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || + if (isLineBreak() || !renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline) return; - + ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); int xPos = tx + m_x - parent()->maxHorizontalVisualOverflow(); @@ -289,7 +311,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) if (xPos >= paintInfo.rect.right() || xPos + w <= paintInfo.rect.x()) return; - bool isPrinting = textObject()->document()->printing(); + bool isPrinting = textRenderer()->document()->printing(); // Determine whether or not we're selected. bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone; @@ -297,18 +319,34 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) // When only painting the selection, don't bother to paint if there is none. return; + if (m_truncation != cNoTruncation) { + TextDirection flowDirection = renderer()->containingBlock()->style()->direction(); + if (flowDirection != direction()) { + // Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin + // at which we start drawing text. + // e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is: + // |Hello|CBA| -> |...He|CBA| + // In order to draw the fragment "He" aligned to the right edge of it's box, we need to start drawing + // farther to the right. + // NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the + // truncated string i.e. |Hello|CBA| -> |...lo|CBA| + int widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine); + int widthOfHiddenText = m_width - widthOfVisibleText; + // FIXME: The hit testing logic also needs to take this translation int account. + tx += direction() == LTR ? widthOfHiddenText : -widthOfHiddenText; + } + } + GraphicsContext* context = paintInfo.context; // Determine whether or not we have composition underlines to draw. - bool containsComposition = object()->document()->frame()->editor()->compositionNode() == object()->node(); - bool useCustomUnderlines = containsComposition && object()->document()->frame()->editor()->compositionUsesCustomUnderlines(); + bool containsComposition = renderer()->node() && renderer()->document()->frame()->editor()->compositionNode() == renderer()->node(); + bool useCustomUnderlines = containsComposition && renderer()->document()->frame()->editor()->compositionUsesCustomUnderlines(); // Set our font. - RenderStyle* styleToUse = object()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(m_firstLine); int d = styleToUse->textDecorationsInEffect(); - const Font* font = &styleToUse->font(); - if (*font != context->font()) - context->setFont(*font); + const Font& font = styleToUse->font(); // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection // and composition underlines. @@ -321,8 +359,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) if (containsComposition && !useCustomUnderlines) paintCompositionBackground(context, tx, ty, styleToUse, font, - object()->document()->frame()->editor()->compositionStart(), - object()->document()->frame()->editor()->compositionEnd()); + renderer()->document()->frame()->editor()->compositionStart(), + renderer()->document()->frame()->editor()->compositionEnd()); paintDocumentMarkers(context, tx, ty, styleToUse, font, true); @@ -369,14 +407,14 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) ShadowData* selectionShadow = textShadow; if (haveSelection) { // Check foreground color first. - Color foreground = paintInfo.forceBlackText ? Color::black : object()->selectionForegroundColor(); + Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor(); if (foreground.isValid() && foreground != selectionFillColor) { if (!paintSelectedTextOnly) paintSelectedTextSeparately = true; selectionFillColor = foreground; } - if (RenderStyle* pseudoStyle = object()->getCachedPseudoStyle(RenderStyle::SELECTION)) { + if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) { ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow(); if (shadow != selectionShadow) { if (!paintSelectedTextOnly) @@ -402,8 +440,9 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) } } - IntPoint textOrigin(m_x + tx, m_y + ty + m_baseline); - TextRun textRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()); + int baseline = renderer()->style(m_firstLine)->font().ascent(); + IntPoint textOrigin(m_x + tx, m_y + ty + baseline); + TextRun textRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()); int sPos = 0; int ePos = 0; @@ -419,9 +458,9 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth); if (!paintSelectedTextSeparately || ePos <= sPos) { // FIXME: Truncate right-to-left text correctly. - paintTextWithShadows(context, 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, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); } else - paintTextWithShadows(context, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); if (textStrokeWidth > 0) context->restore(); @@ -433,7 +472,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) context->save(); updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth); - paintTextWithShadows(context, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); if (selectionStrokeWidth > 0) context->restore(); @@ -449,7 +488,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) paintDocumentMarkers(context, tx, ty, styleToUse, font, false); if (useCustomUnderlines) { - const Vector<CompositionUnderline>& underlines = object()->document()->frame()->editor()->customCompositionUnderlines(); + const Vector<CompositionUnderline>& underlines = renderer()->document()->frame()->editor()->customCompositionUnderlines(); size_t numUnderlines = underlines.size(); for (size_t index = 0; index < numUnderlines; ++index) { @@ -478,14 +517,14 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) { int startPos, endPos; - if (object()->selectionState() == RenderObject::SelectionInside) { + if (renderer()->selectionState() == RenderObject::SelectionInside) { startPos = 0; - endPos = textObject()->textLength(); + endPos = textRenderer()->textLength(); } else { - textObject()->selectionStartEnd(startPos, endPos); - if (object()->selectionState() == RenderObject::SelectionStart) - endPos = textObject()->textLength(); - else if (object()->selectionState() == RenderObject::SelectionEnd) + textRenderer()->selectionStartEnd(startPos, endPos); + if (renderer()->selectionState() == RenderObject::SelectionStart) + endPos = textRenderer()->textLength(); + else if (renderer()->selectionState() == RenderObject::SelectionEnd) startPos = 0; } @@ -493,7 +532,7 @@ void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) ePos = min(endPos - m_start, (int)m_len); } -void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*) +void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font) { // See if we have a selection to paint at all. int sPos, ePos; @@ -502,7 +541,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren return; Color textColor = style->color(); - Color c = object()->selectionBackgroundColor(); + Color c = renderer()->selectionBackgroundColor(); if (!c.isValid() || c.alpha() == 0) return; @@ -516,12 +555,13 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren int y = selectionTop(); int h = selectionHeight(); context->clip(IntRect(m_x + tx, y + ty, m_width, h)); - context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + 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); context->restore(); } -void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*, int startPos, int endPos) +void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font, int startPos, int endPos) { int offset = m_start; int sPos = max(startPos - offset, 0); @@ -538,8 +578,9 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int y = selectionTop(); int h = selectionHeight(); - context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + 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); context->restore(); } @@ -547,7 +588,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& type) { - Frame* frame = object()->document()->frame(); + Frame* frame = renderer()->document()->frame(); if (!frame) return; Page* page = frame->page(); @@ -555,10 +596,10 @@ void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& typ return; RootInlineBox* r = root(); - FloatRect rootRect(tx + r->xPos(), ty + selectionTop(), r->width(), selectionHeight()); - FloatRect textRect(tx + xPos(), rootRect.y(), width(), rootRect.height()); + FloatRect rootRect(tx + r->x(), ty + selectionTop(), r->width(), selectionHeight()); + FloatRect textRect(tx + x(), rootRect.y(), width(), rootRect.height()); - page->chrome()->client()->paintCustomHighlight(object()->node(), type, textRect, rootRect, true, false); + page->chrome()->client()->paintCustomHighlight(renderer()->node(), type, textRect, rootRect, true, false); } #endif @@ -570,27 +611,33 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in if (m_truncation == cFullTruncation) return; - - int width = (m_truncation == cNoTruncation) ? m_width - : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine); + + int width = m_width; + if (m_truncation != cNoTruncation) { + width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine); + if (direction() == RTL) + tx += (m_width - width); + } // Get the text decoration colors. Color underline, overline, linethrough; - object()->getTextDecorationColors(deco, underline, overline, linethrough, true); + renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true); // Use a special function for underlines to get the positioning exactly right. - bool isPrinting = textObject()->document()->printing(); + bool isPrinting = textRenderer()->document()->printing(); context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1. bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255); + int baseline = renderer()->style(m_firstLine)->font().ascent(); + bool setClip = false; int extraOffset = 0; if (!linesAreOpaque && shadow && shadow->next) { context->save(); - IntRect clipRect(tx, ty, width, m_baseline + 2); + IntRect clipRect(tx, ty, width, baseline + 2); for (ShadowData* s = shadow; s; s = s->next) { - IntRect shadowRect(tx, ty, width, m_baseline + 2); + IntRect shadowRect(tx, ty, width, baseline + 2); shadowRect.inflate(s->blur); shadowRect.move(s->x, s->y); clipRect.unite(shadowRect); @@ -598,12 +645,13 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in } context->save(); context->clip(clipRect); - extraOffset += m_baseline + 2; + extraOffset += baseline + 2; ty += extraOffset; setClip = true; } bool setShadow = false; + do { if (shadow) { if (!shadow->next) { @@ -618,16 +666,19 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in if (deco & UNDERLINE) { context->setStrokeColor(underline); + context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. - context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting); + context->drawLineForText(IntPoint(tx, ty + baseline + 1), width, isPrinting); } if (deco & OVERLINE) { context->setStrokeColor(overline); + context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), width, isPrinting); } if (deco & LINE_THROUGH) { context->setStrokeColor(linethrough); - context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting); + context->setStrokeStyle(SolidStroke); + context->drawLineForText(IntPoint(tx, ty + 2 * baseline / 3), width, isPrinting); } } while (shadow); @@ -637,10 +688,10 @@ 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* f, bool grammar) +void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font, bool grammar) { // Never print spelling/grammar markers (5327887) - if (textObject()->document()->printing()) + if (textRenderer()->document()->printing()) return; if (m_truncation == cFullTruncation) @@ -667,17 +718,17 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in // Calculate start & width IntPoint startPoint(tx + m_x, ty + selectionTop()); - TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); + TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); int h = selectionHeight(); - IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, startPoint, h, startPosition, endPosition)); + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, startPosition, endPosition)); start = markerRect.x() - startPoint.x(); width = markerRect.width(); // 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) - object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect); + renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); } // IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to @@ -687,19 +738,20 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so // we pin to two pixels under the baseline. int lineThickness = cMisspellingLineThickness; - int descent = m_height - m_baseline; + int baseline = renderer()->style(m_firstLine)->font().ascent(); + int descent = height() - baseline; int underlineOffset; if (descent <= (2 + lineThickness)) { - // place the underline at the very bottom of the text in small/medium fonts - underlineOffset = m_height - lineThickness; + // Place the underline at the very bottom of the text in small/medium fonts. + underlineOffset = height() - lineThickness; } else { - // in larger fonts, tho, place the underline up near the baseline to prevent big gap - underlineOffset = m_baseline + 2; + // In larger fonts, though, place the underline up near the baseline to prevent a big gap. + underlineOffset = baseline + 2; } 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* f) +void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, 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. @@ -708,27 +760,48 @@ 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(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); + 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(f->selectionRectForText(run, startPoint, h, sPos, ePos)); - object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect); + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); + renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); // Optionally highlight the text - if (object()->document()->frame()->markedTextMatchesAreHighlighted()) { - Color color = theme()->platformTextSearchHighlightColor(); + if (renderer()->document()->frame()->markedTextMatchesAreHighlighted()) { + Color color = marker.activeMatch ? + renderer()->theme()->platformActiveTextSearchHighlightColor() : + renderer()->theme()->platformInactiveTextSearchHighlightColor(); pt->save(); updateGraphicsContext(pt, color, color, 0); // Don't draw text at all! pt->clip(IntRect(tx + m_x, ty + y, m_width, h)); - pt->drawHighlightForText(run, startPoint, h, color, sPos, ePos); + pt->drawHighlightForText(font, run, startPoint, h, color, sPos, ePos); pt->restore(); } } -void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font* f, bool background) +void InlineTextBox::computeRectForReplacementMarker(int tx, int ty, 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(); + int h = selectionHeight(); + + 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); + + // Compute and store the rect associated with this marker. + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); + renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); +} + +void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font& font, bool background) { - Vector<DocumentMarker> markers = object()->document()->markersForNode(object()->node()); + if (!renderer()->node()) + return; + + Vector<DocumentMarker> markers = renderer()->document()->markersForNode(renderer()->node()); Vector<DocumentMarker>::iterator markerIt = markers.begin(); // Give any document markers that touch this run a chance to draw before the text has been drawn. @@ -740,6 +813,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re switch (marker.type) { case DocumentMarker::Grammar: case DocumentMarker::Spelling: + case DocumentMarker::Replacement: if (background) continue; break; @@ -765,13 +839,16 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re // marker intersects this run. Paint it. switch (marker.type) { case DocumentMarker::Spelling: - paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, false); + paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, false); break; case DocumentMarker::Grammar: - paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, true); + paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, true); break; case DocumentMarker::TextMatch: - paintTextMatchMarker(pt, tx, ty, marker, style, f); + paintTextMatchMarker(pt, tx, ty, marker, style, font); + break; + case DocumentMarker::Replacement: + computeRectForReplacementMarker(tx, ty, marker, style, font); break; default: ASSERT_NOT_REACHED(); @@ -797,7 +874,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int if (paintStart <= underline.startOffset) { paintStart = underline.startOffset; useWholeWidth = false; - start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, textPos(), m_firstLine); + start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), m_firstLine); } if (paintEnd != underline.endOffset) { // end points at the last char, not past it paintEnd = min(paintEnd, (unsigned)underline.endOffset); @@ -808,14 +885,15 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int useWholeWidth = false; } if (!useWholeWidth) { - width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); + width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); } // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline. // All other marked text underlines are 1px thick. // If there's not enough space the underline will touch or overlap characters. int lineThickness = 1; - if (underline.thick && m_height - m_baseline >= 2) + int baseline = renderer()->style(m_firstLine)->font().ascent(); + if (underline.thick && height() - baseline >= 2) lineThickness = 2; // We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those. @@ -825,7 +903,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int ctx->setStrokeColor(underline.color); ctx->setStrokeThickness(lineThickness); - ctx->drawLineForText(IntPoint(tx + start, ty + m_height - lineThickness), width, textObject()->document()->printing()); + ctx->drawLineForText(IntPoint(tx + start, ty + height() - lineThickness), width, textRenderer()->document()->printing()); } int InlineTextBox::caretMinOffset() const @@ -845,12 +923,12 @@ unsigned InlineTextBox::caretMaxRenderedOffset() const int InlineTextBox::textPos() const { - if (xPos() == 0) + if (x() == 0) return 0; - RenderBlock *blockElement = object()->containingBlock(); - return direction() == RTL ? xPos() - blockElement->borderRight() - blockElement->paddingRight() - : xPos() - blockElement->borderLeft() - blockElement->paddingLeft(); + RenderBlock *blockElement = renderer()->containingBlock(); + return direction() == RTL ? x() - blockElement->borderRight() - blockElement->paddingRight() + : x() - blockElement->borderLeft() - blockElement->paddingLeft(); } int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const @@ -858,10 +936,10 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const if (isLineBreak()) return 0; - RenderText* text = static_cast<RenderText*>(m_object); + RenderText* text = toRenderText(renderer()); RenderStyle *style = text->style(m_firstLine); const Font* f = &style->font(); - return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), + 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); } @@ -873,12 +951,12 @@ int InlineTextBox::positionForOffset(int offset) const if (isLineBreak()) return m_x; - RenderText* text = static_cast<RenderText*>(m_object); + RenderText* text = toRenderText(renderer()); const Font& f = text->style(m_firstLine)->font(); int from = direction() == RTL ? offset - m_start : 0; int to = direction() == RTL ? m_len : offset - m_start; // FIXME: Do we need to add rightBearing here? - return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride), + return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride), IntPoint(m_x, 0), 0, from, to)).right(); } @@ -906,4 +984,30 @@ bool InlineTextBox::containsCaretOffset(int offset) const return true; } +typedef HashMap<InlineTextBox*, Vector<const SimpleFontData*> > FallbackFontsMap; +static FallbackFontsMap* gFallbackFontsMap; + +void InlineTextBox::setFallbackFonts(const HashSet<const SimpleFontData*>& fallbackFonts) +{ + if (!gFallbackFontsMap) + gFallbackFontsMap = new FallbackFontsMap; + + FallbackFontsMap::iterator it = gFallbackFontsMap->set(this, Vector<const SimpleFontData*>()).first; + ASSERT(it->second.isEmpty()); + copyToVector(fallbackFonts, it->second); +} + +void InlineTextBox::takeFallbackFonts(Vector<const SimpleFontData*>& fallbackFonts) +{ + if (!gFallbackFontsMap) + return; + + FallbackFontsMap::iterator it = gFallbackFontsMap->find(this); + if (it == gFallbackFontsMap->end()) + return; + + fallbackFonts.swap(it->second); + gFallbackFontsMap->remove(it); +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h index d8a250b..3bbb453 100644 --- a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h @@ -1,9 +1,7 @@ /* - * This file is part of the DOM implementation for KDE. - * * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,22 +23,16 @@ #ifndef InlineTextBox_h #define InlineTextBox_h -#include "DocumentMarker.h" #include "InlineRunBox.h" -#include "RenderText.h" +#include "RenderText.h" // so textRenderer() can be inline namespace WebCore { +struct CompositionUnderline; + const unsigned short cNoTruncation = USHRT_MAX; const unsigned short cFullTruncation = USHRT_MAX - 1; -class String; -class StringImpl; -class HitTestResult; -class Position; - -struct CompositionUnderline; - // Helper functions shared by InlineTextBox / SVGRootInlineBox void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness); Color correctedTextColor(Color textColor, Color backgroundColor); @@ -67,46 +59,61 @@ public: void offsetRun(int d) { m_start += d; } + void setFallbackFonts(const HashSet<const SimpleFontData*>&); + void takeFallbackFonts(Vector<const SimpleFontData*>&); + +private: virtual int selectionTop(); virtual int selectionHeight(); +public: virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); bool isSelected(int startPos, int endPos) const; void selectionStartEnd(int& sPos, int& ePos); +private: virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); - RenderText* textObject() const; +public: + RenderText* textRenderer() const; +private: virtual void deleteLine(RenderArena*); virtual void extractLine(); virtual void attachLine(); +public: virtual RenderObject::SelectionState selectionState(); +private: virtual void clearTruncation() { m_truncation = cNoTruncation; } - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox); + virtual int placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool& foundBox); +public: virtual bool isLineBreak() const; void setSpaceAdd(int add) { m_width -= m_toAdd; m_toAdd = add; m_width += m_toAdd; } - int spaceAdd() { return m_toAdd; } +private: virtual bool isInlineTextBox() { return true; } - virtual bool isText() const { return m_treatAsText; } - void setIsText(bool b) { m_treatAsText = b; } +public: virtual int caretMinOffset() const; virtual int caretMaxOffset() const; + +private: virtual unsigned caretMaxRenderedOffset() const; int textPos() const; + +public: virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; virtual int positionForOffset(int offset) const; bool containsCaretOffset(int offset) const; // false for offset after line break +private: int m_start; unsigned short m_len; @@ -114,24 +121,24 @@ public: // denote no truncation (the whole run paints) and full truncation (nothing paints at all). protected: - void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos); - void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background); + void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, int startPos, int endPos); + void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, bool background); void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&); #if PLATFORM(MAC) void paintCustomHighlight(int tx, int ty, const AtomicString& type); #endif private: - void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData* shadow); - 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*); - friend class RenderText; + 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&); }; -inline RenderText* InlineTextBox::textObject() const +inline RenderText* InlineTextBox::textRenderer() const { - return static_cast<RenderText*>(m_object); + return toRenderText(renderer()); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp index 20d0b99..883f74d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp @@ -27,16 +27,19 @@ #include "LayoutState.h" #include "RenderArena.h" +#include "RenderInline.h" #include "RenderLayer.h" #include "RenderView.h" namespace WebCore { LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset) + : m_next(prev) +#ifndef NDEBUG + , m_renderer(renderer) +#endif { - ASSERT(prev); - - m_next = prev; + ASSERT(m_next); bool fixed = renderer->isPositioned() && renderer->style()->position() == FixedPosition; if (fixed) { @@ -50,8 +53,10 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& if (renderer->hasLayer()) m_offset += renderer->layer()->relativePositionOffset(); } else if (renderer->isPositioned() && !fixed) { - if (RenderObject* container = renderer->container()) - m_offset += renderer->offsetForPositionedInContainer(container); + if (RenderObject* container = renderer->container()) { + if (container->isRelPositioned() && container->isRenderInline()) + m_offset += toRenderInline(container)->relativePositionedInlineOffset(renderer); + } } m_clipped = !fixed && prev->m_clipped; @@ -72,16 +77,22 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& layer->subtractScrolledContentOffset(x, y); m_offset = IntSize(x, y); } + + m_layoutDelta = m_next->m_layoutDelta; + // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. } LayoutState::LayoutState(RenderObject* root) : m_clipped(false) + , m_next(0) +#ifndef NDEBUG + , m_renderer(root) +#endif { RenderObject* container = root->container(); - FloatPoint absContentPoint = container->localToAbsoluteForContent(FloatPoint(), false, true); + FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), false, true); m_offset = IntSize(absContentPoint.x(), absContentPoint.y()); - m_next = 0; } #ifndef NDEBUG diff --git a/src/3rdparty/webkit/WebCore/rendering/LayoutState.h b/src/3rdparty/webkit/WebCore/rendering/LayoutState.h index 551c74a..afa2952 100644 --- a/src/3rdparty/webkit/WebCore/rendering/LayoutState.h +++ b/src/3rdparty/webkit/WebCore/rendering/LayoutState.h @@ -41,6 +41,9 @@ public: LayoutState() : m_clipped(false) , m_next(0) +#ifndef NDEBUG + , m_renderer(0) +#endif { } @@ -62,8 +65,14 @@ private: public: bool m_clipped; IntRect m_clipRect; - IntSize m_offset; + IntSize m_offset; // x/y offset from container. + IntSize m_layoutDelta; // Transient offset from the final position of the object + // used to ensure that repaints happen in the correct place. + // This is a total delta accumulated from the root. LayoutState* m_next; +#ifndef NDEBUG + RenderObject* m_renderer; +#endif }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp deleted file mode 100644 index 0455eae..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * 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) 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 "ListMarkerBox.h" - -#include "InlineFlowBox.h" -#include "RenderArena.h" -#include "RenderListMarker.h" - -namespace WebCore { - -ListMarkerBox::ListMarkerBox(RenderObject* obj) - : InlineBox(obj) -{ -} - -bool ListMarkerBox::isText() const -{ - return static_cast<RenderListMarker*>(object())->isText(); -} - -} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h deleted file mode 100644 index 47ae256..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef ListMarkerBox_h -#define ListMarkerBox_h - -#include "InlineBox.h" - -namespace WebCore { - -class ListMarkerBox : public InlineBox { -public: - ListMarkerBox(RenderObject*); - - virtual bool isText() const; -}; - -} // namespace WebCore - -#endif // ListMarkerBox_h diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp index 48ea3ab..fc2790c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -32,12 +32,12 @@ #include "MediaControlElements.h" -#include "Event.h" #include "EventNames.h" -#include "EventHandler.h" #include "FloatConversion.h" #include "Frame.h" #include "HTMLNames.h" +#include "MouseEvent.h" +#include "RenderMedia.h" #include "RenderSlider.h" #include "RenderTheme.h" @@ -59,21 +59,28 @@ MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTML rootStyle->setDisplay(BLOCK); rootStyle->setPosition(RelativePosition); RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(this); - renderer->setParent(mediaElement->renderer()); renderer->setStyle(rootStyle.release()); setRenderer(renderer); setAttached(); setInDocument(true); } +void MediaControlShadowRootElement::updateStyle() +{ + if (renderer()) { + RenderStyle* timelineContainerStyle = m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER); + renderer()->setStyle(timelineContainerStyle); + } +} + // ---------------------------- -MediaControlInputElement::MediaControlInputElement(Document* doc, RenderStyle::PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement) - : HTMLInputElement(inputTag, doc) +MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement) + : HTMLDivElement(divTag, doc) , m_mediaElement(mediaElement) + , m_pseudoStyleId(pseudo) { - setInputType(type); - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(pseudo); + RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style); if (renderer) { setRenderer(renderer); @@ -83,30 +90,111 @@ MediaControlInputElement::MediaControlInputElement(Document* doc, RenderStyle::P setInDocument(true); } +void MediaTextDisplayElement::attachToParent(Element* parent) +{ + parent->addChild(this); + if (renderer() && parent->renderer()) + parent->renderer()->addChild(renderer()); +} + +void MediaTextDisplayElement::update() +{ + if (renderer()) + renderer()->updateFromElement(); + updateStyle(); +} + +void MediaTextDisplayElement::updateStyle() +{ + if (renderer() && m_mediaElement->renderer()) { + RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); + renderer()->setStyle(style); + } +} + +MediaTimeDisplayElement::MediaTimeDisplayElement(Document* doc, HTMLMediaElement* element, bool currentTime) + : MediaTextDisplayElement(doc, currentTime ? MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element) +{ +} + +// ---------------------------- + +MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement, MediaControlElementType displayType) + : HTMLInputElement(inputTag, doc) + , m_mediaElement(mediaElement) + , m_pseudoStyleId(pseudo) + , m_displayType(displayType) +{ + setInputType(type); + updateStyle(); + setInDocument(true); +} + void MediaControlInputElement::attachToParent(Element* parent) { parent->addChild(this); - parent->renderer()->addChild(renderer()); + if (renderer() && parent->renderer()) + parent->renderer()->addChild(renderer()); } void MediaControlInputElement::update() { + updateDisplayType(); if (renderer()) renderer()->updateFromElement(); + updateStyle(); +} + +void MediaControlInputElement::updateStyle() +{ + if (!m_mediaElement || !m_mediaElement->renderer()) + return; + + RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); + + bool needsRenderer = rendererIsNeeded(style); + if (renderer() && !needsRenderer) + detach(); + else if (!renderer() && needsRenderer) { + RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style); + if (!renderer) + return; + renderer->setStyle(style); + setRenderer(renderer); + setAttached(); + if (parent() && parent()->renderer()) { + // Find next sibling with a renderer to determine where to insert. + Node* sibling = nextSibling(); + while (sibling && !sibling->renderer()) + sibling = sibling->nextSibling(); + parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0); + } + } else if (renderer()) + renderer()->setStyle(style); } bool MediaControlInputElement::hitTest(const IntPoint& absPoint) { if (renderer() && renderer()->style()->hasAppearance()) - return theme()->hitTestMediaControlPart(renderer(), absPoint); + return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint); return false; } +void MediaControlInputElement::setDisplayType(MediaControlElementType displayType) +{ + if (displayType == m_displayType) + return; + + m_displayType = displayType; + if (RenderObject* o = renderer()) + o->repaint(); +} + // ---------------------------- MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element) - : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON, "button", element) + : MediaControlInputElement(doc, MEDIA_CONTROLS_MUTE_BUTTON, "button", element, element->muted() ? MediaUnMuteButton : MediaMuteButton) { } @@ -119,30 +207,37 @@ void MediaControlMuteButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +void MediaControlMuteButtonElement::updateDisplayType() +{ + setDisplayType(m_mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton); +} + // ---------------------------- MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* doc, HTMLMediaElement* element) - : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON, "button", element) + : MediaControlInputElement(doc, MEDIA_CONTROLS_PLAY_BUTTON, "button", element, element->canPlay() ? MediaPlayButton : MediaPauseButton) { } void MediaControlPlayButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { - ExceptionCode ec; - if (m_mediaElement->canPlay()) - m_mediaElement->play(ec); - else - m_mediaElement->pause(ec); + m_mediaElement->togglePlayState(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } +void MediaControlPlayButtonElement::updateDisplayType() +{ + setDisplayType(m_mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton); +} + // ---------------------------- MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* doc, HTMLMediaElement* element, bool forward) - : MediaControlInputElement(doc, forward ? RenderStyle::MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : RenderStyle::MEDIA_CONTROLS_SEEK_BACK_BUTTON, "button", element) + : MediaControlInputElement(doc, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON, + "button", element, forward ? MediaSeekForwardButton : MediaSeekBackButton) , m_forward(forward) , m_seeking(false) , m_capturing(false) @@ -157,8 +252,7 @@ void MediaControlSeekButtonElement::defaultEventHandler(Event* event) m_capturing = true; frame->eventHandler()->setCapturingMouseEventsNode(this); } - ExceptionCode ec; - m_mediaElement->pause(ec); + m_mediaElement->pause(); m_seekTimer.startRepeating(cSeekRepeatDelay); event->setDefaultHandled(); } else if (event->type() == eventNames().mouseupEvent) { @@ -191,37 +285,34 @@ void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonE // ---------------------------- -MediaControlTimelineElement::MediaControlTimelineElement(Document* doc, HTMLMediaElement* element) - : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_TIMELINE, "range", element) +MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element) + : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element, MediaTimelineContainer) { - setAttribute(precisionAttr, "float"); } void MediaControlTimelineElement::defaultEventHandler(Event* event) { - RenderSlider* slider = static_cast<RenderSlider*>(renderer()); - bool oldInDragMode = slider && slider->inDragMode(); - float oldTime = narrowPrecisionToFloat(value().toDouble()); - bool oldEnded = m_mediaElement->ended(); + if (event->type() == eventNames().mousedownEvent) + m_mediaElement->beginScrubbing(); HTMLInputElement::defaultEventHandler(event); + if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent ) { + return; + } + float time = narrowPrecisionToFloat(value().toDouble()); - if (oldTime != time || event->type() == eventNames().inputEvent) { + if (time != m_mediaElement->currentTime()) { ExceptionCode ec; m_mediaElement->setCurrentTime(time, ec); } - // Media element stays in non-paused state when it reaches end. If the slider is now dragged - // to some other position the playback resumes which does not match usual media player UIs. - // Get the expected behavior by pausing explicitly in this case. - if (oldEnded && !m_mediaElement->ended() && !m_mediaElement->paused()) { - ExceptionCode ec; - m_mediaElement->pause(ec); - } - // Pause playback during drag, but do it without using DOM API which would generate events - bool inDragMode = slider && slider->inDragMode(); - if (inDragMode != oldInDragMode) - m_mediaElement->setPausedInternal(inDragMode); + + RenderSlider* slider = static_cast<RenderSlider*>(renderer()); + if (slider && slider->inDragMode()) + static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay(); + + if (event->type() == eventNames().mouseupEvent) + m_mediaElement->endScrubbing(); } void MediaControlTimelineElement::update(bool updateDuration) @@ -236,7 +327,7 @@ void MediaControlTimelineElement::update(bool updateDuration) // ---------------------------- MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* doc, HTMLMediaElement* element) - : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element) + : MediaControlInputElement(doc, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element, MediaFullscreenButton) { } @@ -248,6 +339,12 @@ void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +bool MediaControlFullscreenButtonElement::rendererIsNeeded(RenderStyle* style) +{ + return m_mediaElement->supportsFullscreen() && MediaControlInputElement::rendererIsNeeded(style); +} + + // ---------------------------- } //namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h index 4741534..eefb2ce 100644 --- a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h +++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h @@ -43,7 +43,7 @@ namespace WebCore { class Event; class Frame; -enum MediaControlElements { +enum MediaControlElementType { MediaFullscreenButton, MediaMuteButton, MediaPlayButton, MediaSeekBackButton, MediaSeekForwardButton, MediaSlider, MediaSliderThumb, MediaUnMuteButton, MediaPauseButton, MediaTimelineContainer, MediaCurrentTimeDisplay, @@ -56,21 +56,52 @@ public: virtual bool isShadowNode() const { return true; } virtual Node* shadowParentNode() { return m_mediaElement; } + + void updateStyle(); private: HTMLMediaElement* m_mediaElement; }; + // ---------------------------- + +class MediaTextDisplayElement : public HTMLDivElement +{ +public: + MediaTextDisplayElement(Document*, PseudoId, HTMLMediaElement*); + void attachToParent(Element*); + void update(); + void updateStyle(); +protected: + HTMLMediaElement* m_mediaElement; + PseudoId m_pseudoStyleId; +}; + +// ---------------------------- + +class MediaTimeDisplayElement : public MediaTextDisplayElement { +public: + MediaTimeDisplayElement(Document*, HTMLMediaElement*, bool currentTime); +}; + // ---------------------------- class MediaControlInputElement : public HTMLInputElement { public: - MediaControlInputElement(Document*, RenderStyle::PseudoId, const String& type, HTMLMediaElement*); + MediaControlInputElement(Document*, PseudoId, const String& type, HTMLMediaElement*, MediaControlElementType); void attachToParent(Element*); void update(); + virtual void updateStyle(); bool hitTest(const IntPoint& absPoint); + MediaControlElementType displayType() const { return m_displayType; } + protected: + virtual void updateDisplayType() { } + void setDisplayType(MediaControlElementType); + HTMLMediaElement* m_mediaElement; + PseudoId m_pseudoStyleId; + MediaControlElementType m_displayType; // some elements can show multiple types (e.g. play/pause) }; // ---------------------------- @@ -79,6 +110,7 @@ class MediaControlMuteButtonElement : public MediaControlInputElement { public: MediaControlMuteButtonElement(Document*, HTMLMediaElement*); virtual void defaultEventHandler(Event*); + virtual void updateDisplayType(); }; // ---------------------------- @@ -87,6 +119,7 @@ class MediaControlPlayButtonElement : public MediaControlInputElement { public: MediaControlPlayButtonElement(Document*, HTMLMediaElement*); virtual void defaultEventHandler(Event*); + virtual void updateDisplayType(); }; // ---------------------------- @@ -119,6 +152,7 @@ class MediaControlFullscreenButtonElement : public MediaControlInputElement { public: MediaControlFullscreenButtonElement(Document*, HTMLMediaElement*); virtual void defaultEventHandler(Event*); + virtual bool rendererIsNeeded(RenderStyle*); }; // ---------------------------- diff --git a/src/3rdparty/webkit/WebCore/rendering/OverlapTestRequestClient.h b/src/3rdparty/webkit/WebCore/rendering/OverlapTestRequestClient.h new file mode 100644 index 0000000..71400ab --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/OverlapTestRequestClient.h @@ -0,0 +1,39 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OverlapTestRequestClient_h +#define OverlapTestRequestClient_h + +namespace WebCore { + +class OverlapTestRequestClient { +public: + virtual ~OverlapTestRequestClient() { } + virtual void setOverlapTestResult(bool) = 0; +}; + +} // namespace WebCore + +#endif // OverlapTestRequestClient_h diff --git a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h index e2dae3b..3d8939a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h +++ b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h @@ -22,7 +22,7 @@ #ifndef PointerEventsHitRules_h #define PointerEventsHitRules_h -#include "RenderStyle.h" +#include "RenderStyleConstants.h" namespace WebCore { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp index 7483943..a989d6f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp @@ -1,8 +1,6 @@ -/** - * This file is part of the HTML widget for KDE. - * +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,13 +22,10 @@ #include "config.h" #include "RenderApplet.h" -#include "Document.h" #include "Frame.h" -#include "FrameLoader.h" #include "HTMLAppletElement.h" #include "HTMLNames.h" #include "HTMLParamElement.h" -#include "Widget.h" namespace WebCore { @@ -43,33 +38,29 @@ RenderApplet::RenderApplet(HTMLAppletElement* applet, const HashMap<String, Stri setInline(true); } -RenderApplet::~RenderApplet() -{ -} - IntSize RenderApplet::intrinsicSize() const { // FIXME: This doesn't make sense. We can't just start returning // a different size once we've created the widget and expect // layout and sizing to be correct. We should remove this and // pass the appropriate intrinsic size in the constructor. - return m_widget ? IntSize(50, 50) : IntSize(150, 150); + return widget() ? IntSize(50, 50) : IntSize(150, 150); } void RenderApplet::createWidgetIfNecessary() { HTMLAppletElement* element = static_cast<HTMLAppletElement*>(node()); - if (m_widget || !element->isFinishedParsingChildren()) + if (widget() || !element->isFinishedParsingChildren()) return; // FIXME: Java applets can't be resized (this is a bug in Apple's Java implementation). // In order to work around this problem and have a correct size from the start, we will // use fixed widths/heights from the style system when we can, since the widget might // not have an accurate m_width/m_height. - int width = style()->width().isFixed() ? style()->width().value() : - m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - int height = style()->height().isFixed() ? style()->height().value() : - m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + int contentWidth = style()->width().isFixed() ? style()->width().value() : + width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + int contentHeight = style()->height().isFixed() ? style()->height().value() : + height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); for (Node* child = element->firstChild(); child; child = child->nextSibling()) { if (child->hasTagName(paramTag)) { HTMLParamElement* p = static_cast<HTMLParamElement*>(child); @@ -80,7 +71,7 @@ void RenderApplet::createWidgetIfNecessary() Frame* frame = document()->frame(); ASSERT(frame); - setWidget(frame->loader()->createJavaAppletWidget(IntSize(width, height), element, m_args)); + setWidget(frame->loader()->createJavaAppletWidget(IntSize(contentWidth, contentHeight), element, m_args)); } void RenderApplet::layout() diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h index 6746c22..b481d87 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,8 +32,10 @@ namespace WebCore { class RenderApplet : public RenderWidget { public: RenderApplet(HTMLAppletElement*, const HashMap<String, String>& args); - virtual ~RenderApplet(); + void createWidgetIfNecessary(); + + private: virtual const char* renderName() const { return "RenderApplet"; } virtual bool isApplet() const { return true; } @@ -41,9 +43,6 @@ namespace WebCore { virtual void layout(); virtual IntSize intrinsicSize() const; - void createWidgetIfNecessary(); - - private: HashMap<String, String> m_args; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp index 69d08a5..b7bfe4d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp @@ -76,7 +76,7 @@ void* RenderArena::allocate(size_t size) // Use standard malloc so that memory debugging tools work. ASSERT(this); void* block = ::malloc(sizeof(RenderArenaDebugHeader) + size); - RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)block; + RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block); header->arena = this; header->size = size; header->signature = signature; @@ -112,7 +112,7 @@ void RenderArena::free(size_t size, void* ptr) { #ifndef NDEBUG // Use standard free so that memory debugging tools work. - RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)ptr - 1; + RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1; ASSERT(header->signature == signature); ASSERT(header->size == size); ASSERT(header->arena == this); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp index 2532c5b..f407099 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp @@ -40,15 +40,6 @@ RenderBR::~RenderBR() { } -InlineBox* RenderBR::createInlineBox(bool makePlaceholder, bool isRootLineBox, bool isOnlyRun) -{ - // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode - // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.) - InlineTextBox* box = static_cast<InlineTextBox*>(RenderText::createInlineBox(makePlaceholder, isRootLineBox, isOnlyRun)); - box->setIsText(isOnlyRun || document()->inStrictMode()); - return box; -} - int RenderBR::baselinePosition(bool firstLine, bool isRootLineBox) const { if (firstTextBox() && !firstTextBox()->isText()) @@ -82,7 +73,7 @@ int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const return m_lineHeight; } -void RenderBR::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderBR::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderText::styleDidChange(diff, oldStyle); m_lineHeight = -1; @@ -103,9 +94,9 @@ unsigned RenderBR::caretMaxRenderedOffset() const return 1; } -VisiblePosition RenderBR::positionForCoordinates(int /*x*/, int /*y*/) +VisiblePosition RenderBR::positionForPoint(const IntPoint&) { - return VisiblePosition(element(), 0, DOWNSTREAM); + return createVisiblePosition(0, DOWNSTREAM); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.h b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h index b65bb58..7eae8ea 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBR.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h @@ -40,7 +40,7 @@ public: virtual const char* renderName() const { return "RenderBR"; } - virtual IntRect selectionRect(bool) { return IntRect(); } + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* /*repaintContainer*/, bool /*clipToVisibleContent*/) { return IntRect(); } virtual unsigned width(unsigned /*from*/, unsigned /*len*/, const Font&, int /*xpos*/) const { return 0; } virtual unsigned width(unsigned /*from*/, unsigned /*len*/, int /*xpos*/, bool /*firstLine = false*/) const { return 0; } @@ -49,18 +49,16 @@ public: virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; // overrides - virtual InlineBox* createInlineBox(bool, bool, bool isOnlyRun = false); - virtual bool isBR() const { return true; } virtual int caretMinOffset() const; virtual int caretMaxOffset() const; virtual unsigned caretMaxRenderedOffset() const; - virtual VisiblePosition positionForCoordinates(int x, int y); + virtual VisiblePosition positionForPoint(const IntPoint&); protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: mutable int m_lineHeight; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp index 0aa58da..98426ed 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp @@ -25,13 +25,16 @@ #include "Document.h" #include "Element.h" +#include "FloatQuad.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "HTMLFormElement.h" #include "HTMLNames.h" #include "HitTestResult.h" #include "InlineTextBox.h" #include "RenderImage.h" +#include "RenderInline.h" #include "RenderMarquee.h" #include "RenderReplica.h" #include "RenderTableCell.h" @@ -39,6 +42,7 @@ #include "RenderTheme.h" #include "RenderView.h" #include "SelectionController.h" +#include "Settings.h" #include <wtf/StdLibExtras.h> using namespace std; @@ -49,10 +53,16 @@ namespace WebCore { // Number of pixels to allow as a fudge factor when clicking above or below a line. // clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line. -const int verticalLineClickFudgeFactor= 3; +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 { ColumnInfo() : m_desiredColumnWidth(0) @@ -72,7 +82,7 @@ static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; static PercentHeightContainerMap* gPercentHeightContainerMap = 0; -typedef WTF::HashMap<RenderBlock*, RenderFlowSequencedSet*> ContinuationOutlineTableMap; +typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; // Our MarginInfo state used when laying out block children. RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) @@ -109,15 +119,18 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) // ------------------------------------------------------------------------------------------------------- RenderBlock::RenderBlock(Node* node) - : RenderFlow(node) + : RenderBox(node) , m_floatingObjects(0) , m_positionedObjects(0) + , m_inlineContinuation(0) , m_maxMargin(0) , m_overflowHeight(0) , m_overflowWidth(0) , m_overflowLeft(0) , m_overflowTop(0) + , m_lineHeight(-1) { + setChildrenInline(true); } RenderBlock::~RenderBlock() @@ -126,7 +139,7 @@ RenderBlock::~RenderBlock() delete m_positionedObjects; delete m_maxMargin; - if (m_hasColumns) + if (hasColumns()) delete gColumnInfoMap->take(this); if (gPercentHeightDescendantsMap) { @@ -149,15 +162,76 @@ RenderBlock::~RenderBlock() } } -void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderBlock::destroy() +{ + // Detach our continuation first. + if (m_inlineContinuation) + m_inlineContinuation->destroy(); + m_inlineContinuation = 0; + + // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will + // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. + children()->destroyLeftoverChildren(); + + if (!documentBeingDestroyed()) { + if (firstLineBox()) { + // We can't wait for RenderBox::destroy to clear the selection, + // because by then we will have nuked the line boxes. + // FIXME: The SelectionController should be responsible for this when it + // is notified of DOM mutations. + if (isSelectionBorder()) + view()->clearSelection(); + + // If we are an anonymous block, then our line boxes might have children + // 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()) { + while (InlineBox* childBox = box->firstChild()) + childBox->remove(); + } + } + } else if (isInline() && parent()) + parent()->dirtyLinesFromChangedChild(this); + } + + m_lineBoxes.deleteLineBoxes(renderArena()); + + RenderBox::destroy(); +} + +void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { setReplaced(newStyle->isDisplayReplacedType()); - RenderFlow::styleWillChange(diff, newStyle); + + if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) { + if (newStyle->position() == StaticPosition) + // Clear our positioned objects list. Our absolutely positioned descendants will be + // inserted into our containing block's positioned objects list during layout. + removePositionedObjects(0); + else if (style()->position() == StaticPosition) { + // Remove our absolutely positioned descendants from their current containing block. + // They will be inserted into our positioned objects list during layout. + RenderObject* cb = parent(); + while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { + if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { + cb = cb->containingBlock(); + break; + } + cb = cb->parent(); + } + + if (cb->isRenderBlock()) + toRenderBlock(cb)->removePositionedObjects(this); + } + } + + RenderBox::styleWillChange(diff, newStyle); } -void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderFlow::styleDidChange(diff, oldStyle); + RenderBox::styleDidChange(diff, oldStyle); // FIXME: We could save this call when the change only affected non-inherited properties for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -172,14 +246,22 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS m_lineHeight = -1; // Update pseudos for :before and :after now. - if (!isAnonymous() && canHaveChildren()) { - updateBeforeAfterContent(RenderStyle::BEFORE); - updateBeforeAfterContent(RenderStyle::AFTER); + if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { + updateBeforeAfterContent(BEFORE); + updateBeforeAfterContent(AFTER); } updateFirstLetter(); } -void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) +void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId) +{ + // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. + if (parent() && parent()->createsAnonymousWrapper()) + return; + return children()->updateBeforeAfterContent(this, 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())) @@ -203,13 +285,13 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) beforeChild->parent()->addChild(newChild, beforeChild); else - addChildToFlow(newChild, beforeChild->parent()); + addChild(newChild, beforeChild->parent()); return; } ASSERT(anonymousChild->isTable()); - if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP - || newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION + if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) + || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) || newChild->isTableSection() || newChild->isTableRow() || newChild->isTableCell()) { @@ -225,7 +307,7 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi // A block has to either have all of its children inline, or all of its children as blocks. // So, if our children are currently inline and a block child has to be inserted, we move all our // inline children into anonymous block boxes. - if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { + if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { // This is a block with inline content. Wrap the inline content in anonymous blocks. makeChildrenNonInline(beforeChild); madeBoxesNonInline = true; @@ -235,7 +317,7 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi ASSERT(beforeChild->isAnonymousBlock()); ASSERT(beforeChild->parent() == this); } - } else if (!m_childrenInline && (newChild->isFloatingOrPositioned() || newChild->isInline())) { + } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) { // If we're inserting an inline child but all of our children are blocks, then we have to make sure // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise // a new one is created and inserted into our list of children in the appropriate position. @@ -249,17 +331,16 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi if (newChild->isInline()) { // No suitable existing anonymous box - create a new one. RenderBlock* newBox = createAnonymousBlock(); - RenderContainer::addChild(newBox, beforeChild); + RenderBox::addChild(newBox, beforeChild); newBox->addChild(newChild); return; } } - RenderContainer::addChild(newChild, beforeChild); - // ### care about aligned stuff + RenderBox::addChild(newChild, beforeChild); - if (madeBoxesNonInline && parent() && isAnonymousBlock()) - parent()->removeLeftoverAnonymousBlock(this); + if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) + toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); // this object may be dead here } @@ -305,14 +386,19 @@ static void getInlineRun(RenderObject* start, RenderObject* boundary, void RenderBlock::deleteLineBoxTree() { - InlineFlowBox* line = m_firstLineBox; - InlineFlowBox* nextLine; - while (line) { - nextLine = line->nextFlowBox(); - line->deleteLine(renderArena()); - line = nextLine; - } - m_firstLineBox = m_lastLineBox = 0; + m_lineBoxes.deleteLineBoxTree(renderArena()); +} + +RootInlineBox* RenderBlock::createRootBox() +{ + return new (renderArena()) RootInlineBox(this); +} + +RootInlineBox* RenderBlock::createRootInlineBox() +{ + RootInlineBox* rootBox = createRootBox(); + m_lineBoxes.appendLineBox(rootBox); + return rootBox; } void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) @@ -327,7 +413,7 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) ASSERT(isInlineBlockOrInlineTable() || !isInline()); ASSERT(!insertionPoint || insertionPoint->parent() == this); - m_childrenInline = false; + setChildrenInline(false); RenderObject *child = firstChild(); if (!child) @@ -344,16 +430,16 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) child = inlineRunEnd->nextSibling(); - RenderBlock* box = createAnonymousBlock(); - insertChildNode(box, inlineRunStart); + RenderBlock* block = createAnonymousBlock(); + children()->insertChildNode(this, block, inlineRunStart); RenderObject* o = inlineRunStart; - while(o != inlineRunEnd) - { + while (o != inlineRunEnd) { RenderObject* no = o; o = no->nextSibling(); - box->moveChildNode(no); + + moveChild(block, block->children(), this, children(), no); } - box->moveChildNode(inlineRunEnd); + moveChild(block, block->children(), this, children(), inlineRunEnd); } #ifndef NDEBUG @@ -364,7 +450,49 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) repaint(); } -void RenderBlock::removeChild(RenderObject *oldChild) +void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) +{ + ASSERT(child->isAnonymousBlock()); + ASSERT(!child->childrenInline()); + + if (child->inlineContinuation()) + return; + + RenderObject* firstAnChild = child->m_children.firstChild(); + RenderObject* lastAnChild = child->m_children.lastChild(); + if (firstAnChild) { + RenderObject* o = firstAnChild; + while (o) { + o->setParent(this); + o = o->nextSibling(); + } + firstAnChild->setPreviousSibling(child->previousSibling()); + lastAnChild->setNextSibling(child->nextSibling()); + if (child->previousSibling()) + child->previousSibling()->setNextSibling(firstAnChild); + if (child->nextSibling()) + child->nextSibling()->setPreviousSibling(lastAnChild); + } else { + if (child->previousSibling()) + child->previousSibling()->setNextSibling(child->nextSibling()); + if (child->nextSibling()) + child->nextSibling()->setPreviousSibling(child->previousSibling()); + } + if (child == m_children.firstChild()) + m_children.setFirstChild(firstAnChild); + if (child == m_children.lastChild()) + m_children.setLastChild(lastAnChild); + child->setParent(0); + child->setPreviousSibling(0); + child->setNextSibling(0); + + child->children()->setFirstChild(0); + child->m_next = 0; + + child->destroy(); +} + +void RenderBlock::removeChild(RenderObject* oldChild) { // If this child is a block, and if our previous and next siblings are // both anonymous blocks with inline content, then we can go ahead and @@ -372,7 +500,7 @@ void RenderBlock::removeChild(RenderObject *oldChild) RenderObject* prev = oldChild->previousSibling(); RenderObject* next = oldChild->nextSibling(); bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && - !oldChild->continuation() && + (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) && (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) && (!next || (next->isAnonymousBlock() && next->childrenInline())); if (canDeleteAnonymousBlocks && prev && next) { @@ -380,20 +508,22 @@ void RenderBlock::removeChild(RenderObject *oldChild) // 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(); - prev->moveChildNode(no); + moveChild(prevBlock, prevBlock->children(), nextBlock, nextBlock->children(), no); } - RenderBlock* nextBlock = static_cast<RenderBlock*>(next); nextBlock->deleteLineBoxTree(); // Nuke the now-empty block. next->destroy(); } - RenderFlow::removeChild(oldChild); + RenderBox::removeChild(oldChild); RenderObject* child = prev ? prev : next; if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { @@ -401,13 +531,13 @@ void RenderBlock::removeChild(RenderObject *oldChild) // box. We can go ahead and pull the content right back up into our // box. setNeedsLayoutAndPrefWidthsRecalc(); - RenderBlock* anonBlock = static_cast<RenderBlock*>(removeChildNode(child, false)); - m_childrenInline = true; + RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); + setChildrenInline(true); RenderObject* o = anonBlock->firstChild(); while (o) { RenderObject* no = o; o = no->nextSibling(); - moveChildNode(no); + moveChild(this, children(), anonBlock, anonBlock->children(), no); } // Delete the now-empty block's lines and nuke it. @@ -422,10 +552,10 @@ int RenderBlock::overflowHeight(bool includeInterior) const int shadowHeight = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight); - int height = m_height + shadowHeight; + int inflatedHeight = height() + shadowHeight; if (hasReflection()) - height = max(height, reflectionBox().bottom()); - return height; + inflatedHeight = max(inflatedHeight, reflectionBox().bottom()); + return inflatedHeight; } return m_overflowHeight; } @@ -436,10 +566,10 @@ int RenderBlock::overflowWidth(bool includeInterior) const int shadowWidth = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth); - int width = m_width + shadowWidth; + int inflatedWidth = width() + shadowWidth; if (hasReflection()) - width = max(width, reflectionBox().right()); - return width; + inflatedWidth = max(inflatedWidth, reflectionBox().right()); + return inflatedWidth; } return m_overflowWidth; } @@ -475,7 +605,7 @@ int RenderBlock::overflowTop(bool includeInterior) const IntRect RenderBlock::overflowRect(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - IntRect box = borderBox(); + IntRect box = borderBoxRect(); int shadowLeft = 0; int shadowRight = 0; int shadowTop = 0; @@ -508,10 +638,10 @@ IntRect RenderBlock::overflowRect(bool includeInterior) const } if (!includeInterior && hasOverflowClip()) - return borderBox(); + return borderBoxRect(); int l = overflowLeft(includeInterior); - int t = min(overflowTop(includeInterior), -borderTopExtra()); - return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height() + borderBottomExtra()) - t); + int t = overflowTop(includeInterior); + return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height()) - t); } bool RenderBlock::isSelfCollapsingBlock() const @@ -522,7 +652,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension - if (m_height > 0 || + if (height() > 0 || isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || style()->minHeight().isPositive() || style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) @@ -547,7 +677,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // Whether or not we collapse is dependent on whether all our normal flow children // are also self-collapsing. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isFloatingOrPositioned()) continue; if (!child->isSelfCollapsingBlock()) @@ -570,8 +700,8 @@ void RenderBlock::layout() // It's safe to check for control clip here, since controls can never be table cells. if (hasControlClip()) { // Because of the lightweight clip, there can never be any overflow from children. - m_overflowWidth = m_width; - m_overflowHeight = m_height; + m_overflowWidth = width(); + m_overflowHeight = height(); m_overflowLeft = 0; m_overflowTop = 0; } @@ -587,35 +717,29 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (!relayoutChildren && layoutOnlyPositionedObjects()) return; - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } - - LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns && !hasReflection()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); - int oldWidth = m_width; + int oldWidth = width(); int oldColumnWidth = desiredColumnWidth(); calcWidth(); calcColumnWidth(); - m_overflowWidth = m_width; + m_overflowWidth = width(); m_overflowLeft = 0; - if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth()) + if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) relayoutChildren = true; clearFloats(); - int previousHeight = m_height; - m_height = 0; + int previousHeight = height(); + setHeight(0); + m_overflowHeight = 0; - // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track + // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track // our current maximal positive and negative margins. These values are used when we // are collapsed with adjacent blocks, so for example, if you have block A and B // collapsing together, then you'd take the maximal positive margin from both A and B @@ -629,11 +753,11 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (!isCell) { initMaxMarginValues(); - m_topMarginQuirk = style()->marginTop().quirk(); - m_bottomMarginQuirk = style()->marginBottom().quirk(); + setTopMarginQuirk(style()->marginTop().quirk()); + setBottomMarginQuirk(style()->marginBottom().quirk()); - Node* node = element(); - if (node && node->hasTagName(formTag) && static_cast<HTMLFormElement*>(node)->isMalformed()) { + Node* n = node(); + if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { // See if this form is malformed (i.e., unclosed). If so, don't give the form // a bottom margin. setMaxBottomMargins(0, 0); @@ -643,9 +767,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // For overflow:scroll blocks, ensure we have both scrollbars in place always. if (scrollsOverflow()) { if (style()->overflowX() == OSCROLL) - m_layer->setHasHorizontalScrollbar(true); + layer()->setHasHorizontalScrollbar(true); if (style()->overflowY() == OSCROLL) - m_layer->setHasVerticalScrollbar(true); + layer()->setHasVerticalScrollbar(true); } int repaintTop = 0; @@ -658,25 +782,24 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Expand our intrinsic height to encompass floats. int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || - (parent() && parent()->isFlexibleBox() || m_hasColumns))) - m_height = floatBottom() + toAdd; + if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) + setHeight(floatBottom() + toAdd); // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as // we adjust for clean column breaks. int singleColumnBottom = layoutColumns(); // Calculate our new height. - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldHeight != m_height) { - if (oldHeight > m_height && maxFloatBottom > m_height && !childrenInline()) { + if (oldHeight != height()) { + if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) { // One of our children's floats may have become an overhanging float for us. We need to look for it. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { - RenderBlock* block = static_cast<RenderBlock*>(child); - if (block->floatBottom() + block->yPos() > m_height) - addOverhangingFloats(block, -block->xPos(), -block->yPos(), false); + RenderBlock* block = toRenderBlock(child); + if (block->floatBottom() + block->y() > height()) + addOverhangingFloats(block, -block->x(), -block->y(), false); } } } @@ -684,21 +807,14 @@ void RenderBlock::layoutBlock(bool relayoutChildren) layoutColumns(singleColumnBottom); // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight > m_height) + if (m_overflowHeight > height()) m_overflowHeight -= toAdd; - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); } - if (previousHeight != m_height) + if (previousHeight != height()) relayoutChildren = true; - // Some classes of objects (floats and fieldsets with no specified heights and table cells) expand to encompass - // overhanging floats. - if (hasOverhangingFloats() && expandsToEncloseOverhangingFloats()) { - m_height = floatBottom(); - m_height += borderBottom() + paddingBottom(); - } - if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip()) addVisualOverflow(floatRect()); @@ -707,15 +823,15 @@ void RenderBlock::layoutBlock(bool relayoutChildren) positionListMarker(); // Always ensure our overflow width/height are at least as large as our width/height. - m_overflowWidth = max(m_overflowWidth, m_width); - m_overflowHeight = max(m_overflowHeight, m_height); + m_overflowWidth = max(m_overflowWidth, width()); + m_overflowHeight = max(m_overflowHeight, height()); if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -729,12 +845,10 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. if (hasOverflowClip()) - m_layer->updateScrollInfoAfterLayout(); + layer()->updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. - bool didFullRepaint = false; - if (checkForRepaint) - didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + bool didFullRepaint = repainter.repaintAfterLayout(); if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { IntRect repaintRect(m_overflowLeft, repaintTop, m_overflowWidth - m_overflowLeft, repaintBottom - repaintTop); @@ -752,30 +866,35 @@ void RenderBlock::layoutBlock(bool relayoutChildren) repaintRect.setY(y); // Don't allow this rect to spill out of our overflow box. - repaintRect.intersect(IntRect(0, 0, m_width, m_height)); + repaintRect.intersect(IntRect(0, 0, width(), height())); } // Make sure the rect is still non-empty after intersecting for overflow above if (!repaintRect.isEmpty()) { repaintRectangle(repaintRect); // We need to do a partial repaint of our content. if (hasReflection()) - layer()->reflection()->repaintRectangle(repaintRect); + repaintRectangle(reflectedRect(repaintRect)); } } setNeedsLayout(false); } -void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo) +bool RenderBlock::expandsToEncloseOverhangingFloats() const +{ + return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset(); +} + +void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) { - if (child->hasStaticX()) { + if (child->style()->hasStaticX()) { if (style()->direction() == LTR) - child->setStaticX(borderLeft() + paddingLeft()); + child->layer()->setStaticX(borderLeft() + paddingLeft()); else - child->setStaticX(borderRight() + paddingRight()); + child->layer()->setStaticX(borderRight() + paddingRight()); } - if (child->hasStaticY()) { - int y = m_height; + if (child->style()->hasStaticY()) { + int y = height(); if (!marginInfo.canCollapseWithTop()) { child->calcVerticalMargins(); int marginTop = child->marginTop(); @@ -790,7 +909,7 @@ void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& m } y += (collapsedTopPos - collapsedTopNeg) - marginTop; } - child->setStaticY(y); + child->layer()->setStaticY(y); } } @@ -810,143 +929,95 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for // an example of this scenario. int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); - m_height += marginOffset; + setHeight(height() + marginOffset); positionNewFloats(); - m_height -= marginOffset; + setHeight(height() - marginOffset); } -RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled) +bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) { - // Handle positioned children first. - RenderObject* next = handlePositionedChild(child, marginInfo, handled); - if (handled) return next; - - // Handle floating children next. - next = handleFloatingChild(child, marginInfo, handled); - if (handled) return next; - - // See if we have a compact element. If we do, then try to tuck the compact element into the margin space of the next block. - next = handleCompactChild(child, compactInfo, handled); - if (handled) return next; - - // Finally, see if we have a run-in element. - return handleRunInChild(child, handled); + // Handle in the given order + return handlePositionedChild(child, marginInfo) + || handleFloatingChild(child, marginInfo) + || handleRunInChild(child); } -RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) { if (child->isPositioned()) { - handled = true; child->containingBlock()->insertPositionedObject(child); adjustPositionedBlock(child, marginInfo); - return child->nextSibling(); + return true; } - - return 0; + return false; } -RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) { if (child->isFloating()) { - handled = true; insertFloatingObject(child); adjustFloatingBlock(marginInfo); - return child->nextSibling(); - } - - return 0; -} - -RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled) -{ - // FIXME: We only deal with one compact at a time. It is unclear what should be - // done if multiple contiguous compacts are encountered. For now we assume that - // compact A followed by another compact B should simply be treated as block A. - if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) { - // Get the next non-positioned/non-floating RenderBlock. - RenderObject* next = child->nextSibling(); - RenderObject* curr = next; - while (curr && curr->isFloatingOrPositioned()) - curr = curr->nextSibling(); - if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) { - curr->calcWidth(); // So that horizontal margins are correct. - - child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to - // fill the containing block width. - child->calcWidth(); - int childMargins = child->marginLeft() + child->marginRight(); - int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight(); - if (margin >= (childMargins + child->maxPrefWidth())) { - // The compact will fit in the margin. - handled = true; - compactInfo.set(child, curr); - child->setPos(0,0); // This position will be updated to reflect the compact's - // desired position and the line box for the compact will - // pick that position up. - - // Remove the child. - RenderObject* next = child->nextSibling(); - removeChildNode(child); - - // Now insert the child under |curr|. - curr->insertChildNode(child, curr->firstChild()); - return next; - } - else - child->setInline(false); // We didn't fit, so we remain a block-level element. - } - } - return 0; -} - -void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo) -{ - if (compactInfo.matches(child)) { - // We have a compact child to squeeze in. - RenderObject* compactChild = compactInfo.compact(); - int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft(); - if (style()->direction() == RTL) { - compactChild->calcWidth(); // have to do this because of the capped maxwidth - compactXPos = width() - borderRight() - paddingRight() - marginRight() - - compactChild->width() - compactChild->marginRight(); - } - compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space. - compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position. - compactInfo.clear(); + return true; } + return false; } -RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled) +bool RenderBlock::handleRunInChild(RenderBox* child) { // See if we have a run-in element with inline children. If the // children aren't inline, then just treat the run-in as a normal // block. - if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) { - // Get the next non-positioned/non-floating RenderBlock. - RenderObject* curr = child->nextSibling(); - while (curr && curr->isFloatingOrPositioned()) - curr = curr->nextSibling(); - if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) { - // The block acts like an inline, so just null out its - // position. - handled = true; - child->setInline(true); - child->setPos(0,0); - - // Remove the child. - RenderObject* next = child->nextSibling(); - removeChildNode(child); - - // Now insert the child under |curr|. - curr->insertChildNode(child, curr->firstChild()); - return next; + if (!child->isRunIn() || !child->childrenInline() && !child->isReplaced()) + return false; + + RenderBlock* blockRunIn = toRenderBlock(child); + // Get the next non-positioned/non-floating RenderBlock. + RenderObject* curr = blockRunIn->nextSibling(); + while (curr && curr->isFloatingOrPositioned()) + curr = curr->nextSibling(); + + if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn()) + return false; + + RenderBlock* currBlock = toRenderBlock(curr); + + // Remove the old child. + children()->removeChildNode(this, blockRunIn); + + // Create an inline. + Node* runInNode = blockRunIn->node(); + RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); + inlineRunIn->setStyle(blockRunIn->style()); + + bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER; + + // 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) { + 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. } } - return 0; + + // Now insert the new child under |currBlock|. + currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); + + // If the run-in had an element, we need to set the new renderer. + if (runInNode) + runInNode->setRenderer(inlineRunIn); + + // Destroy the block run-in. + blockRunIn->destroy(); + + // The block acts like an inline, so just null out its + // position. + + return true; } -void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate) +int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) { // Get our max pos and neg top margins. int posTop = child->maxTopMargin(true); @@ -975,7 +1046,7 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // has an example of this, a <dt> with 0.8em author-specified inside // a <dl> inside a <td>. if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { - m_topMarginQuirk = false; + setTopMarginQuirk(false); marginInfo.setDeterminedTopQuirk(true); } @@ -985,13 +1056,13 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // This deals with the <td><div><p> case. // Don't do this for a block that split two inlines though. You do // still apply margins in this case. - m_topMarginQuirk = true; + setTopMarginQuirk(true); } if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) marginInfo.setTopQuirk(topQuirk); - int ypos = m_height; + int ypos = height(); if (child->isSelfCollapsingBlock()) { // This child has no height. We need to compute our // position before we collapse the child's margins together, @@ -1010,20 +1081,20 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // is correct, since it could have overflowing content // that needs to be positioned correctly (e.g., a block that // had a specified height of 0 but that actually had subcontent). - ypos = m_height + collapsedTopPos - collapsedTopNeg; + ypos = height() + collapsedTopPos - collapsedTopNeg; } else { if (child->style()->marginTopCollapse() == MSEPARATE) { - m_height += marginInfo.margin() + child->marginTop(); - ypos = m_height; + setHeight(height() + marginInfo.margin() + child->marginTop()); + ypos = height(); } else if (!marginInfo.atTopOfBlock() || (!marginInfo.canCollapseTopWithChildren() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { // We're collapsing with a previous sibling's margins and not // with the top of the block. - m_height += max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop); - ypos = m_height; + setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); + ypos = height(); } marginInfo.setPosMargin(child->maxBottomMargin(true)); @@ -1034,34 +1105,15 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i marginInfo.setSelfCollapsingBlockClearedFloat(false); } - - view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos)); - child->setPos(child->xPos(), ypos); - if (ypos != yPosEstimate) { - if (child->shrinkToAvoidFloats()) - // The child's width depends on the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); - - if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); - - // Our guess was wrong. Make the child lay itself out again. - child->layoutIfNeeded(); - } + + return ypos; } -void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin) +int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) { - int heightIncrease = getClearDelta(child); + int heightIncrease = getClearDelta(child, yPos); if (!heightIncrease) - return; - - // The child needs to be lowered. Move the child so that it just clears the float. - view()->addLayoutDelta(IntSize(0, -heightIncrease)); - child->setPos(child->xPos(), child->yPos() + heightIncrease); + return yPos; if (child->isSelfCollapsingBlock()) { // For self-collapsing blocks that clear, they can still collapse their @@ -1071,7 +1123,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); // Adjust our height such that we are ready to be collapsed with subsequent siblings. - m_height = child->yPos() - max(0, marginInfo.margin()); + setHeight(child->y() - max(0, marginInfo.margin())); // Set a flag that we cleared a float so that we know both to increase the height of the block // to compensate for the clear and to avoid collapsing our margins with the parent block's @@ -1079,7 +1131,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setSelfCollapsingBlockClearedFloat(true); } else // Increase our height by the amount we had to clear. - m_height += heightIncrease; + setHeight(height() + heightIncrease); if (marginInfo.canCollapseWithTop()) { // We can no longer collapse with the top of the block since a clear @@ -1090,34 +1142,24 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf setMaxTopMargins(oldTopPosMargin, oldTopNegMargin); marginInfo.setAtTopOfBlock(false); } - - // If our value of clear caused us to be repositioned vertically to be - // underneath a float, we might have to do another layout to take into account - // the extra space we now have available. - if (child->shrinkToAvoidFloats()) - // The child's width depends on the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); - if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); - child->layoutIfNeeded(); + + return yPos + heightIncrease; } -int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo) +int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) { // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological // relayout if there are intruding floats. - int yPosEstimate = m_height; + int yPosEstimate = height(); if (!marginInfo.canCollapseWithTop()) { int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); yPosEstimate += max(marginInfo.margin(), childMarginTop); } + yPosEstimate += getClearDelta(child, yPosEstimate); return yPosEstimate; } -void RenderBlock::determineHorizontalPosition(RenderObject* child) +void RenderBlock::determineHorizontalPosition(RenderBox* child) { if (style()->direction() == LTR) { int xPos = borderLeft() + paddingLeft(); @@ -1128,7 +1170,7 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need // to shift over as necessary to dodge any floats that might get in the way. if (child->avoidsFloats()) { - int leftOff = leftOffset(m_height); + int leftOff = leftOffset(height(), false); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { if (child->marginLeft() < 0) leftOff += child->marginLeft(); @@ -1140,17 +1182,17 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |leftOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); chPos = leftOff + child->marginLeft(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } else { - int xPos = m_width - borderRight() - paddingRight() - verticalScrollbarWidth(); + int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); int chPos = xPos - (child->width() + child->marginRight()); if (child->avoidsFloats()) { - int rightOff = rightOffset(m_height); + int rightOff = rightOffset(height(), false); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { if (child->marginRight() < 0) rightOff -= child->marginRight(); @@ -1161,12 +1203,12 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |rightOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); chPos = rightOff - child->marginRight() - child->width(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } } @@ -1178,13 +1220,13 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin())); if (!marginInfo.bottomQuirk()) - m_bottomMarginQuirk = false; + setBottomMarginQuirk(false); if (marginInfo.bottomQuirk() && marginBottom() == 0) // We have no bottom margin and our last child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. - m_bottomMarginQuirk = true; + setBottomMarginQuirk(true); } } @@ -1205,17 +1247,17 @@ void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInf // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) - m_height += marginInfo.margin(); + setHeight(height() + marginInfo.margin()); // Now add in our bottom border/padding. - m_height += bottom; + setHeight(height() + bottom); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - m_height = max(m_height, top + bottom); + setHeight(max(height(), top + bottom)); // Always make sure our overflow height is at least our height. - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowHeight = max(height(), m_overflowHeight); // Update our bottom collapsed margin info. setCollapsedBottomMargin(marginInfo); @@ -1244,11 +1286,11 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int top = borderTop() + paddingTop(); int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - m_height = m_overflowHeight = top; + m_overflowHeight = top; + setHeight(m_overflowHeight); // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, MarginInfo marginInfo(this, top, bottom); - CompactInfo compactInfo; // Fieldsets need to find their legend and position it inside the border of the object. // The legend then gets skipped during normal layout. @@ -1257,12 +1299,14 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int previousFloatBottom = 0; maxFloatBottom = 0; - RenderObject* child = firstChild(); - while (child) { - if (legend == child) { - child = child->nextSibling(); + RenderBox* next = firstChildBox(); + + while (next) { + RenderBox* child = next; + next = child->nextSiblingBox(); + + if (legend == child) continue; // Skip the legend, since it has already been positioned up in the fieldset's border. - } int oldTopPosMargin = maxTopPosMargin(); int oldTopNegMargin = maxTopNegMargin(); @@ -1279,12 +1323,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Handle the four types of special elements first. These include positioned content, floating content, compacts and // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. - bool handled = false; - RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled); - if (handled) { - child = next; + if (handleSpecialChild(child, marginInfo)) continue; - } // The child is a normal flow object. Compute its vertical margins now. child->calcVerticalMargins(); @@ -1301,28 +1341,31 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int yPosEstimate = estimateVerticalPosition(child, marginInfo); // Cache our old rect so that we can dirty the proper repaint rects if the child moves. - IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height()); - + IntRect oldRect(child->x(), child->y() , child->width(), child->height()); +#ifndef NDEBUG + IntSize oldLayoutDelta = view()->layoutDelta(); +#endif // Go ahead and position the child as though it didn't collapse with the top. - view()->addLayoutDelta(IntSize(0, child->yPos() - yPosEstimate)); - child->setPos(child->xPos(), yPosEstimate); + view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); + child->setLocation(child->x(), yPosEstimate); bool markDescendantsWithFloats = false; - if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->containsFloats()) + if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) markDescendantsWithFloats = true; else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always mark it for // layout. int fb = max(previousFloatBottom, floatBottom()); - if (fb > m_height || fb > yPosEstimate) + if (fb > yPosEstimate) markDescendantsWithFloats = true; } - if (markDescendantsWithFloats) - child->markAllDescendantsWithFloatsForLayout(); + if (child->isRenderBlock()) { + if (markDescendantsWithFloats) + toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); - if (child->isRenderBlock()) - previousFloatBottom = max(previousFloatBottom, oldRect.y() + static_cast<RenderBlock*>(child)->floatBottom()); + previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); + } bool childHadLayout = child->m_everHadLayout; bool childNeededLayout = child->needsLayout(); @@ -1331,10 +1374,28 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Now determine the correct ypos based off examination of collapsing margin // values. - collapseMargins(child, marginInfo, yPosEstimate); + int yBeforeClear = collapseMargins(child, marginInfo); // Now check for clear. - clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin); + int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); + + view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); + child->setLocation(child->x(), yAfterClear); + + // Now we have a final y position. See if it really does end up being different from our estimate. + if (yAfterClear != yPosEstimate) { + if (child->shrinkToAvoidFloats()) { + // The child's width depends on the line width. + // When the child shifts to clear an item, its width can + // change (because it has more available line width). + // So go ahead and mark the item as dirty. + child->setChildNeedsLayout(true, false); + } + if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) + toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); + // Our guess was wrong. Make the child lay itself out again. + child->layoutIfNeeded(); + } // We are no longer at the top of the block if we encounter a non-empty child. // This has to be done after checking for clear, so that margins can be reset if a clear occurred. @@ -1345,25 +1406,26 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom determineHorizontalPosition(child); // Update our height now that the child has been placed in the correct position. - m_height += child->height(); + setHeight(height() + child->height()); if (child->style()->marginBottomCollapse() == MSEPARATE) { - m_height += child->marginBottom(); + setHeight(height() + child->marginBottom()); marginInfo.clearMargin(); } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. - maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), !childNeededLayout)); - - // Update our overflow in case the child spills out the block. - m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, m_height + child->overflowHeight(false) - child->height()); - m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth); - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); - - // Insert our compact into the block margin if we have one. - insertCompactIfNeeded(child, compactInfo); + if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) + maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); + + // Update our visual overflow in case the child spills out the block, but only if we were going to paint + // the child block ourselves. + if (!child->hasSelfPaintingLayer()) { + m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, height() + child->overflowHeight(false) - child->height()); + m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); + } - IntSize childOffset(child->xPos() - oldRect.x(), child->yPos() - oldRect.y()); + IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); if (childOffset.width() || childOffset.height()) { view()->addLayoutDelta(childOffset); @@ -1377,7 +1439,7 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom if (!childHadLayout && child->checkForRepaintDuringLayout()) child->repaint(); - child = child->nextSibling(); + ASSERT(oldLayoutDelta == view()->layoutDelta()); } // Now do the handling of the bottom of the block, adding in our bottom border/padding and @@ -1390,7 +1452,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) return false; - LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); if (needsPositionedMovementLayout()) { tryLayoutDoingPositionedMovementOnly(); @@ -1404,7 +1466,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() statePusher.pop(); if (hasOverflowClip()) - m_layer->updateScrollInfoAfterLayout(); + layer()->updateScrollInfoAfterLayout(); setNeedsLayout(false); return true; @@ -1413,7 +1475,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() void RenderBlock::layoutPositionedObjects(bool relayoutChildren) { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1421,11 +1483,11 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is // positioned explicitly) this should not incur a performance penalty. - if (relayoutChildren || (r->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) + if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) r->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. - if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) + //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) r->setPrefWidthsDirty(true, false); // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width @@ -1440,7 +1502,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) void RenderBlock::markPositionedObjectsForLayout() { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1469,7 +1531,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. - if (r->m_bottom > m_height && (paintAllDescendants && r->m_renderer->isDescendantOf(this) || r->m_shouldPaint) && !r->m_renderer->hasLayer()) { + if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { r->m_renderer->repaint(); r->m_renderer->repaintOverhangingFloats(); } @@ -1477,18 +1539,18 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) view()->enableLayoutState(); } } - + void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); PaintPhase phase = paintInfo.phase; // Check if we need to do anything at all. // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView // paints the root's background. - if (!isInlineFlow() && !isRoot()) { + if (!isRoot()) { IntRect overflowBox = overflowRect(false); overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.move(tx, ty); @@ -1496,52 +1558,69 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) return; } - bool useControlClip = phase != PaintPhaseBlockBackground && phase != PaintPhaseSelfOutline && phase != PaintPhaseMask && hasControlClip(); + bool pushedClip = pushContentsClip(paintInfo, tx, ty); + paintObject(paintInfo, tx, ty); + if (pushedClip) + popContentsClip(paintInfo, phase, tx, ty); - // Push a clip. - if (useControlClip) { - if (phase == PaintPhaseOutline) - paintInfo.phase = PaintPhaseChildOutlines; - else if (phase == PaintPhaseChildBlockBackground) { - paintInfo.phase = PaintPhaseBlockBackground; - paintObject(paintInfo, tx, ty); - paintInfo.phase = PaintPhaseChildBlockBackgrounds; - } - IntRect clipRect(controlClipRect(tx, ty)); - if (clipRect.isEmpty()) - return; - paintInfo.context->save(); - paintInfo.context->clip(clipRect); - } + // 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)) + layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); +} - paintObject(paintInfo, tx, ty); - - // Pop the clip. - if (useControlClip) { - paintInfo.context->restore(); - if (phase == PaintPhaseOutline) { - paintInfo.phase = PaintPhaseSelfOutline; - paintObject(paintInfo, tx, ty); - paintInfo.phase = phase; - } else if (phase == PaintPhaseChildBlockBackground) - paintInfo.phase = phase; +void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) +{ + const Color& ruleColor = style()->columnRuleColor(); + bool ruleTransparent = style()->columnRuleIsTransparent(); + EBorderStyle ruleStyle = style()->columnRuleStyle(); + int ruleWidth = style()->columnRuleWidth(); + int colGap = columnGap(); + bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; + if (!renderRule) + return; + + // We need to do multiple passes, breaking up our child painting into strips. + int currXOffset = 0; + int ruleAdd = borderLeft() + paddingLeft(); + int ruleX = 0; + Vector<IntRect>* colRects = columnRects(); + unsigned colCount = colRects->size(); + for (unsigned i = 0; i < colCount; i++) { + // For each rect, we clip to the rect, and then we adjust our coords. + IntRect colRect = colRects->at(i); + + // Move to the next position. + if (style()->direction() == LTR) { + ruleX += colRect.width() + colGap / 2; + currXOffset += colRect.width() + colGap; + } else { + ruleX -= (colRect.width() + colGap / 2); + currXOffset -= (colRect.width() + colGap); + } + + // Now paint the column rule. + if (i < colCount - 1) { + int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; + int ruleEnd = ruleStart + ruleWidth; + int ruleTop = ty + borderTop() + paddingTop(); + int ruleBottom = ruleTop + contentHeight(); + drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, + style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); + } + + ruleX = currXOffset; } } -void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) +void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) { // We need to do multiple passes, breaking up our child painting into strips. GraphicsContext* context = paintInfo.context; int currXOffset = 0; int currYOffset = 0; - int ruleAdd = borderLeft() + paddingLeft(); - int ruleX = 0; int colGap = columnGap(); - const Color& ruleColor = style()->columnRuleColor(); - bool ruleTransparent = style()->columnRuleIsTransparent(); - EBorderStyle ruleStyle = style()->columnRuleStyle(); - int ruleWidth = style()->columnRuleWidth(); - bool renderRule = !paintingFloats && ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; Vector<IntRect>* colRects = columnRects(); unsigned colCount = colRects->size(); for (unsigned i = 0; i < colCount; i++) { @@ -1567,27 +1646,14 @@ void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool painti paintContents(info, finalX, finalY); // Move to the next position. - if (style()->direction() == LTR) { - ruleX += colRect.width() + colGap / 2; + if (style()->direction() == LTR) currXOffset += colRect.width() + colGap; - } else { - ruleX -= (colRect.width() + colGap / 2); + else currXOffset -= (colRect.width() + colGap); - } - + currYOffset -= colRect.height(); context->restore(); - - // Now paint the column rule. - if (renderRule && paintInfo.phase == PaintPhaseForeground && i < colCount - 1) { - int ruleStart = ruleX - ruleWidth / 2 + ruleAdd; - int ruleEnd = ruleStart + ruleWidth; - drawBorder(paintInfo.context, tx + ruleStart, ty + borderTop() + paddingTop(), tx + ruleEnd, ty + borderTop() + paddingTop() + contentHeight(), - style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); - } - - ruleX = currXOffset; } } @@ -1600,7 +1666,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) return; if (childrenInline()) - paintLines(paintInfo, tx, ty); + m_lineBoxes.paint(this, paintInfo, tx, ty); else paintChildren(paintInfo, tx, ty); } @@ -1616,23 +1682,23 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) info.paintingRoot = paintingRootForChildren(paintInfo); bool isPrinting = document()->printing(); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + 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->yPos()) > paintInfo.rect.y() && - (ty + child->yPos()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos(), this, true); + inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && + (ty + child->y()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y(), this, true); return; } - if (!child->hasLayer() && !child->isFloating()) + if (!child->hasSelfPaintingLayer() && !child->isFloating()) 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->yPos() + child->height()) > paintInfo.rect.y() && - (ty + child->yPos() + child->height()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos() + child->height() + max(0, child->collapsedMarginBottom()), this, true); + inRootBlockContext() && (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; } } @@ -1642,9 +1708,10 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ { SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); - // Ask the SelectionController if the caret should be painted by this block + // Paint the caret if the SelectionController says so or if caret browsing is enabled + bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled(); RenderObject* caretPainter = selection->caretRenderer(); - if (caretPainter == this && selection->isContentEditable()) { + if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { // Convert the painting offset into the local coordinate system of this renderer, // to match the localCaretRect computed by the SelectionController offsetForContents(tx, ty); @@ -1660,14 +1727,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) { PaintPhase paintPhase = paintInfo.phase; - // If we're a repositioned run-in or a compact, don't paint background/borders. - bool inlineFlow = isInlineFlow(); - // 1. paint background, borders etc - if (!inlineFlow && - (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && - hasBoxDecorations() && style()->visibility() == VISIBLE) { - paintBoxDecorations(paintInfo, tx, ty); + if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { + if (hasBoxDecorations()) + paintBoxDecorations(paintInfo, tx, ty); + if (hasColumns()) + paintColumnRules(paintInfo, tx, ty); } if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { @@ -1683,12 +1748,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); + layer()->subtractScrolledContentOffset(scrolledX, scrolledY); // 2. paint contents if (paintPhase != PaintPhaseSelfOutline) { - if (m_hasColumns) - paintColumns(paintInfo, scrolledX, scrolledY); + if (hasColumns()) + paintColumnContents(paintInfo, scrolledX, scrolledY); else paintContents(paintInfo, scrolledX, scrolledY); } @@ -1696,30 +1761,30 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 3. paint selection // FIXME: Make this work with multi column layouts. For now don't fill gaps. bool isPrinting = document()->printing(); - if (!inlineFlow && !isPrinting && !m_hasColumns) + if (!isPrinting && !hasColumns()) paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. // 4. paint floats. - if (!inlineFlow && (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip)) { - if (m_hasColumns) - paintColumns(paintInfo, scrolledX, scrolledY, true); + if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { + if (hasColumns()) + paintColumnContents(paintInfo, scrolledX, scrolledY, true); else paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); } // 5. paint outline. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) - RenderObject::paintOutline(paintInfo.context, tx, ty, width(), height(), style()); + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) + paintOutline(paintInfo.context, tx, ty, width(), height(), style()); // 6. paint continuation outlines. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { - if (continuation() && continuation()->hasOutline() && continuation()->style()->visibility() == VISIBLE) { - RenderFlow* inlineFlow = static_cast<RenderFlow*>(continuation()->element()->renderer()); - if (!inlineFlow->hasLayer()) - containingBlock()->addContinuationWithOutline(inlineFlow); - else if (!inlineFlow->firstLineBox()) - inlineFlow->paintOutline(paintInfo.context, tx - xPos() + inlineFlow->containingBlock()->xPos(), - ty - yPos() + inlineFlow->containingBlock()->yPos()); + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { + if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) { + RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer()); + if (!inlineRenderer->hasSelfPaintingLayer()) + containingBlock()->addContinuationWithOutline(inlineRenderer); + else if (!inlineRenderer->firstLineBox()) + inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), + ty - y() + inlineRenderer->containingBlock()->y()); } paintContinuationOutlines(paintInfo, tx, ty); } @@ -1727,7 +1792,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 7. paint caret. // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. - if (!inlineFlow && paintPhase == PaintPhaseForeground) { + if (paintPhase == PaintPhaseForeground) { paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); } @@ -1742,11 +1807,11 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { // Only paint the object if our m_shouldPaint flag is set. - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - int currentTX = tx + r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); - int currentTY = ty + r->m_top - r->m_renderer->yPos() + r->m_renderer->marginTop(); + int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); + int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); if (!preservePhase) { currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; @@ -1770,8 +1835,8 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { // We can check the first box and last box and avoid painting if we don't // intersect. - int yPos = ty + firstLineBox()->yPos(); - int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos(); + int yPos = ty + firstLineBox()->y(); + int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y(); if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) return; @@ -1779,7 +1844,7 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) // them. 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 (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - yPos = ty + curr->yPos(); + yPos = ty + curr->y(); h = curr->height(); if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) curr->paintEllipsisBox(paintInfo, tx, ty); @@ -1787,22 +1852,22 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) } } -ContinuationOutlineTableMap* continuationOutlineTable() +static ContinuationOutlineTableMap* continuationOutlineTable() { DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); return &table; } -void RenderBlock::addContinuationWithOutline(RenderFlow* flow) +void RenderBlock::addContinuationWithOutline(RenderInline* flow) { // We can't make this work if the inline is in a layer. We'll just rely on the broken // way of painting. - ASSERT(!flow->layer()); + ASSERT(!flow->layer() && !flow->isInlineContinuation()); ContinuationOutlineTableMap* table = continuationOutlineTable(); - RenderFlowSequencedSet* continuations = table->get(this); + ListHashSet<RenderInline*>* continuations = table->get(this); if (!continuations) { - continuations = new RenderFlowSequencedSet; + continuations = new ListHashSet<RenderInline*>; table->set(this, continuations); } @@ -1815,19 +1880,19 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) if (table->isEmpty()) return; - RenderFlowSequencedSet* continuations = table->get(this); + ListHashSet<RenderInline*>* continuations = table->get(this); if (!continuations) return; // Paint each continuation outline. - RenderFlowSequencedSet::iterator end = continuations->end(); - for (RenderFlowSequencedSet::iterator it = continuations->begin(); it != end; ++it) { + ListHashSet<RenderInline*>::iterator end = continuations->end(); + for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { // Need to add in the coordinates of the intervening blocks. - RenderFlow* flow = *it; + RenderInline* flow = *it; RenderBlock* block = flow->containingBlock(); for ( ; block && block != this; block = block->containingBlock()) { - tx += block->xPos(); - ty += block->yPos(); + tx += block->x(); + ty += block->y(); } ASSERT(block); flow->paintOutline(info.context, tx, ty); @@ -1848,9 +1913,9 @@ void RenderBlock::setSelectionState(SelectionState s) if ((s == SelectionStart && selectionState() == SelectionEnd) || (s == SelectionEnd && selectionState() == SelectionStart)) - m_selectionState = SelectionBoth; + RenderBox::setSelectionState(SelectionBoth); else - m_selectionState = s; + RenderBox::setSelectionState(s); RenderBlock* cb = containingBlock(); if (cb && !cb->isRenderView()) @@ -1859,12 +1924,12 @@ void RenderBlock::setSelectionState(SelectionState s) bool RenderBlock::shouldPaintSelectionGaps() const { - return m_selectionState != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); + return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); } bool RenderBlock::isSelectionRoot() const { - if (!element()) + if (!node()) return false; // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. @@ -1877,27 +1942,27 @@ bool RenderBlock::isSelectionRoot() const return true; if (view() && view()->selectionStart()) { - Node* startElement = view()->selectionStart()->element(); - if (startElement && startElement->rootEditableElement() == element()) + Node* startElement = view()->selectionStart()->node(); + if (startElement && startElement->rootEditableElement() == node()) return true; } return false; } -GapRects RenderBlock::selectionGapRects() +GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* /*repaintContainer*/) { ASSERT(!needsLayout()); if (!shouldPaintSelectionGaps()) return GapRects(); - // FIXME: this is broken with transforms - FloatPoint absContentPoint = localToAbsoluteForContent(FloatPoint()); + // FIXME: this is broken with transforms and a non-null repaintContainer + FloatPoint absContentPoint = localToAbsolute(FloatPoint()); if (hasOverflowClip()) absContentPoint -= layer()->scrolledContentOffset(); - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); @@ -1907,7 +1972,7 @@ GapRects RenderBlock::selectionGapRects() void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) { if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); paintInfo.context->save(); @@ -1916,21 +1981,24 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) } } -static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderObject*>* positionedObjects) +#ifndef BUILDING_ON_TIGER +static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) { if (!positionedObjects) return; - ListHashSet<RenderObject*>::const_iterator end = positionedObjects->end(); - for (ListHashSet<RenderObject*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { - RenderObject* r = *it; - paintInfo->context->clipOut(IntRect(tx + r->xPos(), ty + r->yPos(), r->width(), r->height())); + ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); + for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* r = *it; + paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); } } +#endif GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) { +#ifndef BUILDING_ON_TIGER // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. // Clip out floating and positioned objects when painting selection gaps. if (paintInfo) { @@ -1938,7 +2006,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) - clipOutPositionedObjects(paintInfo, cb->xPos(), cb->yPos(), cb->m_positionedObjects); + clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); if (m_floatingObjects) { for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { FloatingObject* r = it.current(); @@ -1948,6 +2016,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int } } } +#endif // FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is // fixed). @@ -1955,7 +2024,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. return result; - if (m_hasColumns || hasTransform()) { + if (hasColumns() || hasTransform()) { // FIXME: We should learn how to gap fill multiple columns and transforms eventually. lastTop = (ty - blockY) + height(); lastLeft = leftSelectionOffset(rootBlock, height()); @@ -1969,8 +2038,8 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. - if (rootBlock == this && (m_selectionState != SelectionBoth && m_selectionState != SelectionEnd)) - result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height() + borderBottomExtra(), + if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) + result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), rootBlock, blockX, blockY, paintInfo)); return result; } @@ -2007,14 +2076,14 @@ GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop, rootBlock, blockX, blockY, paintInfo)); - if (!paintInfo || ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y()) + if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())) result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); lastSelectedLine = curr; } if (containsStart && !lastSelectedLine) - // Selection must start just after our last line. + // VisibleSelection must start just after our last line. lastSelectedLine = lastRootBox(); if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { @@ -2032,10 +2101,10 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, GapRects result; // Go ahead and jump right to the first block child that contains some selected objects. - RenderObject* curr; - for (curr = firstChild(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSibling()) { } + RenderBox* curr; + for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } - for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSibling()) { + for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { SelectionState childState = curr->selectionState(); if (childState == SelectionBoth || childState == SelectionEnd) sawSelectionEnd = true; @@ -2058,7 +2127,7 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, if (childState == SelectionEnd || childState == SelectionInside) // Fill the gap above the object. result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, - ty + curr->yPos(), rootBlock, blockX, blockY, paintInfo)); + ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past* // our object. We know this if the selection did not end inside our object. @@ -2070,19 +2139,19 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, getHorizontalSelectionGapInfo(childState, leftGap, rightGap); if (leftGap) - result.uniteLeft(fillLeftSelectionGap(this, curr->xPos(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); if (rightGap) - result.uniteRight(fillRightSelectionGap(this, curr->xPos() + curr->width(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as // they can without bumping into floating or positioned objects. Ideally they will go right up // to the border of the root selection block. - lastTop = (ty - blockY) + (curr->yPos() + curr->height()); - lastLeft = leftSelectionOffset(rootBlock, curr->yPos() + curr->height()); - lastRight = rightSelectionOffset(rootBlock, curr->yPos() + curr->height()); + lastTop = (ty - blockY) + (curr->y() + curr->height()); + lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); + lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); } else if (childState != SelectionNone) // We must be a block that has some selected object inside it. Go ahead and recur. - result.unite(static_cast<RenderBlock*>(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->xPos(), ty + curr->yPos(), + result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), lastTop, lastLeft, lastRight, paintInfo)); } return result; @@ -2162,19 +2231,19 @@ void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& left (state == RenderObject::SelectionEnd && !ltr); } -int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) { - int left = leftOffset(y); + int left = leftOffset(yPos, false); if (left == borderLeft() + paddingLeft()) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->leftSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); return left; } else { RenderBlock* cb = this; while (cb != rootBlock) { - left += cb->xPos(); + left += cb->x(); cb = cb->containingBlock(); } } @@ -2182,35 +2251,35 @@ int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) return left; } -int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) { - int right = rightOffset(y); + int right = rightOffset(yPos, false); if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->rightSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); return right; } else { RenderBlock* cb = this; while (cb != rootBlock) { - right += cb->xPos(); + right += cb->x(); cb = cb->containingBlock(); } } return right; } -void RenderBlock::insertPositionedObject(RenderObject *o) +void RenderBlock::insertPositionedObject(RenderBox* o) { // Create the list of special objects if we don't aleady have one if (!m_positionedObjects) - m_positionedObjects = new ListHashSet<RenderObject*>; + m_positionedObjects = new ListHashSet<RenderBox*>; m_positionedObjects->add(o); } -void RenderBlock::removePositionedObject(RenderObject *o) +void RenderBlock::removePositionedObject(RenderBox* o) { if (m_positionedObjects) m_positionedObjects->remove(o); @@ -2221,11 +2290,11 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) if (!m_positionedObjects) return; - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); - Vector<RenderObject*, 16> deadObjects; + Vector<RenderBox*, 16> deadObjects; for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2249,7 +2318,7 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) m_positionedObjects->remove(deadObjects.at(i)); } -void RenderBlock::insertFloatingObject(RenderObject *o) +void RenderBlock::insertFloatingObject(RenderBox* o) { ASSERT(o->isFloating()); @@ -2276,14 +2345,14 @@ void RenderBlock::insertFloatingObject(RenderObject *o) newObj->m_top = -1; newObj->m_bottom = -1; newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); - newObj->m_shouldPaint = !o->hasLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. + newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. newObj->m_isDescendant = true; newObj->m_renderer = o; m_floatingObjects->append(newObj); } -void RenderBlock::removeFloatingObject(RenderObject *o) +void RenderBlock::removeFloatingObject(RenderBox* o) { if (m_floatingObjects) { DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); @@ -2318,7 +2387,7 @@ bool RenderBlock::positionNewFloats() lastFloat = m_floatingObjects->getPrev(); } - int y = m_height; + int y = height(); // The float cannot start above the y position of the last positioned float. if (lastFloat) @@ -2333,7 +2402,7 @@ bool RenderBlock::positionNewFloats() continue; } - RenderObject* o = f->m_renderer; + RenderBox* o = f->m_renderer; int _height = o->height() + o->marginTop() + o->marginBottom(); int ro = rightOffset(); // Constant part of right offset. @@ -2342,7 +2411,7 @@ bool RenderBlock::positionNewFloats() if (ro - lo < fwidth) fwidth = ro - lo; // Never look for more than what will be available. - IntRect oldRect(o->xPos(), o->yPos() , o->width(), o->height()); + IntRect oldRect(o->x(), o->y() , o->width(), o->height()); if (o->style()->clear() & CLEFT) y = max(leftBottom(), y); @@ -2359,7 +2428,7 @@ bool RenderBlock::positionNewFloats() } fx = max(0, fx); f->m_left = fx; - o->setPos(fx + o->marginLeft(), y + o->marginTop()); + o->setLocation(fx + o->marginLeft(), y + o->marginTop()); } else { int heightRemainingLeft = 1; int heightRemainingRight = 1; @@ -2369,7 +2438,7 @@ bool RenderBlock::positionNewFloats() fx = rightRelOffset(y, ro, false, &heightRemainingRight); } f->m_left = fx - f->m_width; - o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop()); + o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); } f->m_top = y; @@ -2402,8 +2471,8 @@ void RenderBlock::newLine(EClear clear) default: break; } - if (m_height < newY) - m_height = newY; + if (height() < newY) + setHeight(newY); } void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) @@ -2461,15 +2530,17 @@ void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) delete containerSet; } -int -RenderBlock::leftOffset() const +HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const { - return borderLeft()+paddingLeft(); + return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; } -int -RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, - int *heightRemaining ) const +int RenderBlock::leftOffset() const +{ + return borderLeft() + paddingLeft(); +} + +int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int left = fixedOffset; if (m_floatingObjects) { @@ -2487,7 +2558,7 @@ RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, } } - if (applyTextIndent && m_firstLine && style()->direction() == LTR) { + if (applyTextIndent && style()->direction() == LTR) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); @@ -2497,15 +2568,12 @@ RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, return left; } -int -RenderBlock::rightOffset() const +int RenderBlock::rightOffset() const { return borderLeft() + paddingLeft() + availableWidth(); } -int -RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, - int *heightRemaining ) const +int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int right = fixedOffset; @@ -2524,7 +2592,7 @@ RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, } } - if (applyTextIndent && m_firstLine && style()->direction() == RTL) { + if (applyTextIndent && style()->direction() == RTL) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); @@ -2535,9 +2603,9 @@ RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, } int -RenderBlock::lineWidth(int y) const +RenderBlock::lineWidth(int y, bool firstLine) const { - int result = rightOffset(y) - leftOffset(y); + int result = rightOffset(y, firstLine) - leftOffset(y, firstLine); return (result < 0) ? 0 : result; } @@ -2578,7 +2646,7 @@ IntRect RenderBlock::floatRect() const FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { IntRect childRect = r->m_renderer->overflowRect(false); childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); result.unite(childRect); @@ -2590,7 +2658,27 @@ IntRect RenderBlock::floatRect() const int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { - int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && width() > 0 ? overflowHeight(false) : 0; + + int bottom = includeSelf && width() > 0 ? height() : 0; + 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 + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem. + // For inline children, we miss relative positioned boxes that might be buried inside <span>s. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + bottom += relativePositionOffsetY(); if (!includeOverflowInterior && hasOverflowClip()) return bottom; @@ -2600,7 +2688,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) bottom = max(bottom, m_overflowHeight + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2610,15 +2698,15 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) // FIXME: Should work for overflow sections too. // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the lowest position. - if (!isRenderView() || r->xPos() + r->width() > 0 || r->xPos() + r->rightmostPosition(false) > 0) { - int lp = r->yPos() + r->lowestPosition(false); + if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { + int lp = r->y() + r->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { Vector<IntRect>* colRects = columnRects(); for (unsigned i = 0; i < colRects->size(); i++) bottom = max(bottom, colRects->at(i).bottom() + relativeOffset); @@ -2629,17 +2717,30 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } } - - if (!includeSelf && lastLineBox()) { - int lp = lastLineBox()->yPos() + lastLineBox()->height(); - bottom = max(bottom, lp); + if (!includeSelf) { + bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset); + if (childrenInline()) { + if (lastLineBox()) { + int childBottomEdge = lastLineBox()->y() + lastLineBox()->height(); + bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); + } + } else { + // Find the last normal flow child. + RenderBox* currBox = lastChildBox(); + while (currBox && currBox->isFloatingOrPositioned()) + currBox = currBox->previousSiblingBox(); + if (currBox) { + int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom(); + bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); + } + } } return bottom; @@ -2647,7 +2748,27 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowWidth(false) : 0; + + int right = includeSelf && height() > 0 ? width() : 0; + + 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 + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + right = max(right, childBox->x() + childBox->rightmostPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + right += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return right; @@ -2657,7 +2778,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel right = max(right, m_overflowWidth + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) { r = *it; @@ -2667,15 +2788,15 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the rightmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int rp = r->xPos() + r->rightmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int rp = r->x() + r->rightmostPosition(false); right = max(right, rp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { // This only matters for LTR if (style()->direction() == LTR) right = max(columnRects()->last().right() + relativeOffset, right); @@ -2686,21 +2807,33 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); right = max(right, rp + relativeOffset); } } } - if (!includeSelf && firstLineBox()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { - int rp = currBox->xPos() + currBox->width(); - // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. - // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. - if (node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR) - rp += 1; - right = max(right, rp); + if (!includeSelf) { + right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset); + if (childrenInline()) { + for (InlineRunBox* 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. + // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. + if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight()) + childRightEdge += 1; + right = max(right, childRightEdge + paddingRight() + relativeOffset); + } + } else { + // Walk all normal flow children. + for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) { + if (currBox->isFloatingOrPositioned()) + continue; + int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight(); + right = max(right, childRightEdge + paddingRight() + relativeOffset); + } } } @@ -2709,7 +2842,26 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowLeft(false) : width(); + + int left = includeSelf && height() > 0 ? 0 : width(); + 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 + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + left = min(left, childBox->x() + childBox->leftmostPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + left += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return left; @@ -2719,7 +2871,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf left = min(left, m_overflowLeft + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2729,15 +2881,15 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the leftmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int lp = r->xPos() + r->leftmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int lp = r->x() + r->leftmostPosition(false); left = min(left, lp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { // This only matters for RTL if (style()->direction() == RTL) left = min(columnRects()->last().x() + relativeOffset, left); @@ -2748,7 +2900,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); left = min(left, lp + relativeOffset); } @@ -2757,7 +2909,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (!includeSelf && firstLineBox()) { for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) - left = min(left, (int)currBox->xPos()); + left = min(left, (int)currBox->x() + relativeOffset); } return left; @@ -2834,31 +2986,33 @@ void RenderBlock::clearFloats() // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted // to avoid floats. bool parentHasFloats = false; - RenderObject *prev = previousSibling(); - while (prev && (!prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) { + RenderObject* prev = previousSibling(); + while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { if (prev->isFloating()) parentHasFloats = true; prev = prev->previousSibling(); } // First add in floats from the parent. - int offset = m_y; - if (parentHasFloats) - addIntrudingFloats(static_cast<RenderBlock *>(parent()), - parent()->borderLeft() + parent()->paddingLeft(), offset); - + int offset = y(); + if (parentHasFloats) { + RenderBlock* parentBlock = toRenderBlock(parent()); + addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset); + } + int xoffset = 0; if (prev) - offset -= prev->yPos(); - else { + offset -= toRenderBox(prev)->y(); + else if (parent()->isBox()) { prev = parent(); - xoffset += prev->borderLeft() + prev->paddingLeft(); + xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft(); } // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. - if (!prev->isRenderBlock()) return; - RenderBlock* block = static_cast<RenderBlock *>(prev); - + if (!prev || !prev->isRenderBlock()) + return; + + RenderBlock* block = toRenderBlock(prev); if (block->m_floatingObjects && block->floatBottom() > offset) addIntrudingFloats(block, xoffset, offset); @@ -2913,7 +3067,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo IntRect floatsOverflowRect; DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); for (FloatingObject* r; (r = it.current()); ++it) { - int bottom = child->yPos() + r->m_bottom; + int bottom = child->y() + r->m_bottom; lowestFloatBottom = max(lowestFloatBottom, bottom); if (bottom > height()) { @@ -2929,8 +3083,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo // The nearest enclosing layer always paints the float (so that zindex and stacking // behaves properly). We always want to propagate the desire to paint the float as // far out as we can, to the outermost block that overlaps the float, stopping only - // if we hit a layer boundary. - if (r->m_renderer->enclosingLayer() == enclosingLayer()) + // if we hit a self-painting layer boundary. + if (r->m_renderer->enclosingSelfPaintingLayer() == enclosingSelfPaintingLayer()) r->m_shouldPaint = false; else floatingObj->m_shouldPaint = false; @@ -2942,7 +3096,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo } m_floatingObjects->append(floatingObj); } - } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasLayer() && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer()) + } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && + r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer()) // The float is not overhanging from this block, so if it is a descendant of the child, the child should // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing // layer. @@ -2950,7 +3105,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo // it should paint. r->m_shouldPaint = true; - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { IntRect floatOverflowRect = r->m_renderer->overflowRect(false); floatOverflowRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); floatsOverflowRect.unite(floatOverflowRect); @@ -3010,7 +3165,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff) bool RenderBlock::avoidsFloats() const { // Floats can't intrude into our box if we have a non-auto column count or width. - return RenderFlow::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); + return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); } bool RenderBlock::containsFloat(RenderObject* o) @@ -3026,9 +3181,9 @@ bool RenderBlock::containsFloat(RenderObject* o) return false; } -void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove) +void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) { - setChildNeedsLayout(true); + setChildNeedsLayout(true, !inLayout); if (floatToRemove) removeFloatingObject(floatToRemove); @@ -3036,14 +3191,16 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRem // Iterate over our children and mark them as needed. if (!childrenInline()) { for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (isBlockFlow() && !child->isFloatingOrPositioned() && - ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats())) - child->markAllDescendantsWithFloatsForLayout(floatToRemove); + if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock()) + continue; + RenderBlock* childBlock = toRenderBlock(child); + if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats()) + childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); } } } -int RenderBlock::getClearDelta(RenderObject *child) +int RenderBlock::getClearDelta(RenderBox* child, int yPos) { // There is no need to compute clearance if we have no floats. if (!containsFloats()) @@ -3071,11 +3228,11 @@ int RenderBlock::getClearDelta(RenderObject *child) // to fit) and not all (we should be using nextFloatBottomBelow and looping). // Do not allow tables to wrap in quirks or even in almost strict mode // (ebay on the PLT, finance.yahoo.com in the real world, versiontracker.com forces even almost strict mode not to work) - int result = clearSet ? max(0, bottom - child->yPos()) : 0; + int result = clearSet ? max(0, bottom - yPos) : 0; if (!result && child->avoidsFloats() && child->style()->width().isFixed() && - child->minPrefWidth() > lineWidth(child->yPos()) && child->minPrefWidth() <= availableWidth() && + child->minPrefWidth() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth() && document()->inStrictMode()) - result = max(0, floatBottom() - child->yPos()); + result = max(0, floatBottom() - yPos); return result; } @@ -3099,12 +3256,10 @@ bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int, int, int, bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - bool inlineFlow = isInlineFlow(); - - int tx = _tx + m_x; - int ty = _ty + m_y + borderTopExtra(); + int tx = _tx + x(); + int ty = _ty + y(); - if (!inlineFlow && !isRenderView()) { + if (!isRenderView()) { // Check if we need to do anything at all. IntRect overflowBox = overflowRect(false); overflowBox.move(tx, ty); @@ -3112,43 +3267,43 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu return false; } - if (isPointInOverflowControl(result, _x, _y, tx, ty)) { - if (hitTestAction == HitTestBlockBackground) { - updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); - return true; - } - return false; + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) { + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); + return true; } - // If we have lightweight control clipping, then we can't have any spillout. - if (!hasControlClip() || controlClipRect(tx, ty).contains(_x, _y)) { + // If we have clipping, then we can't have any spillout. + bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); + bool useClip = (hasControlClip() || useOverflowClip); + bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).contains(_x, _y) : overflowClipRect(tx, ty).contains(_x, _y)); + if (checkChildren) { // Hit test descendants first. int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); + layer()->subtractScrolledContentOffset(scrolledX, scrolledY); // Hit test contents if we don't have columns. - if (!m_hasColumns && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) return true; // Hit test our columns if we do have them. - if (m_hasColumns && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) return true; // Hit test floats. if (hitTestAction == HitTestFloat && m_floatingObjects) { if (isRenderView()) { - scrolledX += static_cast<RenderView*>(this)->frameView()->scrollX(); - scrolledY += static_cast<RenderView*>(this)->frameView()->scrollY(); + scrolledX += toRenderView(this)->frameView()->scrollX(); + scrolledY += toRenderView(this)->frameView()->scrollY(); } FloatingObject* o; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (it.toLast(); (o = it.current()); --it) { - if (o->m_shouldPaint && !o->m_renderer->hasLayer()) { - int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->xPos(); - int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->yPos(); + if (o->m_shouldPaint && !o->m_renderer->hasSelfPaintingLayer()) { + int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->x(); + int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->y(); if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) { updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset)); return true; @@ -3159,11 +3314,10 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } // Now hit test our background - if (!inlineFlow && (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)) { - int topExtra = borderTopExtra(); - IntRect boundsRect(tx, ty - topExtra, m_width, m_height + topExtra + borderBottomExtra()); + if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { + IntRect boundsRect(tx, ty, width(), height()); if (visibleToHitTesting() && boundsRect.contains(_x, _y)) { - updateHitTestResult(result, IntPoint(_x - tx, _y - ty + topExtra)); + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); return true; } } @@ -3209,7 +3363,7 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& { if (childrenInline() && !isTable()) { // We have to hit-test our line boxes. - if (hitTestLines(request, result, x, y, tx, ty, hitTestAction)) { + if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -3218,10 +3372,8 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& HitTestAction childHitTest = hitTestAction; if (hitTestAction == HitTestChildBlockBackgrounds) childHitTest = HitTestChildBlockBackground; - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - // FIXME: We have to skip over inline flows, since they can show up inside RenderTables at the moment (a demoted inline <form> for example). If we ever implement a - // table-specific hit-test method (which we should do for performance reasons anyway), then we can remove this check. - if (!child->hasLayer() && !child->isFloating() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { + for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { + if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -3236,158 +3388,178 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const if (!box) return Position(); - if (!box->object()->element()) - return Position(element(), start ? caretMinOffset() : caretMaxOffset()); + if (!box->renderer()->node()) + return Position(node(), start ? caretMinOffset() : caretMaxOffset()); if (!box->isInlineTextBox()) - return Position(box->object()->element(), start ? box->object()->caretMinOffset() : box->object()->caretMaxOffset()); + return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); InlineTextBox *textBox = static_cast<InlineTextBox *>(box); - return Position(box->object()->element(), start ? textBox->start() : textBox->start() + textBox->len()); + return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len()); } Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const { if (!renderer) - return Position(element(), 0); + return Position(node(), 0); - Node* node = renderer->element() ? renderer->element() : element(); - if (!node) + Node* n = renderer->node() ? renderer->node() : node(); + if (!n) return Position(); - ASSERT(renderer == node->renderer()); + ASSERT(renderer == n->renderer()); int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset(); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now. - ASSERT(!node->isCharacterDataNode() || renderer->isText()); + ASSERT(!n->isCharacterDataNode() || renderer->isText()); - return Position(node, offset); + return Position(n, offset); } -VisiblePosition RenderBlock::positionForCoordinates(int x, int y) +// FIXME: This function should go on RenderObject as an instance method. Then +// all cases in which positionForPoint recurs could call this instead to +// prevent crossing editable boundaries. This would require many tests. +static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& pointInParentCoordinates) { - if (isTable()) - return RenderFlow::positionForCoordinates(x, y); + IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location()); - int top = borderTop(); - int bottom = top + borderTopExtra() + paddingTop() + contentHeight() + paddingBottom() + borderBottomExtra(); + // If this is an anonymous renderer, we just recur normally + Node* childNode = child->node(); + if (!childNode) + return child->positionForPoint(pointInChildCoordinates); - int left = borderLeft(); - int right = left + paddingLeft() + contentWidth() + paddingRight(); + // Otherwise, first make sure that the editability of the parent and child agree. + // If they don't agree, then we return a visible position just before or after the child + RenderObject* ancestor = parent; + while (ancestor && !ancestor->node()) + ancestor = ancestor->parent(); - Node* n = element(); - - int contentsX = x; - int contentsY = y; - offsetForContents(contentsX, contentsY); + // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal + if (!ancestor || ancestor->node()->isContentEditable() == childNode->isContentEditable()) + return child->positionForPoint(pointInChildCoordinates); - if (isReplaced()) { - if (y < 0 || y < height() && x < 0) - return VisiblePosition(n, caretMinOffset(), DOWNSTREAM); - if (y >= height() || y >= 0 && x >= width()) - return VisiblePosition(n, caretMaxOffset(), DOWNSTREAM); - } + // Otherwise return before or after the child, depending on if the click was left or right of the child + int childMidX = child->width() / 2; + if (pointInChildCoordinates.x() < childMidX) + return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM); + return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM); +} - // If we start inside the shadow tree, we will stay inside (even if the point is above or below). - if (!(n && n->isShadowNode()) && !childrenInline()) { - // Don't return positions inside editable roots for coordinates outside those roots, except for coordinates outside - // a document that is entirely editable. - bool isEditableRoot = n && n->rootEditableElement() == n && !n->hasTagName(bodyTag) && !n->hasTagName(htmlTag); - - if (y < top || (isEditableRoot && (y < bottom && x < left))) { - if (!isEditableRoot) - if (RenderObject* c = firstChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, etc. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); - if (p.isNotNull()) - return p; - } - if (n) { - if (Node* sp = n->shadowParentNode()) - n = sp; - if (Node* p = n->parent()) - return VisiblePosition(p, n->nodeIndex(), DOWNSTREAM); - } - return VisiblePosition(n, 0, DOWNSTREAM); - } +VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInContents) +{ + ASSERT(childrenInline()); - if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) { - if (!isEditableRoot) - if (RenderObject* c = lastChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, ect. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); - if (p.isNotNull()) - return p; - } - if (n) { - if (Node* sp = n->shadowParentNode()) - n = sp; - if (Node* p = n->parent()) - return VisiblePosition(p, n->nodeIndex() + 1, DOWNSTREAM); - } - return VisiblePosition(n, 0, DOWNSTREAM); + if (!firstRootBox()) + return createVisiblePosition(0, DOWNSTREAM); + + // look for the closest line box in the root box which is at the passed-in y coordinate + InlineBox* closestBox = 0; + RootInlineBox* firstRootBoxWithChildren = 0; + RootInlineBox* lastRootBoxWithChildren = 0; + for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { + if (!root->firstChild()) + continue; + if (!firstRootBoxWithChildren) + firstRootBoxWithChildren = root; + lastRootBoxWithChildren = root; + + // set the bottom based on whether there is a next root box + // FIXME: This will consider nextRootBox even if it has no children, and maybe it shouldn't. + int bottom; + if (root->nextRootBox()) { + // FIXME: We would prefer to make the break point halfway between the bottom + // of the previous root box and the top of the next root box. + bottom = root->nextRootBox()->topOverflow(); + } else + bottom = root->bottomOverflow() + verticalLineClickFudgeFactor; + + // check if this root line box is located at this y coordinate + if (pointInContents.y() < bottom) { + closestBox = root->closestLeafChildForXPos(pointInContents.x()); + if (closestBox) + break; } } - if (childrenInline()) { - if (!firstRootBox()) - return VisiblePosition(n, 0, DOWNSTREAM); + Settings* settings = document()->settings(); + bool useWindowsBehavior = settings && settings->editingBehavior() == EditingWindowsBehavior; - if (contentsY < firstRootBox()->topOverflow() - verticalLineClickFudgeFactor) - // y coordinate is above first root line box - return VisiblePosition(positionForBox(firstRootBox()->firstLeafChild(), true), DOWNSTREAM); - - // look for the closest line box in the root box which is at the passed-in y coordinate - for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { - // set the bottom based on whether there is a next root box - if (root->nextRootBox()) - // FIXME: make the break point halfway between the bottom of the previous root box and the top of the next root box - bottom = root->nextRootBox()->topOverflow(); - else - bottom = root->bottomOverflow() + verticalLineClickFudgeFactor; - // check if this root line box is located at this y coordinate - if (contentsY < bottom && root->firstChild()) { - InlineBox* closestBox = root->closestLeafChildForXPos(x); - if (closestBox) - // pass the box a y position that is inside it - return closestBox->object()->positionForCoordinates(contentsX, closestBox->m_y); - } + if (useWindowsBehavior && !closestBox && lastRootBoxWithChildren) { + // y coordinate is below last root line box, pretend we hit it + closestBox = lastRootBoxWithChildren->closestLeafChildForXPos(pointInContents.x()); + } + + if (closestBox) { + if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->topOverflow() - verticalLineClickFudgeFactor) { + // y coordinate is above first root line box, so return the start of the first + return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM); } - if (lastRootBox()) - // y coordinate is below last root line box - return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM); + // pass the box a y position that is inside it + return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y)); + } - return VisiblePosition(n, 0, DOWNSTREAM); + if (lastRootBoxWithChildren) { + // We hit this case for Mac behavior when the Y coordinate is below the last box. + ASSERT(!useWindowsBehavior); + return VisiblePosition(positionForBox(lastRootBoxWithChildren->lastLeafChild(), false), DOWNSTREAM); } - - // See if any child blocks exist at this y coordinate. - if (firstChild() && contentsY < firstChild()->yPos()) - return VisiblePosition(n, 0, DOWNSTREAM); - for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { - if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned()) - continue; - RenderObject* next = renderer->nextSibling(); - while (next && next->isFloatingOrPositioned()) - next = next->nextSibling(); - if (next) - bottom = next->yPos(); - else - bottom = top + scrollHeight(); - if (contentsY >= renderer->yPos() && contentsY < bottom) - return renderer->positionForCoordinates(contentsX - renderer->xPos(), contentsY - renderer->yPos()); + + // Can't reach this. We have a root line box, but it has no kids. + // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text + // seems to hit this code path. + return createVisiblePosition(0, DOWNSTREAM); +} + +static inline bool isChildHitTestCandidate(RenderBox* box) +{ + return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned(); +} + +VisiblePosition RenderBlock::positionForPoint(const IntPoint& point) +{ + if (isTable()) + return RenderBox::positionForPoint(point); + + if (isReplaced()) { + if (point.y() < 0 || (point.y() < height() && point.x() < 0)) + return createVisiblePosition(caretMinOffset(), DOWNSTREAM); + if (point.y() >= height() || (point.y() >= 0 && point.x() >= width())) + return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); + } + + int contentsX = point.x(); + int contentsY = point.y(); + offsetForContents(contentsX, contentsY); + IntPoint pointInContents(contentsX, contentsY); + + if (childrenInline()) + return positionForPointWithInlineChildren(pointInContents); + + if (lastChildBox() && contentsY > lastChildBox()->y()) { + for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) { + if (isChildHitTestCandidate(childBox)) + return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); + } + } else { + for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { + // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3). + if (isChildHitTestCandidate(childBox) && contentsY < childBox->frameRect().bottom()) + return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); + } } - - return RenderFlow::positionForCoordinates(x, y); + + // We only get here if there are no hit test candidate children below the click. + return RenderBox::positionForPoint(point); } void RenderBlock::offsetForContents(int& tx, int& ty) const { - ty -= borderTopExtra(); - if (hasOverflowClip()) - m_layer->addScrolledContentOffset(tx, ty); + layer()->addScrolledContentOffset(tx, ty); - if (m_hasColumns) { + if (hasColumns()) { IntPoint contentsPoint(tx, ty); adjustPointToColumnContents(contentsPoint); tx = contentsPoint.x(); @@ -3398,7 +3570,7 @@ void RenderBlock::offsetForContents(int& tx, int& ty) const int RenderBlock::availableWidth() const { // If we have multiple columns, then the available width is reduced to our column width. - if (m_hasColumns) + if (hasColumns()) return desiredColumnWidth(); return contentWidth(); } @@ -3456,20 +3628,20 @@ void RenderBlock::calcColumnWidth() void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) { if (count == 1) { - if (m_hasColumns) { + if (hasColumns()) { delete gColumnInfoMap->take(this); - m_hasColumns = false; + setHasColumns(false); } } else { ColumnInfo* info; - if (m_hasColumns) + if (hasColumns()) info = gColumnInfoMap->get(this); else { if (!gColumnInfoMap) gColumnInfoMap = new ColumnInfoMap; info = new ColumnInfo; gColumnInfoMap->add(this, info); - m_hasColumns = true; + setHasColumns(true); } info->m_desiredColumnCount = count; info->m_desiredColumnWidth = width; @@ -3478,21 +3650,21 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) int RenderBlock::desiredColumnWidth() const { - if (!m_hasColumns) + if (!hasColumns()) return contentWidth(); return gColumnInfoMap->get(this)->m_desiredColumnWidth; } unsigned RenderBlock::desiredColumnCount() const { - if (!m_hasColumns) + if (!hasColumns()) return 1; return gColumnInfoMap->get(this)->m_desiredColumnCount; } Vector<IntRect>* RenderBlock::columnRects() const { - if (!m_hasColumns) + if (!hasColumns()) return 0; return &gColumnInfoMap->get(this)->m_columnRects; } @@ -3500,7 +3672,7 @@ Vector<IntRect>* RenderBlock::columnRects() const int RenderBlock::layoutColumns(int endOfContent) { // Don't do anything if we have no columns - if (!m_hasColumns) + if (!hasColumns()) return -1; ColumnInfo* info = gColumnInfoMap->get(this); @@ -3552,9 +3724,9 @@ int RenderBlock::layoutColumns(int endOfContent) GraphicsContext context((PlatformGraphicsContext*)0); RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0); - m_hasColumns = false; + setHasColumns(false); paintObject(paintInfo, 0, 0); - m_hasColumns = true; + setHasColumns(true); int adjustedBottom = v->bestTruncatedAt(); if (adjustedBottom <= currY) @@ -3592,14 +3764,14 @@ int RenderBlock::layoutColumns(int endOfContent) colCount++; } - m_overflowWidth = max(m_width, currX - colGap); + m_overflowWidth = max(width(), currX - colGap); m_overflowLeft = min(0, currX + desiredColumnWidth + colGap); m_overflowHeight = maxColBottom; int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); if (computeIntrinsicHeight) - m_height = m_overflowHeight + toAdd; + setHeight(m_overflowHeight + toAdd); v->setPrintRect(IntRect()); v->setTruncatedAt(0); @@ -3612,7 +3784,7 @@ int RenderBlock::layoutColumns(int endOfContent) void RenderBlock::adjustPointToColumnContents(IntPoint& point) const { // Just bail if we have no columns. - if (!m_hasColumns) + if (!hasColumns()) return; Vector<IntRect>* colRects = columnRects(); @@ -3641,7 +3813,7 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const void RenderBlock::adjustRectForColumns(IntRect& r) const { // Just bail if we have no columns. - if (!m_hasColumns) + if (!hasColumns()) return; Vector<IntRect>* colRects = columnRects(); @@ -3698,7 +3870,7 @@ void RenderBlock::calcPrefWidths() m_minPrefWidth = m_maxPrefWidth; // A horizontal marquee with inline children has no minimum width. - if (m_layer && m_layer->marquee() && m_layer->marquee()->isHorizontal()) + if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal()) m_minPrefWidth = 0; } @@ -3760,7 +3932,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->firstChild(); if (!result) { // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isInlineFlow()) { + if (!oldEndOfInline && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3770,7 +3942,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->nextSibling(); if (result) break; current = current->parent(); - if (current && current != parent && current->isInlineFlow()) { + if (current && current != parent && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3781,7 +3953,7 @@ RenderObject* InlineMinMaxIterator::next() if (!result) break; - if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isInlineFlow())) + if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) break; current = result; @@ -3800,7 +3972,7 @@ static int getBPMWidth(int childValue, Length cssUnit) return 0; } -static int getBorderPaddingMargin(const RenderObject* child, bool endOfInline) +static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) { RenderStyle* cstyle = child->style(); int result = 0; @@ -3820,7 +3992,7 @@ static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, { if (trailingSpaceChild && trailingSpaceChild->isText()) { // Collapse away the trailing space at the end of a block. - RenderText* t = static_cast<RenderText*>(trailingSpaceChild); + RenderText* t = toRenderText(trailingSpaceChild); const UChar space = ' '; const Font& font = t->style()->font(); // FIXME: This ignores first-line. int spaceWidth = font.width(TextRun(&space, 1)); @@ -3900,10 +4072,10 @@ void RenderBlock::calcInlinePrefWidths() if (!child->isText()) { // Case (1) and (2). Inline replaced and inline flow elements. - if (child->isInlineFlow()) { + if (child->isRenderInline()) { // Add in padding/border/margin from the appropriate side of // the element. - int bpm = getBorderPaddingMargin(child, childIterator.endOfInline); + int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); childMin += bpm; childMax += bpm; @@ -3935,14 +4107,14 @@ void RenderBlock::calcInlinePrefWidths() bool clearPreviousFloat; if (child->isFloating()) { clearPreviousFloat = (prevFloat - && (prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT) - || prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT))); + && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT)) + || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT)))); prevFloat = child; } else clearPreviousFloat = false; bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; - if (canBreakReplacedElement && (autoWrap || oldAutoWrap) || clearPreviousFloat) { + if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) { m_minPrefWidth = max(inlineMin, m_minPrefWidth); inlineMin = 0; } @@ -3986,7 +4158,7 @@ void RenderBlock::calcInlinePrefWidths() } } else if (child->isText()) { // Case (3). Text. - RenderText* t = static_cast<RenderText *>(child); + RenderText* t = toRenderText(child); if (t->isWordBreak()) { m_minPrefWidth = max(inlineMin, m_minPrefWidth); @@ -4077,7 +4249,7 @@ void RenderBlock::calcInlinePrefWidths() } oldAutoWrap = autoWrap; - if (!child->isInlineFlow()) + if (!child->isRenderInline()) previousLeaf = child; } @@ -4104,7 +4276,7 @@ void RenderBlock::calcBlockPrefWidths() continue; } - if (child->isFloating() || child->avoidsFloats()) { + if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) { int floatTotalWidth = floatLeftWidth + floatRightWidth; if (child->style()->clear() & CLEFT) { m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth); @@ -4138,7 +4310,7 @@ void RenderBlock::calcBlockPrefWidths() w = child->maxPrefWidth() + margin; if (!child->isFloating()) { - if (child->avoidsFloats()) { + if (child->isBox() && toRenderBox(child)->avoidsFloats()) { // Determine a left and right max value based off whether or not the floats can fit in the // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin // is smaller than the float width. @@ -4194,11 +4366,19 @@ void RenderBlock::calcBlockPrefWidths() bool RenderBlock::hasLineIfEmpty() const { - return element() && (element()->isContentEditable() && element()->rootEditableElement() == element() || - element()->isShadowNode() && element()->shadowParentNode()->hasTagName(inputTag)); + if (!node()) + return false; + + if (node()->isContentEditable() && node()->rootEditableElement() == node()) + return true; + + if (node()->isShadowNode() && (node()->shadowParentNode()->hasTagName(inputTag) || node()->shadowParentNode()->hasTagName(textareaTag))) + return true; + + return false; } -int RenderBlock::lineHeight(bool b, bool isRootLineBox) const +int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const { // Inline blocks are replaced elements. Otherwise, just pass off to // the base class. If we're being queried as though we're the root line @@ -4206,7 +4386,17 @@ int RenderBlock::lineHeight(bool b, bool isRootLineBox) const // just like a block. if (isReplaced() && !isRootLineBox) return height() + marginTop() + marginBottom(); - return RenderFlow::lineHeight(b, isRootLineBox); + + if (firstLine && document()->usesFirstLineRules()) { + RenderStyle* s = style(firstLine); + if (s != style()) + return s->computedLineHeight(); + } + + if (m_lineHeight == -1) + m_lineHeight = style()->computedLineHeight(); + + return m_lineHeight; } int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const @@ -4228,31 +4418,31 @@ int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside // of our content box. - int baselinePos = (m_layer && (m_layer->marquee() || m_layer->verticalScrollbar() || m_layer->scrollYOffset() != 0)) ? -1 : getBaselineOfLastLineBox(); + int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline(); if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight()) return marginTop() + baselinePos; return height() + marginTop() + marginBottom(); } - return RenderFlow::baselinePosition(b, isRootLineBox); + return RenderBox::baselinePosition(b, isRootLineBox); } -int RenderBlock::getBaselineOfFirstLineBox() const +int RenderBlock::firstLineBoxBaseline() const { if (!isBlockFlow()) - return RenderFlow::getBaselineOfFirstLineBox(); + return -1; if (childrenInline()) { if (firstLineBox()) - return firstLineBox()->yPos() + firstLineBox()->baseline(); + return firstLineBox()->y() + style(true)->font().ascent(); else return -1; } else { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { if (!curr->isFloatingOrPositioned()) { - int result = curr->getBaselineOfFirstLineBox(); + int result = curr->firstLineBoxBaseline(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } } @@ -4260,30 +4450,30 @@ int RenderBlock::getBaselineOfFirstLineBox() const return -1; } -int RenderBlock::getBaselineOfLastLineBox() const +int RenderBlock::lastLineBoxBaseline() const { if (!isBlockFlow()) - return RenderFlow::getBaselineOfLastLineBox(); + return -1; if (childrenInline()) { if (!firstLineBox() && hasLineIfEmpty()) - return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop(); + return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); if (lastLineBox()) - return lastLineBox()->yPos() + lastLineBox()->baseline(); + return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent(); return -1; } else { bool haveNormalFlowChild = false; - for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) { + for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { if (!curr->isFloatingOrPositioned()) { haveNormalFlowChild = true; - int result = curr->getBaselineOfLastLineBox(); + int result = curr->lastLineBoxBaseline(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } if (!haveNormalFlowChild && hasLineIfEmpty()) - return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop(); + return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); } return -1; @@ -4302,31 +4492,32 @@ bool RenderBlock::containsNonZeroBidiLevel() const RenderBlock* RenderBlock::firstLineBlock() const { - const RenderObject* firstLineBlock = this; + RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); bool hasPseudo = false; while (true) { - hasPseudo = firstLineBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LINE); + hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE); if (hasPseudo) break; RenderObject* parentBlock = firstLineBlock->parent(); if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()) break; - firstLineBlock = parentBlock; + ASSERT(parentBlock->isRenderBlock()); + firstLineBlock = toRenderBlock(parentBlock); } if (!hasPseudo) return 0; - return (RenderBlock*)(firstLineBlock); + return firstLineBlock; } void RenderBlock::updateFirstLetter() { if (!document()->usesFirstLetterRules()) return; - // Don't recurse - if (style()->styleType() == RenderStyle::FIRST_LETTER) + // Don't recur + if (style()->styleType() == FIRST_LETTER) return; // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find @@ -4336,7 +4527,7 @@ void RenderBlock::updateFirstLetter() while (true) { // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly // prevents form controls from honoring first-letter. - hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LETTER) + hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER) && firstLetterBlock->canHaveChildren(); if (hasPseudoStyle) break; @@ -4354,7 +4545,7 @@ void RenderBlock::updateFirstLetter() RenderObject* currChild = firstLetterBlock->firstChild(); while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) { if (currChild->isFloatingOrPositioned()) { - if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) + if (currChild->style()->styleType() == FIRST_LETTER) break; currChild = currChild->nextSibling(); } else @@ -4372,8 +4563,8 @@ void RenderBlock::updateFirstLetter() // If the child already has style, then it has already been created, so we just want // to update it. - if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) { - RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER, + if (currChild->style()->styleType() == FIRST_LETTER) { + RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); currChild->setStyle(pseudo); for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) { @@ -4384,22 +4575,27 @@ void RenderBlock::updateFirstLetter() } // If the child does not already have style, we create it here. - if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != RenderStyle::FIRST_LETTER) { + if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) { // Our layout state is not valid for the repaints we are going to trigger by // adding and removing children of firstLetterContainer. view()->disableLayoutState(); - RenderText* textObj = static_cast<RenderText*>(currChild); + RenderText* textObj = toRenderText(currChild); // Create our pseudo style now that we have our firstLetterContainer determined. - RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER, + RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); // Force inline display (except for floating first-letters) - pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE); - pseudoStyle->setPosition( StaticPosition ); // CSS2 says first-letter can't be positioned. + pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); + pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned. - RenderObject* firstLetter = RenderFlow::createAnonymousFlow(document(), pseudoStyle); // anonymous box + RenderObject* firstLetter = 0; + if (pseudoStyle->display() == INLINE) + firstLetter = new (renderArena()) RenderInline(document()); + else + firstLetter = new (renderArena()) RenderBlock(document()); + firstLetter->setStyle(pseudoStyle); firstLetterContainer->addChild(firstLetter, currChild); // The original string is going to be either a generated content string or a DOM node's @@ -4421,10 +4617,10 @@ void RenderBlock::updateFirstLetter() // construct text fragment for the text after the first letter // NOTE: this might empty RenderTextFragment* remainingText = - new (renderArena()) RenderTextFragment(textObj->node(), oldText.get(), length, oldText->length() - length); + new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); remainingText->setStyle(textObj->style()); - if (remainingText->element()) - remainingText->element()->setRenderer(remainingText); + if (remainingText->node()) + remainingText->node()->setRenderer(remainingText); RenderObject* nextObj = textObj->nextSibling(); firstLetterContainer->removeChild(textObj); @@ -4433,7 +4629,7 @@ void RenderBlock::updateFirstLetter() // construct text fragment for the first letter RenderTextFragment* letter = - new (renderArena()) RenderTextFragment(remainingText->node(), oldText.get(), 0, length); + new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(pseudoStyle); letter->setStyle(newStyle.release()); @@ -4460,7 +4656,7 @@ bool RenderBlock::inRootBlockContext() const // (crawling into blocks). static bool shouldCheckLines(RenderObject* obj) { - return !obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn() && + return !obj->isFloatingOrPositioned() && !obj->isRunIn() && obj->isBlockFlow() && obj->style()->height().isAuto() && (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); } @@ -4477,7 +4673,7 @@ static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) else { for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { if (shouldCheckLines(obj)) { - RootInlineBox *box = getLineAtIndex(static_cast<RenderBlock*>(obj), i, count); + RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count); if (box) return box; } @@ -4487,7 +4683,7 @@ static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) return 0; } -int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) +static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) { if (block->style()->visibility() == VISIBLE) { if (block->childrenInline()) { @@ -4497,18 +4693,18 @@ int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& co } } else { - RenderObject* normalFlowChildWithoutLines = 0; - for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { + RenderBox* normalFlowChildWithoutLines = 0; + for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (shouldCheckLines(obj)) { - int result = getHeightForLineCount(static_cast<RenderBlock*>(obj), l, false, count); + int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); if (result != -1) - return result + obj->yPos() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); + return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); } - else if (!obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn()) + else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) normalFlowChildWithoutLines = obj; } if (normalFlowChildWithoutLines && l == 0) - return normalFlowChildWithoutLines->yPos() + normalFlowChildWithoutLines->height(); + return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); } } @@ -4531,7 +4727,7 @@ int RenderBlock::lineCount() else for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) if (shouldCheckLines(obj)) - count += static_cast<RenderBlock*>(obj)->lineCount(); + count += toRenderBlock(obj)->lineCount(); } return count; } @@ -4550,20 +4746,20 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const if (childrenInline()) { for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { if (box->firstChild()) - left = min(left, x + box->firstChild()->xPos()); + left = min(left, x + box->firstChild()->x()); if (box->lastChild()) - right = max(right, x + box->lastChild()->xPos() + box->lastChild()->width()); + right = max(right, x + box->lastChild()->x() + box->lastChild()->width()); } } else { - for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) { + for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (!obj->isFloatingOrPositioned()) { if (obj->isBlockFlow() && !obj->hasOverflowClip()) - static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->xPos(), left, right); + toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right); else if (obj->style()->visibility() == VISIBLE) { // We are a replaced element or some kind of non-block-flow object. - left = min(left, x + obj->xPos()); - right = max(right, x + obj->xPos() + obj->width()); + left = min(left, x + obj->x()); + right = max(right, x + obj->x() + obj->width()); } } } @@ -4575,7 +4771,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const for (; (r = it.current()); ++it) { // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { - int floatLeft = r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); + int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); int floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); right = max(right, floatRight); @@ -4620,7 +4816,7 @@ void RenderBlock::clearTruncation() else for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) if (shouldCheckLines(obj)) - static_cast<RenderBlock*>(obj)->clearTruncation(); + toRenderBlock(obj)->clearTruncation(); } } @@ -4646,6 +4842,218 @@ void RenderBlock::setMaxBottomMargins(int pos, int neg) m_maxMargin->m_bottomNeg = neg; } +void RenderBlock::absoluteRects(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 + // shape). + if (inlineContinuation()) { + rects.append(IntRect(tx, ty - collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom())); + inlineContinuation()->absoluteRects(rects, + tx - x() + inlineContinuation()->containingBlock()->x(), + ty - y() + inlineContinuation()->containingBlock()->y()); + } else + rects.append(IntRect(tx, ty, width(), height())); +} + +void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads) +{ + // 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 + // shape). + if (inlineContinuation()) { + FloatRect localRect(0, -collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom()); + quads.append(localToAbsoluteQuad(localRect)); + inlineContinuation()->absoluteQuads(quads); + } else + quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); +} + +IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) +{ + IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + if (inlineContinuation()) + r.inflateY(collapsedMarginTop()); + return r; +} + +RenderObject* RenderBlock::hoverAncestor() const +{ + return inlineContinuation() ? inlineContinuation() : RenderBox::hoverAncestor(); +} + +void RenderBlock::updateDragState(bool dragOn) +{ + RenderBox::updateDragState(dragOn); + if (inlineContinuation()) + inlineContinuation()->updateDragState(dragOn); +} + +RenderStyle* RenderBlock::outlineStyleForRepaint() const +{ + return inlineContinuation() ? inlineContinuation()->style() : style(); +} + +void RenderBlock::childBecameNonInline(RenderObject*) +{ + makeChildrenNonInline(); + if (isAnonymousBlock() && parent() && parent()->isRenderBlock()) + toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); + // |this| may be dead here +} + +void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point) +{ + if (result.innerNode()) + return; + + Node* n = node(); + if (inlineContinuation()) + // We are in the margins of block elements that are part of a continuation. In + // this case we're actually still inside the enclosing inline element that was + // split. Go ahead and set our inner node accordingly. + n = inlineContinuation()->node(); + + if (n) { + result.setInnerNode(n); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(n); + result.setLocalPoint(point); + } +} + +IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +{ + // Do the normal calculation in most cases. + if (firstChild()) + return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); + + // This is a special case: + // The element is not an inline element, and it's empty. So we have to + // calculate a fake position to indicate where objects are to be inserted. + + // FIXME: This does not take into account either :first-line or :first-letter + // However, as soon as some content is entered, the line boxes will be + // constructed and this kludge is not called any more. So only the caret size + // of an empty :first-line'd block is wrong. I think we can live with that. + RenderStyle* currentStyle = firstLineStyle(); + int height = lineHeight(true); + + enum CaretAlignment { alignLeft, alignRight, alignCenter }; + + CaretAlignment alignment = alignLeft; + + switch (currentStyle->textAlign()) { + case TAAUTO: + case JUSTIFY: + if (currentStyle->direction() == RTL) + alignment = alignRight; + break; + case LEFT: + case WEBKIT_LEFT: + break; + case CENTER: + case WEBKIT_CENTER: + alignment = alignCenter; + break; + case RIGHT: + case WEBKIT_RIGHT: + alignment = alignRight; + break; + } + + int x = borderLeft() + paddingLeft(); + int w = width(); + + switch (alignment) { + case alignLeft: + break; + case alignCenter: + x = (x + w - (borderRight() + paddingRight())) / 2; + break; + case alignRight: + x = w - (borderRight() + paddingRight()) - caretWidth; + break; + } + + if (extraWidthToEndOfLine) { + if (isRenderBlock()) { + *extraWidthToEndOfLine = w - (x + caretWidth); + } else { + // FIXME: This code looks wrong. + // myRight and containerRight are set up, but then clobbered. + // So *extraWidthToEndOfLine will always be 0 here. + + int myRight = x + caretWidth; + // FIXME: why call localToAbsoluteForContent() twice here, too? + FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); + + int containerRight = containingBlock()->x() + containingBlockWidthForContent(); + FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); + + *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); + } + } + + int y = paddingTop() + borderTop(); + + return IntRect(x, y, caretWidth, height); +} + +void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, 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 + // shape). + if (inlineContinuation()) { + // FIXME: This check really isn't accurate. + bool nextInlineHasLineBox = inlineContinuation()->firstLineBox(); + // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block. + 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())); + + if (!hasOverflowClip() && !hasControlClip()) { + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())); + + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { + RenderBox* box = toRenderBox(curr); + FloatPoint pos; + // FIXME: This doesn't work correctly with transforms. + if (box->layer()) + pos = curr->localToAbsolute(); + else + pos = FloatPoint(tx + box->x(), ty + box->y()); + box->addFocusRingRects(graphicsContext, pos.x(), pos.y()); + } + } + } + + if (inlineContinuation()) + inlineContinuation()->addFocusRingRects(graphicsContext, + tx - x() + inlineContinuation()->containingBlock()->x(), + ty - y() + inlineContinuation()->containingBlock()->y()); +} + +RenderBlock* RenderBlock::createAnonymousBlock() const +{ + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(style()); + newStyle->setDisplay(BLOCK); + + RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); + newBox->setStyle(newStyle.release()); + return newBox; +} + const char* RenderBlock::renderName() const { if (isBody()) @@ -4661,8 +5069,6 @@ const char* RenderBlock::renderName() const return "RenderBlock (generated)"; if (isRelPositioned()) return "RenderBlock (relative positioned)"; - if (isCompact()) - return "RenderBlock (compact)"; if (isRunIn()) return "RenderBlock (run-in)"; return "RenderBlock"; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h index 902460d..31eae7c8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h @@ -27,27 +27,39 @@ #include "DeprecatedPtrList.h" #include "GapRects.h" -#include "RenderFlow.h" +#include "RenderBox.h" +#include "RenderLineBoxList.h" #include "RootInlineBox.h" #include <wtf/ListHashSet.h> namespace WebCore { class InlineIterator; -class BidiRun; class Position; +class RenderInline; class RootInlineBox; +struct BidiRun; + template <class Iterator, class Run> class BidiResolver; +template <class Iterator> class MidpointState; typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver; +typedef MidpointState<InlineIterator> LineMidpointState; enum CaretType { CursorCaret, DragCaret }; -class RenderBlock : public RenderFlow { +class RenderBlock : public RenderBox { public: RenderBlock(Node*); virtual ~RenderBlock(); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + + virtual void destroy(); + virtual const char* renderName() const; // These two functions are overridden for inline-block. @@ -56,13 +68,19 @@ public: virtual bool isRenderBlock() const { return true; } virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); } - virtual bool isInlineFlow() const { return isInline() && !isReplaced(); } virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); } - virtual bool childrenInline() const { return m_childrenInline; } - virtual void setChildrenInline(bool b) { m_childrenInline = b; } void makeChildrenNonInline(RenderObject* insertionPoint = 0); + virtual void removeLeftoverAnonymousBlock(RenderBlock* child); + + RenderLineBoxList* lineBoxes() { return &m_lineBoxes; } + const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; } + + InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); } + InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } + void deleteLineBoxTree(); + virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } // The height (and width) of a block when you include overflow spillage out of the bottom // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside @@ -78,8 +96,6 @@ public: void addVisualOverflow(const IntRect&); virtual bool isSelfCollapsingBlock() const; - virtual bool isTopMarginQuirk() const { return m_topMarginQuirk; } - virtual bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; } virtual int maxTopMargin(bool positive) const { return positive ? maxTopPosMargin() : maxTopNegMargin(); } virtual int maxBottomMargin(bool positive) const { return positive ? maxBottomPosMargin() : maxBottomNegMargin(); } @@ -101,7 +117,7 @@ public: } } - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild); + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject*); virtual void repaintOverhangingFloats(bool paintAllDescendants); @@ -112,47 +128,53 @@ public: void layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom); void layoutPositionedObjects(bool relayoutChildren); - void insertPositionedObject(RenderObject*); - void removePositionedObject(RenderObject*); - virtual void removePositionedObjects(RenderBlock*); + void insertPositionedObject(RenderBox*); + void removePositionedObject(RenderBox*); + void removePositionedObjects(RenderBlock*); void addPercentHeightDescendant(RenderBox*); static void removePercentHeightDescendant(RenderBox*); + HashSet<RenderBox*>* percentHeightDescendants() const; virtual void positionListMarker() { } virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set. + virtual void updateBeforeAfterContent(PseudoId); + + RootInlineBox* createRootInlineBox(); + // Called to lay out the legend for a fieldset. virtual RenderObject* layoutLegend(bool /*relayoutChildren*/) { return 0; } // the implementation of the following functions is in bidi.cpp struct FloatWithRect { - FloatWithRect(RenderObject* f) + FloatWithRect(RenderBox* f) : object(f) - , rect(IntRect(f->xPos() - f->marginLeft(), f->yPos() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom())) + , rect(IntRect(f->x() - f->marginLeft(), f->y() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom())) { } - RenderObject* object; + RenderBox* object; IntRect rect; }; - void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end); - RootInlineBox* determineStartPosition(bool& fullLayout, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats); + void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end, bool previousLineBrokeCleanly); + RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, + InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats); RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& yPos); bool matchedEndLine(const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop); - bool generatesLineBoxesForInlineChild(RenderObject*); - void skipTrailingWhitespace(InlineIterator&); - int skipLeadingWhitespace(InlineBidiResolver&); - void fitBelowFloats(int widthToFit, int& availableWidth); - InlineIterator findNextLineBreak(InlineBidiResolver&, EClear* clear = 0); - RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool lastLine, RenderObject* endObject); - InlineFlowBox* createLineBoxes(RenderObject*); - void computeHorizontalPositionsForLine(RootInlineBox*, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd); + bool generatesLineBoxesForInlineChild(RenderObject*, bool isLineEmpty = true, bool previousLineBrokeCleanly = true); + void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly); + int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly); + void fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth); + InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, EClear* clear = 0); + RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject); + InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine); + void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd); void computeVerticalPositionsForLine(RootInlineBox*, BidiRun*); void checkLinesForOverflow(); void deleteEllipsisLineBoxes(); @@ -163,29 +185,30 @@ public: virtual void paintObject(PaintInfo&, int tx, int ty); void paintFloats(PaintInfo&, int tx, int ty, bool preservePhase = false); void paintContents(PaintInfo&, int tx, int ty); - void paintColumns(PaintInfo&, int tx, int ty, bool paintFloats = false); + void paintColumnContents(PaintInfo&, int tx, int ty, bool paintFloats = false); + void paintColumnRules(PaintInfo&, int tx, int ty); void paintChildren(PaintInfo&, int tx, int ty); void paintEllipsisBoxes(PaintInfo&, int tx, int ty); void paintSelection(PaintInfo&, int tx, int ty); void paintCaret(PaintInfo&, int tx, int ty, CaretType); - void insertFloatingObject(RenderObject*); - void removeFloatingObject(RenderObject*); + void insertFloatingObject(RenderBox*); + void removeFloatingObject(RenderBox*); // Called from lineWidth, to position the floats added in the last line. // Returns ture if and only if it has positioned any floats. bool positionNewFloats(); void clearFloats(); - int getClearDelta(RenderObject* child); - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0); + int getClearDelta(RenderBox* child, int yPos); + void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true); void markPositionedObjectsForLayout(); - virtual bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } - virtual bool containsFloat(RenderObject*); + bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } + bool containsFloat(RenderObject*); virtual bool avoidsFloats() const; - virtual bool hasOverhangingFloats() { return !hasColumns() && floatBottom() > m_height; } + bool hasOverhangingFloats() { return parent() && !hasColumns() && floatBottom() > height(); } void addIntrudingFloats(RenderBlock* prev, int xoffset, int yoffset); int addOverhangingFloats(RenderBlock* child, int xoffset, int yoffset, bool makeChildPaintOtherFloats); @@ -195,18 +218,18 @@ public: inline int rightBottom(); IntRect floatRect() const; - virtual int lineWidth(int) const; + int lineWidth(int y, bool firstLine) const; virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; int rightOffset() const; int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; - int rightOffset(int y) const { return rightRelOffset(y, rightOffset(), true); } + int rightOffset(int y, bool firstLine) const { return rightRelOffset(y, rightOffset(), firstLine); } int leftOffset() const; int leftRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; - int leftOffset(int y) const { return leftRelOffset(y, leftOffset(), true); } + int leftOffset(int y, bool firstLine) const { return leftRelOffset(y, leftOffset(), firstLine); } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -214,7 +237,7 @@ public: virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty); - virtual VisiblePosition positionForCoordinates(int x, int y); + virtual VisiblePosition positionForPoint(const IntPoint&); // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) virtual int availableWidth() const; @@ -223,8 +246,8 @@ public: void calcInlinePrefWidths(); void calcBlockPrefWidths(); - virtual int getBaselineOfFirstLineBox() const; - virtual int getBaselineOfLastLineBox() const; + virtual int firstLineBoxBaseline() const; + virtual int lastLineBoxBaseline() const; RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); } RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); } @@ -238,38 +261,22 @@ public: bool inRootBlockContext() const; - void setHasMarkupTruncation(bool b = true) { m_hasMarkupTruncation = b; } - bool hasMarkupTruncation() const { return m_hasMarkupTruncation; } + virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); + virtual RenderStyle* outlineStyleForRepaint() const; + + virtual RenderObject* hoverAncestor() const; + virtual void updateDragState(bool dragOn); + virtual void updateHitTestResult(HitTestResult&, const IntPoint&); + + virtual void childBecameNonInline(RenderObject* child); - virtual bool hasSelectedChildren() const { return m_selectionState != SelectionNone; } - virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); } virtual void setSelectionState(SelectionState s); - struct BlockSelectionInfo { - RenderBlock* m_block; - GapRects m_rects; - SelectionState m_state; - - BlockSelectionInfo() - : m_block(0) - , m_state(SelectionNone) - { - } - - BlockSelectionInfo(RenderBlock* b) - : m_block(b) - , m_rects(b->needsLayout() ? GapRects() : b->selectionGapRects()) - , m_state(b->selectionState()) - { - } - - RenderBlock* block() const { return m_block; } - GapRects rects() const { return m_rects; } - SelectionState state() const { return m_state; } - }; - - virtual IntRect selectionRect(bool) { return selectionGapRects(); } - GapRects selectionGapRects(); + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool /*clipToVisibleContent*/) + { + return selectionGapRectsForRepaint(repaintContainer); + } + GapRects selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer); virtual bool shouldPaintSelectionGaps() const; bool isSelectionRoot() const; GapRects fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, @@ -290,6 +297,9 @@ public: int leftSelectionOffset(RenderBlock* rootBlock, int y); int rightSelectionOffset(RenderBlock* rootBlock, int y); + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + // Helper methods for computing line counts and heights for line counts. RootInlineBox* lineAtIndex(int); int lineCount(); @@ -300,12 +310,24 @@ public: unsigned desiredColumnCount() const; Vector<IntRect>* columnRects() const; void setDesiredColumnCountAndWidth(int count, int width); + int columnGap() const; void adjustRectForColumns(IntRect&) const; - void addContinuationWithOutline(RenderFlow*); + void addContinuationWithOutline(RenderInline*); void paintContinuationOutlines(PaintInfo&, int tx, int ty); + RenderInline* inlineContinuation() const { return m_inlineContinuation; } + void setInlineContinuation(RenderInline* c) { m_inlineContinuation = c; } + + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + + // This function is a convenience helper for creating an anonymous block that inherits its + // style from this RenderBlock. + RenderBlock* createAnonymousBlock() const; + private: void adjustPointToColumnContents(IntPoint&) const; void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust @@ -313,24 +335,28 @@ private: void markLinesDirtyInVerticalRange(int top, int bottom); protected: - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); void newLine(EClear); virtual bool hasLineIfEmpty() const; bool layoutOnlyPositionedObjects(); + virtual RootInlineBox* createRootBox(); // Subclassed by SVG. + private: Position positionForBox(InlineBox*, bool start = true) const; Position positionForRenderer(RenderObject*, bool start = true) const; + VisiblePosition positionForPointWithInlineChildren(const IntPoint&); // Adjust tx and ty from painting offsets to the local coords of this renderer void offsetForContents(int& tx, int& ty) const; - int columnGap() const; void calcColumnWidth(); int layoutColumns(int endOfContent = -1); + bool expandsToEncloseOverhangingFloats() const; + protected: struct FloatingObject { enum Type { @@ -352,7 +378,7 @@ protected: Type type() { return static_cast<Type>(m_type); } - RenderObject* m_renderer; + RenderBox* m_renderer; int m_top; int m_bottom; int m_left; @@ -362,25 +388,6 @@ protected: bool m_isDescendant : 1; }; - // The following helper functions and structs are used by layoutBlockChildren. - class CompactInfo { - // A compact child that needs to be collapsed into the margin of the following block. - RenderObject* m_compact; - - // The block with the open margin that the compact child is going to place itself within. - RenderObject* m_block; - - public: - RenderObject* compact() const { return m_compact; } - RenderObject* block() const { return m_block; } - bool matches(RenderObject* child) const { return m_compact && m_block == child; } - - void clear() { set(0, 0); } - void set(RenderObject* c, RenderObject* b) { m_compact = c; m_block = b; } - - CompactInfo() { clear(); } - }; - class MarginInfo { // Collapsing flags for whether we can collapse our margins with our children's margins. bool m_canCollapseWithChildren : 1; @@ -447,27 +454,31 @@ protected: int margin() const { return m_posMargin - m_negMargin; } }; - void adjustPositionedBlock(RenderObject* child, const MarginInfo&); + void adjustPositionedBlock(RenderBox* child, const MarginInfo&); void adjustFloatingBlock(const MarginInfo&); - RenderObject* handleSpecialChild(RenderObject* child, const MarginInfo&, CompactInfo&, bool& handled); - RenderObject* handleFloatingChild(RenderObject* child, const MarginInfo&, bool& handled); - RenderObject* handlePositionedChild(RenderObject* child, const MarginInfo&, bool& handled); - RenderObject* handleCompactChild(RenderObject* child, CompactInfo&, bool& handled); - RenderObject* handleRunInChild(RenderObject* child, bool& handled); - void collapseMargins(RenderObject* child, MarginInfo&, int yPosEstimate); - void clearFloatsIfNeeded(RenderObject* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin); - void insertCompactIfNeeded(RenderObject* child, CompactInfo&); - int estimateVerticalPosition(RenderObject* child, const MarginInfo&); - void determineHorizontalPosition(RenderObject* child); + bool handleSpecialChild(RenderBox* child, const MarginInfo&); + bool handleFloatingChild(RenderBox* child, const MarginInfo&); + bool handlePositionedChild(RenderBox* child, const MarginInfo&); + bool handleRunInChild(RenderBox* child); + int collapseMargins(RenderBox* child, MarginInfo&); + int clearFloatsIfNeeded(RenderBox* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin, int yPos); + int estimateVerticalPosition(RenderBox* child, const MarginInfo&); + void determineHorizontalPosition(RenderBox* child); void handleBottomOfBlock(int top, int bottom, MarginInfo&); void setCollapsedBottomMargin(const MarginInfo&); // End helper functions and structs used by layoutBlockChildren. private: - typedef ListHashSet<RenderObject*>::const_iterator Iterator; + typedef ListHashSet<RenderBox*>::const_iterator Iterator; DeprecatedPtrList<FloatingObject>* m_floatingObjects; - ListHashSet<RenderObject*>* m_positionedObjects; - + ListHashSet<RenderBox*>* m_positionedObjects; + + // An inline can be split with blocks occurring in between the inline content. + // When this occurs we need a pointer to our next object. We can basically be + // split into a sequence of inlines and blocks. The continuation will either be + // an anonymous block (that houses other blocks) or it will be an inline flow. + RenderInline* m_inlineContinuation; + // Allocated only when some of these fields have non-default values struct MaxMargin { MaxMargin(const RenderBlock* o) @@ -492,13 +503,33 @@ private: MaxMargin* m_maxMargin; protected: + RenderObjectChildList m_children; + 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>. + // How much content overflows out of our block vertically or horizontally. int m_overflowHeight; int m_overflowWidth; int m_overflowLeft; int m_overflowTop; + + mutable int m_lineHeight; }; +inline RenderBlock* toRenderBlock(RenderObject* o) +{ + ASSERT(!o || o->isRenderBlock()); + return static_cast<RenderBlock*>(o); +} + +inline const RenderBlock* toRenderBlock(const RenderObject* o) +{ + ASSERT(!o || o->isRenderBlock()); + return static_cast<const RenderBlock*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderBlock(const RenderBlock* o); + } // namespace WebCore #endif // RenderBlock_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp index 78691de..ab0d153 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp @@ -30,21 +30,28 @@ #include "Document.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "htmlediting.h" #include "HTMLElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" +#include "FloatQuad.h" #include "Frame.h" #include "Page.h" #include "RenderArena.h" #include "RenderFlexibleBox.h" +#include "RenderInline.h" #include "RenderLayer.h" -#include "RenderReplica.h" #include "RenderTableCell.h" #include "RenderTheme.h" #include "RenderView.h" +#include "TransformState.h" #include <algorithm> #include <math.h> +#if ENABLE(WML) +#include "WMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -55,24 +62,19 @@ using namespace HTMLNames; typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap; static OverrideSizeMap* gOverrideSizeMap = 0; -bool RenderBox::s_wasFloating = false; bool RenderBox::s_hadOverflowClip = false; RenderBox::RenderBox(Node* node) - : RenderObject(node) - , m_width(0) - , m_height(0) - , m_x(0) - , m_y(0) + : RenderBoxModelObject(node) , m_marginLeft(0) , m_marginRight(0) , m_marginTop(0) , m_marginBottom(0) , m_minPrefWidth(-1) , m_maxPrefWidth(-1) - , m_layer(0) , m_inlineBoxWrapper(0) { + setIsBox(); } RenderBox::~RenderBox() @@ -87,60 +89,107 @@ void RenderBox::destroy() if (hasOverrideSize()) gOverrideSizeMap->remove(this); - // This must be done before we destroy the RenderObject. - if (m_layer) - m_layer->clearClipRects(); - if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); - RenderObject::destroy(); + RenderBoxModelObject::destroy(); } -void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderBox::removeFloatingOrPositionedChildFromBlockLists() { - s_wasFloating = isFloating(); - s_hadOverflowClip = hasOverflowClip(); + ASSERT(isFloatingOrPositioned()); + + if (documentBeingDestroyed()) + return; - RenderObject::styleWillChange(diff, newStyle); + if (isFloating()) { + RenderBlock* outermostBlock = containingBlock(); + for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) { + if (p->containsFloat(this)) + outermostBlock = p; + } + + if (outermostBlock) + outermostBlock->markAllDescendantsWithFloatsForLayout(this, false); + } + + if (isPositioned()) { + RenderObject* p; + for (p = parent(); p; p = p->parent()) { + if (p->isRenderBlock()) + toRenderBlock(p)->removePositionedObject(this); + } + } } -void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { - // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen - // during the style change (it's used by absoluteClippedOverflowRect()). - if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) - static_cast<RenderView*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize()); + s_hadOverflowClip = hasOverflowClip(); + + if (style()) { + // The background of the root element or the body element could propagate up to + // the canvas. Just dirty the entire canvas when our style changes substantially. + if (diff >= StyleDifferenceRepaint && node() && + (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag))) + view()->repaint(); + + // When a layout hint happens and an object's position style changes, we have to do a layout + // to dirty the render tree using the old position value now. + if (diff == StyleDifferenceLayout && parent() && style()->position() != newStyle->position()) { + markContainingBlocksForLayout(); + if (style()->position() == StaticPosition) + repaint(); + if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)) + removeFloatingOrPositionedChildFromBlockLists(); + } + } + + RenderBoxModelObject::styleWillChange(diff, newStyle); +} - RenderObject::styleDidChange(diff, oldStyle); +void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBoxModelObject::styleDidChange(diff, oldStyle); if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); - // The root and the RenderView always paint their backgrounds/borders. - if (isRoot() || isRenderView()) - setHasBoxDecorations(true); + // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the + // new zoomed coordinate space. + if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) { + int left = scrollLeft(); + if (left) { + left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom(); + setScrollLeft(left); + } + int top = scrollTop(); + if (top) { + top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom(); + setScrollTop(top); + } + } - setInline(style()->isDisplayInlineType()); + // Set the text color if we're the body. + if (isBody()) + document()->setTextColor(style()->color()); +} - switch (style()->position()) { - case AbsolutePosition: - case FixedPosition: - setPositioned(true); - break; - default: - setPositioned(false); +void RenderBox::updateBoxModelInfoFromStyle() +{ + RenderBoxModelObject::updateBoxModelInfoFromStyle(); - if (style()->isFloating()) - setFloating(true); + bool isRootObject = isRoot(); + bool isViewObject = isRenderView(); - if (style()->position() == RelativePosition) - setRelPositioned(true); - break; - } + // The root and the RenderView always paint their backgrounds/borders. + if (isRootObject || isViewObject) + setHasBoxDecorations(true); + + setPositioned(style()->position() == AbsolutePosition || style()->position() == FixedPosition); + setFloating(!isPositioned() && style()->isFloating()); // We also handle <body> and <html>, whose overflow applies to the viewport. - if (!isRoot() && (isRenderBlock() || isTableRow() || isTableSection()) && style()->overflowX() != OVISIBLE) { + if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) { bool boxHasOverflowClip = true; if (isBody()) { // Overflow on the body can propagate to the viewport under the following conditions. @@ -148,7 +197,7 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty // (2) We are the primary <body> (can be checked by looking at document.body). // (3) The root element has visible overflow. if (document()->documentElement()->hasTagName(htmlTag) && - document()->body() == element() && + document()->body() == node() && document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE) boxHasOverflowClip = false; } @@ -163,52 +212,220 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty } } - setHasTransform(style()->hasTransform()); + setHasTransform(style()->hasTransformRelatedProperty()); setHasReflection(style()->boxReflect()); +} - if (requiresLayer()) { - if (!m_layer) { - if (s_wasFloating && isFloating()) - setChildNeedsLayout(true); - m_layer = new (renderArena()) RenderLayer(this); - setHasLayer(true); - m_layer->insertOnlyThisLayer(); - if (parent() && !needsLayout() && containingBlock()) - m_layer->updateLayerPositions(); - } - } else if (m_layer && !isRoot() && !isRenderView()) { - ASSERT(m_layer->parent()); - RenderLayer* layer = m_layer; - m_layer = 0; - setHasLayer(false); - setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit. - setHasReflection(false); - layer->removeOnlyThisLayer(); - if (s_wasFloating && isFloating()) - setChildNeedsLayout(true); +void RenderBox::layout() +{ + ASSERT(needsLayout()); + + RenderObject* child = firstChild(); + if (!child) { + setNeedsLayout(false); + return; } - // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the - // new zoomed coordinate space. - if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) { - int left = scrollLeft(); - if (left) { - left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom(); - setScrollLeft(left); - } - int top = scrollTop(); - if (top) { - top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom(); - setScrollTop(top); - } + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); + while (child) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); + child = child->nextSibling(); } + statePusher.pop(); + setNeedsLayout(false); +} + +// More IE extensions. clientWidth and clientHeight represent the interior of an object +// excluding border and scrollbar. +int RenderBox::clientWidth() const +{ + return width() - borderLeft() - borderRight() - verticalScrollbarWidth(); +} - if (m_layer) - m_layer->styleChanged(diff, oldStyle); +int RenderBox::clientHeight() const +{ + return height() - borderTop() - borderBottom() - horizontalScrollbarHeight(); +} - // Set the text color if we're the body. - if (isBody()) - document()->setTextColor(style()->color()); +int RenderBox::scrollWidth() const +{ + if (hasOverflowClip()) + return layer()->scrollWidth(); + // For objects with visible overflow, this matches IE. + if (style()->direction() == LTR) + return max(clientWidth(), rightmostPosition(true, false) - borderLeft()); + return clientWidth() - min(0, leftmostPosition(true, false) - borderLeft()); +} + +int RenderBox::scrollHeight() const +{ + if (hasOverflowClip()) + return layer()->scrollHeight(); + // For objects with visible overflow, this matches IE. + return max(clientHeight(), lowestPosition(true, false) - borderTop()); +} + +int RenderBox::scrollLeft() const +{ + return hasOverflowClip() ? layer()->scrollXOffset() : 0; +} + +int RenderBox::scrollTop() const +{ + return hasOverflowClip() ? layer()->scrollYOffset() : 0; +} + +void RenderBox::setScrollLeft(int newLeft) +{ + if (hasOverflowClip()) + layer()->scrollToXOffset(newLeft); +} + +void RenderBox::setScrollTop(int newTop) +{ + if (hasOverflowClip()) + layer()->scrollToYOffset(newTop); +} + +void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty) +{ + rects.append(IntRect(tx, ty, width(), height())); +} + +void RenderBox::absoluteQuads(Vector<FloatQuad>& quads) +{ + quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); +} + +IntRect RenderBox::absoluteContentBox() const +{ + IntRect rect = contentBoxRect(); + FloatPoint absPos = localToAbsolute(FloatPoint()); + rect.move(absPos.x(), absPos.y()); + return rect; +} + +FloatQuad RenderBox::absoluteContentQuad() const +{ + IntRect rect = contentBoxRect(); + return localToAbsoluteQuad(FloatRect(rect)); +} + +IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const +{ + IntRect box = borderBoundingBox(); + adjustRectForOutlineAndShadow(box); + + FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); + box = containerRelativeQuad.enclosingBoundingBox(); + + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + box.move(view()->layoutDelta()); + + return box; +} + +void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +{ + graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); +} + + +IntRect RenderBox::reflectionBox() const +{ + IntRect result; + if (!style()->boxReflect()) + return result; + IntRect box = borderBoxRect(); + result = box; + switch (style()->boxReflect()->direction()) { + case ReflectionBelow: + result.move(0, box.height() + reflectionOffset()); + break; + case ReflectionAbove: + result.move(0, -box.height() - reflectionOffset()); + break; + case ReflectionLeft: + result.move(-box.width() - reflectionOffset(), 0); + break; + case ReflectionRight: + result.move(box.width() + reflectionOffset(), 0); + break; + } + return result; +} + +int RenderBox::reflectionOffset() const +{ + if (!style()->boxReflect()) + return 0; + if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight) + return style()->boxReflect()->offset().calcValue(borderBoxRect().width()); + return style()->boxReflect()->offset().calcValue(borderBoxRect().height()); +} + +IntRect RenderBox::reflectedRect(const IntRect& r) const +{ + if (!style()->boxReflect()) + return IntRect(); + + IntRect box = borderBoxRect(); + IntRect result = r; + switch (style()->boxReflect()->direction()) { + case ReflectionBelow: + result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom())); + break; + case ReflectionAbove: + result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom())); + break; + case ReflectionLeft: + result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right())); + break; + case ReflectionRight: + result.setX(box.right() + reflectionOffset() + (box.right() - r.right())); + break; + } + return result; +} + +int RenderBox::verticalScrollbarWidth() const +{ + return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0; +} + +int RenderBox::horizontalScrollbarHeight() const +{ + return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0; +} + +bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) +{ + RenderLayer* l = layer(); + if (l && l->scroll(direction, granularity, multiplier)) + return true; + RenderBlock* b = containingBlock(); + if (b && !b->isRenderView()) + return b->scroll(direction, granularity, multiplier); + return false; +} + +bool RenderBox::canBeProgramaticallyScrolled(bool) const +{ + return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode()); +} + +void RenderBox::autoscroll() +{ + if (layer()) + layer()->autoscroll(); +} + +void RenderBox::panScroll(const IntPoint& source) +{ + if (layer()) + layer()->panScrollFromPoint(source); } int RenderBox::minPrefWidth() const @@ -251,22 +468,12 @@ void RenderBox::setOverrideSize(int s) int RenderBox::overrideWidth() const { - return hasOverrideSize() ? overrideSize() : m_width; + return hasOverrideSize() ? overrideSize() : width(); } int RenderBox::overrideHeight() const { - return hasOverrideSize() ? overrideSize() : m_height; -} - -void RenderBox::setPos(int xPos, int yPos) -{ - // Optimize for the case where we don't move at all. - if (xPos == m_x && yPos == m_y) - return; - - m_x = xPos; - m_y = yPos; + return hasOverrideSize() ? overrideSize() : height(); } int RenderBox::calcBorderBoxWidth(int width) const @@ -300,27 +507,23 @@ int RenderBox::calcContentBoxHeight(int height) const } // Hit Testing -bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action) +bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // Check kids first. for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - // FIXME: We have to skip over inline flows, since they can show up inside table rows - // at the moment (a demoted inline <form> for example). If we ever implement a - // table-specific hit-test method (which we should do for performance reasons anyway), - // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (!child->hasLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } } // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). - if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } @@ -331,8 +534,8 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // default implementation. Just pass paint through to the children PaintInfo childInfo(paintInfo); @@ -345,7 +548,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { const FillLayer* bgLayer = style()->backgroundLayers(); Color bgColor = style()->backgroundColor(); - if (!style()->hasBackground() && element() && element()->hasTagName(HTMLNames::htmlTag)) { + 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> @@ -379,9 +582,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); - int my = max(by, paintInfo.rect.y()); - - paintFillLayers(paintInfo, bgColor, bgLayer, my, paintInfo.rect.height(), bx, by, bw, bh); + paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh); if (style()->hasBorder() && style()->display() != INLINE) paintBorder(paintInfo.context, tx, ty, w, h, style()); @@ -398,20 +599,12 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) } int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); + int h = height(); // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat // balloon layout is an example of this). borderFitAdjust(tx, w); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have // custom shadows of their own. paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); @@ -424,7 +617,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) // independent of the body. Go through the DOM to get to the root element's render object, // since the root could be inline and wrapped in an anonymous block. if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground()) - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); if (style()->hasAppearance()) theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h)); } @@ -440,35 +633,38 @@ void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); + int h = height(); // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat // balloon layout is an example of this). borderFitAdjust(tx, w); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } -void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int tx, int ty, int w, int h) +void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h) { // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; StyleImage* maskBoxImage = style()->maskBoxImage().image(); - if ((maskBoxImage && style()->maskLayers()->hasImage()) || style()->maskLayers()->next()) + if (maskBoxImage && style()->maskLayers()->hasImage()) { + pushTransparencyLayer = true; + } else { // We have to use an extra image buffer to hold the mask. Multiple mask images need // to composite together using source-over so that they can then combine into a single unified mask that // can be composited with the content using destination-in. SVG images need to be able to set compositing modes // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer // and composite that buffer as the mask. - pushTransparencyLayer = true; + // 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()) { + if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) { + pushTransparencyLayer = true; + // We found one image that can be used in rendering, exit the loop + break; + } + } + } CompositeOperator compositeOp = CompositeDestinationIn; if (pushTransparencyLayer) { @@ -477,7 +673,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int compositeOp = CompositeSourceOver; } - paintFillLayers(paintInfo, Color(), style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp); + paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp); paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp); if (pushTransparencyLayer) @@ -486,7 +682,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int IntRect RenderBox::maskClipRect() { - IntRect bbox = borderBox(); + IntRect bbox = borderBoxRect(); if (style()->maskBoxImage().image()) return bbox; @@ -503,79 +699,39 @@ IntRect RenderBox::maskClipRect() return result; } -void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int clipY, int clipH, 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) { if (!fillLayer) return; - paintFillLayers(paintInfo, c, fillLayer->next(), clipY, clipH, tx, ty, width, height, op); - paintFillLayer(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, op); + paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op); + paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op); } -void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int clipY, int clipH, 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) { - paintFillLayerExtended(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, 0, op); -} - -IntSize RenderBox::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const -{ - StyleImage* bg = bgLayer->image(); - bg->setImageContainerSize(IntSize(scaledWidth, scaledHeight)); // Use the box established by background-origin. - - if (bgLayer->isSizeSet()) { - int w = scaledWidth; - int h = scaledHeight; - Length bgWidth = bgLayer->size().width(); - Length bgHeight = bgLayer->size().height(); - - if (bgWidth.isFixed()) - w = bgWidth.value(); - else if (bgWidth.isPercent()) - w = bgWidth.calcValue(scaledWidth); - - if (bgHeight.isFixed()) - h = bgHeight.value(); - else if (bgHeight.isPercent()) - h = bgHeight.calcValue(scaledHeight); - - // If one of the values is auto we have to use the appropriate - // scale to maintain our aspect ratio. - if (bgWidth.isAuto() && !bgHeight.isAuto()) - w = bg->imageSize(this, style()->effectiveZoom()).width() * h / bg->imageSize(this, style()->effectiveZoom()).height(); - else if (!bgWidth.isAuto() && bgHeight.isAuto()) - h = bg->imageSize(this, style()->effectiveZoom()).height() * w / bg->imageSize(this, style()->effectiveZoom()).width(); - else if (bgWidth.isAuto() && bgHeight.isAuto()) { - // If both width and height are auto, we just want to use the image's - // intrinsic size. - w = bg->imageSize(this, style()->effectiveZoom()).width(); - h = bg->imageSize(this, style()->effectiveZoom()).height(); - } - - return IntSize(max(1, w), max(1, h)); - } else - return bg->imageSize(this, style()->effectiveZoom()); + paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op); } void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) { - if (isInlineFlow() || - style()->borderImage().image() && style()->borderImage().image()->data() == image || - style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image) { + if (!parent()) + return; + + if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) || + (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) { repaint(); return; } bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true); - if (!didFullRepaint) { + if (!didFullRepaint) repaintLayerRectsForImage(image, style()->maskLayers(), false); - } } bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground) { - IntRect absoluteRect; + IntRect rendererRect; RenderBox* layerRenderer = 0; for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) { @@ -590,287 +746,35 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer int rw; int rh; - if (FrameView* frameView = static_cast<RenderView*>(layerRenderer)->frameView()) { + if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) { rw = frameView->contentsWidth(); rh = frameView->contentsHeight(); } else { rw = layerRenderer->width(); rh = layerRenderer->height(); } - absoluteRect = IntRect(-layerRenderer->marginLeft(), + rendererRect = IntRect(-layerRenderer->marginLeft(), -layerRenderer->marginTop(), max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw), max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh)); } else { layerRenderer = this; - absoluteRect = borderBox(); + rendererRect = borderBoxRect(); } - - layerRenderer->computeAbsoluteRepaintRect(absoluteRect); } IntRect repaintRect; IntPoint phase; IntSize tileSize; - layerRenderer->calculateBackgroundImageGeometry(curLayer, absoluteRect.x(), absoluteRect.y(), absoluteRect.width(), absoluteRect.height(), repaintRect, phase, tileSize); - view()->repaintViewRectangle(repaintRect); - if (repaintRect == absoluteRect) + layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize); + layerRenderer->repaintRectangle(repaintRect); + if (repaintRect == rendererRect) return true; } } return false; } -void RenderBox::calculateBackgroundImageGeometry(const FillLayer* bgLayer, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize) -{ - int pw; - int ph; - int left = 0; - int right = 0; - int top = 0; - int bottom = 0; - int cx; - int cy; - int rw = 0; - int rh = 0; - - // CSS2 chapter 14.2.1 - - if (bgLayer->attachment()) { - // Scroll - if (bgLayer->origin() != BorderFillBox) { - left = borderLeft(); - right = borderRight(); - top = borderTop(); - bottom = borderBottom(); - if (bgLayer->origin() == ContentFillBox) { - left += paddingLeft(); - right += paddingRight(); - top += paddingTop(); - bottom += paddingBottom(); - } - } - - // The background of the box generated by the root element covers the entire canvas including - // its margins. Since those were added in already, we have to factor them out when computing the - // box used by background-origin/size/position. - if (isRoot()) { - rw = width() - left - right; - rh = height() - top - bottom; - left += marginLeft(); - right += marginRight(); - top += marginTop(); - bottom += marginBottom(); - } - cx = tx; - cy = ty; - pw = w - left - right; - ph = h - top - bottom; - } else { - // Fixed - IntRect vr = viewRect(); - cx = vr.x(); - cy = vr.y(); - pw = vr.width(); - ph = vr.height(); - } - - int sx = 0; - int sy = 0; - int cw; - int ch; - - IntSize scaledImageSize; - if (isRoot() && bgLayer->attachment()) - scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh); - else - scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph); - - int scaledImageWidth = scaledImageSize.width(); - int scaledImageHeight = scaledImageSize.height(); - - EFillRepeat backgroundRepeat = bgLayer->repeat(); - - int xPosition; - if (isRoot() && bgLayer->attachment()) - xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true); - else - xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true); - if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatXFill) { - cw = pw + left + right; - sx = scaledImageWidth ? scaledImageWidth - (xPosition + left) % scaledImageWidth : 0; - } else { - cx += max(xPosition + left, 0); - sx = -min(xPosition + left, 0); - cw = scaledImageWidth + min(xPosition + left, 0); - } - - int yPosition; - if (isRoot() && bgLayer->attachment()) - yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true); - else - yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true); - if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatYFill) { - ch = ph + top + bottom; - sy = scaledImageHeight ? scaledImageHeight - (yPosition + top) % scaledImageHeight : 0; - } else { - cy += max(yPosition + top, 0); - sy = -min(yPosition + top, 0); - ch = scaledImageHeight + min(yPosition + top, 0); - } - - if (!bgLayer->attachment()) { - sx += max(tx - cx, 0); - sy += max(ty - cy, 0); - } - - destRect = IntRect(cx, cy, cw, ch); - destRect.intersect(IntRect(tx, ty, w, h)); - phase = IntPoint(sx, sy); - tileSize = IntSize(scaledImageWidth, scaledImageHeight); -} - -void RenderBox::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int clipY, int clipH, - int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) -{ - GraphicsContext* context = paintInfo.context; - bool includeLeftEdge = box ? box->includeLeftEdge() : true; - bool includeRightEdge = box ? box->includeRightEdge() : true; - int bLeft = includeLeftEdge ? borderLeft() : 0; - int bRight = includeRightEdge ? borderRight() : 0; - int pLeft = includeLeftEdge ? paddingLeft() : 0; - int pRight = includeRightEdge ? paddingRight() : 0; - - bool clippedToBorderRadius = false; - if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) { - context->save(); - context->addRoundedRectClip(IntRect(tx, ty, w, h), - includeLeftEdge ? style()->borderTopLeftRadius() : IntSize(), - includeRightEdge ? style()->borderTopRightRadius() : IntSize(), - includeLeftEdge ? style()->borderBottomLeftRadius() : IntSize(), - includeRightEdge ? style()->borderBottomRightRadius() : IntSize()); - clippedToBorderRadius = true; - } - - if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { - // Clip to the padding or content boxes as necessary. - bool includePadding = bgLayer->clip() == ContentFillBox; - int x = tx + bLeft + (includePadding ? pLeft : 0); - int y = ty + borderTop() + (includePadding ? paddingTop() : 0); - int width = w - bLeft - bRight - (includePadding ? pLeft + pRight : 0); - int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0); - context->save(); - context->clip(IntRect(x, y, width, height)); - } else if (bgLayer->clip() == TextFillBox) { - // We have to draw our text into a mask that can then be used to clip background drawing. - // First figure out how big the mask has to be. It should be no bigger than what we need - // to actually render, so we should intersect the dirty rect with the border box of the background. - IntRect maskRect(tx, ty, w, h); - maskRect.intersect(paintInfo.rect); - - // Now create the mask. - auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); - if (!maskImage.get()) - return; - - GraphicsContext* maskImageContext = maskImage->context(); - maskImageContext->translate(-maskRect.x(), -maskRect.y()); - - // Now add the text to the clip. We do this by painting using a special paint phase that signals to - // InlineTextBoxes that they should just add their contents to the clip. - PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0); - if (box) - box->paint(info, tx - box->xPos(), ty - box->yPos()); - else - paint(info, tx, ty); - - // The mask has been created. Now we just need to clip to it. - context->save(); - context->clipToImageBuffer(maskRect, maskImage.get()); - } - - StyleImage* bg = bgLayer->image(); - bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom()); - Color bgColor = c; - - // When this style flag is set, change existing background colors and images to a solid white background. - // If there's no bg color or image, leave it untouched to avoid affecting transparency. - // We don't try to avoid loading the background images, because this style flag is only set - // when printing, and at that point we've already loaded the background images anyway. (To avoid - // loading the background images we'd have to do this check when applying styles rather than - // while rendering.) - if (style()->forceBackgroundsToWhite()) { - // Note that we can't reuse this variable below because the bgColor might be changed - bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0; - if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { - bgColor = Color::white; - shouldPaintBackgroundImage = false; - } - } - - // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with - // no background in the child document should show the parent's background. - bool isTransparent = false; - if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && view()->frameView()) { - Node* elt = document()->ownerElement(); - if (elt) { - if (!elt->hasTagName(frameTag)) { - // 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(); - isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway. - } - } else - isTransparent = view()->frameView()->isTransparent(); - - // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. - if (isTransparent) - view()->frameView()->setUseSlowRepaints(); // The parent must show behind the child. - } - - // Paint the color first underneath all images. - if (!bgLayer->next()) { - IntRect rect(tx, clipY, w, clipH); - // If we have an alpha and we are painting the root element, go ahead and blend with the base background color. - if (isRoot() && (!bgColor.isValid() || bgColor.alpha() < 0xFF) && !isTransparent) { - Color baseColor = view()->frameView()->baseBackgroundColor(); - if (baseColor.alpha() > 0) { - context->save(); - context->setCompositeOperation(CompositeCopy); - context->fillRect(rect, baseColor); - context->restore(); - } else - context->clearRect(rect); - } - - if (bgColor.isValid() && bgColor.alpha() > 0) - context->fillRect(rect, bgColor); - } - - // no progressive loading of the background image - if (shouldPaintBackgroundImage) { - IntRect destRect; - IntPoint phase; - IntSize tileSize; - - calculateBackgroundImageGeometry(bgLayer, tx, ty, w, h, destRect, phase, tileSize); - if (!destRect.isEmpty()) { - CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; - context->drawTiledImage(bg->image(this, tileSize), destRect, phase, tileSize, compositeOp); - } - } - - if (bgLayer->clip() != BorderFillBox) - // Undo the background clip - context->restore(); - - if (clippedToBorderRadius) - // Undo the border radius clip - context->restore(); -} - #if PLATFORM(MAC) void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText) @@ -885,18 +789,63 @@ void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, b InlineBox* boxWrap = inlineBoxWrapper(); RootInlineBox* r = boxWrap ? boxWrap->root() : 0; if (r) { - FloatRect rootRect(tx + r->xPos(), ty + r->selectionTop(), r->width(), r->selectionHeight()); - FloatRect imageRect(tx + m_x, rootRect.y(), width(), rootRect.height()); + FloatRect rootRect(tx + r->x(), ty + r->selectionTop(), r->width(), r->selectionHeight()); + FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height()); page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false); } else { - FloatRect imageRect(tx + m_x, ty + m_y, width(), height()); + FloatRect imageRect(tx + x(), ty + y(), width(), height()); page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false); } } #endif -IntRect RenderBox::getOverflowClipRect(int tx, int ty) +bool RenderBox::pushContentsClip(PaintInfo& paintInfo, int tx, int ty) +{ + if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask) + return false; + + bool isControlClip = hasControlClip(); + bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer(); + + if (!isControlClip && !isOverflowClip) + return false; + + if (paintInfo.phase == PaintPhaseOutline) + paintInfo.phase = PaintPhaseChildOutlines; + else if (paintInfo.phase == PaintPhaseChildBlockBackground) { + paintInfo.phase = PaintPhaseBlockBackground; + paintObject(paintInfo, tx, ty); + paintInfo.phase = PaintPhaseChildBlockBackgrounds; + } + IntRect clipRect(isControlClip ? controlClipRect(tx, ty) : overflowClipRect(tx, ty)); + paintInfo.context->save(); + if (style()->hasBorderRadius()) { + IntSize topLeft, topRight, bottomLeft, bottomRight; + IntRect borderRect = IntRect(tx, ty, width(), height()); + style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight); + + paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight); + } + + paintInfo.context->clip(clipRect); + return true; +} + +void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, int tx, int ty) +{ + ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer())); + + paintInfo.context->restore(); + if (originalPhase == PaintPhaseOutline) { + paintInfo.phase = PaintPhaseSelfOutline; + paintObject(paintInfo, tx, ty); + paintInfo.phase = originalPhase; + } else if (originalPhase == PaintPhaseChildBlockBackground) + paintInfo.phase = originalPhase; +} + +IntRect RenderBox::overflowClipRect(int tx, int ty) { // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property // here. @@ -906,103 +855,68 @@ IntRect RenderBox::getOverflowClipRect(int tx, int ty) int clipX = tx + bLeft; int clipY = ty + bTop; - int clipWidth = m_width - bLeft - borderRight(); - int clipHeight = m_height - bTop - borderBottom() + borderTopExtra() + borderBottomExtra(); + int clipWidth = width() - bLeft - borderRight(); + int clipHeight = height() - bTop - borderBottom(); // Subtract out scrollbars if we have them. - if (m_layer) { - clipWidth -= m_layer->verticalScrollbarWidth(); - clipHeight -= m_layer->horizontalScrollbarHeight(); + if (layer()) { + clipWidth -= layer()->verticalScrollbarWidth(); + clipHeight -= layer()->horizontalScrollbarHeight(); } return IntRect(clipX, clipY, clipWidth, clipHeight); } -IntRect RenderBox::getClipRect(int tx, int ty) +IntRect RenderBox::clipRect(int tx, int ty) { int clipX = tx; int clipY = ty; - int clipWidth = m_width; - int clipHeight = m_height; + int clipWidth = width(); + int clipHeight = height(); if (!style()->clipLeft().isAuto()) { - int c = style()->clipLeft().calcValue(m_width); + int c = style()->clipLeft().calcValue(width()); clipX += c; clipWidth -= c; } if (!style()->clipRight().isAuto()) - clipWidth -= m_width - style()->clipRight().calcValue(m_width); + clipWidth -= width() - style()->clipRight().calcValue(width()); if (!style()->clipTop().isAuto()) { - int c = style()->clipTop().calcValue(m_height); + int c = style()->clipTop().calcValue(height()); clipY += c; clipHeight -= c; } if (!style()->clipBottom().isAuto()) - clipHeight -= m_height - style()->clipBottom().calcValue(m_height); + clipHeight -= height() - style()->clipBottom().calcValue(height()); return IntRect(clipX, clipY, clipWidth, clipHeight); } -int RenderBox::containingBlockWidth() const +int RenderBox::containingBlockWidthForContent() const { RenderBlock* cb = containingBlock(); - if (!cb) - return 0; if (shrinkToAvoidFloats()) - return cb->lineWidth(m_y); + return cb->lineWidth(y(), false); return cb->availableWidth(); } -IntSize RenderBox::offsetForPositionedInContainer(RenderObject* container) const +void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const { - if (!container->isRelPositioned() || !container->isInlineFlow()) - return IntSize(); - - // When we have an enclosing relpositioned inline, we need to add in the offset of the first line - // box from the rest of the content, but only in the cases where we know we're positioned - // relative to the inline itself. - - IntSize offset; - RenderFlow* flow = static_cast<RenderFlow*>(container); - int sx; - int sy; - if (flow->firstLineBox()) { - sx = flow->firstLineBox()->xPos(); - sy = flow->firstLineBox()->yPos(); - } else { - sx = flow->staticX(); - sy = flow->staticY(); - } - - if (!hasStaticX()) - offset.setWidth(sx); - // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside - // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct - // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers - // do. - else if (!style()->isOriginalDisplayInlineType()) - // Avoid adding in the left border/padding of the containing block twice. Subtract it out. - offset.setWidth(sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft())); - - if (!hasStaticY()) - offset.setHeight(sy); - - return offset; -} + if (repaintContainer == this) + return; -FloatPoint RenderBox::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const -{ if (RenderView* v = view()) { - if (LayoutState* layoutState = v->layoutState()) { + if (v->layoutStateEnabled() && !repaintContainer) { + LayoutState* layoutState = v->layoutState(); IntSize offset = layoutState->m_offset; - offset.expand(m_x, m_y); - localPoint += offset; - if (style()->position() == RelativePosition && m_layer) - localPoint += m_layer->relativePositionOffset(); - return localPoint; + offset.expand(x(), y()); + if (style()->position() == RelativePosition && layer()) + offset += layer()->relativePositionOffset(); + transformState.move(offset); + return; } } @@ -1010,73 +924,53 @@ FloatPoint RenderBox::localToAbsolute(FloatPoint localPoint, bool fixed, bool us fixed = true; RenderObject* o = container(); - if (o) { - if (useTransforms && m_layer && m_layer->transform()) { - fixed = false; // Elements with transforms act as a containing block for fixed position descendants - localPoint = m_layer->transform()->mapPoint(localPoint); - } + if (!o) + return; - localPoint += offsetFromContainer(o); + bool hasTransform = hasLayer() && layer()->transform(); + if (hasTransform) + fixed = false; // Elements with transforms act as a containing block for fixed position descendants - return o->localToAbsoluteForContent(localPoint, fixed, useTransforms); - } - - return FloatPoint(); + IntSize containerOffset = offsetFromContainer(o); + + bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); + if (useTransforms && shouldUseTransformFromContainer(o)) { + TransformationMatrix t; + getTransformFromContainer(o, containerOffset, t); + transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); + } else + transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); + + o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); } -FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { // We don't expect absoluteToLocal() to be called during layout (yet) - ASSERT(!view() || !view()->layoutState()); + ASSERT(!view() || !view()->layoutStateEnabled()); if (style()->position() == FixedPosition) fixed = true; - if (useTransforms && m_layer && m_layer->transform()) - fixed = false; - - RenderObject* o = container(); - if (o) { - FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms); - - // Take into account space above a vertically aligned table cell - // (see localToAbsoluteForContent()) - localPoint.move(0.0f, -static_cast<float>(borderTopExtra())); - - localPoint -= offsetFromContainer(o); - - if (useTransforms && m_layer && m_layer->transform()) - localPoint = m_layer->transform()->inverse().mapPoint(localPoint); - - return localPoint; - } + bool hasTransform = hasLayer() && layer()->transform(); + if (hasTransform) + fixed = false; // Elements with transforms act as a containing block for fixed position descendants - return FloatPoint(); -} - -FloatQuad RenderBox::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const -{ - if (style()->position() == FixedPosition) - fixed = true; - RenderObject* o = container(); - if (o) { - FloatQuad quad = localQuad; - if (m_layer && m_layer->transform()) { - fixed = false; // Elements with transforms act as a containing block for fixed position descendants - quad = m_layer->transform()->mapQuad(quad); - } + if (!o) + return; - quad += offsetFromContainer(o); + o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); - // Take into account space above a vertically aligned table cell - // (see localToAbsoluteForContent()) - quad.move(0.0f, static_cast<float>(o->borderTopExtra())); + IntSize containerOffset = offsetFromContainer(o); - return o->localToAbsoluteQuad(quad, fixed); - } - - return FloatQuad(); + bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); + if (useTransforms && shouldUseTransformFromContainer(o)) { + TransformationMatrix t; + getTransformFromContainer(o, containerOffset, t); + transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); + } else + transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } IntSize RenderBox::offsetFromContainer(RenderObject* o) const @@ -1090,24 +984,29 @@ IntSize RenderBox::offsetFromContainer(RenderObject* o) const if (!isInline() || isReplaced()) { RenderBlock* cb; if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition - && (cb = static_cast<RenderBlock*>(o))->hasColumns()) { - IntRect rect(m_x, m_y, 1, 1); + && (cb = toRenderBlock(o))->hasColumns()) { + IntRect rect(x(), y(), 1, 1); cb->adjustRectForColumns(rect); offset.expand(rect.x(), rect.y()); } else - offset.expand(m_x, m_y); + offset.expand(x(), y()); } if (o->hasOverflowClip()) - offset -= o->layer()->scrolledContentOffset(); + offset -= toRenderBox(o)->layer()->scrolledContentOffset(); - if (style()->position() == AbsolutePosition) - offset += offsetForPositionedInContainer(o); + if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline()) + offset += toRenderInline(o)->relativePositionedInlineOffset(this); return offset; } -void RenderBox::dirtyLineBoxes(bool fullLayout, bool /*isRootLineBox*/) +InlineBox* RenderBox::createInlineBox() +{ + return new (renderArena()) InlineBox(this); +} + +void RenderBox::dirtyLineBoxes(bool fullLayout) { if (m_inlineBoxWrapper) { if (fullLayout) { @@ -1118,23 +1017,23 @@ void RenderBox::dirtyLineBoxes(bool fullLayout, bool /*isRootLineBox*/) } } -void RenderBox::position(InlineBox* box) +void RenderBox::positionLineBox(InlineBox* box) { if (isPositioned()) { // Cache the x position only if we were an INLINE type originally. bool wasInline = style()->isOriginalDisplayInlineType(); - if (wasInline && hasStaticX()) { + if (wasInline && style()->hasStaticX()) { // The value is cached in the xPos of the box. We only need this value if // our object was inline originally, since otherwise it would have ended up underneath // the inlines. - setStaticX(box->xPos()); + layer()->setStaticX(box->x()); setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. - } else if (!wasInline && hasStaticY()) { + } else if (!wasInline && style()->hasStaticY()) { // Our object was a block originally, so we make our normal flow position be // just below the line box (as though all the inlines that came before us got // wrapped in an anonymous block, which is what would have happened had we been - // in flow). This value was cached in the yPos() of the box. - setStaticY(box->yPos()); + // in flow). This value was cached in the y() of the box. + layer()->setStaticY(box->y()); setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. } @@ -1142,8 +1041,7 @@ void RenderBox::position(InlineBox* box) box->remove(); box->destroy(renderArena()); } else if (isReplaced()) { - m_x = box->xPos(); - m_y = box->yPos(); + setLocation(box->x(), box->y()); m_inlineBoxWrapper = box; } } @@ -1158,7 +1056,7 @@ void RenderBox::deleteLineBoxWrapper() } } -IntRect RenderBox::absoluteClippedOverflowRect() +IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return IntRect(); @@ -1166,9 +1064,12 @@ IntRect RenderBox::absoluteClippedOverflowRect() IntRect r = overflowRect(false); RenderView* v = view(); - if (v) + if (v) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); - + } + if (style()) { if (style()->hasAppearance()) // The theme may wish to inflate the rect used when repainting. @@ -1181,18 +1082,24 @@ IntRect RenderBox::absoluteClippedOverflowRect() r.inflate(v->maximalOutlineSize()); } } - computeAbsoluteRepaintRect(r); + computeRectForRepaint(repaintContainer, r); return r; } -void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) { if (RenderView* v = view()) { - if (LayoutState* layoutState = v->layoutState()) { - if (style()->position() == RelativePosition && m_layer) - rect.move(m_layer->relativePositionOffset()); + // LayoutState is only valid for root-relative repainting + if (v->layoutStateEnabled() && !repaintContainer) { + LayoutState* layoutState = v->layoutState(); + + if (layer() && layer()->transform()) + rect = layer()->transform()->mapRect(rect); - rect.move(m_x, m_y); + if (style()->position() == RelativePosition && layer()) + rect.move(layer()->relativePositionOffset()); + + rect.move(x(), y()); rect.move(layoutState->m_offset); if (layoutState->m_clipped) rect.intersect(layoutState->m_clipRect); @@ -1203,18 +1110,21 @@ void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) if (hasReflection()) rect.unite(reflectedRect(rect)); + if (repaintContainer == this) + return; + RenderObject* o = container(); if (!o) return; IntPoint topLeft = rect.location(); - topLeft.move(m_x, m_y); + topLeft.move(x(), y()); if (style()->position() == FixedPosition) fixed = true; if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) { - RenderBlock* cb = static_cast<RenderBlock*>(o); + RenderBlock* cb = toRenderBlock(o); if (cb->hasColumns()) { IntRect repaintRect(topLeft, rect.size()); cb->adjustRectForColumns(repaintRect); @@ -1225,92 +1135,63 @@ void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box // in the parent's coordinate space that encloses us. - if (m_layer && m_layer->transform()) { + if (layer() && layer()->transform()) { fixed = false; - rect = m_layer->transform()->mapRect(rect); + rect = layer()->transform()->mapRect(rect); // FIXME: this clobbers topLeft adjustment done for multicol above topLeft = rect.location(); - topLeft.move(m_x, m_y); + topLeft.move(x(), y()); } - if (style()->position() == AbsolutePosition) - topLeft += offsetForPositionedInContainer(o); - else if (style()->position() == RelativePosition && m_layer) { + if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline()) + topLeft += toRenderInline(o)->relativePositionedInlineOffset(this); + else if (style()->position() == RelativePosition && layer()) { // Apply the relative position offset when invalidating a rectangle. The layer // is translated, but the render box isn't, so we need to do this to get the // right dirty rect. Since this is called from RenderObject::setStyle, the relative position // flag on the RenderObject has been cleared, so use the one on the style(). - topLeft += m_layer->relativePositionOffset(); + topLeft += layer()->relativePositionOffset(); } // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. if (o->hasOverflowClip()) { + RenderBox* containerBox = toRenderBox(o); + // o->height() is inaccurate if we're in the middle of a layout of |o|, 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. - topLeft -= o->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden. + topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden. IntRect repaintRect(topLeft, rect.size()); - IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height()); + IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height()); rect = intersection(repaintRect, boxRect); if (rect.isEmpty()) return; } else rect.setLocation(topLeft); - o->computeAbsoluteRepaintRect(rect, fixed); + o->computeRectForRepaint(repaintContainer, rect, fixed); } void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect) { - int newX = m_x; - int newY = m_y; - int newWidth = m_width; - int newHeight = m_height; + int newX = x(); + int newY = y(); + int newWidth = width(); + int newHeight = height(); if (rect.x() != newX || rect.y() != newY) { // The child moved. Invalidate the object's old and new positions. We have to do this // since the object may not have gotten a layout. - m_x = rect.x(); - m_y = rect.y(); - m_width = rect.width(); - m_height = rect.height(); + m_frameRect = rect; repaint(); repaintOverhangingFloats(true); - - m_x = newX; - m_y = newY; - m_width = newWidth; - m_height = newHeight; + m_frameRect = IntRect(newX, newY, newWidth, newHeight); repaint(); repaintOverhangingFloats(true); } } -int RenderBox::relativePositionOffsetX() const -{ - if (!style()->left().isAuto()) { - if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL) - return -style()->right().calcValue(containingBlockWidth()); - return style()->left().calcValue(containingBlockWidth()); - } - if (!style()->right().isAuto()) - return -style()->right().calcValue(containingBlockWidth()); - return 0; -} - -int RenderBox::relativePositionOffsetY() const -{ - if (!style()->top().isAuto()) { - if (!style()->top().isPercent() || containingBlock()->style()->height().isFixed()) - return style()->top().calcValue(containingBlockHeight()); - } else if (!style()->bottom().isAuto()) { - if (!style()->bottom().isPercent() || containingBlock()->style()->height().isFixed()) - return -style()->bottom().calcValue(containingBlockHeight()); - } - return 0; -} - void RenderBox::calcWidth() { if (isPositioned()) { @@ -1326,7 +1207,7 @@ void RenderBox::calcWidth() // width. Use the width from the style context. if (hasOverrideSize() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isFlexibleBox() && parent()->isFlexingChildren()) { - m_width = overrideSize(); + setWidth(overrideSize()); return; } @@ -1334,10 +1215,10 @@ void RenderBox::calcWidth() bool stretching = (parent()->style()->boxAlign() == BSTRETCH); bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching); - Length width = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width(); + Length w = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width(); RenderBlock* cb = containingBlock(); - int containerWidth = max(0, containingBlockWidth()); + int containerWidth = max(0, containingBlockWidthForContent()); Length marginLeft = style()->marginLeft(); Length marginRight = style()->marginRight(); @@ -1347,42 +1228,42 @@ void RenderBox::calcWidth() m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); if (treatAsReplaced) - m_width = max(width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()); + setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth())); return; } // Width calculations if (treatAsReplaced) - m_width = width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); + setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); else { // Calculate Width - m_width = calcWidthUsing(Width, containerWidth); + setWidth(calcWidthUsing(Width, containerWidth)); // Calculate MaxWidth if (!style()->maxWidth().isUndefined()) { int maxW = calcWidthUsing(MaxWidth, containerWidth); - if (m_width > maxW) { - m_width = maxW; - width = style()->maxWidth(); + if (width() > maxW) { + setWidth(maxW); + w = style()->maxWidth(); } } // Calculate MinWidth int minW = calcWidthUsing(MinWidth, containerWidth); - if (m_width < minW) { - m_width = minW; - width = style()->minWidth(); + if (width() < minW) { + setWidth(minW); + w = style()->minWidth(); } } if (stretchesToMinIntrinsicWidth()) { - m_width = max(m_width, minPrefWidth()); - width = Length(m_width, Fixed); + setWidth(max(width(), minPrefWidth())); + w = Length(width(), Fixed); } // Margin calculations - if (width.isAuto()) { + if (w.isAuto()) { m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); } else { @@ -1391,18 +1272,18 @@ void RenderBox::calcWidth() calcHorizontalMargins(marginLeft, marginRight, containerWidth); } - if (containerWidth && containerWidth != (m_width + m_marginLeft + m_marginRight) + if (containerWidth && containerWidth != (width() + m_marginLeft + m_marginRight) && !isFloating() && !isInline() && !cb->isFlexibleBox()) { if (cb->style()->direction() == LTR) - m_marginRight = containerWidth - m_width - m_marginLeft; + m_marginRight = containerWidth - width() - m_marginLeft; else - m_marginLeft = containerWidth - m_width - m_marginRight; + m_marginLeft = containerWidth - width() - m_marginRight; } } int RenderBox::calcWidthUsing(WidthType widthType, int cw) { - int width = m_width; + int widthResult = width(); Length w; if (widthType == Width) w = style()->width(); @@ -1415,24 +1296,23 @@ int RenderBox::calcWidthUsing(WidthType widthType, int cw) int marginLeft = style()->marginLeft().calcMinValue(cw); int marginRight = style()->marginRight().calcMinValue(cw); if (cw) - width = cw - marginLeft - marginRight; + widthResult = cw - marginLeft - marginRight; if (sizesToIntrinsicWidth(widthType)) { - width = max(width, minPrefWidth()); - width = min(width, maxPrefWidth()); + widthResult = max(widthResult, minPrefWidth()); + widthResult = min(widthResult, maxPrefWidth()); } } else - width = calcBorderBoxWidth(w.calcValue(cw)); + widthResult = calcBorderBoxWidth(w.calcValue(cw)); - return width; + return widthResult; } bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const { // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks, // but they allow text to sit on the same line as the marquee. - if (isFloating() || (isCompact() && isInline()) - || (isInlineBlockOrInlineTable() && !isHTMLMarquee())) + if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee())) return true; // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both @@ -1467,20 +1347,20 @@ void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& ma return; } - if ((marginLeft.isAuto() && marginRight.isAuto() && m_width < containerWidth) + if ((marginLeft.isAuto() && marginRight.isAuto() && width() < containerWidth) || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) { - m_marginLeft = max(0, (containerWidth - m_width) / 2); - m_marginRight = containerWidth - m_width - m_marginLeft; - } else if ((marginRight.isAuto() && m_width < containerWidth) + m_marginLeft = max(0, (containerWidth - width()) / 2); + m_marginRight = containerWidth - width() - m_marginLeft; + } else if ((marginRight.isAuto() && width() < containerWidth) || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) { m_marginLeft = marginLeft.calcValue(containerWidth); - m_marginRight = containerWidth - m_width - m_marginLeft; - } else if ((marginLeft.isAuto() && m_width < containerWidth) + m_marginRight = containerWidth - width() - m_marginLeft; + } else if ((marginLeft.isAuto() && width() < containerWidth) || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) { m_marginRight = marginRight.calcValue(containerWidth); - m_marginLeft = containerWidth - m_width - m_marginRight; + m_marginLeft = containerWidth - width() - m_marginRight; } else { - // This makes auto margins 0 if we failed a m_width < containerWidth test above (css2.1, 10.3.3). + // This makes auto margins 0 if we failed a width() < containerWidth test above (css2.1, 10.3.3). m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); } @@ -1492,6 +1372,7 @@ void RenderBox::calcHeight() if (isTableCell() || (isInline() && !isReplaced())) return; + Length h; if (isPositioned()) calcAbsoluteVertical(); else { @@ -1501,7 +1382,6 @@ void RenderBox::calcHeight() if (isTable()) return; - Length h; bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL; bool stretching = parent()->style()->boxAlign() == BSTRETCH; bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching); @@ -1522,44 +1402,49 @@ void RenderBox::calcHeight() // Block children of horizontal flexible boxes fill the height of the box. if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isStretchingChildren()) { - h = Length(parent()->contentHeight() - marginTop() - marginBottom() - + h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() - borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed); checkMinMaxHeight = false; } - int height; + int heightResult; if (checkMinMaxHeight) { - height = calcHeightUsing(style()->height()); - if (height == -1) - height = m_height; + heightResult = calcHeightUsing(style()->height()); + if (heightResult == -1) + heightResult = height(); int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset. - int maxH = style()->maxHeight().isUndefined() ? height : calcHeightUsing(style()->maxHeight()); + int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight()); if (maxH == -1) - maxH = height; - height = min(maxH, height); - height = max(minH, height); - } else + maxH = heightResult; + heightResult = min(maxH, heightResult); + heightResult = max(minH, heightResult); + } else { // The only times we don't check min/max height are when a fixed length has // been given as an override. Just use that. The value has already been adjusted // for box-sizing. - height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); + heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); + } - m_height = height; + setHeight(heightResult); } // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height - // is specified. - if (stretchesToViewHeight() && !document()->printing()) { + // is specified. When we're printing, we also need this quirk if the body or root has a percentage + // 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()); + if (stretchesToViewHeight() || printingNeedsBaseHeight) { int margins = collapsedMarginTop() + collapsedMarginBottom(); - int visHeight = view()->viewHeight(); + int visHeight = document()->printing() ? view()->frameView()->visibleHeight() : view()->viewHeight(); if (isRoot()) - m_height = max(m_height, visHeight - margins); + setHeight(max(height(), visHeight - margins)); else { - int marginsBordersPadding = margins + parent()->marginTop() + parent()->marginBottom() - + parent()->borderTop() + parent()->borderBottom() - + parent()->paddingTop() + parent()->paddingBottom(); - m_height = max(m_height, visHeight - marginsBordersPadding); + int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom() + + parentBox()->borderTop() + parentBox()->borderBottom() + + parentBox()->paddingTop() + parentBox()->paddingBottom(); + setHeight(max(height(), visHeight - marginsBordersPadding)); } } } @@ -1630,7 +1515,7 @@ int RenderBox::calcPercentageHeight(const Length& height) if (result != -1) result = cb->calcContentBoxHeight(result); } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) { - // Don't allow this to affect the block' m_height member variable, since this + // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. int oldHeight = cb->height(); cb->calcHeight(); @@ -1669,7 +1554,7 @@ int RenderBox::calcReplacedWidthUsing(Length width) const case Fixed: return calcContentBoxWidth(width.value()); case Percent: { - const int cw = isPositioned() ? containingBlockWidthForPositioned(container()) : containingBlockWidth(); + const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockWidthForContent(); if (cw > 0) return calcContentBoxWidth(width.calcMinValue(cw)); } @@ -1698,12 +1583,12 @@ int RenderBox::calcReplacedHeightUsing(Length height) const RenderObject* cb = isPositioned() ? container() : containingBlock(); while (cb->isAnonymous()) { cb = cb->containingBlock(); - static_cast<RenderBlock*>(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this)); + toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this)); } if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) { ASSERT(cb->isRenderBlock()); - RenderBlock* block = static_cast<RenderBlock*>(cb); + RenderBlock* block = toRenderBlock(cb); int oldHeight = block->height(); block->calcHeight(); int newHeight = block->calcContentBoxHeight(block->contentHeight()); @@ -1711,7 +1596,7 @@ int RenderBox::calcReplacedHeightUsing(Length height) const return calcContentBoxHeight(height.calcValue(newHeight)); } - int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : cb->availableHeight(); + int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableHeight(); // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside @@ -1742,7 +1627,7 @@ int RenderBox::availableHeightUsing(const Length& h) const return calcContentBoxHeight(h.value()); if (isRenderView()) - return static_cast<const RenderView*>(this)->frameView()->visibleHeight(); + return toRenderView(this)->frameView()->visibleHeight(); // We need to stop here, since we don't want to increase the height of the table // artificially. We're going to rely on this cell getting expanded to some new @@ -1754,7 +1639,7 @@ int RenderBox::availableHeightUsing(const Length& h) const return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight())); if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) { - RenderBlock* block = const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this)); + RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this)); int oldHeight = block->height(); block->calcHeight(); int newHeight = block->calcContentBoxHeight(block->contentHeight()); @@ -1781,65 +1666,46 @@ void RenderBox::calcVerticalMargins() m_marginBottom = style()->marginBottom().calcMinValue(cw); } -int RenderBox::staticX() const -{ - return m_layer ? m_layer->staticX() : 0; -} - -int RenderBox::staticY() const -{ - return m_layer ? m_layer->staticY() : 0; -} - -void RenderBox::setStaticX(int staticX) -{ - ASSERT(isPositioned() || isRelPositioned()); - m_layer->setStaticX(staticX); -} - -void RenderBox::setStaticY(int staticY) +int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const { - ASSERT(isPositioned() || isRelPositioned()); - - if (staticY == m_layer->staticY()) - return; + if (containingBlock->isBox()) { + const RenderBox* containingBlockBox = toRenderBox(containingBlock); + return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth(); + } - m_layer->setStaticY(staticY); - setChildNeedsLayout(true, false); -} - -int RenderBox::containingBlockWidthForPositioned(const RenderObject* containingBlock) const -{ - if (containingBlock->isInlineFlow()) { - ASSERT(containingBlock->isRelPositioned()); - - const RenderFlow* flow = static_cast<const RenderFlow*>(containingBlock); - InlineFlowBox* first = flow->firstLineBox(); - InlineFlowBox* last = flow->lastLineBox(); + ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned()); - // If the containing block is empty, return a width of 0. - if (!first || !last) - return 0; + const RenderInline* flow = toRenderInline(containingBlock); + InlineFlowBox* first = flow->firstLineBox(); + InlineFlowBox* last = flow->lastLineBox(); - int fromLeft; - int fromRight; - if (containingBlock->style()->direction() == LTR) { - fromLeft = first->xPos() + first->borderLeft(); - fromRight = last->xPos() + last->width() - last->borderRight(); - } else { - fromRight = first->xPos() + first->width() - first->borderRight(); - fromLeft = last->xPos() + last->borderLeft(); - } + // If the containing block is empty, return a width of 0. + if (!first || !last) + return 0; - return max(0, (fromRight - fromLeft)); + int fromLeft; + int fromRight; + if (containingBlock->style()->direction() == LTR) { + fromLeft = first->x() + first->borderLeft(); + fromRight = last->x() + last->width() - last->borderRight(); + } else { + fromRight = first->x() + first->width() - first->borderRight(); + fromLeft = last->x() + last->borderLeft(); } - return containingBlock->width() - containingBlock->borderLeft() - containingBlock->borderRight() - containingBlock->verticalScrollbarWidth(); + return max(0, (fromRight - fromLeft)); } -int RenderBox::containingBlockHeightForPositioned(const RenderObject* containingBlock) const -{ - return containingBlock->height() - containingBlock->borderTop() - containingBlock->borderBottom(); +int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const +{ + int heightResult = 0; + if (containingBlock->isBox()) + heightResult = toRenderBox(containingBlock)->height(); + else if (containingBlock->isRenderInline()) { + ASSERT(containingBlock->isRelPositioned()); + heightResult = toRenderInline(containingBlock)->linesBoundingBox().height(); + } + return heightResult - containingBlock->borderTop() - containingBlock->borderBottom(); } void RenderBox::calcAbsoluteHorizontal() @@ -1864,7 +1730,7 @@ void RenderBox::calcAbsoluteHorizontal() // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1. // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater - // than or less than the computed m_width. Be careful of box-sizing and + // than or less than the computed width(). Be careful of box-sizing and // percentage issues. // The following is based off of the W3C Working Draft from April 11, 2006 of @@ -1876,8 +1742,8 @@ void RenderBox::calcAbsoluteHorizontal() // We don't use containingBlock(), since we may be positioned by an enclosing // relative positioned inline. - const RenderObject* containerBlock = container(); - + const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); + const int containerWidth = containingBlockWidthForPositioned(containerBlock); // To match WinIE, in quirks mode use the parent's 'direction' property @@ -1919,25 +1785,35 @@ void RenderBox::calcAbsoluteHorizontal() if (left.isAuto() && right.isAuto()) { if (containerDirection == LTR) { // 'staticX' should already have been set through layout of the parent. - int staticPosition = staticX() - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); + int staticPosition = layer()->staticX() - containerBlock->borderLeft(); + for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { + if (po->isBox()) + staticPosition += toRenderBox(po)->x(); + } left.setValue(Fixed, staticPosition); } else { RenderObject* po = parent(); // 'staticX' should already have been set through layout of the parent. - int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); + int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight(); + if (po->isBox()) + staticPosition -= toRenderBox(po)->width(); + for (; po && po != containerBlock; po = po->parent()) { + if (po->isBox()) + staticPosition -= toRenderBox(po)->x(); + } right.setValue(Fixed, staticPosition); } } // Calculate constraint equation values for 'width' case. + int widthResult; + int xResult; calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection, containerWidth, bordersPlusPadding, left, right, marginLeft, marginRight, - m_width, m_marginLeft, m_marginRight, m_x); + widthResult, m_marginLeft, m_marginRight, xResult); + setWidth(widthResult); + setX(xResult); // Calculate constraint equation values for 'max-width' case. if (!style()->maxWidth().isUndefined()) { @@ -1951,11 +1827,11 @@ void RenderBox::calcAbsoluteHorizontal() left, right, marginLeft, marginRight, maxWidth, maxMarginLeft, maxMarginRight, maxXPos); - if (m_width > maxWidth) { - m_width = maxWidth; + if (width() > maxWidth) { + setWidth(maxWidth); m_marginLeft = maxMarginLeft; m_marginRight = maxMarginRight; - m_x = maxXPos; + m_frameRect.setX(maxXPos); } } @@ -1971,25 +1847,28 @@ void RenderBox::calcAbsoluteHorizontal() left, right, marginLeft, marginRight, minWidth, minMarginLeft, minMarginRight, minXPos); - if (m_width < minWidth) { - m_width = minWidth; + if (width() < minWidth) { + setWidth(minWidth); m_marginLeft = minMarginLeft; m_marginRight = minMarginRight; - m_x = minXPos; + m_frameRect.setX(minXPos); } } - if (stretchesToMinIntrinsicWidth() && m_width < minPrefWidth() - bordersPlusPadding) + if (stretchesToMinIntrinsicWidth() && width() < minPrefWidth() - bordersPlusPadding) { calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection, containerWidth, bordersPlusPadding, left, right, marginLeft, marginRight, - m_width, m_marginLeft, m_marginRight, m_x); + widthResult, m_marginLeft, m_marginRight, xResult); + setWidth(widthResult); + setX(xResult); + } - // Put m_width into correct form. - m_width += bordersPlusPadding; + // Put width() into correct form. + setWidth(width() + bordersPlusPadding); } -void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock, TextDirection containerDirection, +void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, const int containerWidth, const int bordersPlusPadding, const Length left, const Length right, const Length marginLeft, const Length marginRight, int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos) @@ -2145,15 +2024,15 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* c // Use computed values to calculate the horizontal position. // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively - // positioned, inline containing block because right now, it is using the xPos + // positioned, inline because right now, it is using the xPos // of the first line box when really it should use the last line box. When // this is fixed elsewhere, this block should be removed. - if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) { - const RenderFlow* flow = static_cast<const RenderFlow*>(containerBlock); + if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) { + const RenderInline* flow = toRenderInline(containerBlock); InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos()); + xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->x() - firstLine->x()); return; } } @@ -2176,7 +2055,7 @@ void RenderBox::calcAbsoluteVertical() // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); + const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const int containerHeight = containingBlockHeightForPositioned(containerBlock); @@ -2207,21 +2086,23 @@ void RenderBox::calcAbsoluteVertical() // Calculate the static distance if needed. if (top.isAuto() && bottom.isAuto()) { // staticY should already have been set through layout of the parent() - int staticTop = staticY() - containerBlock->borderTop(); + int staticTop = layer()->staticY() - containerBlock->borderTop(); for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - if (!po->isTableRow()) - staticTop += po->yPos(); + if (po->isBox() && !po->isTableRow()) + staticTop += toRenderBox(po)->y(); } top.setValue(Fixed, staticTop); } - int height; // Needed to compute overflow. + int h; // Needed to compute overflow. + int y; // Calculate constraint equation values for 'height' case. calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding, top, bottom, marginTop, marginBottom, - height, m_marginTop, m_marginBottom, m_y); + h, m_marginTop, m_marginBottom, y); + setY(y); // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults). // see FIXME 3 @@ -2237,11 +2118,11 @@ void RenderBox::calcAbsoluteVertical() top, bottom, marginTop, marginBottom, maxHeight, maxMarginTop, maxMarginBottom, maxYPos); - if (height > maxHeight) { - height = maxHeight; + if (h > maxHeight) { + h = maxHeight; m_marginTop = maxMarginTop; m_marginBottom = maxMarginBottom; - m_y = maxYPos; + m_frameRect.setY(maxYPos); } } @@ -2256,19 +2137,19 @@ void RenderBox::calcAbsoluteVertical() top, bottom, marginTop, marginBottom, minHeight, minMarginTop, minMarginBottom, minYPos); - if (height < minHeight) { - height = minHeight; + if (h < minHeight) { + h = minHeight; m_marginTop = minMarginTop; m_marginBottom = minMarginBottom; - m_y = minYPos; + m_frameRect.setY(minYPos); } } // Set final height value. - m_height = height + bordersPlusPadding; + setHeight(h + bordersPlusPadding); } -void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock, +void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject* containerBlock, const int containerHeight, const int bordersPlusPadding, const Length top, const Length bottom, const Length marginTop, const Length marginBottom, int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos) @@ -2277,17 +2158,17 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co // converted to the static position in calcAbsoluteVertical() ASSERT(!(top.isAuto() && bottom.isAuto())); - int contentHeight = m_height - bordersPlusPadding; + int contentHeight = height() - bordersPlusPadding; int topValue = 0; - bool heightIsAuto = height.isAuto(); + bool heightIsAuto = h.isAuto(); bool topIsAuto = top.isAuto(); bool bottomIsAuto = bottom.isAuto(); // Height is never unsolved for tables. if (isTable()) { - height.setValue(Fixed, contentHeight); + h.setValue(Fixed, contentHeight); heightIsAuto = false; } @@ -2303,7 +2184,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co // NOTE: It is not necessary to solve for 'bottom' in the over constrained // case because the value is not used for any further calculations. - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = top.calcValue(containerHeight); const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding); @@ -2370,7 +2251,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co heightValue = contentHeight; } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) { // RULE 4: (solve of top) - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight)); } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) { // RULE 5: (solve of height) @@ -2378,7 +2259,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight))); } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) { // RULE 6: (no need solve of bottom) - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = top.calcValue(containerHeight); } } @@ -2397,7 +2278,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // We don't use containingBlock(), since we may be positioned by an enclosing // relative positioned inline. - const RenderObject* containerBlock = container(); + const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const int containerWidth = containingBlockWidthForPositioned(containerBlock); @@ -2419,8 +2300,8 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // NOTE: This value of width is FINAL in that the min/max width calculations // are dealt with in calcReplacedWidth(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); - const int availableSpace = containerWidth - m_width; + setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); + const int availableSpace = containerWidth - width(); /*-----------------------------------------------------------------------*\ * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' @@ -2432,16 +2313,20 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // see FIXME 1 if (containerDirection == LTR) { // 'staticX' should already have been set through layout of the parent. - int staticPosition = staticX() - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); + int staticPosition = layer()->staticX() - containerBlock->borderLeft(); + for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { + if (po->isBox()) + staticPosition += toRenderBox(po)->x(); + } left.setValue(Fixed, staticPosition); } else { RenderObject* po = parent(); // 'staticX' should already have been set through layout of the parent. - int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); + int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight(); + for ( ; po && po != containerBlock; po = po->parent()) { + if (po->isBox()) + staticPosition += toRenderBox(po)->x(); + } right.setValue(Fixed, staticPosition); } } @@ -2538,7 +2423,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() \*-----------------------------------------------------------------------*/ // NOTE: It is not necessary to solve for 'right' when the direction is // LTR because the value is not used. - int totalWidth = m_width + leftValue + rightValue + m_marginLeft + m_marginRight; + int totalWidth = width() + leftValue + rightValue + m_marginLeft + m_marginRight; if (totalWidth > containerWidth && (containerDirection == RTL)) leftValue = containerWidth - (totalWidth - leftValue); @@ -2549,16 +2434,16 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // of the first line box when really it should use the last line box. When // this is fixed elsewhere, this block should be removed. if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) { - const RenderFlow* flow = static_cast<const RenderFlow*>(containerBlock); + const RenderInline* flow = toRenderInline(containerBlock); InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - m_x = leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos()); + m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->x() - firstLine->x())); return; } } - m_x = leftValue + m_marginLeft + containerBlock->borderLeft(); + m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft()); } void RenderBox::calcAbsoluteVerticalReplaced() @@ -2570,7 +2455,7 @@ void RenderBox::calcAbsoluteVerticalReplaced() // the numbers correspond to numbers in spec) // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); + const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const int containerHeight = containingBlockHeightForPositioned(containerBlock); @@ -2588,8 +2473,8 @@ void RenderBox::calcAbsoluteVerticalReplaced() // NOTE: This value of height is FINAL in that the min/max height calculations // are dealt with in calcReplacedHeight(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - m_height = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); - const int availableSpace = containerHeight - m_height; + setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom()); + const int availableSpace = containerHeight - height(); /*-----------------------------------------------------------------------*\ * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' @@ -2598,10 +2483,10 @@ void RenderBox::calcAbsoluteVerticalReplaced() // see FIXME 2 if (top.isAuto() && bottom.isAuto()) { // staticY should already have been set through layout of the parent(). - int staticTop = staticY() - containerBlock->borderTop(); + int staticTop = layer()->staticY() - containerBlock->borderTop(); for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - if (!po->isTableRow()) - staticTop += po->yPos(); + if (po->isBox() && !po->isTableRow()) + staticTop += toRenderBox(po)->y(); } top.setValue(Fixed, staticTop); } @@ -2690,7 +2575,7 @@ void RenderBox::calcAbsoluteVerticalReplaced() // or not. // Use computed values to calculate the vertical position. - m_y = topValue + m_marginTop + containerBlock->borderTop(); + m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop()); } IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine) @@ -2701,12 +2586,11 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements. // FIXME: What about border and padding? - const int caretWidth = 1; - IntRect rect(xPos(), yPos(), caretWidth, m_height); + IntRect rect(x(), y(), caretWidth, height()); TextDirection direction = box ? box->direction() : style()->direction(); if ((!caretOffset) ^ (direction == LTR)) - rect.move(IntSize(m_width - caretWidth, 0)); + rect.move(IntSize(width() - caretWidth, 0)); if (box) { RootInlineBox* rootBox = box->root(); @@ -2724,22 +2608,22 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid // // FIXME: ignoring :first-line, missing good reason to take care of int fontHeight = style()->font().height(); - if (fontHeight > rect.height() || !isReplaced() && !isTable()) + if (fontHeight > rect.height() || (!isReplaced() && !isTable())) rect.setHeight(fontHeight); if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = xPos() + m_width - rect.right(); + *extraWidthToEndOfLine = x() + width() - rect.right(); // Move to local coords - rect.move(-xPos(), -yPos()); + rect.move(-x(), -y()); return rect; } int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_width) + if (!includeSelf || !width()) return 0; - int bottom = m_height; + int bottom = height(); if (isRelPositioned()) bottom += relativePositionOffsetY(); return bottom; @@ -2747,9 +2631,9 @@ int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_height) + if (!includeSelf || !height()) return 0; - int right = m_width; + int right = width(); if (isRelPositioned()) right += relativePositionOffsetX(); return right; @@ -2757,12 +2641,133 @@ int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeS int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_height) - return m_width; + if (!includeSelf || !height()) + return width(); int left = 0; if (isRelPositioned()) left += relativePositionOffsetX(); return left; } +bool RenderBox::isAfterContent(RenderObject* child) const +{ + return (child && child->style()->styleType() == AFTER && (!child->isText() || child->isBR())); +} + +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())); + + int xPos = point.x(); + int yPos = point.y(); + + if (isTable() && node()) { + int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft(); + int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom(); + + if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) { + if (xPos <= right / 2) + return createVisiblePosition(firstDeepEditingPositionForNode(node())); + return createVisiblePosition(lastDeepEditingPositionForNode(node())); + } + } + + // Pass off to the closest child. + int minDist = INT_MAX; + RenderBox* closestRenderer = 0; + int newX = xPos; + int newY = yPos; + if (isTableRow()) { + newX += x(); + newY += y(); + } + for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) { + if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() ) + || renderObject->style()->visibility() != VISIBLE) + continue; + + if (!renderObject->isBox()) + continue; + + RenderBox* renderer = toRenderBox(renderObject); + + int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y()); + int bottom = top + renderer->contentHeight(); + int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x()); + int right = left + renderer->contentWidth(); + + if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) { + if (renderer->isTableRow()) + return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y()); + return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y()); + } + + // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces + // and use a different compare depending on which piece (x, y) is in. + IntPoint cmp; + if (xPos > right) { + if (yPos < top) + cmp = IntPoint(right, top); + else if (yPos > bottom) + cmp = IntPoint(right, bottom); + else + cmp = IntPoint(right, yPos); + } else if (xPos < left) { + if (yPos < top) + cmp = IntPoint(left, top); + else if (yPos > bottom) + cmp = IntPoint(left, bottom); + else + cmp = IntPoint(left, yPos); + } else { + if (yPos < top) + cmp = IntPoint(xPos, top); + else + cmp = IntPoint(xPos, bottom); + } + + int x1minusx2 = cmp.x() - xPos; + int y1minusy2 = cmp.y() - yPos; + + int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2; + if (dist < minDist) { + closestRenderer = renderer; + minDist = dist; + } + } + + if (closestRenderer) + return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y()); + + return createVisiblePosition(firstDeepEditingPositionForNode(node())); +} + +bool RenderBox::shrinkToAvoidFloats() const +{ + // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this + // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the + // current remaining width on a line. + if ((isInline() && !isHTMLMarquee()) || !avoidsFloats()) + return false; + + // All auto-width objects that avoid floats should always use lineWidth. + return style()->width().isAuto(); +} + +bool RenderBox::avoidsFloats() const +{ + return isReplaced() || hasOverflowClip() || isHR(); +} + +#if ENABLE(SVG) + +TransformationMatrix RenderBox::localTransform() const +{ + return TransformationMatrix(1, 0, 0, 1, x(), y()); +} + +#endif + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h index 54349fa..95c0637 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h @@ -23,19 +23,127 @@ #ifndef RenderBox_h #define RenderBox_h -#include "RenderObject.h" +#include "RenderBoxModelObject.h" +#include "ScrollTypes.h" namespace WebCore { - enum WidthType { Width, MinWidth, MaxWidth }; +enum WidthType { Width, MinWidth, MaxWidth }; -class RenderBox : public RenderObject { +class RenderBox : public RenderBoxModelObject { public: RenderBox(Node*); virtual ~RenderBox(); - virtual const char* renderName() const { return "RenderBox"; } + // Use this with caution! No type checking is done! + RenderBox* firstChildBox() const; + RenderBox* lastChildBox() const; + int x() const { return m_frameRect.x(); } + int y() const { return m_frameRect.y(); } + int width() const { return m_frameRect.width(); } + int height() const { return m_frameRect.height(); } + + void setX(int x) { m_frameRect.setX(x); } + void setY(int y) { m_frameRect.setY(y); } + void setWidth(int width) { m_frameRect.setWidth(width); } + void setHeight(int height) { m_frameRect.setHeight(height); } + + IntPoint location() const { return m_frameRect.location(); } + IntSize size() const { return m_frameRect.size(); } + + void setLocation(const IntPoint& location) { m_frameRect.setLocation(location); } + void setLocation(int x, int y) { setLocation(IntPoint(x, y)); } + + void setSize(const IntSize& size) { m_frameRect.setSize(size); } + void move(int dx, int dy) { m_frameRect.move(dx, dy); } + + IntRect frameRect() const { return m_frameRect; } + void setFrameRect(const IntRect& rect) { m_frameRect = rect; } + + IntRect borderBoxRect() const { return IntRect(0, 0, width(), height()); } + virtual IntRect borderBoundingBox() const { return borderBoxRect(); } + + // The content area of the box (excludes padding and border). + IntRect contentBoxRect() const { return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), contentWidth(), contentHeight()); } + // The content box in absolute coords. Ignores transforms. + IntRect absoluteContentBox() const; + // The content box converted to absolute coords (taking transforms into account). + FloatQuad absoluteContentQuad() const; + + // Bounds of the outline box in absolute coords. Respects transforms + virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const; + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + + // Use this with caution! No type checking is done! + RenderBox* previousSiblingBox() const; + RenderBox* nextSiblingBox() const; + RenderBox* parentBox() const; + + // The height of a block when you include normal flow overflow spillage out of the bottom + // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside + // it would have an overflow height of borderTop() + paddingTop() + 100px. + virtual int overflowHeight(bool /*includeInterior*/ = true) const { return height(); } + virtual int overflowWidth(bool /*includeInterior*/ = true) const { return width(); } + virtual void setOverflowHeight(int) { } + virtual void setOverflowWidth(int) { } + virtual int overflowLeft(bool /*includeInterior*/ = true) const { return 0; } + virtual int overflowTop(bool /*includeInterior*/ = true) const { return 0; } + virtual IntRect overflowRect(bool /*includeInterior*/ = true) const { return borderBoxRect(); } + + int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } + int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } + + // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) + // to return the remaining width on a given line (and the height of a single line). + virtual int offsetWidth() const { return width(); } + virtual int offsetHeight() const { return height(); } + + // More IE extensions. clientWidth and clientHeight represent the interior of an object + // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth. + int clientLeft() const { return borderLeft(); } + int clientTop() const { return borderTop(); } + int clientWidth() const; + int clientHeight() const; + + // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the + // object has overflow:hidden/scroll/auto specified and also has overflow. + // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like + // textareas can scroll shadow content (but pretend that they are the objects that are + // scrolling). + virtual int scrollLeft() const; + virtual int scrollTop() const; + virtual int scrollWidth() const; + virtual int scrollHeight() const; + virtual void setScrollLeft(int); + virtual void setScrollTop(int); + + virtual int marginTop() const { return m_marginTop; } + virtual int marginBottom() const { return m_marginBottom; } + virtual int marginLeft() const { return m_marginLeft; } + virtual int marginRight() const { return m_marginRight; } + + // The following five functions are used to implement collapsing margins. + // All objects know their maximal positive and negative margins. The + // formula for computing a collapsed margin is |maxPosMargin| - |maxNegmargin|. + // For a non-collapsing box, such as a leaf element, this formula will simply return + // the margin of the element. Blocks override the maxTopMargin and maxBottomMargin + // methods. + virtual bool isSelfCollapsingBlock() const { return false; } + int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); } + int collapsedMarginBottom() const { return maxBottomMargin(true) - maxBottomMargin(false); } + virtual int maxTopMargin(bool positive) const { return positive ? std::max(0, marginTop()) : -std::min(0, marginTop()); } + virtual int maxBottomMargin(bool positive) const { return positive ? std::max(0, marginBottom()) : -std::min(0, marginBottom()); } + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + IntRect reflectionBox() const; + int reflectionOffset() const; + // Given a rect in the object's coordinate space, returns the corresponding rect in the reflection. + IntRect reflectedRect(const IntRect&) const; + + virtual void layout(); virtual void paint(PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -44,33 +152,13 @@ public: virtual int minPrefWidth() const; virtual int maxPrefWidth() const; - virtual int overrideSize() const; - virtual int overrideWidth() const; - virtual int overrideHeight() const; + int overrideSize() const; + int overrideWidth() const; + int overrideHeight() const; virtual void setOverrideSize(int); - virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; - virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; - virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const; - virtual IntSize offsetFromContainer(RenderObject*) const; - - virtual int xPos() const { return m_x; } - virtual int yPos() const { return m_y; } - virtual void setPos(int x, int y); - - virtual int width() const { return m_width; } - virtual int height() const { return m_height; } - virtual void setWidth(int width) { m_width = width; } - virtual void setHeight(int height) { m_height = height; } - - virtual int marginTop() const { return m_marginTop; } - virtual int marginBottom() const { return m_marginBottom; } - virtual int marginLeft() const { return m_marginLeft; } - virtual int marginRight() const { return m_marginRight; } - - virtual IntRect borderBox() const { return IntRect(0, -borderTopExtra(), width(), height() + borderTopExtra() + borderBottomExtra()); } - + int calcBorderBoxWidth(int width) const; int calcBorderBoxHeight(int height) const; int calcContentBoxWidth(int width) const; @@ -84,28 +172,28 @@ public: // shifted. -dwh void calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth); - virtual void position(InlineBox*); + void positionLineBox(InlineBox*); - virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false); + virtual InlineBox* createInlineBox(); + void dirtyLineBoxes(bool fullLayout); // For inline replaced elements, this function returns the inline box that owns us. Enables // the replaced RenderObject to quickly determine what line it is contained on and to easily // iterate over structures on the line. - virtual InlineBox* inlineBoxWrapper() const { return m_inlineBoxWrapper; } - virtual void setInlineBoxWrapper(InlineBox* boxWrapper) { m_inlineBoxWrapper = boxWrapper; } - virtual void deleteLineBoxWrapper(); + InlineBox* inlineBoxWrapper() const { return m_inlineBoxWrapper; } + void setInlineBoxWrapper(InlineBox* boxWrapper) { m_inlineBoxWrapper = boxWrapper; } + void deleteLineBoxWrapper(); virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual IntRect absoluteClippedOverflowRect(); - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); - IntSize offsetForPositionedInContainer(RenderObject*) const; + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); virtual void repaintDuringLayoutIfMoved(const IntRect&); - virtual int containingBlockWidth() const; + virtual int containingBlockWidthForContent() const; virtual void calcWidth(); virtual void calcHeight(); @@ -132,31 +220,36 @@ public: int calcPercentageHeight(const Length& height); + // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) + virtual int availableWidth() const { return contentWidth(); } virtual int availableHeight() const; int availableHeightUsing(const Length&) const; void calcVerticalMargins(); - int relativePositionOffsetX() const; - int relativePositionOffsetY() const; - IntSize relativePositionOffset() const { return IntSize(relativePositionOffsetX(), relativePositionOffsetY()); } + virtual int verticalScrollbarWidth() const; + int horizontalScrollbarHeight() const; + virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); + virtual bool canBeProgramaticallyScrolled(bool) const; + virtual void autoscroll(); + virtual void stopAutoscroll() { } + virtual void panScroll(const IntPoint&); + bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); } + bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); } + bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } + bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } + bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } - virtual RenderLayer* layer() const { return m_layer; } - virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, - int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver); - IntSize calculateBackgroundSize(const FillLayer*, int scaledWidth, int scaledHeight) const; - - virtual int staticX() const; - virtual int staticY() const; - virtual void setStaticX(int staticX); - virtual void setStaticY(int staticY); - - virtual IntRect getOverflowClipRect(int tx, int ty); - virtual IntRect getClipRect(int tx, int ty); + virtual IntRect overflowClipRect(int tx, int ty); + IntRect clipRect(int tx, int ty); + virtual bool hasControlClip() const { return false; } + virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const { return IntRect(); } + bool pushContentsClip(PaintInfo&, int tx, int ty); + void popContentsClip(PaintInfo&, PaintPhase originalPhase, int tx, int ty); + virtual void paintObject(PaintInfo&, int /*tx*/, int /*ty*/) { ASSERT_NOT_REACHED(); } virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); @@ -165,25 +258,40 @@ public: // that just updates the object's position. virtual void tryLayoutDoingPositionedMovementOnly() { - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); // If we shrink to fit our width may have changed, so we still need full layout. - if (oldWidth != m_width) + if (oldWidth != width()) return; calcHeight(); setNeedsLayout(false); } - virtual IntRect maskClipRect(); + IntRect maskClipRect(); + + virtual VisiblePosition positionForPoint(const IntPoint&); + + void removeFloatingOrPositionedChildFromBlockLists(); + virtual int firstLineBoxBaseline() const { return -1; } + virtual int lastLineBoxBaseline() const { return -1; } + + bool shrinkToAvoidFloats() const; + virtual bool avoidsFloats() const; + +#if ENABLE(SVG) + virtual TransformationMatrix localTransform() const; +#endif + protected: - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateBoxModelInfoFromStyle(); - void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); - void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, 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 = CompositeSourceOver); + void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); - void paintMaskImages(const PaintInfo&, int clipY, int clipHeight, int tx, int ty, int width, int height); + void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height); #if PLATFORM(MAC) void paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText); @@ -193,22 +301,26 @@ protected: virtual bool shouldCalculateSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; + private: + bool includeVerticalScrollbarSize() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } + bool includeHorizontalScrollbarSize() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } + void paintRootBoxDecorations(PaintInfo&, int tx, int ty); // Returns true if we did a full repaint bool repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground); - - void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize); - - int containingBlockWidthForPositioned(const RenderObject* containingBlock) const; - int containingBlockHeightForPositioned(const RenderObject* containingBlock) const; + + int containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const; + int containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const; void calcAbsoluteVertical(); - void calcAbsoluteHorizontalValues(Length width, const RenderObject* cb, TextDirection containerDirection, + void calcAbsoluteHorizontalValues(Length width, const RenderBoxModelObject* cb, TextDirection containerDirection, int containerWidth, int bordersPlusPadding, Length left, Length right, Length marginLeft, Length marginRight, int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos); - void calcAbsoluteVerticalValues(Length height, const RenderObject* cb, + void calcAbsoluteVerticalValues(Length height, const RenderBoxModelObject* cb, int containerHeight, int bordersPlusPadding, Length top, Length bottom, Length marginTop, Length marginBottom, int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos); @@ -219,16 +331,16 @@ private: // This function calculates the minimum and maximum preferred widths for an object. // These values are used in shrink-to-fit layout systems. // These include tables, positioned objects, floats and flexible boxes. - virtual void calcPrefWidths() = 0; + virtual void calcPrefWidths() { setPrefWidthsDirty(false); } protected: - // The width/height of the contents + borders + padding. - int m_width; - int m_height; + bool isAfterContent(RenderObject* child) const; - int m_x; - int m_y; +private: + // The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent). + IntRect m_frameRect; +protected: int m_marginLeft; int m_marginRight; int m_marginTop; @@ -240,18 +352,54 @@ protected: // The preferred width of the element if it never breaks any lines at all. int m_maxPrefWidth; - // A pointer to our layer if we have one. - RenderLayer* m_layer; - // For inline replaced elements, the inline box that owns us. InlineBox* m_inlineBoxWrapper; private: // Used to store state between styleWillChange and styleDidChange - static bool s_wasFloating; static bool s_hadOverflowClip; }; +inline RenderBox* toRenderBox(RenderObject* o) +{ + ASSERT(!o || o->isBox()); + return static_cast<RenderBox*>(o); +} + +inline const RenderBox* toRenderBox(const RenderObject* o) +{ + ASSERT(!o || o->isBox()); + return static_cast<const RenderBox*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderBox(const RenderBox*); + +inline RenderBox* RenderBox::previousSiblingBox() const +{ + return toRenderBox(previousSibling()); +} + +inline RenderBox* RenderBox::nextSiblingBox() const +{ + return toRenderBox(nextSibling()); +} + +inline RenderBox* RenderBox::parentBox() const +{ + return toRenderBox(parent()); +} + +inline RenderBox* RenderBox::firstChildBox() const +{ + return toRenderBox(firstChild()); +} + +inline RenderBox* RenderBox::lastChildBox() const +{ + return toRenderBox(lastChild()); +} + } // namespace WebCore #endif // RenderBox_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp new file mode 100644 index 0000000..8973e64 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp @@ -0,0 +1,1177 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) + * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderBoxModelObject.h" + +#include "GraphicsContext.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "ImageBuffer.h" +#include "RenderBlock.h" +#include "RenderInline.h" +#include "RenderLayer.h" +#include "RenderView.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +bool RenderBoxModelObject::s_wasFloating = false; +bool RenderBoxModelObject::s_hadLayer = false; +bool RenderBoxModelObject::s_layerWasSelfPainting = false; + +RenderBoxModelObject::RenderBoxModelObject(Node* node) + : RenderObject(node) + , m_layer(0) +{ +} + +RenderBoxModelObject::~RenderBoxModelObject() +{ + // Our layer should have been destroyed and cleared by now + ASSERT(!hasLayer()); + ASSERT(!m_layer); +} + +void RenderBoxModelObject::destroyLayer() +{ + ASSERT(!hasLayer()); // Callers should have already called setHasLayer(false) + ASSERT(m_layer); + m_layer->destroy(renderArena()); + m_layer = 0; +} + +void RenderBoxModelObject::destroy() +{ + // This must be done before we destroy the RenderObject. + if (m_layer) + m_layer->clearClipRects(); + + // RenderObject::destroy calls back to destroyLayer() for layer destruction + RenderObject::destroy(); +} + +bool RenderBoxModelObject::hasSelfPaintingLayer() const +{ + return m_layer && m_layer->isSelfPaintingLayer(); +} + +void RenderBoxModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +{ + s_wasFloating = isFloating(); + s_hadLayer = hasLayer(); + if (s_hadLayer) + s_layerWasSelfPainting = layer()->isSelfPaintingLayer(); + + // If our z-index changes value or our visibility changes, + // we need to dirty our stacking context's z-order list. + if (style() && newStyle) { + if (parent()) { + // Do a repaint with the old style first, e.g., for example if we go from + // having an outline to not having an outline. + if (diff == StyleDifferenceRepaintLayer) { + layer()->repaintIncludingDescendants(); + if (!(style()->clip() == newStyle->clip())) + layer()->clearClipRectsIncludingDescendants(); + } else if (diff == StyleDifferenceRepaint || newStyle->outlineSize() < style()->outlineSize()) + repaint(); + } + + if (diff == StyleDifferenceLayout) { + // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could + // end up being destroyed. + if (hasLayer()) { + if (style()->position() != newStyle->position() || + style()->zIndex() != newStyle->zIndex() || + style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || + !(style()->clip() == newStyle->clip()) || + style()->hasClip() != newStyle->hasClip() || + style()->opacity() != newStyle->opacity() || + style()->transform() != newStyle->transform()) + layer()->repaintIncludingDescendants(); + } else if (newStyle->hasTransform() || newStyle->opacity() < 1) { + // If we don't have a layer yet, but we are going to get one because of transform or opacity, + // then we need to repaint the old position of the object. + repaint(); + } + } + + if (hasLayer() && (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || + style()->zIndex() != newStyle->zIndex() || + style()->visibility() != newStyle->visibility())) { + layer()->dirtyStackingContextZOrderLists(); + if (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || style()->visibility() != newStyle->visibility()) + layer()->dirtyZOrderLists(); + } + } + + RenderObject::styleWillChange(diff, newStyle); +} + +void RenderBoxModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderObject::styleDidChange(diff, oldStyle); + updateBoxModelInfoFromStyle(); + + if (requiresLayer()) { + if (!layer()) { + if (s_wasFloating && isFloating()) + setChildNeedsLayout(true); + m_layer = new (renderArena()) RenderLayer(this); + setHasLayer(true); + m_layer->insertOnlyThisLayer(); + if (parent() && !needsLayout() && containingBlock()) + m_layer->updateLayerPositions(); + } + } else if (layer() && layer()->parent()) { + setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit. + setHasReflection(false); + m_layer->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer + if (s_wasFloating && isFloating()) + setChildNeedsLayout(true); + } + + if (layer()) { + layer()->styleChanged(diff, oldStyle); + if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting) + setChildNeedsLayout(true); + } +} + +void RenderBoxModelObject::updateBoxModelInfoFromStyle() +{ + // Set the appropriate bits for a box model object. Since all bits are cleared in styleWillChange, + // we only check for bits that could possibly be set to true. + setHasBoxDecorations(style()->hasBorder() || style()->hasBackground() || style()->hasAppearance() || style()->boxShadow()); + setInline(style()->isDisplayInlineType()); + setRelPositioned(style()->position() == RelativePosition); +} + +int RenderBoxModelObject::relativePositionOffsetX() const +{ + if (!style()->left().isAuto()) { + if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL) + return -style()->right().calcValue(containingBlockWidthForContent()); + return style()->left().calcValue(containingBlockWidthForContent()); + } + if (!style()->right().isAuto()) + return -style()->right().calcValue(containingBlockWidthForContent()); + return 0; +} + +int RenderBoxModelObject::relativePositionOffsetY() const +{ + if (!style()->top().isAuto()) + return style()->top().calcValue(containingBlock()->availableHeight()); + else if (!style()->bottom().isAuto()) + return -style()->bottom().calcValue(containingBlock()->availableHeight()); + + return 0; +} + +int RenderBoxModelObject::offsetLeft() const +{ + // If the element is the HTML body element or does not have an associated box + // return 0 and stop this algorithm. + if (isBody()) + return 0; + + RenderBoxModelObject* offsetPar = offsetParent(); + int xPos = (isBox() ? toRenderBox(this)->x() : 0); + + // If the offsetParent of the element is null, or is the HTML body element, + // return the distance between the canvas origin and the left border edge + // of the element and stop this algorithm. + if (offsetPar) { + if (offsetPar->isBox() && !offsetPar->isBody()) + xPos -= toRenderBox(offsetPar)->borderLeft(); + if (!isPositioned()) { + if (isRelPositioned()) + xPos += relativePositionOffsetX(); + RenderObject* curr = parent(); + while (curr && curr != offsetPar) { + // FIXME: What are we supposed to do inside SVG content? + if (curr->isBox() && !curr->isTableRow()) + xPos += toRenderBox(curr)->x(); + curr = curr->parent(); + } + if (offsetPar->isBox() && offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) + xPos += toRenderBox(offsetPar)->x(); + } + } + + return xPos; +} + +int RenderBoxModelObject::offsetTop() const +{ + // If the element is the HTML body element or does not have an associated box + // return 0 and stop this algorithm. + if (isBody()) + return 0; + + RenderBoxModelObject* offsetPar = offsetParent(); + int yPos = (isBox() ? toRenderBox(this)->y() : 0); + + // If the offsetParent of the element is null, or is the HTML body element, + // return the distance between the canvas origin and the top border edge + // of the element and stop this algorithm. + if (offsetPar) { + if (offsetPar->isBox() && !offsetPar->isBody()) + yPos -= toRenderBox(offsetPar)->borderTop(); + if (!isPositioned()) { + if (isRelPositioned()) + yPos += relativePositionOffsetY(); + RenderObject* curr = parent(); + while (curr && curr != offsetPar) { + // FIXME: What are we supposed to do inside SVG content? + if (curr->isBox() && !curr->isTableRow()) + yPos += toRenderBox(curr)->y(); + curr = curr->parent(); + } + if (offsetPar->isBox() && offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) + yPos += toRenderBox(offsetPar)->y(); + } + } + return yPos; +} + +int RenderBoxModelObject::paddingTop(bool) const +{ + int w = 0; + Length padding = style()->paddingTop(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBoxModelObject::paddingBottom(bool) const +{ + int w = 0; + Length padding = style()->paddingBottom(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBoxModelObject::paddingLeft(bool) const +{ + int w = 0; + Length padding = style()->paddingLeft(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBoxModelObject::paddingRight(bool) const +{ + int w = 0; + Length padding = style()->paddingRight(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + + +void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) +{ + GraphicsContext* context = paintInfo.context; + bool includeLeftEdge = box ? box->includeLeftEdge() : true; + bool includeRightEdge = box ? box->includeRightEdge() : true; + int bLeft = includeLeftEdge ? borderLeft() : 0; + int bRight = includeRightEdge ? borderRight() : 0; + int pLeft = includeLeftEdge ? paddingLeft() : 0; + int pRight = includeRightEdge ? paddingRight() : 0; + + bool clippedToBorderRadius = false; + if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) { + context->save(); + + IntSize topLeft, topRight, bottomLeft, bottomRight; + IntRect borderRect(tx, ty, w, h); + style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight); + + context->addRoundedRectClip(borderRect, includeLeftEdge ? topLeft : IntSize(), + includeRightEdge ? topRight : IntSize(), + includeLeftEdge ? bottomLeft : IntSize(), + includeRightEdge ? bottomRight : IntSize()); + clippedToBorderRadius = true; + } + + if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { + // Clip to the padding or content boxes as necessary. + bool includePadding = bgLayer->clip() == ContentFillBox; + int x = tx + bLeft + (includePadding ? pLeft : 0); + int y = ty + borderTop() + (includePadding ? paddingTop() : 0); + int width = w - bLeft - bRight - (includePadding ? pLeft + pRight : 0); + int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0); + context->save(); + context->clip(IntRect(x, y, width, height)); + } else if (bgLayer->clip() == TextFillBox) { + // We have to draw our text into a mask that can then be used to clip background drawing. + // First figure out how big the mask has to be. It should be no bigger than what we need + // to actually render, so we should intersect the dirty rect with the border box of the background. + IntRect maskRect(tx, ty, w, h); + maskRect.intersect(paintInfo.rect); + + // Now create the mask. + OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); + if (!maskImage) + return; + + GraphicsContext* maskImageContext = maskImage->context(); + maskImageContext->translate(-maskRect.x(), -maskRect.y()); + + // Now add the text to the clip. We do this by painting using a special paint phase that signals to + // InlineTextBoxes that they should just add their contents to the clip. + PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0); + if (box) + box->paint(info, tx - box->x(), ty - box->y()); + else { + int x = isBox() ? toRenderBox(this)->x() : 0; + int y = isBox() ? toRenderBox(this)->y() : 0; + paint(info, tx - x, ty - y); + } + + // The mask has been created. Now we just need to clip to it. + context->save(); + context->clipToImageBuffer(maskRect, maskImage.get()); + } + + StyleImage* bg = bgLayer->image(); + bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom()); + Color bgColor = c; + + // When this style flag is set, change existing background colors and images to a solid white background. + // If there's no bg color or image, leave it untouched to avoid affecting transparency. + // We don't try to avoid loading the background images, because this style flag is only set + // when printing, and at that point we've already loaded the background images anyway. (To avoid + // loading the background images we'd have to do this check when applying styles rather than + // while rendering.) + if (style()->forceBackgroundsToWhite()) { + // Note that we can't reuse this variable below because the bgColor might be changed + bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0; + if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { + bgColor = Color::white; + shouldPaintBackgroundImage = false; + } + } + + bool isRoot = this->isRoot(); + + // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with + // no background in the child document should show the parent's background. + bool isOpaqueRoot = false; + if (isRoot) { + isOpaqueRoot = true; + if (!bgLayer->next() && !(bgColor.isValid() && bgColor.alpha() == 255) && view()->frameView()) { + Element* ownerElement = document()->ownerElement(); + if (ownerElement) { + if (!ownerElement->hasTagName(frameTag)) { + // 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(); + if (body) { + // Can't scroll a frameset document anyway. + isOpaqueRoot = body->hasLocalName(framesetTag); + } + } + } else + isOpaqueRoot = !view()->frameView()->isTransparent(); + } + view()->frameView()->setContentIsOpaque(isOpaqueRoot); + } + + // Paint the color first underneath all images. + if (!bgLayer->next()) { + IntRect rect(tx, ty, w, h); + rect.intersect(paintInfo.rect); + // If we have an alpha and we are painting the root element, go ahead and blend with the base background color. + if (isOpaqueRoot) { + Color baseColor = view()->frameView()->baseBackgroundColor(); + if (baseColor.alpha() > 0) { + context->save(); + context->setCompositeOperation(CompositeCopy); + context->fillRect(rect, baseColor); + context->restore(); + } else + context->clearRect(rect); + } + + if (bgColor.isValid() && bgColor.alpha() > 0) + context->fillRect(rect, bgColor); + } + + // no progressive loading of the background image + if (shouldPaintBackgroundImage) { + IntRect destRect; + IntPoint phase; + IntSize tileSize; + + calculateBackgroundImageGeometry(bgLayer, tx, ty, w, h, destRect, phase, tileSize); + IntPoint destOrigin = destRect.location(); + destRect.intersect(paintInfo.rect); + 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); + } + } + + if (bgLayer->clip() != BorderFillBox) + // Undo the background clip + context->restore(); + + if (clippedToBorderRadius) + // Undo the border radius clip + context->restore(); +} + +IntSize RenderBoxModelObject::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const +{ + StyleImage* bg = bgLayer->image(); + bg->setImageContainerSize(IntSize(scaledWidth, scaledHeight)); // Use the box established by background-origin. + + if (bgLayer->isSizeSet()) { + int w = scaledWidth; + int h = scaledHeight; + Length bgWidth = bgLayer->size().width(); + Length bgHeight = bgLayer->size().height(); + + if (bgWidth.isFixed()) + w = bgWidth.value(); + else if (bgWidth.isPercent()) + w = bgWidth.calcValue(scaledWidth); + + if (bgHeight.isFixed()) + h = bgHeight.value(); + else if (bgHeight.isPercent()) + h = bgHeight.calcValue(scaledHeight); + + // If one of the values is auto we have to use the appropriate + // scale to maintain our aspect ratio. + if (bgWidth.isAuto() && !bgHeight.isAuto()) + w = bg->imageSize(this, style()->effectiveZoom()).width() * h / bg->imageSize(this, style()->effectiveZoom()).height(); + else if (!bgWidth.isAuto() && bgHeight.isAuto()) + h = bg->imageSize(this, style()->effectiveZoom()).height() * w / bg->imageSize(this, style()->effectiveZoom()).width(); + else if (bgWidth.isAuto() && bgHeight.isAuto()) { + // If both width and height are auto, we just want to use the image's + // intrinsic size. + w = bg->imageSize(this, style()->effectiveZoom()).width(); + h = bg->imageSize(this, style()->effectiveZoom()).height(); + } + + return IntSize(max(1, w), max(1, h)); + } else + return bg->imageSize(this, style()->effectiveZoom()); +} + +void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgLayer, int tx, int ty, int w, int h, + IntRect& destRect, IntPoint& phase, IntSize& tileSize) +{ + int pw; + int ph; + int left = 0; + int right = 0; + int top = 0; + int bottom = 0; + int cx; + int cy; + int rw = 0; + int rh = 0; + + // CSS2 chapter 14.2.1 + + if (bgLayer->attachment()) { + // Scroll + if (bgLayer->origin() != BorderFillBox) { + left = borderLeft(); + right = borderRight(); + top = borderTop(); + bottom = borderBottom(); + if (bgLayer->origin() == ContentFillBox) { + left += paddingLeft(); + right += paddingRight(); + top += paddingTop(); + bottom += paddingBottom(); + } + } + + // The background of the box generated by the root element covers the entire canvas including + // its margins. Since those were added in already, we have to factor them out when computing the + // box used by background-origin/size/position. + if (isRoot()) { + rw = toRenderBox(this)->width() - left - right; + rh = toRenderBox(this)->height() - top - bottom; + left += marginLeft(); + right += marginRight(); + top += marginTop(); + bottom += marginBottom(); + } + cx = tx; + cy = ty; + pw = w - left - right; + ph = h - top - bottom; + } else { + // Fixed + IntRect vr = viewRect(); + cx = vr.x(); + cy = vr.y(); + pw = vr.width(); + ph = vr.height(); + } + + int sx = 0; + int sy = 0; + int cw; + int ch; + + IntSize scaledImageSize; + if (isRoot() && bgLayer->attachment()) + scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh); + else + scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph); + + int scaledImageWidth = scaledImageSize.width(); + int scaledImageHeight = scaledImageSize.height(); + + EFillRepeat backgroundRepeat = bgLayer->repeat(); + + int xPosition; + if (isRoot() && bgLayer->attachment()) + xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true); + else + xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true); + if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatXFill) { + cw = pw + left + right; + sx = scaledImageWidth ? scaledImageWidth - (xPosition + left) % scaledImageWidth : 0; + } else { + cx += max(xPosition + left, 0); + sx = -min(xPosition + left, 0); + cw = scaledImageWidth + min(xPosition + left, 0); + } + + int yPosition; + if (isRoot() && bgLayer->attachment()) + yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true); + else + yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true); + if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatYFill) { + ch = ph + top + bottom; + sy = scaledImageHeight ? scaledImageHeight - (yPosition + top) % scaledImageHeight : 0; + } else { + cy += max(yPosition + top, 0); + sy = -min(yPosition + top, 0); + ch = scaledImageHeight + min(yPosition + top, 0); + } + + if (!bgLayer->attachment()) { + sx += max(tx - cx, 0); + sy += max(ty - cy, 0); + } + + destRect = IntRect(cx, cy, cw, ch); + destRect.intersect(IntRect(tx, ty, w, h)); + phase = IntPoint(sx, sy); + tileSize = IntSize(scaledImageWidth, scaledImageHeight); +} + +int RenderBoxModelObject::verticalPosition(bool firstLine) const +{ + // This method determines the vertical position for inline elements. + ASSERT(isInline()); + if (!isInline()) + return 0; + + int vpos = 0; + EVerticalAlign va = style()->verticalAlign(); + if (va == TOP) + vpos = PositionTop; + else if (va == BOTTOM) + vpos = PositionBottom; + else { + bool checkParent = parent()->isRenderInline() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM; + vpos = checkParent ? toRenderInline(parent())->verticalPositionFromCache(firstLine) : 0; + // don't allow elements nested inside text-top to have a different valignment. + if (va == BASELINE) + return vpos; + + const Font& f = parent()->style(firstLine)->font(); + int fontsize = f.pixelSize(); + + if (va == SUB) + vpos += fontsize / 5 + 1; + else if (va == SUPER) + vpos -= fontsize / 3 + 1; + else if (va == TEXT_TOP) + vpos += baselinePosition(firstLine) - f.ascent(); + else if (va == MIDDLE) + 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. + vpos -= (lineHeight(firstLine) - baselinePosition(firstLine)); + } else if (va == BASELINE_MIDDLE) + vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine); + else if (va == LENGTH) + vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine)); + } + + return vpos; +} + +bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style, + const NinePieceImage& ninePieceImage, CompositeOperator op) +{ + StyleImage* styleImage = ninePieceImage.image(); + if (!styleImage) + return false; + + if (!styleImage->isLoaded()) + return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either. + + if (!styleImage->canRender(style->effectiveZoom())) + return false; + + // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function + // doesn't have any understanding of the zoom that is in effect on the tile. + styleImage->setImageContainerSize(IntSize(w, h)); + IntSize imageSize = styleImage->imageSize(this, 1.0f); + int imageWidth = imageSize.width(); + int imageHeight = imageSize.height(); + + int topSlice = min(imageHeight, ninePieceImage.m_slices.top().calcValue(imageHeight)); + int bottomSlice = min(imageHeight, ninePieceImage.m_slices.bottom().calcValue(imageHeight)); + int leftSlice = min(imageWidth, ninePieceImage.m_slices.left().calcValue(imageWidth)); + int rightSlice = min(imageWidth, ninePieceImage.m_slices.right().calcValue(imageWidth)); + + ENinePieceImageRule hRule = ninePieceImage.horizontalRule(); + ENinePieceImageRule vRule = ninePieceImage.verticalRule(); + + bool fitToBorder = style->borderImage() == ninePieceImage; + + int leftWidth = fitToBorder ? style->borderLeftWidth() : leftSlice; + int topWidth = fitToBorder ? style->borderTopWidth() : topSlice; + int rightWidth = fitToBorder ? style->borderRightWidth() : rightSlice; + int bottomWidth = fitToBorder ? style->borderBottomWidth() : bottomSlice; + + bool drawLeft = leftSlice > 0 && leftWidth > 0; + bool drawTop = topSlice > 0 && topWidth > 0; + bool drawRight = rightSlice > 0 && rightWidth > 0; + bool drawBottom = bottomSlice > 0 && bottomWidth > 0; + bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - leftWidth - rightWidth) > 0 && + (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0; + + Image* image = styleImage->image(this, imageSize); + + if (drawLeft) { + // Paint the top and bottom left corners. + + // 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), + 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), + 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, + h - topWidth - bottomWidth), + IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice), + Image::StretchTile, (Image::TileRule)vRule, op); + } + + if (drawRight) { + // Paint the top and bottom right corners + // 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), + 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), + IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op); + + // Paint the right edge. + graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, + h - topWidth - bottomWidth), + IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice), + Image::StretchTile, (Image::TileRule)vRule, op); + } + + // Paint the top edge. + if (drawTop) + graphicsContext->drawTiledImage(image, 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, + 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, + h - topWidth - bottomWidth), + IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice), + (Image::TileRule)hRule, (Image::TileRule)vRule, op); + + return true; +} + +void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, + const RenderStyle* style, bool begin, bool end) +{ + if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage())) + return; + + const Color& topColor = style->borderTopColor(); + const Color& bottomColor = style->borderBottomColor(); + const Color& leftColor = style->borderLeftColor(); + const Color& rightColor = style->borderRightColor(); + + bool topTransparent = style->borderTopIsTransparent(); + bool bottomTransparent = style->borderBottomIsTransparent(); + bool rightTransparent = style->borderRightIsTransparent(); + bool leftTransparent = style->borderLeftIsTransparent(); + + EBorderStyle topStyle = style->borderTopStyle(); + EBorderStyle bottomStyle = style->borderBottomStyle(); + EBorderStyle leftStyle = style->borderLeftStyle(); + EBorderStyle rightStyle = style->borderRightStyle(); + + bool renderTop = topStyle > BHIDDEN && !topTransparent; + bool renderLeft = leftStyle > BHIDDEN && begin && !leftTransparent; + bool renderRight = rightStyle > BHIDDEN && end && !rightTransparent; + bool renderBottom = bottomStyle > BHIDDEN && !bottomTransparent; + + bool renderRadii = false; + IntSize topLeft, topRight, bottomLeft, bottomRight; + + if (style->hasBorderRadius()) { + IntRect borderRect = IntRect(tx, ty, w, h); + + IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; + style->getBorderRadiiForRect(borderRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + if (begin) { + topLeft = topLeftRadius; + bottomLeft = bottomLeftRadius; + } + if (end) { + topRight = topRightRadius; + bottomRight = bottomRightRadius; + } + + renderRadii = true; + + // Clip to the rounded rectangle. + graphicsContext->save(); + graphicsContext->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight); + } + + int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan; + float thickness; + bool upperLeftBorderStylesMatch = renderLeft && (topStyle == leftStyle) && (topColor == leftColor); + bool upperRightBorderStylesMatch = renderRight && (topStyle == rightStyle) && (topColor == rightColor) && (topStyle != OUTSET) && (topStyle != RIDGE) && (topStyle != INSET) && (topStyle != GROOVE); + bool lowerLeftBorderStylesMatch = renderLeft && (bottomStyle == leftStyle) && (bottomColor == leftColor) && (bottomStyle != OUTSET) && (bottomStyle != RIDGE) && (bottomStyle != INSET) && (bottomStyle != GROOVE); + bool lowerRightBorderStylesMatch = renderRight && (bottomStyle == rightStyle) && (bottomColor == rightColor); + + if (renderTop) { + bool ignore_left = (renderRadii && topLeft.width() > 0) || + (topColor == leftColor && topTransparent == leftTransparent && topStyle >= OUTSET && + (leftStyle == DOTTED || leftStyle == DASHED || leftStyle == SOLID || leftStyle == OUTSET)); + + bool ignore_right = (renderRadii && topRight.width() > 0) || + (topColor == rightColor && topTransparent == rightTransparent && topStyle >= OUTSET && + (rightStyle == DOTTED || rightStyle == DASHED || rightStyle == SOLID || rightStyle == INSET)); + + int x = tx; + int x2 = tx + w; + if (renderRadii) { + x += topLeft.width(); + x2 -= topRight.width(); + } + + drawLineForBoxSide(graphicsContext, x, ty, x2, ty + style->borderTopWidth(), BSTop, topColor, style->color(), topStyle, + ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth()); + + if (renderRadii) { + int leftY = ty; + + // We make the arc double thick and let the clip rect take care of clipping the extra off. + // We're doing this because it doesn't seem possible to match the curve of the clip exactly + // with the arc-drawing function. + thickness = style->borderTopWidth() * 2; + + if (topLeft.width()) { + int leftX = tx; + // The inner clip clips inside the arc. This is especially important for 1px borders. + bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width()) + && (style->borderTopWidth() < topLeft.height()) + && (topStyle != DOUBLE || style->borderTopWidth() > 6); + if (applyLeftInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2), + style->borderTopWidth()); + } + + firstAngleStart = 90; + firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45; + + // Draw upper left arc + drawArcForBoxSide(graphicsContext, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan, + BSTop, topColor, style->color(), topStyle, true); + if (applyLeftInnerClip) + graphicsContext->restore(); + } + + if (topRight.width()) { + int rightX = tx + w - topRight.width() * 2; + bool applyRightInnerClip = (style->borderRightWidth() < topRight.width()) + && (style->borderTopWidth() < topRight.height()) + && (topStyle != DOUBLE || style->borderTopWidth() > 6); + if (applyRightInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2), + style->borderTopWidth()); + } + + if (upperRightBorderStylesMatch) { + secondAngleStart = 0; + secondAngleSpan = 90; + } else { + secondAngleStart = 45; + secondAngleSpan = 45; + } + + // Draw upper right arc + drawArcForBoxSide(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan, + BSTop, topColor, style->color(), topStyle, false); + if (applyRightInnerClip) + graphicsContext->restore(); + } + } + } + + if (renderBottom) { + bool ignore_left = (renderRadii && bottomLeft.width() > 0) || + (bottomColor == leftColor && bottomTransparent == leftTransparent && bottomStyle >= OUTSET && + (leftStyle == DOTTED || leftStyle == DASHED || leftStyle == SOLID || leftStyle == OUTSET)); + + bool ignore_right = (renderRadii && bottomRight.width() > 0) || + (bottomColor == rightColor && bottomTransparent == rightTransparent && bottomStyle >= OUTSET && + (rightStyle == DOTTED || rightStyle == DASHED || rightStyle == SOLID || rightStyle == INSET)); + + int x = tx; + int x2 = tx + w; + if (renderRadii) { + x += bottomLeft.width(); + x2 -= bottomRight.width(); + } + + drawLineForBoxSide(graphicsContext, x, ty + h - style->borderBottomWidth(), x2, ty + h, BSBottom, bottomColor, style->color(), bottomStyle, + ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth()); + + if (renderRadii) { + thickness = style->borderBottomWidth() * 2; + + if (bottomLeft.width()) { + int leftX = tx; + int leftY = ty + h - bottomLeft.height() * 2; + bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width()) + && (style->borderBottomWidth() < bottomLeft.height()) + && (bottomStyle != DOUBLE || style->borderBottomWidth() > 6); + if (applyLeftInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2), + style->borderBottomWidth()); + } + + if (lowerLeftBorderStylesMatch) { + firstAngleStart = 180; + firstAngleSpan = 90; + } else { + firstAngleStart = 225; + firstAngleSpan = 45; + } + + // Draw lower left arc + drawArcForBoxSide(graphicsContext, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan, + BSBottom, bottomColor, style->color(), bottomStyle, true); + if (applyLeftInnerClip) + graphicsContext->restore(); + } + + if (bottomRight.width()) { + int rightY = ty + h - bottomRight.height() * 2; + int rightX = tx + w - bottomRight.width() * 2; + bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width()) + && (style->borderBottomWidth() < bottomRight.height()) + && (bottomStyle != DOUBLE || style->borderBottomWidth() > 6); + if (applyRightInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(rightX, rightY, bottomRight.width() * 2, bottomRight.height() * 2), + style->borderBottomWidth()); + } + + secondAngleStart = 270; + secondAngleSpan = lowerRightBorderStylesMatch ? 90 : 45; + + // Draw lower right arc + drawArcForBoxSide(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan, + BSBottom, bottomColor, style->color(), bottomStyle, false); + if (applyRightInnerClip) + graphicsContext->restore(); + } + } + } + + if (renderLeft) { + bool ignore_top = (renderRadii && topLeft.height() > 0) || + (topColor == leftColor && topTransparent == leftTransparent && leftStyle >= OUTSET && + (topStyle == DOTTED || topStyle == DASHED || topStyle == SOLID || topStyle == OUTSET)); + + bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) || + (bottomColor == leftColor && bottomTransparent == leftTransparent && leftStyle >= OUTSET && + (bottomStyle == DOTTED || bottomStyle == DASHED || bottomStyle == SOLID || bottomStyle == INSET)); + + int y = ty; + int y2 = ty + h; + if (renderRadii) { + y += topLeft.height(); + y2 -= bottomLeft.height(); + } + + drawLineForBoxSide(graphicsContext, tx, y, tx + style->borderLeftWidth(), y2, BSLeft, leftColor, style->color(), leftStyle, + ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); + + if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) { + int topX = tx; + thickness = style->borderLeftWidth() * 2; + + if (!upperLeftBorderStylesMatch && topLeft.width()) { + int topY = ty; + bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width()) + && (style->borderTopWidth() < topLeft.height()) + && (leftStyle != DOUBLE || style->borderLeftWidth() > 6); + if (applyTopInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2), + style->borderLeftWidth()); + } + + firstAngleStart = 135; + firstAngleSpan = 45; + + // Draw top left arc + drawArcForBoxSide(graphicsContext, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan, + BSLeft, leftColor, style->color(), leftStyle, true); + if (applyTopInnerClip) + graphicsContext->restore(); + } + + if (!lowerLeftBorderStylesMatch && bottomLeft.width()) { + int bottomY = ty + h - bottomLeft.height() * 2; + bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width()) + && (style->borderBottomWidth() < bottomLeft.height()) + && (leftStyle != DOUBLE || style->borderLeftWidth() > 6); + if (applyBottomInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2), + style->borderLeftWidth()); + } + + secondAngleStart = 180; + secondAngleSpan = 45; + + // Draw bottom left arc + drawArcForBoxSide(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan, + BSLeft, leftColor, style->color(), leftStyle, false); + if (applyBottomInnerClip) + graphicsContext->restore(); + } + } + } + + if (renderRight) { + bool ignore_top = (renderRadii && topRight.height() > 0) || + ((topColor == rightColor) && (topTransparent == rightTransparent) && + (rightStyle >= DOTTED || rightStyle == INSET) && + (topStyle == DOTTED || topStyle == DASHED || topStyle == SOLID || topStyle == OUTSET)); + + bool ignore_bottom = (renderRadii && bottomRight.height() > 0) || + ((bottomColor == rightColor) && (bottomTransparent == rightTransparent) && + (rightStyle >= DOTTED || rightStyle == INSET) && + (bottomStyle == DOTTED || bottomStyle == DASHED || bottomStyle == SOLID || bottomStyle == INSET)); + + int y = ty; + int y2 = ty + h; + if (renderRadii) { + y += topRight.height(); + y2 -= bottomRight.height(); + } + + drawLineForBoxSide(graphicsContext, tx + w - style->borderRightWidth(), y, tx + w, y2, BSRight, rightColor, style->color(), rightStyle, + ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); + + if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) { + thickness = style->borderRightWidth() * 2; + + if (!upperRightBorderStylesMatch && topRight.width()) { + int topX = tx + w - topRight.width() * 2; + int topY = ty; + bool applyTopInnerClip = (style->borderRightWidth() < topRight.width()) + && (style->borderTopWidth() < topRight.height()) + && (rightStyle != DOUBLE || style->borderRightWidth() > 6); + if (applyTopInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2), + style->borderRightWidth()); + } + + firstAngleStart = 0; + firstAngleSpan = 45; + + // Draw top right arc + drawArcForBoxSide(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan, + BSRight, rightColor, style->color(), rightStyle, true); + if (applyTopInnerClip) + graphicsContext->restore(); + } + + if (!lowerRightBorderStylesMatch && bottomRight.width()) { + int bottomX = tx + w - bottomRight.width() * 2; + int bottomY = ty + h - bottomRight.height() * 2; + bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width()) + && (style->borderBottomWidth() < bottomRight.height()) + && (rightStyle != DOUBLE || style->borderRightWidth() > 6); + if (applyBottomInnerClip) { + graphicsContext->save(); + graphicsContext->addInnerRoundedRectClip(IntRect(bottomX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2), + style->borderRightWidth()); + } + + secondAngleStart = 315; + secondAngleSpan = 45; + + // Draw bottom right arc + drawArcForBoxSide(graphicsContext, bottomX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan, + BSRight, rightColor, style->color(), rightStyle, false); + if (applyBottomInnerClip) + graphicsContext->restore(); + } + } + } + + if (renderRadii) + graphicsContext->restore(); +} + +void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end) +{ + // FIXME: Deal with border-image. Would be great to use border-image as a mask. + + IntRect rect(tx, ty, w, h); + bool hasBorderRadius = s->hasBorderRadius(); + bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255; + for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) { + context->save(); + + IntSize shadowOffset(shadow->x, shadow->y); + int shadowBlur = shadow->blur; + IntRect fillRect(rect); + + if (hasBorderRadius) { + IntRect shadowRect(rect); + shadowRect.inflate(shadowBlur); + shadowRect.move(shadowOffset); + context->clip(shadowRect); + + // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not + // bleed in (due to antialiasing) if the context is transformed. + IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0); + shadowOffset -= extraOffset; + fillRect.move(extraOffset); + } + + context->setShadow(shadowOffset, shadowBlur, shadow->color); + if (hasBorderRadius) { + IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; + s->getBorderRadiiForRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + IntSize topLeft = begin ? topLeftRadius : IntSize(); + IntSize topRight = end ? topRightRadius : IntSize(); + IntSize bottomLeft = begin ? bottomLeftRadius : IntSize(); + IntSize bottomRight = end ? bottomRightRadius : IntSize(); + + if (!hasOpaqueBackground) + context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + } else { + if (!hasOpaqueBackground) + context->clipOut(rect); + context->fillRect(fillRect, Color::black); + } + context->restore(); + } +} + +int RenderBoxModelObject::containingBlockWidthForContent() const +{ + return containingBlock()->availableWidth(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h new file mode 100644 index 0000000..9feaf2f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 2006, 2007, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderBoxModelObject_h +#define RenderBoxModelObject_h + +#include "RenderObject.h" + +namespace WebCore { + +// Values for vertical alignment. +const int PositionTop = -0x7fffffff; +const int PositionBottom = 0x7fffffff; +const int PositionUndefined = 0x80000000; + +// This class is the base for all objects that adhere to the CSS box model as described +// at http://www.w3.org/TR/CSS21/box.html + +class RenderBoxModelObject : public RenderObject { +public: + RenderBoxModelObject(Node*); + virtual ~RenderBoxModelObject(); + + virtual void destroy(); + + int relativePositionOffsetX() const; + int relativePositionOffsetY() const; + IntSize relativePositionOffset() const { return IntSize(relativePositionOffsetX(), relativePositionOffsetY()); } + + // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) + // to return the remaining width on a given line (and the height of a single line). + virtual int offsetLeft() const; + virtual int offsetTop() const; + virtual int offsetWidth() const = 0; + virtual int offsetHeight() const = 0; + + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateBoxModelInfoFromStyle(); + + bool hasSelfPaintingLayer() const; + RenderLayer* layer() const { return m_layer; } + virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } + + // This will work on inlines to return the bounding box of all of the lines' border boxes. + virtual IntRect borderBoundingBox() const = 0; + + // Virtual since table cells override + virtual int paddingTop(bool includeIntrinsicPadding = true) const; + virtual int paddingBottom(bool includeIntrinsicPadding = true) const; + virtual int paddingLeft(bool includeIntrinsicPadding = true) const; + virtual int paddingRight(bool includeIntrinsicPadding = true) const; + + virtual int borderTop() const { return style()->borderTopWidth(); } + virtual int borderBottom() const { return style()->borderBottomWidth(); } + virtual int borderLeft() const { return style()->borderLeftWidth(); } + virtual int borderRight() const { return style()->borderRightWidth(); } + + virtual int marginTop() const = 0; + virtual int marginBottom() const = 0; + virtual int marginLeft() const = 0; + virtual int marginRight() const = 0; + + bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; } + bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; } + + virtual int containingBlockWidthForContent() const; + + virtual void childBecameNonInline(RenderObject* /*child*/) { } + + 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*, 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); + + // The difference between this inline's baseline position and the line's baseline position. + int verticalPosition(bool firstLine) const; + + // Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed + void destroyLayer(); + +protected: + void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize); + IntSize calculateBackgroundSize(const FillLayer*, int scaledWidth, int scaledHeight) const; + +private: + virtual bool isBoxModelObject() const { return true; } + friend class RenderView; + + RenderLayer* m_layer; + + // Used to store state between styleWillChange and styleDidChange + static bool s_wasFloating; + static bool s_hadLayer; + static bool s_layerWasSelfPainting; +}; + +inline RenderBoxModelObject* toRenderBoxModelObject(RenderObject* o) +{ + ASSERT(!o || o->isBoxModelObject()); + return static_cast<RenderBoxModelObject*>(o); +} + +inline const RenderBoxModelObject* toRenderBoxModelObject(const RenderObject* o) +{ + ASSERT(!o || o->isBoxModelObject()); + return static_cast<const RenderBoxModelObject*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderBoxModelObject(const RenderBoxModelObject*); + +} // namespace WebCore + +#endif // RenderBoxModelObject_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp index 10e21c3..b266f42 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp @@ -69,7 +69,7 @@ void RenderButton::removeChild(RenderObject* oldChild) m_inner->removeChild(oldChild); } -void RenderButton::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { if (m_inner) { // RenderBlock::setStyle is going to apply a new style to the inner block, which @@ -81,7 +81,7 @@ void RenderButton::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne RenderBlock::styleWillChange(diff, newStyle); } -void RenderButton::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderButton::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -108,23 +108,26 @@ void RenderButton::setupInnerStyle(RenderStyle* innerStyle) // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is // safe to modify. innerStyle->setBoxFlex(1.0f); - if (style()->hasAppearance()) - theme()->adjustButtonInnerStyle(innerStyle); + + innerStyle->setPaddingTop(Length(theme()->buttonInternalPaddingTop(), Fixed)); + innerStyle->setPaddingRight(Length(theme()->buttonInternalPaddingRight(), Fixed)); + innerStyle->setPaddingBottom(Length(theme()->buttonInternalPaddingBottom(), Fixed)); + innerStyle->setPaddingLeft(Length(theme()->buttonInternalPaddingLeft(), Fixed)); } void RenderButton::updateFromElement() { // If we're an input element, we may need to change our button text. - if (element()->hasTagName(inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(element()); + if (node()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); String value = input->valueWithDefault(); setText(value); } #if ENABLE(WML) - else if (element()->hasTagName(WMLNames::doTag)) { - WMLDoElement* doElement = static_cast<WMLDoElement*>(element()); + else if (node()->hasTagName(WMLNames::doTag)) { + WMLDoElement* doElement = static_cast<WMLDoElement*>(node()); String value = doElement->label(); if (value.isEmpty()) @@ -140,7 +143,7 @@ bool RenderButton::canHaveChildren() const // Input elements can't have children, but button elements can. We'll // write the code assuming any other button types that might emerge in the future // can also have children. - return !element()->hasTagName(inputTag); + return !node()->hasTagName(inputTag); } void RenderButton::setText(const String& str) @@ -161,22 +164,29 @@ void RenderButton::setText(const String& str) } } -void RenderButton::updateBeforeAfterContent(RenderStyle::PseudoId type) +void RenderButton::updateBeforeAfterContent(PseudoId type) { if (m_inner) - m_inner->updateBeforeAfterContentForContainer(type, this); + m_inner->children()->updateBeforeAfterContent(m_inner, type, this); else - updateBeforeAfterContentForContainer(type, this); + children()->updateBeforeAfterContent(this, type); } IntRect RenderButton::controlClipRect(int tx, int ty) const { // Clip to the padding box to at least give content the extra padding space. - return IntRect(tx + borderLeft(), ty + borderTop(), m_width - borderLeft() - borderRight(), m_height - borderTop() - borderBottom()); + return IntRect(tx + borderLeft(), ty + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom()); } void RenderButton::timerFired(Timer<RenderButton>*) { + // FIXME Bug 25110: Ideally we would stop our timer when our Document + // enters the page cache. But we currently have no way of being notified + // when that happens, so we'll just ignore the timer firing as long as + // we're in the cache. + if (document()->inPageCache()) + return; + repaint(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.h b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h index 24e4767..89f7cf8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderButton.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h @@ -39,6 +39,7 @@ public: RenderButton(Node*); virtual const char* renderName() const { return "RenderButton"; } + virtual bool isRenderButton() const { return true; } virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0); virtual void removeChild(RenderObject*); @@ -48,7 +49,7 @@ public: void setupInnerStyle(RenderStyle*); virtual void updateFromElement(); - virtual void updateBeforeAfterContent(RenderStyle::PseudoId); + virtual void updateBeforeAfterContent(PseudoId); virtual bool hasControlClip() const { return true; } virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const; @@ -58,8 +59,8 @@ public: virtual bool canHaveChildren() const; protected: - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual bool hasLineIfEmpty() const { return true; } @@ -72,6 +73,21 @@ protected: bool m_default; }; +inline RenderButton* toRenderButton(RenderObject* o) +{ + ASSERT(!o || o->isRenderButton()); + return static_cast<RenderButton*>(o); +} + +inline const RenderButton* toRenderButton(const RenderObject* o) +{ + ASSERT(!o || o->isRenderButton()); + return static_cast<const RenderButton*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderButton(const RenderButton*); + } // namespace WebCore #endif // RenderButton_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp deleted file mode 100644 index 9f6d737..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp +++ /dev/null @@ -1,701 +0,0 @@ -/** - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "RenderContainer.h" - -#include "AXObjectCache.h" -#include "Document.h" -#include "RenderCounter.h" -#include "RenderImageGeneratedContent.h" -#include "RenderLayer.h" -#include "RenderListItem.h" -#include "RenderTable.h" -#include "RenderTextFragment.h" -#include "RenderView.h" -#include "htmlediting.h" - -namespace WebCore { - -RenderContainer::RenderContainer(Node* node) - : RenderBox(node) - , m_firstChild(0) - , m_lastChild(0) -{ -} - -RenderContainer::~RenderContainer() -{ -} - -void RenderContainer::destroy() -{ - destroyLeftoverChildren(); - RenderBox::destroy(); -} - -void RenderContainer::destroyLeftoverChildren() -{ - while (m_firstChild) { - if (m_firstChild->isListMarker() || (m_firstChild->style()->styleType() == RenderStyle::FIRST_LETTER && !m_firstChild->isText())) - m_firstChild->remove(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment. - else { - // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields. - if (m_firstChild->element()) - m_firstChild->element()->setRenderer(0); - m_firstChild->destroy(); - } - } -} - -bool RenderContainer::canHaveChildren() const -{ - return true; -} - -static void updateListMarkerNumbers(RenderObject* child) -{ - for (RenderObject* r = child; r; r = r->nextSibling()) - if (r->isListItem()) - static_cast<RenderListItem*>(r)->updateValue(); -} - -void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - bool needsTable = false; - - if (newChild->isListItem()) - updateListMarkerNumbers(beforeChild ? beforeChild : m_lastChild); - else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) - needsTable = !isTable(); - else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) - needsTable = !isTable(); - else if (newChild->isTableSection()) - needsTable = !isTable(); - else if (newChild->isTableRow()) - needsTable = !isTableSection(); - else if (newChild->isTableCell()) { - needsTable = !isTableRow(); - // I'm not 100% sure this is the best way to fix this, but without this - // change we recurse infinitely when trying to render the CSS2 test page: - // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. - // See Radar 2925291. - if (needsTable && isTableCell() && !m_firstChild && !newChild->isTableCell()) - needsTable = false; - } - - if (needsTable) { - RenderTable* table; - RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : m_lastChild; - if (afterChild && afterChild->isAnonymous() && afterChild->isTable()) - table = static_cast<RenderTable*>(afterChild); - else { - table = new (renderArena()) RenderTable(document() /* is anonymous */); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE); - table->setStyle(newStyle.release()); - addChild(table, beforeChild); - } - table->addChild(newChild); - } else { - // just add it... - insertChildNode(newChild, beforeChild); - } - - if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { - RefPtr<StringImpl> textToTransform = static_cast<RenderText*>(newChild)->originalText(); - if (textToTransform) - static_cast<RenderText*>(newChild)->setText(textToTransform.release(), true); - } -} - -RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove) -{ - ASSERT(oldChild->parent() == this); - - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or - // that a positioned child got yanked). We also repaint, so that the area exposed when the child - // disappears gets repainted properly. - if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { - oldChild->setNeedsLayoutAndPrefWidthsRecalc(); - oldChild->repaint(); - } - - // If we have a line box wrapper, delete it. - oldChild->deleteLineBoxWrapper(); - - if (!documentBeingDestroyed() && fullRemove) { - // if we remove visible child from an invisible parent, we don't know the layer visibility any more - RenderLayer* layer = 0; - if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { - layer = enclosingLayer(); - layer->dirtyVisibleContentStatus(); - } - - // Keep our layer hierarchy updated. - if (oldChild->firstChild() || oldChild->hasLayer()) { - if (!layer) layer = enclosingLayer(); - oldChild->removeLayers(layer); - } - - // renumber ordered lists - if (oldChild->isListItem()) - updateListMarkerNumbers(oldChild->nextSibling()); - - if (oldChild->isPositioned() && childrenInline()) - dirtyLinesFromChangedChild(oldChild); - } - - // If oldChild is the start or end of the selection, then clear the selection to - // avoid problems of invalid pointers. - // FIXME: The SelectionController should be responsible for this when it - // is notified of DOM mutations. - if (!documentBeingDestroyed() && oldChild->isSelectionBorder()) - view()->clearSelection(); - - // remove the child - if (oldChild->previousSibling()) - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); - if (oldChild->nextSibling()) - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); - - if (m_firstChild == oldChild) - m_firstChild = oldChild->nextSibling(); - if (m_lastChild == oldChild) - m_lastChild = oldChild->previousSibling(); - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); - - return oldChild; -} - -void RenderContainer::removeChild(RenderObject* oldChild) -{ - // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode - // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on - // layout anyway). - oldChild->removeFromObjectLists(); - - removeChildNode(oldChild); -} - -RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type) -{ - if (type == RenderStyle::BEFORE) { - RenderObject* first = this; - do { - // Skip list markers. - first = first->firstChild(); - while (first && first->isListMarker()) - first = first->nextSibling(); - } while (first && first->isAnonymous() && first->style()->styleType() == RenderStyle::NOPSEUDO); - if (first && first->style()->styleType() != type) - return 0; - return first; - } - if (type == RenderStyle::AFTER) { - RenderObject* last = this; - do { - last = last->lastChild(); - } while (last && last->isAnonymous() && last->style()->styleType() == RenderStyle::NOPSEUDO && !last->isListMarker()); - if (last && last->style()->styleType() != type) - return 0; - return last; - } - - ASSERT_NOT_REACHED(); - return 0; -} - -void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type) -{ - // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. - if (parent() && parent()->createsAnonymousWrapper()) - return; - updateBeforeAfterContentForContainer(type, this); -} - -static RenderObject* findBeforeAfterParent(RenderObject* object) -{ - // Only table parts need to search for the :before or :after parent - if (!(object->isTable() || object->isTableSection() || object->isTableRow())) - return object; - - RenderObject* beforeAfterParent = object; - while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())) - beforeAfterParent = beforeAfterParent->firstChild(); - return beforeAfterParent; -} - -void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject) -{ - // In CSS2, before/after pseudo-content cannot nest. Check this first. - if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER) - return; - - RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); - RenderObject* child = beforeAfterContainer(type); - - // Whether or not we currently have generated content attached. - bool oldContentPresent = child; - - // Whether or not we now want generated content. - bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE; - - // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate - // :after content and not :before content. - if (newContentWanted && type == RenderStyle::BEFORE && isInlineContinuation()) - newContentWanted = false; - - // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, - // then we don't generate the :after content. - if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && continuation()) - newContentWanted = false; - - // If we don't want generated content any longer, or if we have generated content, but it's no longer - // identical to the new content data we want to build render objects for, then we nuke all - // of the old generated content. - if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) { - // Nuke the child. - if (child && child->style()->styleType() == type) { - oldContentPresent = false; - child->destroy(); - child = (type == RenderStyle::BEFORE) ? m_firstChild : m_lastChild; - } - } - - // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we - // have no generated content and can now return. - if (!newContentWanted) - return; - - if (isInlineFlow() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && - !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) - // According to the CSS2 spec (the end of section 12.1), the only allowed - // display values for the pseudo style are NONE and INLINE for inline flows. - // FIXME: CSS2.1 lifted this restriction, but block display types will crash. - // For now we at least relax the restriction to allow all inline types like inline-block - // and inline-table. - pseudoElementStyle->setDisplay(INLINE); - - if (oldContentPresent) { - if (child && child->style()->styleType() == type) { - // We have generated content present still. We want to walk this content and update our - // style information with the new pseudo-element style. - child->setStyle(pseudoElementStyle); - - RenderObject* beforeAfterParent = findBeforeAfterParent(child); - if (!beforeAfterParent) - return; - - // Note that if we ever support additional types of generated content (which should be way off - // in the future), this code will need to be patched. - for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { - if (genChild->isText()) - // Generated text content is a child whose style also needs to be set to the pseudo-element style. - genChild->setStyle(pseudoElementStyle); - else if (genChild->isImage()) { - // Images get an empty style that inherits from the 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() == RenderStyle::FIRST_LETTER); - } - } - return; // We've updated the generated content. That's all we needed to do. - } - - RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? firstChild() : 0; - - // Generated content consists of a single container that houses multiple children (specified - // by the content property). This generated content container gets the pseudo-element style set on it. - RenderObject* generatedContentContainer = 0; - - // Walk our list of generated content and create render objects for each. - for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->m_next) { - RenderObject* renderer = 0; - switch (content->m_type) { - case CONTENT_NONE: - break; - case CONTENT_TEXT: - renderer = new (renderArena()) RenderTextFragment(document() /* anonymous object */, content->m_content.m_text); - renderer->setStyle(pseudoElementStyle); - break; - case CONTENT_OBJECT: { - RenderImageGeneratedContent* image = new (renderArena()) RenderImageGeneratedContent(document()); // anonymous object - RefPtr<RenderStyle> style = RenderStyle::create(); - style->inheritFrom(pseudoElementStyle); - image->setStyle(style.release()); - if (StyleImage* styleImage = content->m_content.m_image) - image->setStyleImage(styleImage); - renderer = image; - break; - } - case CONTENT_COUNTER: - renderer = new (renderArena()) RenderCounter(document(), *content->m_content.m_counter); - renderer->setStyle(pseudoElementStyle); - break; - } - - if (renderer) { - if (!generatedContentContainer) { - // Make a generated box that might be any display type now that we are able to drill down into children - // to find the original content properly. - generatedContentContainer = RenderObject::createObject(document(), pseudoElementStyle); - generatedContentContainer->setStyle(pseudoElementStyle); - addChild(generatedContentContainer, insertBefore); - } - generatedContentContainer->addChild(renderer); - } - } -} - -bool RenderContainer::isAfterContent(RenderObject* child) const -{ - if (!child) - return false; - if (child->style()->styleType() != RenderStyle::AFTER) - return false; - // Text nodes don't have their own styles, so ignore the style on a text node. - if (child->isText() && !child->isBR()) - return false; - return true; -} - -static void invalidateCountersInContainer(RenderObject* container) -{ - if (!container) - return; - container = findBeforeAfterParent(container); - if (!container) - return; - for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) { - if (content->isCounter()) - static_cast<RenderCounter*>(content)->invalidate(); - } -} - -void RenderContainer::invalidateCounters() -{ - if (documentBeingDestroyed()) - return; - - invalidateCountersInContainer(beforeAfterContainer(RenderStyle::BEFORE)); - invalidateCountersInContainer(beforeAfterContainer(RenderStyle::AFTER)); -} - -void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend) -{ - ASSERT(newChild->parent() == 0); - ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); - - newChild->setParent(this); - RenderObject* lChild = m_lastChild; - - if (lChild) { - newChild->setPreviousSibling(lChild); - lChild->setNextSibling(newChild); - } else - m_firstChild = newChild; - - m_lastChild = newChild; - - if (fullAppend) { - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children - // and don't have a layer attached to ourselves. - RenderLayer* layer = 0; - if (newChild->firstChild() || newChild->hasLayer()) { - layer = enclosingLayer(); - newChild->addLayers(layer, newChild); - } - - // if the new child is visible but this object was not, tell the layer it has some visible content - // that needs to be drawn and layer visibility optimization can't be used - if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) { - if (!layer) - layer = enclosingLayer(); - if (layer) - layer->setHasVisibleContent(true); - } - - if (!newChild->isFloatingOrPositioned() && childrenInline()) - dirtyLinesFromChangedChild(newChild); - } - - newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); -} - -void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool fullInsert) -{ - if (!beforeChild) { - appendChildNode(child); - return; - } - - ASSERT(!child->parent()); - while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock()) - beforeChild = beforeChild->parent(); - ASSERT(beforeChild->parent() == this); - - ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell())); - - if (beforeChild == m_firstChild) - m_firstChild = child; - - RenderObject* prev = beforeChild->previousSibling(); - child->setNextSibling(beforeChild); - beforeChild->setPreviousSibling(child); - if(prev) prev->setNextSibling(child); - child->setPreviousSibling(prev); - - child->setParent(this); - - if (fullInsert) { - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children - // and don't have a layer attached to ourselves. - RenderLayer* layer = 0; - if (child->firstChild() || child->hasLayer()) { - layer = enclosingLayer(); - child->addLayers(layer, child); - } - - // if the new child is visible but this object was not, tell the layer it has some visible content - // that needs to be drawn and layer visibility optimization can't be used - if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) { - if (!layer) - layer = enclosingLayer(); - if (layer) - layer->setHasVisibleContent(true); - } - - - if (!child->isFloating() && childrenInline()) - dirtyLinesFromChangedChild(child); - } - - child->setNeedsLayoutAndPrefWidthsRecalc(); - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); -} - -void RenderContainer::layout() -{ - ASSERT(needsLayout()); - - LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y)); - - RenderObject* child = m_firstChild; - while (child) { - child->layoutIfNeeded(); - ASSERT(child->isRenderInline() || !child->needsLayout()); - child = child->nextSibling(); - } - - statePusher.pop(); - setNeedsLayout(false); -} - -void RenderContainer::removeLeftoverAnonymousBlock(RenderBlock* child) -{ - ASSERT(child->isAnonymousBlock()); - ASSERT(!child->childrenInline()); - - if (child->continuation()) - return; - - RenderObject* firstAnChild = child->firstChild(); - RenderObject* lastAnChild = child->lastChild(); - if (firstAnChild) { - RenderObject* o = firstAnChild; - while(o) { - o->setParent(this); - o = o->nextSibling(); - } - firstAnChild->setPreviousSibling(child->previousSibling()); - lastAnChild->setNextSibling(child->nextSibling()); - if (child->previousSibling()) - child->previousSibling()->setNextSibling(firstAnChild); - if (child->nextSibling()) - child->nextSibling()->setPreviousSibling(lastAnChild); - } else { - if (child->previousSibling()) - child->previousSibling()->setNextSibling(child->nextSibling()); - if (child->nextSibling()) - child->nextSibling()->setPreviousSibling(child->previousSibling()); - } - if (child == m_firstChild) - m_firstChild = firstAnChild; - if (child == m_lastChild) - m_lastChild = lastAnChild; - child->setParent(0); - child->setPreviousSibling(0); - child->setNextSibling(0); - if (!child->isText()) { - RenderContainer *c = static_cast<RenderContainer*>(child); - c->m_firstChild = 0; - c->m_next = 0; - } - child->destroy(); -} - -VisiblePosition RenderContainer::positionForCoordinates(int x, int y) -{ - // no children...return this render object's element, if there is one, and offset 0 - if (!m_firstChild) - return VisiblePosition(element(), 0, DOWNSTREAM); - - if (isTable() && element()) { - int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft(); - int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom(); - - if (x < 0 || x > right || y < 0 || y > bottom) { - if (x <= right / 2) - return VisiblePosition(Position(element(), 0)); - else - return VisiblePosition(Position(element(), maxDeepOffset(element()))); - } - } - - // Pass off to the closest child. - int minDist = INT_MAX; - RenderObject* closestRenderer = 0; - int newX = x; - int newY = y; - if (isTableRow()) { - newX += xPos(); - newY += yPos(); - } - for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) { - if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow() - || renderer->style()->visibility() != VISIBLE) - continue; - - int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos()); - int bottom = top + renderer->contentHeight(); - int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos()); - int right = left + renderer->contentWidth(); - - if (x <= right && x >= left && y <= top && y >= bottom) { - if (renderer->isTableRow()) - return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos()); - return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos()); - } - - // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces - // and use a different compare depending on which piece (x, y) is in. - IntPoint cmp; - if (x > right) { - if (y < top) - cmp = IntPoint(right, top); - else if (y > bottom) - cmp = IntPoint(right, bottom); - else - cmp = IntPoint(right, y); - } else if (x < left) { - if (y < top) - cmp = IntPoint(left, top); - else if (y > bottom) - cmp = IntPoint(left, bottom); - else - cmp = IntPoint(left, y); - } else { - if (y < top) - cmp = IntPoint(x, top); - else - cmp = IntPoint(x, bottom); - } - - int x1minusx2 = cmp.x() - x; - int y1minusy2 = cmp.y() - y; - - int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2; - if (dist < minDist) { - closestRenderer = renderer; - minDist = dist; - } - } - - if (closestRenderer) - return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos()); - - return VisiblePosition(element(), 0, DOWNSTREAM); -} - -void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool) -{ - if (!m_firstChild && (isInline() || isAnonymousBlock())) { - FloatPoint absPos = localToAbsoluteForContent(FloatPoint()); - absoluteRects(rects, absPos.x(), absPos.y()); - return; - } - - if (!m_firstChild) - return; - - unsigned offset = start; - for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) { - if (child->isText() || child->isInline() || child->isAnonymousBlock()) { - FloatPoint absPos = child->localToAbsoluteForContent(FloatPoint()); - child->absoluteRects(rects, absPos.x(), absPos.y()); - } - } -} - -void RenderContainer::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool /*useSelectionHeight*/) -{ - if (!m_firstChild && (isInline() || isAnonymousBlock())) { - absoluteQuads(quads); - return; - } - - if (!m_firstChild) - return; - - unsigned offset = start; - for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) { - if (child->isText() || child->isInline() || child->isAnonymousBlock()) - child->absoluteQuads(quads); - } -} - -#undef DEBUG_LAYOUT - -} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h deleted file mode 100644 index 68aba84..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2001 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef RenderContainer_h -#define RenderContainer_h - -#include "RenderBox.h" - -namespace WebCore { - -// Base class for rendering objects that can have children. -class RenderContainer : public RenderBox { -public: - RenderContainer(Node*); - virtual ~RenderContainer(); - - virtual RenderObject* firstChild() const { return m_firstChild; } - virtual RenderObject* lastChild() const { return m_lastChild; } - - virtual bool canHaveChildren() const; - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject*); - - virtual void destroy(); - void destroyLeftoverChildren(); - - virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true); - virtual void appendChildNode(RenderObject*, bool fullAppend = true); - virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true); - - // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our - // change in parentage is not going to affect anything. - virtual void moveChildNode(RenderObject* child) { appendChildNode(child->parent()->removeChildNode(child, false), false); } - - virtual void layout(); - virtual void calcPrefWidths() { setPrefWidthsDirty(false); } - - virtual void removeLeftoverAnonymousBlock(RenderBlock* child); - - RenderObject* beforeAfterContainer(RenderStyle::PseudoId); - virtual void updateBeforeAfterContent(RenderStyle::PseudoId); - void updateBeforeAfterContentForContainer(RenderStyle::PseudoId, RenderContainer*); - bool isAfterContent(RenderObject* child) const; - virtual void invalidateCounters(); - - virtual VisiblePosition positionForCoordinates(int x, int y); - - virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - -private: - RenderObject* m_firstChild; - RenderObject* m_lastChild; -}; - -} // namespace WebCore - -#endif // RenderContainer_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp index 598f40d..fd6d80d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp @@ -116,7 +116,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b isReset = false; return true; } - if (Node* e = object->element()) { + if (Node* e = object->node()) { if (e->hasTagName(olTag)) { value = static_cast<HTMLOListElement*>(e)->start(); isReset = true; @@ -251,13 +251,6 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const return text.impl(); } -void RenderCounter::dirtyLineBoxes(bool fullLayout, bool dummy) -{ - if (prefWidthsDirty()) - calcPrefWidths(0); - RenderText::dirtyLineBoxes(fullLayout, dummy); -} - void RenderCounter::calcPrefWidths(int lead) { setTextInternal(originalText()); @@ -278,7 +271,11 @@ static void destroyCounterNodeChildren(AtomicStringImpl* identifier, CounterNode child->parent()->removeChild(child); ASSERT(counterMaps().get(child->renderer())->get(identifier) == child); counterMaps().get(child->renderer())->remove(identifier); - child->renderer()->invalidateCounters(); + if (!child->renderer()->documentBeingDestroyed()) { + RenderObjectChildList* children = child->renderer()->virtualChildren(); + if (children) + children->invalidateCounters(child->renderer()); + } delete child; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h index 10be066..55aab73 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h @@ -37,7 +37,6 @@ public: virtual bool isCounter() const; virtual PassRefPtr<StringImpl> originalText() const; - virtual void dirtyLineBoxes(bool, bool); virtual void calcPrefWidths(int leadWidth); void invalidate(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.cpp new file mode 100644 index 0000000..b207a31 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.cpp @@ -0,0 +1,122 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderDataGrid.h" + +#include "FocusController.h" +#include "Frame.h" +#include "GraphicsContext.h" +#include "Page.h" +#include "Scrollbar.h" + +using std::min; + +namespace WebCore { + +static const int cDefaultWidth = 300; + +RenderDataGrid::RenderDataGrid(Element* elt) + : RenderBlock(elt) +{ +} + +RenderDataGrid::~RenderDataGrid() +{ +} + +void RenderDataGrid::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 = calcContentBoxWidth(cDefaultWidth); + + 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 RenderDataGrid::paintObject(PaintInfo& paintInfo, int tx, int ty) +{ + if (style()->visibility() != VISIBLE) + return; + + // Paint our background and border. + RenderBlock::paintObject(paintInfo, tx, ty); + + if (paintInfo.phase != PaintPhaseForeground) + return; + + // Paint our column headers first. + paintColumnHeaders(paintInfo, tx, ty); +} + +void RenderDataGrid::paintColumnHeaders(PaintInfo&, int, int) +{ + gridElement()->columns(); + +} + +void RenderDataGrid::rebuildColumns() +{ +} + +// Scrolling implementation functions +void RenderDataGrid::valueChanged(Scrollbar*) +{ + // FIXME: Implement. +} + +void RenderDataGrid::invalidateScrollbarRect(Scrollbar*, const IntRect&) +{ + // FIXME: Implement. +} + +bool RenderDataGrid::isActive() const +{ + Page* page = document()->frame()->page(); + return page && page->focusController()->isActive(); +} + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.h b/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.h new file mode 100644 index 0000000..6a4b32e --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderDataGrid.h @@ -0,0 +1,70 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderDataGrid_h +#define RenderDataGrid_h + +#include "HTMLDataGridElement.h" +#include "RenderBlock.h" +#include "ScrollbarClient.h" +#include "StyleImage.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class RenderDataGrid : public RenderBlock, private ScrollbarClient { +public: + RenderDataGrid(Element*); + ~RenderDataGrid(); + + virtual const char* renderName() const { return "RenderDataGrid"; } + + virtual bool canHaveChildren() const { return false; } + + virtual void calcPrefWidths(); + + virtual void paintObject(PaintInfo&, int tx, int ty); + + void columnsChanged(); + +private: + void paintColumnHeaders(PaintInfo&, int tx, int ty); + void rebuildColumns(); + + HTMLDataGridElement* gridElement() const { return static_cast<HTMLDataGridElement*>(node()); } + + // ScrollbarClient interface. + virtual void valueChanged(Scrollbar*); + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual bool isActive() const; + virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on data grids yet. If we did this would have to change. + + RefPtr<Scrollbar> m_vBar; +}; + +} + +#endif // RenderDataGrid_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp index 0e944f4..1275882 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp @@ -48,7 +48,7 @@ RenderFieldset::RenderFieldset(Node* element) void RenderFieldset::calcPrefWidths() { RenderBlock::calcPrefWidths(); - if (RenderObject* legend = findLegend()) { + if (RenderBox* legend = findLegend()) { int legendMinWidth = legend->minPrefWidth(); Length legendMarginLeft = legend->style()->marginLeft(); @@ -66,7 +66,7 @@ void RenderFieldset::calcPrefWidths() RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) { - RenderObject* legend = findLegend(); + RenderBox* legend = findLegend(); if (legend) { if (relayoutChildren) legend->setNeedsLayout(true); @@ -79,18 +79,18 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) xPos = borderLeft() + paddingLeft(); break; case CENTER: - xPos = (m_width - legend->width()) / 2; + xPos = (width() - legend->width()) / 2; break; default: - xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight(); + xPos = width() - paddingRight() - borderRight() - legend->width() - legend->marginRight(); } } else { switch (legend->style()->textAlign()) { case RIGHT: - xPos = m_width - paddingRight() - borderRight() - legend->width(); + xPos = width() - paddingRight() - borderRight() - legend->width(); break; case CENTER: - xPos = (m_width - legend->width()) / 2; + xPos = (width() - legend->width()) / 2; break; default: xPos = borderLeft() + paddingLeft() + legend->marginLeft(); @@ -98,22 +98,22 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) } int b = borderTop(); int h = legend->height(); - legend->setPos(xPos, max((b-h)/2, 0)); - m_height = max(b,h) + paddingTop(); + legend->setLocation(xPos, max((b-h)/2, 0)); + setHeight(max(b,h) + paddingTop()); } return legend; } -RenderObject* RenderFieldset::findLegend() const +RenderBox* RenderFieldset::findLegend() const { for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) { - if (!legend->isFloatingOrPositioned() && legend->element() && - legend->element()->hasTagName(legendTag) + if (!legend->isFloatingOrPositioned() && legend->node() && + legend->node()->hasTagName(legendTag) #if ENABLE(WML) - || legend->element()->hasTagName(WMLNames::insertedLegendTag) + || legend->node()->hasTagName(WMLNames::insertedLegendTag) #endif ) - return legend; + return toRenderBox(legend); } return 0; } @@ -121,30 +121,26 @@ RenderObject* RenderFieldset::findLegend() const void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - RenderObject* legend = findLegend(); + int h = height(); + RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintBoxDecorations(paintInfo, tx, ty); - int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2; - int legendBottom = ty + legend->yPos() + legend->height(); + int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; + int legendBottom = ty + legend->y() + legend->height(); h -= yOff; - ty += yOff - borderTopExtra(); - - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; + ty += yOff; paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); if (!style()->hasBorder()) return; // Save time by not saving and restoring the GraphicsContext in the straight border case if (!style()->hasBorderRadius()) - return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->xPos(), legend->width(), legendBottom); + return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->x(), legend->width(), legendBottom); // We have rounded borders, create a clipping region // around the legend and paint the border as normal @@ -154,7 +150,7 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int clipTop = ty; int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height()); - graphicsContext->clipOut(IntRect(tx + legend->xPos(), clipTop, + graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop, legend->width(), clipHeight)); paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true); @@ -167,20 +163,16 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - RenderObject* legend = findLegend(); + int h = height(); + RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintMask(paintInfo, tx, ty); - int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2; + int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; h -= yOff; - ty += yOff - borderTopExtra(); - - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; + ty += yOff; - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, @@ -204,17 +196,17 @@ void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, in if (render_t) { if (lx >= borderLeftWidth) - drawBorder(graphicsContext, tx, ty, tx + min(lx, w), ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, + drawLineForBoxSide(graphicsContext, tx, ty, tx + min(lx, w), ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0), (lx >= w && render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0)); if (lx + lw <= w - borderRightWidth) - drawBorder(graphicsContext, tx + max(0, lx + lw), ty, tx + w, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, + drawLineForBoxSide(graphicsContext, tx + max(0, lx + lw), ty, tx + w, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, (lx + lw <= 0 && render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0), (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0)); } if (render_b) - drawBorder(graphicsContext, tx, ty + h - style->borderBottomWidth(), tx + w, ty + h, BSBottom, bc, style->color(), bs, + drawLineForBoxSide(graphicsContext, tx, ty + h - style->borderBottomWidth(), tx + w, ty + h, BSBottom, bc, style->color(), bs, (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? style->borderLeftWidth() : 0), (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? style->borderRightWidth() : 0)); @@ -238,7 +230,7 @@ void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, in startY = lb; } - drawBorder(graphicsContext, tx, startY, tx + borderLeftWidth, ty + h, BSLeft, lc, style->color(), ls, + drawLineForBoxSide(graphicsContext, tx, startY, tx + borderLeftWidth, ty + h, BSLeft, lc, style->color(), ls, ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); } @@ -262,12 +254,12 @@ void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, in startY = lb; } - drawBorder(graphicsContext, tx + w - borderRightWidth, startY, tx + w, ty + h, BSRight, rc, style->color(), rs, + drawLineForBoxSide(graphicsContext, tx + w - borderRightWidth, startY, tx + w, ty + h, BSRight, rc, style->color(), rs, ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); } } -void RenderFieldset::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderFieldset::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h index 47d1a91..ed57d3a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h @@ -41,13 +41,12 @@ public: virtual void calcPrefWidths(); virtual bool avoidsFloats() const { return true; } - virtual bool expandsToEncloseOverhangingFloats() const { return style()->height().isAuto(); } virtual bool stretchesToMinIntrinsicWidth() const { return true; } - RenderObject* findLegend() const; + RenderBox* findLegend() const; protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp index 6a4bb54..72623f7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp @@ -22,6 +22,7 @@ #include "RenderFileUploadControl.h" #include "FileList.h" +#include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLInputElement.h" @@ -73,7 +74,7 @@ RenderFileUploadControl::~RenderFileUploadControl() m_fileChooser->disconnectClient(); } -void RenderFileUploadControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderFileUploadControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); if (m_button) @@ -84,12 +85,12 @@ void RenderFileUploadControl::styleDidChange(RenderStyle::Diff diff, const Rende void RenderFileUploadControl::valueChanged() { - // onChange may destroy this renderer + // dispatchFormControlChangeEvent may destroy this renderer RefPtr<FileChooser> fileChooser = m_fileChooser; HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node()); inputElement->setFileListFromRenderer(fileChooser->filenames()); - inputElement->onChange(); + inputElement->dispatchFormControlChangeEvent(); // only repaint if it doesn't seem we have been destroyed if (!fileChooser->disconnected()) @@ -147,13 +148,13 @@ void RenderFileUploadControl::updateFromElement() int RenderFileUploadControl::maxFilenameWidth() const { - return max(0, contentWidth() - m_button->renderer()->width() - afterButtonSpacing + return max(0, contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0)); } PassRefPtr<RenderStyle> RenderFileUploadControl::createButtonStyle(const RenderStyle* parentStyle) const { - RefPtr<RenderStyle> style = getCachedPseudoStyle(RenderStyle::FILE_UPLOAD_BUTTON); + RefPtr<RenderStyle> style = getCachedPseudoStyle(FILE_UPLOAD_BUTTON); if (!style) { style = RenderStyle::create(); if (parentStyle) @@ -190,7 +191,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) // Determine where the filename should be placed int contentLeft = tx + borderLeft() + paddingLeft(); - int buttonAndIconWidth = m_button->renderer()->width() + afterButtonSpacing + int buttonAndIconWidth = m_button->renderBox()->width() + afterButtonSpacing + (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0); int textX; if (style()->direction() == LTR) @@ -198,25 +199,24 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) else textX = contentLeft + contentWidth() - buttonAndIconWidth - style()->font().width(textRun); // We want to match the button's baseline - RenderButton* buttonRenderer = static_cast<RenderButton*>(m_button->renderer()); + RenderButton* buttonRenderer = toRenderButton(m_button->renderer()); int textY = buttonRenderer->absoluteBoundingBoxRect().y() + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop() + buttonRenderer->baselinePosition(true, false); - paintInfo.context->setFont(style()->font()); paintInfo.context->setFillColor(style()->color()); // Draw the filename - paintInfo.context->drawBidiText(textRun, IntPoint(textX, textY)); + paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY)); if (m_fileChooser->icon()) { // Determine where the icon should be placed int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2; int iconX; if (style()->direction() == LTR) - iconX = contentLeft + m_button->renderer()->width() + afterButtonSpacing; + iconX = contentLeft + m_button->renderBox()->width() + afterButtonSpacing; else - iconX = contentLeft + contentWidth() - m_button->renderer()->width() - afterButtonSpacing - iconWidth; + iconX = contentLeft + contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - iconWidth; // Draw the file icon m_fileChooser->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight)); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h index 60e7a7b..85bc09f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h @@ -55,7 +55,7 @@ public: bool allowsMultipleFiles(); protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: int maxFilenameWidth() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp index 08bc567..1dcef36 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp @@ -45,11 +45,11 @@ public: lastOrdinal = 1; if (!forward) { // No choice, since we're going backwards, we have to find out the highest ordinal up front. - RenderObject* child = box->firstChild(); + RenderBox* child = box->firstChildBox(); while (child) { if (child->style()->boxOrdinalGroup() > lastOrdinal) lastOrdinal = child->style()->boxOrdinalGroup(); - child = child->nextSibling(); + child = child->nextSiblingBox(); } } @@ -61,29 +61,28 @@ public: currentOrdinal = forward ? 0 : lastOrdinal+1; } - RenderObject* first() { + RenderBox* first() { reset(); return next(); } - RenderObject* next() { - + RenderBox* next() { do { if (!current) { if (forward) { currentOrdinal++; if (currentOrdinal > lastOrdinal) return 0; - current = box->firstChild(); + current = box->firstChildBox(); } else { currentOrdinal--; if (currentOrdinal == 0) return 0; - current = box->lastChild(); + current = box->lastChildBox(); } } else - current = forward ? current->nextSibling() : current->previousSibling(); + current = forward ? current->nextSiblingBox() : current->previousSiblingBox(); if (current && current->style()->boxOrdinalGroup() > lastOrdinal) lastOrdinal = current->style()->boxOrdinalGroup(); } while (!current || current->style()->boxOrdinalGroup() != currentOrdinal || @@ -93,7 +92,7 @@ public: private: RenderFlexibleBox* box; - RenderObject* current; + RenderBox* current; bool forward; unsigned int currentOrdinal; unsigned int lastOrdinal; @@ -112,13 +111,10 @@ RenderFlexibleBox::~RenderFlexibleBox() void RenderFlexibleBox::calcHorizontalPrefWidths() { - RenderObject *child = firstChild(); - while (child) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // positioned children don't affect the minmaxwidth - if (child->isPositioned() || child->style()->visibility() == COLLAPSE) { - child = child->nextSibling(); + if (child->isPositioned() || child->style()->visibility() == COLLAPSE) continue; - } // A margin basically has three types: fixed, percentage, and auto (variable). // Auto and percentage margins simply become 0 when computing min/max width. @@ -134,21 +130,15 @@ void RenderFlexibleBox::calcHorizontalPrefWidths() m_minPrefWidth += child->minPrefWidth() + margin; m_maxPrefWidth += child->maxPrefWidth() + margin; - - child = child->nextSibling(); } } void RenderFlexibleBox::calcVerticalPrefWidths() { - RenderObject *child = firstChild(); - while(child != 0) - { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Positioned children and collapsed children don't affect the min/max width - if (child->isPositioned() || child->style()->visibility() == COLLAPSE) { - child = child->nextSibling(); + if (child->isPositioned() || child->style()->visibility() == COLLAPSE) continue; - } // A margin basically has three types: fixed, percentage, and auto (variable). // Auto/percentage margins simply become 0 when computing min/max width. @@ -166,8 +156,6 @@ void RenderFlexibleBox::calcVerticalPrefWidths() w = child->maxPrefWidth() + margin; m_maxPrefWidth = max(w, m_maxPrefWidth); - - child = child->nextSibling(); } } @@ -212,29 +200,22 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) if (!relayoutChildren && layoutOnlyPositionedObjects()) return; - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } - - LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y), !hasReflection()); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection()); - int previousWidth = m_width; - int previousHeight = m_height; + int previousWidth = width(); + int previousHeight = height(); calcWidth(); calcHeight(); - m_overflowWidth = m_width; + m_overflowWidth = width(); - if (previousWidth != m_width || previousHeight != m_height || + if (previousWidth != width() || previousHeight != height() || (parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->style()->boxAlign() == BSTRETCH)) relayoutChildren = true; - m_height = 0; + setHeight(0); m_overflowHeight = 0; m_flexingChildren = m_stretchingChildren = false; @@ -243,9 +224,9 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) // For overflow:scroll blocks, ensure we have both scrollbars in place always. if (scrollsOverflow()) { if (style()->overflowX() == OSCROLL) - m_layer->setHasHorizontalScrollbar(true); + layer()->setHasHorizontalScrollbar(true); if (style()->overflowY() == OSCROLL) - m_layer->setHasVerticalScrollbar(true); + layer()->setHasVerticalScrollbar(true); } if (isHorizontal()) @@ -253,21 +234,21 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) else layoutVerticalBox(relayoutChildren); - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldHeight != m_height) { + if (oldHeight != height()) { // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight > m_height) + if (m_overflowHeight > height()) m_overflowHeight -= (borderBottom() + paddingBottom() + horizontalScrollbarHeight()); - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); } - if (previousHeight != m_height) + if (previousHeight != height()) relayoutChildren = true; layoutPositionedObjects(relayoutChildren || isRoot()); - if (!isFloatingOrPositioned() && m_height == 0) { + if (!isFloatingOrPositioned() && height() == 0) { // We are a block with no border and padding and a computed height // of 0. The CSS spec states that zero-height blocks collapse their margins // together. @@ -286,15 +267,15 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) } // Always ensure our overflow width is at least as large as our width. - if (m_overflowWidth < m_width) - m_overflowWidth = m_width; + if (m_overflowWidth < width()) + m_overflowWidth = width(); if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -311,11 +292,10 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. if (hasOverflowClip()) - m_layer->updateScrollInfoAfterLayout(); + layer()->updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + repainter.repaintAfterLayout(); setNeedsLayout(false); } @@ -332,11 +312,11 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) unsigned int lowestFlexGroup = 0; bool haveFlex = false; int remainingSpace = 0; - m_overflowHeight = m_height; + m_overflowHeight = height(); // The first walk over our kids is to find out if we have any flexible children. FlexBoxIterator iterator(this); - RenderObject* child = iterator.next(); + RenderBox* child = iterator.next(); while (child) { // Check to see if this child flexes. if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { @@ -361,8 +341,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) // their preferred widths. The second pass handles flexing the children. do { // Reset our height. - m_height = yPos; - m_overflowHeight = m_height; + setHeight(yPos); + m_overflowHeight = height(); xPos = borderLeft() + paddingLeft(); // Our first pass is done without flexing. We simply lay the children @@ -388,9 +368,10 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) // Update our height and overflow height. if (style()->boxAlign() == BBASELINE) { - int ascent = child->marginTop() + child->getBaselineOfFirstLineBox(); + int ascent = child->firstLineBoxBaseline(); if (ascent == -1) - ascent = child->marginTop() + child->height() + child->marginBottom(); + ascent = child->height() + child->marginBottom(); + ascent += child->marginTop(); int descent = (child->marginTop() + child->height() + child->marginBottom()) - ascent; // Update our maximum ascent. @@ -400,28 +381,28 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) maxDescent = max(maxDescent, descent); // Now update our height. - m_height = max(yPos + maxAscent + maxDescent, m_height); + setHeight(max(yPos + maxAscent + maxDescent, height())); } else - m_height = max(m_height, yPos + child->marginTop() + child->height() + child->marginBottom()); + setHeight(max(height(), yPos + child->marginTop() + child->height() + child->marginBottom())); child = iterator.next(); } if (!iterator.first() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); - m_height += toAdd; + setHeight(height() + toAdd); // Always make sure our overflowheight is at least our height. - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); - oldHeight = m_height; + oldHeight = height(); calcHeight(); relayoutChildren = false; - if (oldHeight != m_height) + if (oldHeight != height()) heightSpecified = true; // Now that our height is actually known, we can place our boxes. @@ -430,13 +411,13 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) while (child) { if (child->isPositioned()) { child->containingBlock()->insertPositionedObject(child); - if (child->hasStaticX()) { + if (child->style()->hasStaticX()) { if (style()->direction() == LTR) - child->setStaticX(xPos); - else child->setStaticX(width() - xPos); + child->layer()->setStaticX(xPos); + else child->layer()->setStaticX(width() - xPos); } - if (child->hasStaticY()) - child->setStaticY(yPos); + if (child->style()->hasStaticY()) + child->layer()->setStaticY(yPos); child = iterator.next(); continue; } @@ -445,7 +426,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) // fill the height of a containing box by default. // Now do a layout. int oldChildHeight = child->height(); - static_cast<RenderBox*>(child)->calcHeight(); + child->calcHeight(); if (oldChildHeight != child->height()) child->setChildNeedsLayout(true, false); child->layoutIfNeeded(); @@ -458,9 +439,10 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) childY += child->marginTop() + max(0, (contentHeight() - (child->height() + child->marginTop() + child->marginBottom()))/2); break; case BBASELINE: { - int ascent = child->marginTop() + child->getBaselineOfFirstLineBox(); + int ascent = child->firstLineBoxBaseline(); if (ascent == -1) - ascent = child->marginTop() + child->height() + child->marginBottom(); + ascent = child->height() + child->marginBottom(); + ascent += child->marginTop(); childY += child->marginTop() + (maxAscent - ascent); break; } @@ -475,10 +457,10 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) placeChild(child, xPos, childY); if (child->isRenderBlock()) - static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect()); + toRenderBlock(child)->addVisualOverflow(toRenderBlock(child)->floatRect()); m_overflowHeight = max(m_overflowHeight, childY + child->overflowHeight(false)); - m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false)); + m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); xPos += child->width() + child->marginRight(); @@ -619,7 +601,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) remainingSpace -= (remainingSpace/totalChildren); totalChildren--; - placeChild(child, child->xPos()+offset, child->yPos()); + placeChild(child, child->x()+offset, child->y()); child = iterator.next(); } } @@ -634,7 +616,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) child = iterator.next(); continue; } - placeChild(child, child->xPos()+offset, child->yPos()); + placeChild(child, child->x()+offset, child->y()); child = iterator.next(); } } @@ -646,20 +628,20 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) } if (child) { - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); - RenderObject* lastChild = child; + RenderBox* lastChild = child; while ((child = iterator.next())) { if (!child->isPositioned()) lastChild = child; } - m_overflowWidth = max(lastChild->xPos() + lastChild->overflowWidth(false), m_overflowWidth); + m_overflowWidth = max(lastChild->x() + lastChild->overflowWidth(false), m_overflowWidth); } // So that the calcHeight in layoutBlock() knows to relayout positioned objects because of // a height change, we revert our height back to the intrinsic height before returning. if (heightSpecified) - m_height = oldHeight; + setHeight(oldHeight); } void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) @@ -667,7 +649,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) int xPos = borderLeft() + paddingLeft(); int yPos = borderTop() + paddingTop(); if( style()->direction() == RTL ) - xPos = m_width - paddingRight() - borderRight(); + xPos = width() - paddingRight() - borderRight(); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); bool heightSpecified = false; int oldHeight = 0; @@ -679,7 +661,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // The first walk over our kids is to find out if we have any flexible children. FlexBoxIterator iterator(this); - RenderObject *child = iterator.next(); + RenderBox* child = iterator.next(); while (child) { // Check to see if this child flexes. if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { @@ -714,13 +696,13 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // Dirty all the positioned objects. if (child->isRenderBlock()) { - static_cast<RenderBlock*>(child)->markPositionedObjectsForLayout(); - static_cast<RenderBlock*>(child)->clearTruncation(); + toRenderBlock(child)->markPositionedObjectsForLayout(); + toRenderBlock(child)->clearTruncation(); } } child->layoutIfNeeded(); if (child->style()->height().isAuto() && child->isBlockFlow()) - maxLineCount = max(maxLineCount, static_cast<RenderBlock*>(child)->lineCount()); + maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount()); } child = iterator.next(); } @@ -733,7 +715,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow()) continue; - RenderBlock* blockChild = static_cast<RenderBlock*>(child); + RenderBlock* blockChild = toRenderBlock(child); int lineCount = blockChild->lineCount(); if (lineCount <= numVisibleLines) continue; @@ -762,9 +744,9 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) InlineBox* anchorBox = lastLine->lastChild(); if (!anchorBox) continue; - if (!anchorBox->object()->element()) + if (!anchorBox->renderer()->node()) continue; - if (!anchorBox->object()->element()->isLink()) + if (!anchorBox->renderer()->node()->isLink()) continue; RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1); @@ -781,23 +763,27 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) int totalWidth = ellipsisAndSpaceWidth + anchorBox->width(); // See if this width can be accommodated on the last visible line - RenderBlock* destBlock = static_cast<RenderBlock*>(lastVisibleLine->object()); - RenderBlock* srcBlock = static_cast<RenderBlock*>(lastLine->object()); + RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer()); + RenderBlock* srcBlock = toRenderBlock(lastLine->renderer()); // FIXME: Directions of src/destBlock could be different from our direction and from one another. if (srcBlock->style()->direction() != LTR) continue; if (destBlock->style()->direction() != LTR) continue; + int ltr = true; + + int blockRightEdge = destBlock->rightOffset(lastVisibleLine->y(), false); + int blockLeftEdge = destBlock->leftOffset(lastVisibleLine->y(), false); - int blockEdge = destBlock->rightOffset(lastVisibleLine->yPos()); - if (!lastVisibleLine->canAccommodateEllipsis(true, blockEdge, - lastVisibleLine->xPos() + lastVisibleLine->width(), + int blockEdge = ltr ? blockRightEdge : blockLeftEdge; + if (!lastVisibleLine->canAccommodateEllipsis(ltr, blockEdge, + lastVisibleLine->x() + lastVisibleLine->width(), totalWidth)) continue; // Let the truncation code kick in. - lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, true, blockEdge, totalWidth, anchorBox); + lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox); destBlock->setHasMarkupTruncation(true); } } @@ -808,9 +794,9 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // Our first pass is done without flexing. We simply lay the children // out within the box. do { - m_height = borderTop() + paddingTop(); - int minHeight = m_height + toAdd; - m_overflowHeight = m_height; + setHeight(borderTop() + paddingTop()); + int minHeight = height() + toAdd; + m_overflowHeight = height(); child = iterator.first(); while (child) { @@ -821,14 +807,14 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (child->isPositioned()) { child->containingBlock()->insertPositionedObject(child); - if (child->hasStaticX()) { + if (child->style()->hasStaticX()) { if (style()->direction() == LTR) - child->setStaticX(borderLeft()+paddingLeft()); + child->layer()->setStaticX(borderLeft()+paddingLeft()); else - child->setStaticX(borderRight()+paddingRight()); + child->layer()->setStaticX(borderRight()+paddingRight()); } - if (child->hasStaticY()) - child->setStaticY(m_height); + if (child->style()->hasStaticY()) + child->layer()->setStaticY(height()); child = iterator.next(); continue; } @@ -837,7 +823,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) child->calcVerticalMargins(); // Add in the child's marginTop to our height. - m_height += child->marginTop(); + setHeight(height() + child->marginTop()); // Now do a layout. child->layoutIfNeeded(); @@ -864,39 +850,39 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } // Place the child. - placeChild(child, childX, m_height); - m_height += child->height() + child->marginBottom(); + placeChild(child, childX, height()); + setHeight(height() + child->height() + child->marginBottom()); if (child->isRenderBlock()) - static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect()); + toRenderBlock(child)->addVisualOverflow(toRenderBlock(child)->floatRect()); // See if this child has made our overflow need to grow. - m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth); - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); + m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); child = iterator.next(); } - yPos = m_height; + yPos = height(); if (!iterator.first() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); - m_height += toAdd; + setHeight(height() + toAdd); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - if (m_height < minHeight) - m_height = minHeight; + if (height() < minHeight) + setHeight(minHeight); // Always make sure our overflowheight is at least our height. - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); // Now we have to calc our height, so we know how much space we have remaining. - oldHeight = m_height; + oldHeight = height(); calcHeight(); - if (oldHeight != m_height) + if (oldHeight != height()) heightSpecified = true; remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos; @@ -1028,7 +1014,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) offset += remainingSpace/totalChildren; remainingSpace -= (remainingSpace/totalChildren); totalChildren--; - placeChild(child, child->xPos(), child->yPos()+offset); + placeChild(child, child->x(), child->y()+offset); child = iterator.next(); } } @@ -1043,7 +1029,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) child = iterator.next(); continue; } - placeChild(child, child->xPos(), child->yPos()+offset); + placeChild(child, child->x(), child->y()+offset); child = iterator.next(); } } @@ -1055,28 +1041,28 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } if (child) { - m_overflowTop = min(child->yPos() + child->overflowTop(false), m_overflowTop); + m_overflowTop = min(child->y() + child->overflowTop(false), m_overflowTop); - RenderObject* lastChild = child; + RenderBox* lastChild = child; while ((child = iterator.next())) { if (!child->isPositioned()) lastChild = child; } - m_overflowHeight = max(lastChild->yPos() + lastChild->overflowHeight(false), m_overflowHeight); + m_overflowHeight = max(lastChild->y() + lastChild->overflowHeight(false), m_overflowHeight); } // So that the calcHeight in layoutBlock() knows to relayout positioned objects because of // a height change, we revert our height back to the intrinsic height before returning. if (heightSpecified) - m_height = oldHeight; + setHeight(oldHeight); } -void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y) +void RenderFlexibleBox::placeChild(RenderBox* child, int x, int y) { - IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height()); + IntRect oldRect(child->x(), child->y() , child->width(), child->height()); // Place the child. - child->setPos(x, y); + child->setLocation(x, y); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to @@ -1085,7 +1071,7 @@ void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y) child->repaintDuringLayoutIfMoved(oldRect); } -int RenderFlexibleBox::allowedChildFlex(RenderObject* child, bool expanding, unsigned int group) +int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group) { if (child->isPositioned() || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group) return 0; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h index f48caf5..a0f84ce 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h @@ -48,10 +48,10 @@ public: virtual bool isFlexingChildren() const { return m_flexingChildren; } virtual bool isStretchingChildren() const { return m_stretchingChildren; } - void placeChild(RenderObject* child, int x, int y); + void placeChild(RenderBox* child, int x, int y); protected: - int allowedChildFlex(RenderObject* child, bool expanding, unsigned group); + int allowedChildFlex(RenderBox* child, bool expanding, unsigned group); bool hasMultipleLines() const { return style()->boxLines() == MULTIPLE; } bool isVertical() const { return style()->boxOrient() == VERTICAL; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp deleted file mode 100644 index 86a92f3..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "RenderFlow.h" - -#include "Document.h" -#include "GraphicsContext.h" -#include "HTMLNames.h" -#include "InlineTextBox.h" -#include "RenderArena.h" -#include "RenderInline.h" -#include "RenderLayer.h" -#include "RenderView.h" - -using namespace std; - -namespace WebCore { - -using namespace HTMLNames; - -#ifndef NDEBUG - -RenderFlow::~RenderFlow() -{ - ASSERT(!m_firstLineBox); - ASSERT(!m_lastLineBox); -} - -#endif - -RenderFlow* RenderFlow::createAnonymousFlow(Document* doc, PassRefPtr<RenderStyle> style) -{ - RenderFlow* result; - if (style->display() == INLINE) - result = new (doc->renderArena()) RenderInline(doc); - else - result = new (doc->renderArena()) RenderBlock(doc); - result->setStyle(style); - return result; -} - -RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild) -{ - if (beforeChild && beforeChild->parent() == this) - return this; - - RenderFlow* curr = continuation(); - RenderFlow* nextToLast = this; - RenderFlow* last = this; - while (curr) { - if (beforeChild && beforeChild->parent() == curr) { - if (curr->firstChild() == beforeChild) - return last; - return curr; - } - - nextToLast = last; - last = curr; - curr = curr->continuation(); - } - - if (!beforeChild && !last->firstChild()) - return nextToLast; - return last; -} - -void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild) -{ - if (beforeChild && (beforeChild->parent()->isTableRow() || beforeChild->parent()->isTableSection() || beforeChild->parent()->isTable())) { - RenderObject* anonymousTablePart = beforeChild->parent(); - ASSERT(anonymousTablePart->isAnonymous()); - while (!anonymousTablePart->isTable()) { - anonymousTablePart = anonymousTablePart->parent(); - ASSERT(anonymousTablePart->isAnonymous()); - } - return anonymousTablePart->addChild(newChild, beforeChild); - } - - RenderFlow* flow = continuationBefore(beforeChild); - ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || - beforeChild->parent()->isRenderInline()); - RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) : - (flow->continuation() ? flow->continuation() : flow); - - if (newChild->isFloatingOrPositioned()) - return beforeChildParent->addChildToFlow(newChild, beforeChild); - - // A continuation always consists of two potential candidates: an inline or an anonymous - // block box holding block children. - bool childInline = newChild->isInline(); - bool bcpInline = beforeChildParent->isInline(); - bool flowInline = flow->isInline(); - - if (flow == beforeChildParent) - return flow->addChildToFlow(newChild, beforeChild); - else { - // The goal here is to match up if we can, so that we can coalesce and create the - // minimal # of continuations needed for the inline. - if (childInline == bcpInline) - return beforeChildParent->addChildToFlow(newChild, beforeChild); - else if (flowInline == childInline) - return flow->addChildToFlow(newChild, 0); // Just treat like an append. - else - return beforeChildParent->addChildToFlow(newChild, beforeChild); - } -} - -void RenderFlow::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - if (continuation()) - return addChildWithContinuation(newChild, beforeChild); - return addChildToFlow(newChild, beforeChild); -} - -void RenderFlow::extractLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - m_lastLineBox = box->prevFlowBox(); - 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()) - curr->setExtracted(); - - checkConsistency(); -} - -void RenderFlow::attachLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - if (m_lastLineBox) { - m_lastLineBox->setNextLineBox(box); - box->setPreviousLineBox(m_lastLineBox); - } else - m_firstLineBox = box; - InlineFlowBox* last = box; - for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) { - curr->setExtracted(false); - last = curr; - } - m_lastLineBox = last; - - checkConsistency(); -} - -void RenderFlow::removeLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - if (box == m_firstLineBox) - m_firstLineBox = box->nextFlowBox(); - if (box == m_lastLineBox) - m_lastLineBox = box->prevFlowBox(); - if (box->nextLineBox()) - box->nextLineBox()->setPreviousLineBox(box->prevLineBox()); - if (box->prevLineBox()) - box->prevLineBox()->setNextLineBox(box->nextLineBox()); - - checkConsistency(); -} - -void RenderFlow::deleteLineBoxes() -{ - if (m_firstLineBox) { - RenderArena* arena = renderArena(); - InlineRunBox* next; - for (InlineRunBox* curr = m_firstLineBox; curr; curr = next) { - next = curr->nextLineBox(); - curr->destroy(arena); - } - m_firstLineBox = 0; - m_lastLineBox = 0; - } -} - -void RenderFlow::destroy() -{ - // Detach our continuation first. - if (m_continuation) - m_continuation->destroy(); - m_continuation = 0; - - // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will - // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. - RenderContainer::destroyLeftoverChildren(); - - if (!documentBeingDestroyed()) { - if (m_firstLineBox) { - // We can't wait for RenderContainer::destroy to clear the selection, - // because by then we will have nuked the line boxes. - // FIXME: The SelectionController should be responsible for this when it - // is notified of DOM mutations. - if (isSelectionBorder()) - view()->clearSelection(); - - // If line boxes are contained inside a root, that means we're an inline. - // In that case, we need to remove all the line boxes so that the parent - // lines aren't pointing to deleted children. If the first line box does - // not have a parent that means they are either already disconnected or - // root lines that can just be destroyed without disconnecting. - if (m_firstLineBox->parent()) { - for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox()) - box->remove(); - } - - // If we are an anonymous block, then our line boxes might have children - // 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 = m_firstLineBox; box; box = box->nextFlowBox()) { - while (InlineBox* childBox = box->firstChild()) - childBox->remove(); - } - } - } else if (isInline() && parent()) - parent()->dirtyLinesFromChangedChild(this); - } - - deleteLineBoxes(); - - RenderContainer::destroy(); -} - -void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child) -{ - if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable()) - return; - - // If we have no first line box, then just bail early. - if (!firstLineBox()) { - // For an empty inline, go ahead and propagate the check up to our parent, unless the parent - // is already dirty. - if (isInline() && !parent()->selfNeedsLayout()) - parent()->dirtyLinesFromChangedChild(this); - return; - } - - // Try to figure out which line box we belong in. First try to find a previous - // line box by examining our siblings. If we didn't find a line box, then use our - // parent's first line box. - RootInlineBox* box = 0; - RenderObject* curr = 0; - for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { - if (curr->isFloatingOrPositioned()) - continue; - - if (curr->isReplaced()) { - InlineBox* wrapper = curr->inlineBoxWrapper(); - if (wrapper) - box = wrapper->root(); - } else if (curr->isText()) { - InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox(); - if (textBox) - box = textBox->root(); - } else if (curr->isInlineFlow()) { - InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox(); - if (runBox) - box = runBox->root(); - } - - if (box) - break; - } - if (!box) - box = firstLineBox()->root(); - - // If we found a line box, then dirty it. - if (box) { - RootInlineBox* adjacentBox; - box->markDirty(); - - // dirty the adjacent lines that might be affected - // NOTE: we dirty the previous line because RootInlineBox objects cache - // the address of the first object on the next line after a BR, which we may be - // invalidating here. For more info, see how RenderBlock::layoutInlineChildren - // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, - // despite the name, actually returns the first RenderObject after the BR. - // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." - adjacentBox = box->prevRootBox(); - if (adjacentBox) - adjacentBox->markDirty(); - if (child->isBR() || (curr && curr->isBR())) { - adjacentBox = box->nextRootBox(); - if (adjacentBox) - adjacentBox->markDirty(); - } - } -} - -int RenderFlow::lineHeight(bool firstLine, bool /*isRootLineBox*/) const -{ - if (firstLine) { - RenderStyle* s = style(firstLine); - Length lh = s->lineHeight(); - if (lh.isNegative()) { - if (s == style()) { - if (m_lineHeight == -1) - m_lineHeight = RenderObject::lineHeight(false); - return m_lineHeight; - } - return s->font().lineSpacing(); - } - if (lh.isPercent()) - return lh.calcMinValue(s->fontSize()); - return lh.value(); - } - - if (m_lineHeight == -1) - m_lineHeight = RenderObject::lineHeight(false); - return m_lineHeight; -} - -void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox) -{ - if (!isRootLineBox && isReplaced()) - return RenderContainer::dirtyLineBoxes(fullLayout, isRootLineBox); - - if (fullLayout) - deleteLineBoxes(); - else { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - curr->dirtyLineBoxes(); - } -} - -InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool /*isOnlyRun*/) -{ - checkConsistency(); - - if (!isRootLineBox && - (isReplaced() || makePlaceHolderBox)) // Inline tables and inline blocks - return RenderContainer::createInlineBox(false, isRootLineBox); // (or positioned element placeholders). - - InlineFlowBox* flowBox = 0; - if (isInlineFlow()) - flowBox = new (renderArena()) InlineFlowBox(this); - else - flowBox = new (renderArena()) RootInlineBox(this); - - if (!m_firstLineBox) - m_firstLineBox = m_lastLineBox = flowBox; - else { - m_lastLineBox->setNextLineBox(flowBox); - flowBox->setPreviousLineBox(m_lastLineBox); - m_lastLineBox = flowBox; - } - - checkConsistency(); - - return flowBox; -} - -void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty) -{ - // Only paint during the foreground/selection phases. - if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseOutline - && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines && paintInfo.phase != PaintPhaseTextClip - && paintInfo.phase != PaintPhaseMask) - return; - - bool inlineFlow = isInlineFlow(); - if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. - - // If we have no lines then we have no work to do. - if (!firstLineBox()) - return; - - // We can check the first box and last box and avoid painting if we don't - // intersect. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in the following extremely obscure way: - // if some line in the middle has a huge overflow, it might actually extend below the last line. - int yPos = firstLineBox()->root()->topOverflow() - maximalOutlineSize(paintInfo.phase); - int h = maximalOutlineSize(paintInfo.phase) + lastLineBox()->root()->bottomOverflow() - yPos; - yPos += ty; - if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) - return; - - PaintInfo info(paintInfo); - RenderFlowSequencedSet outlineObjects; - info.outlineObjects = &outlineObjects; - - // See if our root lines intersect with the dirty rect. If so, then we paint - // them. 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. - RenderView* v = view(); - bool usePrintRect = !v->printRect().isEmpty(); - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { - 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. - // The whole way objects break across pages needs to be redone. - // Try to avoid splitting a line vertically, but only if it's less than the height - // of the entire page. - if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= v->printRect().height()) { - if (ty + curr->root()->bottomOverflow() > v->printRect().bottom()) { - if (ty + curr->root()->topOverflow() < v->truncatedAt()) - v->setBestTruncatedAt(ty + curr->root()->topOverflow(), this); - // If we were able to truncate, don't paint. - if (ty + curr->root()->topOverflow() >= v->truncatedAt()) - break; - } - } - } - - int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - maximalOutlineSize(info.phase); - int bottom = curr->root()->bottomOverflow() + maximalOutlineSize(info.phase); - h = bottom - top; - yPos = ty + top; - if (yPos < info.rect.bottom() && yPos + h > info.rect.y()) - curr->paint(info, tx, ty); - } - - if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) { - RenderFlowSequencedSet::iterator end = info.outlineObjects->end(); - for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) { - RenderFlow* flow = *it; - flow->paintOutline(info.context, tx, ty); - } - info.outlineObjects->clear(); - } -} - -bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) -{ - if (hitTestAction != HitTestForeground) - return false; - - bool inlineFlow = isInlineFlow(); - if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. - - // If we have no lines then we have no work to do. - if (!firstLineBox()) - return false; - - // We can check the first box and last box and avoid hit testing if we don't - // contain the point. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in the following extremely obscure way: - // if some line in the middle has a huge overflow, it might actually extend below the last line. - if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow())) - return false; - - // 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()) { - if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) { - bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty); - if (inside) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); - return true; - } - } - } - - return false; -} - -IntRect RenderFlow::absoluteClippedOverflowRect() -{ - if (isInlineFlow()) { - // Only compacts and run-ins are allowed in here during layout. - ASSERT(!view() || !view()->layoutState() || isCompact() || isRunIn()); - - if (!firstLineBox() && !continuation()) - return IntRect(); - - // Find our leftmost position. - int left = 0; - int top = firstLineBox() ? firstLineBox()->yPos() : 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - if (curr == firstLineBox() || curr->xPos() < left) - left = curr->xPos(); - } - - // Now invalidate a rectangle. - int ow = style() ? style()->outlineSize() : 0; - if (isCompact()) - left -= m_x; - - // We need to add in the relative position offsets of any inlines (including us) up to our - // containing block. - RenderBlock* cb = containingBlock(); - for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; - inlineFlow = inlineFlow->parent()) { - if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) - inlineFlow->layer()->relativePositionOffset(left, top); - } - - IntRect r(-ow + left, -ow + top, width() + ow * 2, height() + ow * 2); - if (cb->hasColumns()) - cb->adjustRectForColumns(r); - - if (cb->hasOverflowClip()) { - // 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 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); - } - cb->computeAbsoluteRepaintRect(r); - - if (ow) { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) { - IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow); - r.unite(childRect); - } - } - - if (continuation() && !continuation()->isInline()) { - IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow); - r.unite(contRect); - } - } - - return r; - } - - return RenderContainer::absoluteClippedOverflowRect(); -} - -int RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_width > 0 ? overflowHeight(false) : 0; - - int bottom = includeSelf && m_width > 0 ? m_height : 0; - 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 - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - bottom = max(bottom, c->yPos() + c->lowestPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - bottom += relativePositionOffsetY(); - - return bottom; -} - -int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowWidth(false) : 0; - - int right = includeSelf && m_height > 0 ? m_width : 0; - 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 - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - right = max(right, c->xPos() + c->rightmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - right += relativePositionOffsetX(); - - return right; -} - -int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowLeft(false) : m_width; - - int left = includeSelf && m_height > 0 ? 0 : m_width; - 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 - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - left = min(left, c->xPos() + c->leftmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - left += relativePositionOffsetX(); - - return left; -} - -IntRect RenderFlow::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) -{ - // Do the normal calculation in most cases. - if (firstChild() || style()->display() == INLINE) - return RenderContainer::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); - - // This is a special case: - // The element is not an inline element, and it's empty. So we have to - // calculate a fake position to indicate where objects are to be inserted. - - // FIXME: This does not take into account either :first-line or :first-letter - // However, as soon as some content is entered, the line boxes will be - // constructed and this kludge is not called any more. So only the caret size - // of an empty :first-line'd block is wrong. I think we can live with that. - RenderStyle* currentStyle = firstLineStyle(); - int height = lineHeight(true); - const int caretWidth = 1; - - enum CaretAlignment { alignLeft, alignRight, alignCenter }; - - CaretAlignment alignment = alignLeft; - - switch (currentStyle->textAlign()) { - case TAAUTO: - case JUSTIFY: - if (currentStyle->direction() == RTL) - alignment = alignRight; - break; - case LEFT: - case WEBKIT_LEFT: - break; - case CENTER: - case WEBKIT_CENTER: - alignment = alignCenter; - break; - case RIGHT: - case WEBKIT_RIGHT: - alignment = alignRight; - break; - } - - int x = borderLeft() + paddingLeft(); - int w = width(); - - switch (alignment) { - case alignLeft: - break; - case alignCenter: - x = (x + w - (borderRight() + paddingRight())) / 2; - break; - case alignRight: - x = w - (borderRight() + paddingRight()); - break; - } - - if (extraWidthToEndOfLine) { - if (isRenderBlock()) { - *extraWidthToEndOfLine = w - (x + caretWidth); - } else { - // FIXME: This code looks wrong. - // myRight and containerRight are set up, but then clobbered. - // So *extraWidthToEndOfLine will always be 0 here. - - int myRight = x + caretWidth; - // FIXME: why call localToAbsoluteForContent() twice here, too? - FloatPoint absRightPoint = localToAbsoluteForContent(FloatPoint(myRight, 0)); - - int containerRight = containingBlock()->xPos() + containingBlockWidth(); - FloatPoint absContainerPoint = localToAbsoluteForContent(FloatPoint(containerRight, 0)); - - *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); - } - } - - int y = paddingTop() + borderTop(); - - return IntRect(x, y, caretWidth, height); -} - -void RenderFlow::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) -{ - if (isRenderBlock()) { - // Continuations should include their margins in the outline rect. - if (continuation()) { - bool nextInlineHasLineBox = continuation()->firstLineBox(); - bool prevInlineHasLineBox = static_cast<RenderFlow*>(continuation()->element()->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())); - } - - if (!hasOverflowClip() && !hasControlClip()) { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - graphicsContext->addFocusRingRect(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height())); - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - if (!curr->isText() && !curr->isListMarker()) { - FloatPoint pos; - // FIXME: This doesn't work correctly with transforms. - if (curr->layer()) - pos = curr->localToAbsolute(); - else - pos = FloatPoint(tx + curr->xPos(), ty + curr->yPos()); - curr->addFocusRingRects(graphicsContext, pos.x(), pos.y()); - } - } - - if (continuation()) { - if (isInline()) - continuation()->addFocusRingRects(graphicsContext, - tx - containingBlock()->xPos() + continuation()->xPos(), - ty - containingBlock()->yPos() + continuation()->yPos()); - else - continuation()->addFocusRingRects(graphicsContext, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos()); - } -} - -void RenderFlow::paintOutline(GraphicsContext* graphicsContext, int tx, int ty) -{ - if (!hasOutline()) - return; - - if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) { - int ow = style()->outlineWidth(); - Color oc = style()->outlineColor(); - if (!oc.isValid()) - oc = style()->color(); - - graphicsContext->initFocusRing(ow, style()->outlineOffset()); - addFocusRingRects(graphicsContext, tx, ty); - if (style()->outlineStyleIsAuto()) - graphicsContext->drawFocusRing(oc); - else - addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); - graphicsContext->clearFocusRing(); - } - - if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE) - return; - - Vector<IntRect> rects; - - rects.append(IntRect()); - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - rects.append(IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height())); - - rects.append(IntRect()); - - for (unsigned i = 1; i < rects.size() - 1; i++) - paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1)); -} - -void RenderFlow::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty, - const IntRect& lastline, const IntRect& thisline, const IntRect& nextline) -{ - int ow = style()->outlineWidth(); - EBorderStyle os = style()->outlineStyle(); - Color oc = style()->outlineColor(); - if (!oc.isValid()) - oc = style()->color(); - - int offset = style()->outlineOffset(); - - int t = ty + thisline.y() - offset; - int l = tx + thisline.x() - offset; - int b = ty + thisline.bottom() + offset; - int r = tx + thisline.right() + offset; - - // left edge - drawBorder(graphicsContext, - l - ow, - t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0), - l, - b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0), - BSLeft, - oc, style()->color(), os, - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow), - (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow)); - - // right edge - drawBorder(graphicsContext, - r, - t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0), - r + ow, - b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0), - BSRight, - oc, style()->color(), os, - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow), - (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow)); - // upper edge - if (thisline.x() < lastline.x()) - drawBorder(graphicsContext, - l - ow, - t - ow, - min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())), - t , - BSTop, oc, style()->color(), os, - ow, - (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow); - - if (lastline.right() < thisline.right()) - drawBorder(graphicsContext, - max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow), - t - ow, - r + ow, - t , - BSTop, oc, style()->color(), os, - (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow, - ow); - - // lower edge - if (thisline.x() < nextline.x()) - drawBorder(graphicsContext, - l - ow, - b, - min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000), - b + ow, - BSBottom, oc, style()->color(), os, - ow, - (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow); - - if (nextline.right() < thisline.right()) - drawBorder(graphicsContext, - max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow), - b, - r + ow, - b + ow, - BSBottom, oc, style()->color(), os, - (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow, - ow); -} - -void RenderFlow::calcMargins(int containerWidth) -{ - m_marginLeft = style()->marginLeft().calcMinValue(containerWidth); - m_marginRight = style()->marginRight().calcMinValue(containerWidth); -} - -#ifndef NDEBUG - -void RenderFlow::checkConsistency() const -{ -#ifdef CHECK_CONSISTENCY - const InlineFlowBox* prev = 0; - for (const InlineFlowBox* child = m_firstLineBox; child != 0; child = child->nextFlowBox()) { - ASSERT(child->object() == this); - ASSERT(child->prevFlowBox() == prev); - prev = child; - } - ASSERT(prev == m_lastLineBox); -#endif -} - -#endif - -} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h deleted file mode 100644 index 7e3a345..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef RenderFlow_h -#define RenderFlow_h - -#include "RenderContainer.h" - -namespace WebCore { - -/** - * all geometry managing stuff is only in the block elements. - * - * Inline elements don't layout themselves, but the whole paragraph - * gets flowed by the surrounding block element. This is, because - * one needs to know the whole paragraph to calculate bidirectional - * behaviour of text, so putting the layouting routines in the inline - * elements is impossible. - */ -class RenderFlow : public RenderContainer { -public: - RenderFlow(Node* node) - : RenderContainer(node) - , m_continuation(0) - , m_firstLineBox(0) - , m_lastLineBox(0) - , m_lineHeight(-1) - , m_childrenInline(true) - , m_firstLine(false) - , m_topMarginQuirk(false) - , m_bottomMarginQuirk(false) - , m_hasMarkupTruncation(false) - , m_selectionState(SelectionNone) - , m_hasColumns(false) - , m_isContinuation(false) - { - } -#ifndef NDEBUG - virtual ~RenderFlow(); -#endif - - virtual RenderFlow* continuation() const { return m_continuation; } - void setContinuation(RenderFlow* c) { m_continuation = c; } - RenderFlow* continuationBefore(RenderObject* beforeChild); - - void addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild); - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) = 0; - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - - static RenderFlow* createAnonymousFlow(Document*, PassRefPtr<RenderStyle>); - - void extractLineBox(InlineFlowBox*); - void attachLineBox(InlineFlowBox*); - void removeLineBox(InlineFlowBox*); - void deleteLineBoxes(); - virtual void destroy(); - - virtual void dirtyLinesFromChangedChild(RenderObject* child); - - virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; - - InlineFlowBox* firstLineBox() const { return m_firstLineBox; } - InlineFlowBox* lastLineBox() const { return m_lastLineBox; } - - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun=false); - virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false); - - void paintLines(PaintInfo&, int tx, int ty); - bool hitTestLines(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - - virtual IntRect absoluteClippedOverflowRect(); - - virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - - virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine); - void paintOutline(GraphicsContext*, int tx, int ty); - - virtual bool hasColumns() const { return m_hasColumns; } - - void calcMargins(int containerWidth); - - void checkConsistency() const; - -private: - // An inline can be split with blocks occurring in between the inline content. - // When this occurs we need a pointer to our next object. We can basically be - // split into a sequence of inlines and blocks. The continuation will either be - // an anonymous block (that houses other blocks) or it will be an inline flow. - RenderFlow* m_continuation; - -protected: - // For block flows, each box represents the root inline box for a line in the - // paragraph. - // For inline flows, each box represents a portion of that inline. - InlineFlowBox* m_firstLineBox; - InlineFlowBox* m_lastLineBox; - - mutable int m_lineHeight; - - // These bitfields are moved here from subclasses to pack them together - // from RenderBlock - bool m_childrenInline : 1; - bool m_firstLine : 1; - bool m_topMarginQuirk : 1; - bool m_bottomMarginQuirk : 1; - bool m_hasMarkupTruncation : 1; - unsigned m_selectionState : 3; // SelectionState - bool m_hasColumns : 1; - - // from RenderInline - bool m_isContinuation : 1; // Whether or not we're a continuation of an inline. -}; - -#ifdef NDEBUG -inline void RenderFlow::checkConsistency() const -{ -} -#endif - -} // namespace WebCore - -#endif // RenderFlow_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp index 83401fc..b15d55c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp @@ -1,7 +1,6 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 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 @@ -29,6 +28,7 @@ #include "RenderView.h" #include "SVGForeignObjectElement.h" #include "SVGLength.h" +#include "SVGRenderSupport.h" #include "SVGTransformList.h" namespace WebCore { @@ -38,93 +38,84 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node) { } -TransformationMatrix RenderForeignObject::translationForAttributes() +TransformationMatrix RenderForeignObject::translationForAttributes() const { - SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(element()); + SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign)); } -void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY) +void RenderForeignObject::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled()) return; - paintInfo.context->save(); - paintInfo.context->concatCTM(TransformationMatrix().translate(parentX, parentY)); - paintInfo.context->concatCTM(localTransform()); - paintInfo.context->concatCTM(translationForAttributes()); - paintInfo.context->clip(getClipRect(parentX, parentY)); + // Copy the paint info so that modifications to the damage rect do not affect callers + PaintInfo childPaintInfo = paintInfo; + childPaintInfo.context->save(); + applyTransformToPaintInfo(childPaintInfo, localToParentTransform()); + childPaintInfo.context->clip(clipRect(0, 0)); float opacity = style()->opacity(); if (opacity < 1.0f) - // FIXME: Possible optimization by clipping to bbox here, once relativeBBox is implemented & clip, mask and filter support added. - paintInfo.context->beginTransparencyLayer(opacity); + childPaintInfo.context->beginTransparencyLayer(opacity); - PaintInfo pi(paintInfo); - pi.rect = absoluteTransform().inverse().mapRect(paintInfo.rect); - RenderBlock::paint(pi, 0, 0); + RenderBlock::paint(childPaintInfo, 0, 0); if (opacity < 1.0f) - paintInfo.context->endTransparencyLayer(); + childPaintInfo.context->endTransparencyLayer(); - paintInfo.context->restore(); + childPaintInfo.context->restore(); } -void RenderForeignObject::computeAbsoluteRepaintRect(IntRect& r, bool f) +FloatRect RenderForeignObject::objectBoundingBox() const { - TransformationMatrix transform = translationForAttributes() * localTransform(); - r = transform.mapRect(r); + return borderBoxRect(); +} - RenderBlock::computeAbsoluteRepaintRect(r, f); +FloatRect RenderForeignObject::repaintRectInLocalCoordinates() const +{ + // 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(); } -bool RenderForeignObject::requiresLayer() +void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) { - return false; + rect = localToParentTransform().mapRect(rect); + RenderBlock::computeRectForRepaint(repaintContainer, rect, fixed); } -bool RenderForeignObject::calculateLocalTransform() +TransformationMatrix RenderForeignObject::localToParentTransform() const { - TransformationMatrix oldTransform = m_localTransform; - m_localTransform = static_cast<SVGForeignObjectElement*>(element())->animatedLocalTransform(); - return (oldTransform != m_localTransform); + return localTransform() * translationForAttributes(); } void RenderForeignObject::layout() { ASSERT(needsLayout()); + ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - // Arbitrary affine transforms are incompatible with LayoutState. - view()->disableLayoutState(); - - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBounds(); - } - - calculateLocalTransform(); - - RenderBlock::layout(); - - m_absoluteBounds = absoluteClippedOverflowRect(); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + m_localTransform = static_cast<SVGForeignObjectElement*>(node())->animatedLocalTransform(); - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + RenderBlock::layout(); + repainter.repaintAfterLayout(); - view()->enableLayoutState(); setNeedsLayout(false); } -bool RenderForeignObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +bool RenderForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { - TransformationMatrix totalTransform = absoluteTransform(); - totalTransform *= translationForAttributes(); - double localX, localY; - totalTransform.inverse().map(x, y, &localX, &localY); - return RenderBlock::nodeAtPoint(request, result, static_cast<int>(localX), static_cast<int>(localY), tx, ty, 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); +} + +bool RenderForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h index c7f30e9..8fdb816 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h @@ -1,7 +1,6 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 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 @@ -39,20 +38,24 @@ public: virtual void paint(PaintInfo&, int parentX, int parentY); - virtual TransformationMatrix localTransform() const { return m_localTransform; } - virtual bool calculateLocalTransform(); + virtual TransformationMatrix localToParentTransform() const; - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed); - virtual bool requiresLayer(); + 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 bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); private: - TransformationMatrix translationForAttributes(); + TransformationMatrix translationForAttributes() const; + + virtual TransformationMatrix localTransform() const { return m_localTransform; } TransformationMatrix m_localTransform; - IntRect m_absoluteBounds; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp index 15bd24e..a7b131b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp @@ -1,10 +1,8 @@ -/** - * 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) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,15 +23,12 @@ #include "config.h" #include "RenderFrame.h" -#include "RenderFrameSet.h" + #include "FrameView.h" -#include "HTMLFrameSetElement.h" -#include "HTMLNames.h" +#include "HTMLFrameElement.h" namespace WebCore { -using namespace HTMLNames; - RenderFrame::RenderFrame(HTMLFrameElement* frame) : RenderPart(frame) { @@ -42,21 +37,25 @@ RenderFrame::RenderFrame(HTMLFrameElement* frame) FrameEdgeInfo RenderFrame::edgeInfo() const { - return FrameEdgeInfo(element()->noResize(), element()->hasFrameBorder()); + HTMLFrameElement* element = static_cast<HTMLFrameElement*>(node()); + return FrameEdgeInfo(element->noResize(), element->hasFrameBorder()); } void RenderFrame::viewCleared() { - if (element() && m_widget && m_widget->isFrameView()) { - FrameView* view = static_cast<FrameView*>(m_widget); - int marginw = element()->getMarginWidth(); - int marginh = element()->getMarginHeight(); - - if (marginw != -1) - view->setMarginWidth(marginw); - if (marginh != -1) - view->setMarginHeight(marginh); - } + HTMLFrameElement* element = static_cast<HTMLFrameElement*>(node()); + if (!element || !widget() || !widget()->isFrameView()) + return; + + FrameView* view = static_cast<FrameView*>(widget()); + + int marginw = element->getMarginWidth(); + int marginh = element->getMarginHeight(); + + if (marginw != -1) + view->setMarginWidth(marginw); + if (marginh != -1) + view->setMarginHeight(marginh); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h index 49aedd3..2716e14 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h @@ -1,9 +1,7 @@ /* - * This file is part of the KDE project. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,23 +23,23 @@ #ifndef RenderFrame_h #define RenderFrame_h -#include "HTMLFrameElement.h" #include "RenderPart.h" #include "RenderFrameSet.h" namespace WebCore { +class HTMLFrameElement; + class RenderFrame : public RenderPart { public: RenderFrame(HTMLFrameElement*); + FrameEdgeInfo edgeInfo() const; + +private: virtual const char* renderName() const { return "RenderFrame"; } virtual bool isFrame() const { return true; } - HTMLFrameElement* element() const { return static_cast<HTMLFrameElement*>(RenderPart::element()); } - - FrameEdgeInfo edgeInfo() const; - virtual void viewCleared(); }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp index d93fa86..5995117 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp @@ -42,7 +42,7 @@ namespace WebCore { RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet) - : RenderContainer(frameSet) + : RenderBox(frameSet) , m_isResizing(false) , m_isChildResizing(false) { @@ -126,8 +126,8 @@ void RenderFrameSet::paint(PaintInfo& paintInfo, int tx, int ty) return; // Add in our offsets. - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); int rows = frameSet()->totalRows(); int cols = frameSet()->totalCols(); @@ -161,11 +161,11 @@ bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& r if (action != HitTestForeground) return false; - bool inside = RenderContainer::nodeAtPoint(request, result, x, y, tx, ty, action) - || m_isResizing || canResize(IntPoint(x, y)); + bool inside = RenderBox::nodeAtPoint(request, result, x, y, tx, ty, action) + || m_isResizing; if (inside && frameSet()->noResize() - && !request.readonly && !result.innerNode()) { + && !request.readOnly() && !result.innerNode()) { result.setInnerNode(node()); result.setInnerNonSharedNode(node()); } @@ -457,8 +457,8 @@ void RenderFrameSet::layout() oldBounds = absoluteClippedOverflowRect(); if (!parent()->isFrameSet() && !document()->printing()) { - m_width = view()->viewWidth(); - m_height = view()->viewHeight(); + setWidth(view()->viewWidth()); + setHeight(view()->viewHeight()); } size_t cols = frameSet()->totalCols(); @@ -470,12 +470,12 @@ void RenderFrameSet::layout() } int borderThickness = frameSet()->border(); - layOutAxis(m_rows, frameSet()->rowLengths(), m_height - (rows - 1) * borderThickness); - layOutAxis(m_cols, frameSet()->colLengths(), m_width - (cols - 1) * borderThickness); + layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); + layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); positionFrames(); - RenderContainer::layout(); + RenderBox::layout(); computeEdgeInfo(); @@ -491,7 +491,7 @@ void RenderFrameSet::layout() void RenderFrameSet::positionFrames() { - RenderObject* child = firstChild(); + RenderBox* child = firstChildBox(); if (!child) return; @@ -504,7 +504,7 @@ void RenderFrameSet::positionFrames() int xPos = 0; int height = m_rows.m_sizes[r]; for (int c = 0; c < cols; c++) { - child->setPos(xPos, yPos); + child->setLocation(xPos, yPos); int width = m_cols.m_sizes[c]; // has to be resized and itself resize its contents @@ -517,7 +517,7 @@ void RenderFrameSet::positionFrames() xPos += width + borderThickness; - child = child->nextSibling(); + child = child->nextSiblingBox(); if (!child) return; } @@ -525,7 +525,7 @@ void RenderFrameSet::positionFrames() } // all the remaining frames are hidden to avoid ugly spurious unflowed frames - for (; child; child = child->nextSibling()) { + for (; child; child = child->nextSiblingBox()) { child->setWidth(0); child->setHeight(0); child->setNeedsLayout(false); @@ -564,8 +564,9 @@ bool RenderFrameSet::userResize(MouseEvent* evt) if (needsLayout()) return false; if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) { - startResizing(m_cols, evt->pageX() - xPos()); - startResizing(m_rows, evt->pageY() - yPos()); + FloatPoint pos = localToAbsolute(); + startResizing(m_cols, evt->absoluteLocation().x() - pos.x()); + startResizing(m_rows, evt->absoluteLocation().y() - pos.y()); if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) { setIsResizing(true); return true; @@ -573,8 +574,9 @@ bool RenderFrameSet::userResize(MouseEvent* evt) } } else { if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) { - continueResizing(m_cols, evt->pageX() - xPos()); - continueResizing(m_rows, evt->pageY() - yPos()); + FloatPoint pos = localToAbsolute(); + continueResizing(m_cols, evt->absoluteLocation().x() - pos.x()); + continueResizing(m_rows, evt->absoluteLocation().y() - pos.y()); if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) { setIsResizing(false); return true; @@ -605,11 +607,6 @@ bool RenderFrameSet::isResizingColumn() const return m_isResizing && m_cols.m_splitBeingResized != noSplit; } -bool RenderFrameSet::canResize(const IntPoint& p) const -{ - return hitTestSplit(m_cols, p.x()) != noSplit || hitTestSplit(m_rows, p.y()) != noSplit; -} - bool RenderFrameSet::canResizeRow(const IntPoint& p) const { int r = hitTestSplit(m_rows, p.y()); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h index 5401c1b..294e5df 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h @@ -23,7 +23,7 @@ #ifndef RenderFrameSet_h #define RenderFrameSet_h -#include "RenderContainer.h" +#include "RenderBox.h" namespace WebCore { @@ -53,11 +53,16 @@ private: Vector<bool> m_allowBorder; }; -class RenderFrameSet : public RenderContainer { +class RenderFrameSet : public RenderBox { public: RenderFrameSet(HTMLFrameSetElement*); virtual ~RenderFrameSet(); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + virtual const char* renderName() const { return "RenderFrameSet"; } virtual bool isFrameSet() const { return true; } @@ -93,7 +98,6 @@ private: inline HTMLFrameSetElement* frameSet() const; - bool canResize(const IntPoint&) const; void setIsResizing(bool); void layOutAxis(GridAxis&, const Length*, int availableSpace); @@ -110,6 +114,8 @@ private: void paintRowBorder(const PaintInfo& paintInfo, const IntRect& rect); void paintColumnBorder(const PaintInfo& paintInfo, const IntRect& rect); + RenderObjectChildList m_children; + GridAxis m_rows; GridAxis m_cols; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp index cc8c2c1..1fc07f0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp @@ -31,6 +31,7 @@ #include "HTMLCanvasElement.h" #include "HTMLNames.h" #include "RenderView.h" +#include "FrameView.h" namespace WebCore { @@ -39,32 +40,33 @@ using namespace HTMLNames; RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element) : RenderReplaced(element, element->size()) { + view()->frameView()->setIsVisuallyNonEmpty(); } void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, int tx, int ty) { - IntRect rect = contentBox(); + IntRect rect = contentBoxRect(); rect.move(tx, ty); static_cast<HTMLCanvasElement*>(node())->paint(paintInfo.context, rect); } void RenderHTMLCanvas::canvasSizeChanged() { - IntSize size = static_cast<HTMLCanvasElement*>(node())->size(); - IntSize zoomedSize(size.width() * style()->effectiveZoom(), size.height() * style()->effectiveZoom()); + IntSize canvasSize = static_cast<HTMLCanvasElement*>(node())->size(); + IntSize zoomedSize(canvasSize.width() * style()->effectiveZoom(), canvasSize.height() * style()->effectiveZoom()); - if (size == intrinsicSize()) + if (canvasSize == intrinsicSize()) return; - setIntrinsicSize(size); + setIntrinsicSize(canvasSize); if (!prefWidthsDirty()) setPrefWidthsDirty(true); - IntSize oldSize = IntSize(m_width, m_height); + IntSize oldSize = size(); calcWidth(); calcHeight(); - if (oldSize == IntSize(m_width, m_height)) + if (oldSize == size()) return; if (!selfNeedsLayout()) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp index fc6f19b..cd84a09 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp @@ -37,7 +37,8 @@ #include "HitTestResult.h" #include "Page.h" #include "RenderView.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> +#include <wtf/UnusedParam.h> #if ENABLE(WML) #include "WMLImageElement.h" @@ -281,21 +282,21 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) // layout when we get added in to the render tree hierarchy later. if (containingBlock()) { // lets see if we need to relayout at all.. - int oldwidth = m_width; - int oldheight = m_height; + int oldwidth = width(); + int oldheight = height(); if (!prefWidthsDirty()) setPrefWidthsDirty(true); calcWidth(); calcHeight(); - if (imageSizeChanged || m_width != oldwidth || m_height != oldheight) { + if (imageSizeChanged || width() != oldwidth || height() != oldheight) { shouldRepaint = false; if (!selfNeedsLayout()) setNeedsLayout(true); } - m_width = oldwidth; - m_height = oldheight; + setWidth(oldwidth); + setHeight(oldheight); } } @@ -304,16 +305,39 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) if (rect) { // The image changed rect is in source image coordinates (pre-zooming), // so map from the bounds of the image to the contentsBox. - repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSize(1.0f)), contentBox())); + repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSize(1.0f)), contentBoxRect())); // Guard against too-large changed rects. - repaintRect.intersect(contentBox()); + repaintRect.intersect(contentBoxRect()); } else - repaintRect = contentBox(); + repaintRect = contentBoxRect(); repaintRectangle(repaintRect); + +#if USE(ACCELERATED_COMPOSITING) + if (hasLayer()) { + // Tell any potential compositing layers that the image needs updating. + layer()->rendererContentChanged(); + } +#endif } } +void RenderImage::notifyFinished(CachedResource* newImage) +{ + if (documentBeingDestroyed()) + return; + +#if USE(ACCELERATED_COMPOSITING) + if ((newImage == m_cachedImage) && hasLayer()) { + // tell any potential compositing layers + // that the image is done and they can reference it directly. + layer()->rendererContentChanged(); + } +#else + UNUSED_PARAM(newImage); +#endif +} + void RenderImage::resetAnimation() { if (m_cachedImage) { @@ -371,9 +395,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) } if (!m_altText.isEmpty()) { - String text = m_altText; - text.replace('\\', backslashAsCurrencySymbol()); - context->setFont(style()->font()); + String text = document()->displayStringModifiedByEncoding(m_altText); context->setFillColor(style()->color()); int ax = tx + leftBorder + leftPad; int ay = ty + topBorder + topPad; @@ -386,9 +408,9 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) int textWidth = font.width(textRun); if (errorPictureDrawn) { if (usableWidth >= textWidth && font.height() <= imageY) - context->drawText(textRun, IntPoint(ax, ay + ascent)); + context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); } else if (usableWidth >= textWidth && cHeight >= font.height()) - context->drawText(textRun, IntPoint(ax, ay + ascent)); + context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); } } } else if (hasImage() && cWidth > 0 && cHeight > 0) { @@ -398,13 +420,13 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) - paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true); + paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif IntSize contentSize(cWidth, cHeight); bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, contentSize); IntRect rect(IntPoint(tx + leftBorder + leftPad, ty + topBorder + topPad), contentSize); - HTMLImageElement* imageElt = (element() && element()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(element()) : 0; + 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); } @@ -417,41 +439,42 @@ int RenderImage::minimumReplacedHeight() const HTMLMapElement* RenderImage::imageMap() { - HTMLImageElement* i = element() && element()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(element()) : 0; + HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0; return i ? i->document()->getImageMap(i->useMap()) : 0; } bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - bool inside = RenderReplaced::nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction); + HitTestResult tempResult(result.point()); + bool inside = RenderReplaced::nodeAtPoint(request, tempResult, _x, _y, _tx, _ty, hitTestAction); - if (inside && element()) { - int tx = _tx + m_x; - int ty = _ty + m_y; + if (inside && node()) { + int tx = _tx + x(); + int ty = _ty + y(); - HTMLMapElement* map = imageMap(); - if (map) { - // we're a client side image map - inside = map->mapMouseEvent(_x - tx, _y - ty, IntSize(contentWidth(), contentHeight()), result); - result.setInnerNonSharedNode(element()); + if (HTMLMapElement* map = imageMap()) { + if (map->mapMouseEvent(_x - tx, _y - ty, IntSize(contentWidth(), contentHeight()), tempResult)) + tempResult.setInnerNonSharedNode(node()); } } + if (inside) + result = tempResult; return inside; } void RenderImage::updateAltText() { - if (!element()) + if (!node()) return; - if (element()->hasTagName(inputTag)) - m_altText = static_cast<HTMLInputElement*>(element())->altText(); - else if (element()->hasTagName(imgTag)) - m_altText = static_cast<HTMLImageElement*>(element())->altText(); + if (node()->hasTagName(inputTag)) + m_altText = static_cast<HTMLInputElement*>(node())->altText(); + else if (node()->hasTagName(imgTag)) + m_altText = static_cast<HTMLImageElement*>(node())->altText(); #if ENABLE(WML) - else if (element()->hasTagName(WMLNames::imgTag)) - m_altText = static_cast<WMLImageElement*>(element())->altText(); + else if (node()->hasTagName(WMLNames::imgTag)) + m_altText = static_cast<WMLImageElement*>(node())->altText(); #endif } @@ -492,8 +515,10 @@ bool RenderImage::isHeightSpecified() const int RenderImage::calcReplacedWidth(bool includeMaxWidth) const { if (imageHasRelativeWidth()) - if (RenderObject* cb = isPositioned() ? container() : containingBlock()) - setImageContainerSize(IntSize(cb->availableWidth(), cb->availableHeight())); + if (RenderObject* cb = isPositioned() ? container() : containingBlock()) { + if (cb->isBox()) + setImageContainerSize(IntSize(toRenderBox(cb)->availableWidth(), toRenderBox(cb)->availableHeight())); + } int width; if (isWidthSpecified()) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h index 71896d6..042452f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderImage.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h @@ -48,6 +48,7 @@ public: virtual int minimumReplacedHeight() const; virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void notifyFinished(CachedResource*); bool setImageSizeForAltText(CachedImage* newImage = 0); @@ -102,6 +103,21 @@ protected: friend class RenderImageScaleObserver; }; +inline RenderImage* toRenderImage(RenderObject* o) +{ + ASSERT(!o || o->isRenderImage()); + return static_cast<RenderImage*>(o); +} + +inline const RenderImage* toRenderImage(const RenderObject* o) +{ + ASSERT(!o || o->isRenderImage()); + return static_cast<const RenderImage*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderImage(const RenderImage*); + } // namespace WebCore #endif // RenderImage_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h index cab0192..9f8330d8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h @@ -27,16 +27,14 @@ #define RenderImageGeneratedContent_h #include "RenderImage.h" +#include "StyleImage.h" #include <wtf/RefPtr.h> -#include "RenderStyle.h" - namespace WebCore { class StyleImage; -class RenderImageGeneratedContent : public RenderImage -{ +class RenderImageGeneratedContent : public RenderImage { public: RenderImageGeneratedContent(Node*); virtual ~RenderImageGeneratedContent(); @@ -53,12 +51,14 @@ protected: virtual bool imageHasRelativeWidth() const { return m_styleImage->imageHasRelativeWidth(); } virtual bool imageHasRelativeHeight() const { return m_styleImage->imageHasRelativeHeight(); } virtual IntSize imageSize(float multiplier) const { return m_styleImage->imageSize(this, multiplier); } - virtual WrappedImagePtr imagePtr() const { return m_styleImage->data(); } + + // |m_styleImage| can be 0 if we get a callback for a background image from RenderObject::setStyle. + virtual WrappedImagePtr imagePtr() const { return m_styleImage ? m_styleImage->data() : 0; } private: RefPtr<StyleImage> m_styleImage; }; -} +} // namespace WebCore -#endif +#endif // RenderImageGeneratedContent_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp index 40e5029..3965d94 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp @@ -25,28 +25,95 @@ #include "config.h" #include "RenderInline.h" -#include "Document.h" +#include "FloatQuad.h" +#include "GraphicsContext.h" +#include "HitTestResult.h" +#include "Page.h" #include "RenderArena.h" #include "RenderBlock.h" +#include "RenderView.h" #include "VisiblePosition.h" +#if ENABLE(DASHBOARD_SUPPORT) +#include "Frame.h" +#endif + +using namespace std; + namespace WebCore { RenderInline::RenderInline(Node* node) - : RenderFlow(node) + : RenderBoxModelObject(node) + , m_continuation(0) + , m_lineHeight(-1) + , m_verticalPosition(PositionUndefined) { + setChildrenInline(true); } RenderInline::~RenderInline() { } -void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderInline::destroy() +{ + // Detach our continuation first. + if (m_continuation) + m_continuation->destroy(); + m_continuation = 0; + + // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will + // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. + children()->destroyLeftoverChildren(); + + if (!documentBeingDestroyed()) { + if (firstLineBox()) { + // We can't wait for RenderBoxModelObject::destroy to clear the selection, + // because by then we will have nuked the line boxes. + // FIXME: The SelectionController should be responsible for this when it + // is notified of DOM mutations. + if (isSelectionBorder()) + view()->clearSelection(); + + // If line boxes are contained inside a root, that means we're an inline. + // In that case, we need to remove all the line boxes so that the parent + // lines aren't pointing to deleted children. If the first line box does + // 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()) + box->remove(); + } + } else if (isInline() && parent()) + parent()->dirtyLinesFromChangedChild(this); + } + + m_lineBoxes.deleteLineBoxes(renderArena()); + + RenderBoxModelObject::destroy(); +} + +RenderInline* RenderInline::inlineContinuation() const +{ + if (!m_continuation || m_continuation->isInline()) + return toRenderInline(m_continuation); + return toRenderBlock(m_continuation)->inlineContinuation(); +} + +void RenderInline::updateBoxModelInfoFromStyle() { - RenderFlow::styleDidChange(diff, oldStyle); + RenderBoxModelObject::updateBoxModelInfoFromStyle(); - setInline(true); - setHasReflection(false); + setInline(true); // Needed for run-ins, since run-in is considered a block display type. + + // FIXME: Support transforms and reflections on inline flows someday. + setHasTransform(false); + setHasReflection(false); +} + +void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBoxModelObject::styleDidChange(diff, oldStyle); // Ensure that all of the split inlines pick up the new style. We // only do this if we're an inline, since we don't want to propagate @@ -54,36 +121,27 @@ void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* old // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. - RenderFlow* currCont = continuation(); - while (currCont) { - if (currCont->isInline()) { - RenderFlow* nextCont = currCont->continuation(); - currCont->setContinuation(0); - currCont->setStyle(style()); - currCont->setContinuation(nextCont); - } - currCont = currCont->continuation(); + for (RenderInline* currCont = inlineContinuation(); currCont; currCont = currCont->inlineContinuation()) { + RenderBoxModelObject* nextCont = currCont->continuation(); + currCont->setContinuation(0); + currCont->setStyle(style()); + currCont->setContinuation(nextCont); } m_lineHeight = -1; // Update pseudos for :before and :after now. - if (!isAnonymous()) { - updateBeforeAfterContent(RenderStyle::BEFORE); - updateBeforeAfterContent(RenderStyle::AFTER); + if (!isAnonymous() && document()->usesBeforeAfterRules()) { + children()->updateBeforeAfterContent(this, BEFORE); + children()->updateBeforeAfterContent(this, AFTER); } } -bool RenderInline::isInlineContinuation() const -{ - return m_isContinuation; -} - static inline bool isAfterContent(RenderObject* child) { if (!child) return false; - if (child->style()->styleType() != RenderStyle::AFTER) + if (child->style()->styleType() != AFTER) return false; // Text nodes don't have their own styles, so ignore the style on a text node. if (child->isText() && !child->isBR()) @@ -91,7 +149,46 @@ static inline bool isAfterContent(RenderObject* child) return true; } -void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) +void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + if (continuation()) + return addChildToContinuation(newChild, beforeChild); + return addChildIgnoringContinuation(newChild, beforeChild); +} + +static RenderBoxModelObject* nextContinuation(RenderObject* renderer) +{ + if (renderer->isInline() && !renderer->isReplaced()) + return toRenderInline(renderer)->continuation(); + return toRenderBlock(renderer)->inlineContinuation(); +} + +RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild) +{ + if (beforeChild && beforeChild->parent() == this) + return this; + + RenderBoxModelObject* curr = nextContinuation(this); + RenderBoxModelObject* nextToLast = this; + RenderBoxModelObject* last = this; + while (curr) { + if (beforeChild && beforeChild->parent() == curr) { + if (curr->firstChild() == beforeChild) + return last; + return curr; + } + + nextToLast = last; + last = curr; + curr = nextContinuation(curr); + } + + if (!beforeChild && !last->firstChild()) + return nextToLast; + return last; +} + +void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) { // Make sure we don't append things after :after-generated content if we have it. if (!beforeChild && isAfterContent(lastChild())) @@ -108,14 +205,15 @@ void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeCh RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); newBox->setStyle(newStyle.release()); - RenderFlow* oldContinuation = continuation(); + RenderBoxModelObject* oldContinuation = continuation(); setContinuation(newBox); // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after // content gets properly destroyed. bool isLastChild = (beforeChild == lastChild()); - updateBeforeAfterContent(RenderStyle::AFTER); + if (document()->usesBeforeAfterRules()) + children()->updateBeforeAfterContent(this, AFTER); if (isLastChild && beforeChild != lastChild()) beforeChild = 0; // We destroyed the last child, so now we need to update our insertion // point to be 0. It's just a straight append now. @@ -124,22 +222,21 @@ void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeCh return; } - RenderContainer::addChild(newChild, beforeChild); + RenderBoxModelObject::addChild(newChild, beforeChild); newChild->setNeedsLayoutAndPrefWidthsRecalc(); } -RenderInline* RenderInline::cloneInline(RenderFlow* src) +RenderInline* RenderInline::cloneInline(RenderInline* src) { - RenderInline* o = new (src->renderArena()) RenderInline(src->element()); - o->m_isContinuation = true; + RenderInline* o = new (src->renderArena()) RenderInline(src->node()); o->setStyle(src->style()); return o; } void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, - RenderObject* beforeChild, RenderFlow* oldCont) + RenderObject* beforeChild, RenderBoxModelObject* oldCont) { // Create a clone of this inline. RenderInline* clone = cloneInline(this); @@ -151,18 +248,18 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); - clone->addChildToFlow(removeChildNode(tmp), 0); + clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0); tmp->setNeedsLayoutAndPrefWidthsRecalc(); } // Hook |clone| up as the continuation of the middle block. - middleBlock->setContinuation(clone); + middleBlock->setInlineContinuation(clone); // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. - RenderFlow* curr = static_cast<RenderFlow*>(parent()); - RenderFlow* currChild = this; + RenderBoxModelObject* curr = static_cast<RenderBoxModelObject*>(parent()); + RenderBoxModelObject* currChild = this; // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone. // There will eventually be a better approach to this problem that will let us nest to a much @@ -171,23 +268,26 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, unsigned splitDepth = 1; const unsigned cMaxSplitDepth = 200; while (curr && curr != fromBlock) { + ASSERT(curr->isRenderInline()); if (splitDepth < cMaxSplitDepth) { // Create a new clone. RenderInline* cloneChild = clone; - clone = cloneInline(curr); + clone = cloneInline(toRenderInline(curr)); // Insert our child clone as the first child. - clone->addChildToFlow(cloneChild, 0); + clone->addChildIgnoringContinuation(cloneChild, 0); // Hook the clone up as a continuation of |curr|. - RenderFlow* oldCont = curr->continuation(); - curr->setContinuation(clone); + RenderInline* inlineCurr = toRenderInline(curr); + oldCont = inlineCurr->continuation(); + inlineCurr->setContinuation(clone); clone->setContinuation(oldCont); // Someone may have indirectly caused a <q> to split. When this happens, the :after content // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after // content gets properly destroyed. - curr->updateBeforeAfterContent(RenderStyle::AFTER); + if (document()->usesBeforeAfterRules()) + inlineCurr->children()->updateBeforeAfterContent(this, AFTER); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. @@ -195,19 +295,19 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); - clone->addChildToFlow(curr->removeChildNode(tmp), 0); + clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0); tmp->setNeedsLayoutAndPrefWidthsRecalc(); } } // Keep walking up the chain. currChild = curr; - curr = static_cast<RenderFlow*>(curr->parent()); + curr = static_cast<RenderBoxModelObject*>(curr->parent()); splitDepth++; } // Now we are at the block level. We need to put the clone into the toBlock. - toBlock->appendChildNode(clone); + toBlock->children()->appendChildNode(toBlock, clone); // Now take all the children after currChild and remove them from the fromBlock // and put them in the toBlock. @@ -215,12 +315,12 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, while (o) { RenderObject* tmp = o; o = tmp->nextSibling(); - toBlock->appendChildNode(fromBlock->removeChildNode(tmp)); + toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp)); } } void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, - RenderObject* newChild, RenderFlow* oldCont) + RenderObject* newChild, RenderBoxModelObject* oldCont) { RenderBlock* pre = 0; RenderBlock* block = containingBlock(); @@ -232,6 +332,7 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) { // We can reuse this block and make it the preBlock of the next continuation. pre = block; + pre->removePositionedObjects(0); block = block->containingBlock(); } else { // No anonymous block available for use. Make one. @@ -243,9 +344,9 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); if (madeNewBeforeBlock) - block->insertChildNode(pre, boxFirst); - block->insertChildNode(newBlockBox, boxFirst); - block->insertChildNode(post, boxFirst); + block->children()->insertChildNode(block, pre, boxFirst); + block->children()->insertChildNode(block, newBlockBox, boxFirst); + block->children()->insertChildNode(block, post, boxFirst); block->setChildrenInline(false); if (madeNewBeforeBlock) { @@ -253,7 +354,7 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox while (o) { RenderObject* no = o; o = no->nextSibling(); - pre->appendChildNode(block->removeChildNode(no)); + pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no)); no->setNeedsLayoutAndPrefWidthsRecalc(); } } @@ -264,12 +365,10 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox // time in makeChildrenNonInline by just setting this explicitly up front. newBlockBox->setChildrenInline(false); - // We don't just call addChild, since it would pass things off to the - // continuation, so we call addChildToFlow explicitly instead. We delayed - // adding the newChild until now so that the |newBlockBox| would be fully + // We delayed adding the newChild until now so that the |newBlockBox| would be fully // connected, thus allowing newChild access to a renderArena should it need // to wrap itself in additional boxes (e.g., table construction). - newBlockBox->addChildToFlow(newChild, 0); + newBlockBox->addChild(newChild); // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) // get deleted properly. Because objects moves from the pre block into the post block, we want to @@ -279,121 +378,656 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox post->setNeedsLayoutAndPrefWidthsRecalc(); } -void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty) -{ - paintLines(paintInfo, tx, ty); -} - -void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel) +void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild) { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height())); - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) - curr->absoluteRects(rects, tx + curr->xPos(), ty + curr->yPos(), false); + RenderBoxModelObject* flow = continuationBefore(beforeChild); + ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline()); + RenderBoxModelObject* beforeChildParent = 0; + if (beforeChild) + beforeChildParent = static_cast<RenderBoxModelObject*>(beforeChild->parent()); + else { + RenderBoxModelObject* cont = nextContinuation(flow); + if (cont) + beforeChildParent = cont; + else + beforeChildParent = flow; } - if (continuation() && topLevel) - continuation()->absoluteRects(rects, - tx - containingBlock()->xPos() + continuation()->xPos(), - ty - containingBlock()->yPos() + continuation()->yPos(), - topLevel); -} + if (newChild->isFloatingOrPositioned()) + return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); -void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel) -{ - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - FloatRect localRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()); - quads.append(localToAbsoluteQuad(localRect)); - } - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) - curr->absoluteQuads(quads, false); - } + // A continuation always consists of two potential candidates: an inline or an anonymous + // block box holding block children. + bool childInline = newChild->isInline(); + bool bcpInline = beforeChildParent->isInline(); + bool flowInline = flow->isInline(); - if (continuation() && topLevel) - continuation()->absoluteQuads(quads, topLevel); + if (flow == beforeChildParent) + return flow->addChildIgnoringContinuation(newChild, beforeChild); + else { + // The goal here is to match up if we can, so that we can coalesce and create the + // minimal # of continuations needed for the inline. + if (childInline == bcpInline) + return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); + else if (flowInline == childInline) + return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append. + else + return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); + } } -bool RenderInline::requiresLayer() +void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty) { - return isRelPositioned() || isTransparent() || hasMask(); + m_lineBoxes.paint(this, paintInfo, tx, ty); } -int RenderInline::width() const +void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { - // 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()) { - if (curr == firstLineBox() || curr->xPos() < leftSide) - leftSide = curr->xPos(); - if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide) - rightSide = curr->xPos() + curr->width(); - } + if (InlineRunBox* curr = firstLineBox()) { + for (; curr; curr = curr->nextLineBox()) + rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())); + } else + rects.append(IntRect(tx, ty, 0, 0)); - return rightSide - leftSide; + if (continuation()) { + if (continuation()->isBox()) { + RenderBox* box = toRenderBox(continuation()); + continuation()->absoluteRects(rects, + tx - containingBlock()->x() + box->x(), + ty - containingBlock()->y() + box->y()); + } else + continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y()); + } } -int RenderInline::height() const +void RenderInline::absoluteQuads(Vector<FloatQuad>& quads) { - // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been - // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug - // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now. - ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist. - if (firstLineBox() && lastLineBox()) - return lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos(); - return 0; + if (InlineRunBox* curr = firstLineBox()) { + for (; curr; curr = curr->nextLineBox()) { + FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height()); + quads.append(localToAbsoluteQuad(localRect)); + } + } else + quads.append(localToAbsoluteQuad(FloatRect())); + + if (continuation()) + continuation()->absoluteQuads(quads); } int RenderInline::offsetLeft() const { - int x = RenderFlow::offsetLeft(); + int x = RenderBoxModelObject::offsetLeft(); if (firstLineBox()) - x += firstLineBox()->xPos(); + x += firstLineBox()->x(); return x; } int RenderInline::offsetTop() const { - int y = RenderFlow::offsetTop(); + int y = RenderBoxModelObject::offsetTop(); if (firstLineBox()) - y += firstLineBox()->yPos(); + y += firstLineBox()->y(); return y; } +int RenderInline::marginLeft() const +{ + Length margin = style()->marginLeft(); + if (margin.isAuto()) + return 0; + if (margin.isFixed()) + return margin.value(); + if (margin.isPercent()) + return margin.calcMinValue(max(0, containingBlock()->availableWidth())); + return 0; +} + +int RenderInline::marginRight() const +{ + Length margin = style()->marginRight(); + if (margin.isAuto()) + return 0; + if (margin.isFixed()) + return margin.value(); + if (margin.isPercent()) + return margin.calcMinValue(max(0, containingBlock()->availableWidth())); + return 0; +} + const char* RenderInline::renderName() const { if (isRelPositioned()) return "RenderInline (relative positioned)"; if (isAnonymous()) return "RenderInline (generated)"; + if (isRunIn()) + return "RenderInline (run-in)"; return "RenderInline"; } bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) { - return hitTestLines(request, result, x, y, tx, ty, hitTestAction); + return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction); } -VisiblePosition RenderInline::positionForCoordinates(int x, int y) +VisiblePosition RenderInline::positionForPoint(const IntPoint& point) { - // Translate the coords from the pre-anonymous block to the post-anonymous block. + // FIXME: Does not deal with relative positioned inlines (should it?) RenderBlock* cb = containingBlock(); - int parentBlockX = cb->xPos() + x; - int parentBlockY = cb->yPos() + y; - for (RenderObject* c = continuation(); c; c = c->continuation()) { - RenderObject* contBlock = c; - if (c->isInline()) - contBlock = c->containingBlock(); + if (firstLineBox()) { + // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We + // should try to find a result by asking our containing block. + return cb->positionForPoint(point); + } + + // Translate the coords from the pre-anonymous block to the post-anonymous block. + int parentBlockX = cb->x() + point.x(); + int parentBlockY = cb->y() + point.y(); + RenderBoxModelObject* c = continuation(); + while (c) { + RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c); if (c->isInline() || c->firstChild()) - return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos()); + return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y()); + c = toRenderBlock(c)->inlineContinuation(); + } + + return RenderBoxModelObject::positionForPoint(point); +} + +IntRect RenderInline::linesBoundingBox() const +{ + IntRect result; + + // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been + // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug + // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now. + ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist. + if (firstLineBox() && lastLineBox()) { + // 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()) { + if (curr == firstLineBox() || curr->x() < leftSide) + leftSide = curr->x(); + if (curr == firstLineBox() || curr->x() + curr->width() > rightSide) + rightSide = curr->x() + curr->width(); + } + result.setWidth(rightSide - leftSide); + result.setX(leftSide); + result.setHeight(lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y()); + result.setY(firstLineBox()->y()); } - return RenderFlow::positionForCoordinates(x, y); + return result; +} + +IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + // Only run-ins are allowed in here during layout. + ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn()); + + if (!firstLineBox() && !continuation()) + return IntRect(); + + // Find our leftmost position. + IntRect boundingBox(linesBoundingBox()); + int left = boundingBox.x(); + int top = boundingBox.y(); + + // Now invalidate a rectangle. + int ow = style() ? style()->outlineSize() : 0; + + // We need to add in the relative position offsets of any inlines (including us) up to our + // containing block. + RenderBlock* cb = containingBlock(); + for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; + inlineFlow = inlineFlow->parent()) { + if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) + toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top); + } + + IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2); + if (cb->hasColumns()) + cb->adjustRectForColumns(r); + + if (cb->hasOverflowClip()) { + // 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 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); + } + + // FIXME: need to ensure that we compute the correct repaint rect when the repaint container + // is an inline. + if (repaintContainer != this) + cb->computeRectForRepaint(repaintContainer, r); + + if (ow) { + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText()) { + IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow); + r.unite(childRect); + } + } + + if (continuation() && !continuation()->isInline()) { + IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow); + r.unite(contRect); + } + } + + return r; +} + +IntRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) +{ + IntRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText()) + r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + } + return r; +} + +void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) +{ + if (RenderView* v = view()) { + // LayoutState is only valid for root-relative repainting + if (v->layoutStateEnabled() && !repaintContainer) { + LayoutState* layoutState = v->layoutState(); + if (style()->position() == RelativePosition && layer()) + rect.move(layer()->relativePositionOffset()); + rect.move(layoutState->m_offset); + if (layoutState->m_clipped) + rect.intersect(layoutState->m_clipRect); + return; + } + } + + if (repaintContainer == this) + return; + + RenderObject* o = container(); + if (!o) + return; + + IntPoint topLeft = rect.location(); + + if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) { + RenderBlock* cb = toRenderBlock(o); + if (cb->hasColumns()) { + IntRect repaintRect(topLeft, rect.size()); + cb->adjustRectForColumns(repaintRect); + topLeft = repaintRect.location(); + rect = repaintRect; + } + } + + if (style()->position() == RelativePosition && layer()) { + // Apply the relative position offset when invalidating a rectangle. The layer + // is translated, but the render box isn't, so we need to do this to get the + // right dirty rect. Since this is called from RenderObject::setStyle, the relative position + // flag on the RenderObject has been cleared, so use the one on the style(). + topLeft += layer()->relativePositionOffset(); + } + + // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, + // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. + if (o->hasOverflowClip()) { + RenderBox* containerBox = toRenderBox(o); + + // o->height() is inaccurate if we're in the middle of a layout of |o|, 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. + topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden. + + IntRect repaintRect(topLeft, rect.size()); + IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height()); + rect = intersection(repaintRect, boxRect); + if (rect.isEmpty()) + return; + } else + rect.setLocation(topLeft); + + o->computeRectForRepaint(repaintContainer, rect, fixed); +} + +void RenderInline::updateDragState(bool dragOn) +{ + RenderBoxModelObject::updateDragState(dragOn); + if (continuation()) + continuation()->updateDragState(dragOn); +} + +void RenderInline::childBecameNonInline(RenderObject* child) +{ + // We have to split the parent flow. + RenderBlock* newBox = containingBlock()->createAnonymousBlock(); + RenderBoxModelObject* oldContinuation = continuation(); + setContinuation(newBox); + RenderObject* beforeChild = child->nextSibling(); + children()->removeChildNode(this, child); + splitFlow(beforeChild, newBox, child, oldContinuation); +} + +void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point) +{ + if (result.innerNode()) + return; + + Node* n = node(); + IntPoint localPoint(point); + if (n) { + if (isInlineContinuation()) { + // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space + // of the principal renderer's containing block. This will end up being the innerNonSharedNode. + RenderBlock* firstBlock = n->renderer()->containingBlock(); + + // Get our containing block. + RenderBox* block = containingBlock(); + localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y()); + } + + result.setInnerNode(n); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(n); + result.setLocalPoint(localPoint); + } +} + +void RenderInline::dirtyLineBoxes(bool fullLayout) +{ + if (fullLayout) + m_lineBoxes.deleteLineBoxes(renderArena()); + else + m_lineBoxes.dirtyLineBoxes(); +} + +InlineFlowBox* RenderInline::createFlowBox() +{ + return new (renderArena()) InlineFlowBox(this); +} + +InlineFlowBox* RenderInline::createInlineFlowBox() +{ + InlineFlowBox* flowBox = createFlowBox(); + m_lineBoxes.appendLineBox(flowBox); + return flowBox; +} + +int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const +{ + if (firstLine && document()->usesFirstLineRules()) { + RenderStyle* s = style(firstLine); + if (s != style()) + return s->computedLineHeight(); + } + + if (m_lineHeight == -1) + m_lineHeight = style()->computedLineHeight(); + + return m_lineHeight; +} + +int RenderInline::verticalPositionFromCache(bool firstLine) const +{ + if (firstLine) // We're only really a first-line style if the document actually uses first-line rules. + firstLine = document()->usesFirstLineRules(); + int vpos = m_verticalPosition; + if (m_verticalPosition == PositionUndefined || firstLine) { + vpos = verticalPosition(firstLine); + if (!firstLine) + m_verticalPosition = vpos; + } + return vpos; +} + +IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const +{ + ASSERT(isRelPositioned()); + if (!isRelPositioned()) + return IntSize(); + + // When we have an enclosing relpositioned inline, we need to add in the offset of the first line + // box from the rest of the content, but only in the cases where we know we're positioned + // relative to the inline itself. + + IntSize offset; + int sx; + int sy; + if (firstLineBox()) { + sx = firstLineBox()->x(); + sy = firstLineBox()->y(); + } else { + sx = layer()->staticX(); + sy = layer()->staticY(); + } + + if (!child->style()->hasStaticX()) + offset.setWidth(sx); + // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside + // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct + // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers + // do. + else if (!child->style()->isOriginalDisplayInlineType()) + // Avoid adding in the left border/padding of the containing block twice. Subtract it out. + offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft())); + + if (!child->style()->hasStaticY()) + offset.setHeight(sy); + + return offset; +} + +void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) +{ + if (!parent()) + return; + + // FIXME: We can do better. + repaint(); +} + +void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +{ + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())); + + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText() && !curr->isListMarker()) { + FloatPoint pos(tx, ty); + // FIXME: This doesn't work correctly with transforms. + if (curr->hasLayer()) + pos = curr->localToAbsolute(); + else if (curr->isBox()) + pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y()); + curr->addFocusRingRects(graphicsContext, pos.x(), pos.y()); + } + } + + if (continuation()) { + if (continuation()->isInline()) + continuation()->addFocusRingRects(graphicsContext, + tx - containingBlock()->x() + continuation()->containingBlock()->x(), + ty - containingBlock()->y() + continuation()->containingBlock()->y()); + else + continuation()->addFocusRingRects(graphicsContext, + tx - containingBlock()->x() + toRenderBox(continuation())->x(), + ty - containingBlock()->y() + toRenderBox(continuation())->y()); + } +} + +void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty) +{ + if (!hasOutline()) + return; + + if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) { + int ow = style()->outlineWidth(); + Color oc = style()->outlineColor(); + if (!oc.isValid()) + oc = style()->color(); + + graphicsContext->initFocusRing(ow, style()->outlineOffset()); + addFocusRingRects(graphicsContext, tx, ty); + if (style()->outlineStyleIsAuto()) + graphicsContext->drawFocusRing(oc); + else + addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); + graphicsContext->clearFocusRing(); + } + + if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE) + return; + + Vector<IntRect> rects; + + rects.append(IntRect()); + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + rects.append(IntRect(curr->x(), curr->y(), curr->width(), curr->height())); + + rects.append(IntRect()); + + for (unsigned i = 1; i < rects.size() - 1; i++) + paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1)); +} + +void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty, + const IntRect& lastline, const IntRect& thisline, const IntRect& nextline) +{ + int ow = style()->outlineWidth(); + EBorderStyle os = style()->outlineStyle(); + Color oc = style()->outlineColor(); + if (!oc.isValid()) + oc = style()->color(); + + int offset = style()->outlineOffset(); + + int t = ty + thisline.y() - offset; + int l = tx + thisline.x() - offset; + int b = ty + thisline.bottom() + offset; + int r = tx + thisline.right() + offset; + + // left edge + drawLineForBoxSide(graphicsContext, + l - ow, + t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0), + l, + b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0), + BSLeft, + oc, style()->color(), os, + (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow), + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow)); + + // right edge + drawLineForBoxSide(graphicsContext, + r, + t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0), + r + ow, + b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0), + BSRight, + oc, style()->color(), os, + (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow), + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow)); + // upper edge + if (thisline.x() < lastline.x()) + drawLineForBoxSide(graphicsContext, + l - ow, + t - ow, + min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())), + t , + BSTop, oc, style()->color(), os, + ow, + (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow); + + if (lastline.right() < thisline.right()) + drawLineForBoxSide(graphicsContext, + max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow), + t - ow, + r + ow, + t , + BSTop, oc, style()->color(), os, + (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow, + ow); + + // lower edge + if (thisline.x() < nextline.x()) + drawLineForBoxSide(graphicsContext, + l - ow, + b, + min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000), + b + ow, + BSBottom, oc, style()->color(), os, + ow, + (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow); + + if (nextline.right() < thisline.right()) + drawLineForBoxSide(graphicsContext, + max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow), + b, + r + ow, + b + ow, + BSBottom, oc, style()->color(), os, + (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow, + ow); +} + +#if ENABLE(DASHBOARD_SUPPORT) +void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions) +{ + // Convert the style regions to absolute coordinates. + if (style()->visibility() != VISIBLE) + return; + + const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions(); + unsigned i, count = styleRegions.size(); + for (i = 0; i < count; i++) { + StyleDashboardRegion styleRegion = styleRegions[i]; + + IntRect linesBoundingBox = this->linesBoundingBox(); + int w = linesBoundingBox.width(); + int h = linesBoundingBox.height(); + + DashboardRegionValue region; + region.label = styleRegion.label; + region.bounds = IntRect(linesBoundingBox.x() + styleRegion.offset.left().value(), + linesBoundingBox.y() + styleRegion.offset.top().value(), + w - styleRegion.offset.left().value() - styleRegion.offset.right().value(), + h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value()); + region.type = styleRegion.type; + + RenderObject* container = containingBlock(); + if (!container) + container = this; + + region.clip = region.bounds; + container->computeAbsoluteRepaintRect(region.clip); + if (region.clip.height() < 0) { + region.clip.setHeight(0); + region.clip.setWidth(0); + } + + FloatPoint absPos = container->localToAbsolute(); + region.bounds.setX(absPos.x() + region.bounds.x()); + region.bounds.setY(absPos.y() + region.bounds.y()); + + if (document()->frame()) { + float pageScaleFactor = document()->frame()->page()->chrome()->scaleFactor(); + if (pageScaleFactor != 1.0f) { + region.bounds.scale(pageScaleFactor); + region.clip.scale(pageScaleFactor); + } + } + + regions.append(region); + } } +#endif } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h index 1c42a6f..cf6b84b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderInline.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h @@ -25,60 +25,147 @@ #ifndef RenderInline_h #define RenderInline_h -#include "RenderFlow.h" +#include "RenderBoxModelObject.h" +#include "RenderLineBoxList.h" namespace WebCore { class Position; -class RenderInline : public RenderFlow { +class RenderInline : public RenderBoxModelObject { public: RenderInline(Node*); virtual ~RenderInline(); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + + virtual void destroy(); + virtual const char* renderName() const; virtual bool isRenderInline() const { return true; } - virtual bool isInlineFlow() const { return true; } - virtual bool childrenInline() const { return true; } - virtual bool isInlineContinuation() const; + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); + void addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild); + virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild); void splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, - RenderObject* beforeChild, RenderFlow* oldCont); + RenderObject* beforeChild, RenderBoxModelObject* oldCont); void splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, - RenderObject* newChild, RenderFlow* oldCont); + RenderObject* newChild, RenderBoxModelObject* oldCont); - virtual void layout() { } // Do nothing for layout() + virtual void layout() { ASSERT_NOT_REACHED(); } // Do nothing for layout() virtual void paint(PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - // overrides RenderObject - virtual bool requiresLayer(); - - virtual int width() const; - virtual int height() const; + virtual bool requiresLayer() const { return isRelPositioned() || isTransparent() || hasMask(); } - // used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) to return - // the remaining width on a given line (and the height of a single line). virtual int offsetLeft() const; virtual int offsetTop() const; + virtual int offsetWidth() const { return linesBoundingBox().width(); } + virtual int offsetHeight() const { return linesBoundingBox().height(); } + + // Just ignore top/bottom margins on RenderInlines. + virtual int marginTop() const { return 0; } + virtual int marginBottom() const { return 0; } + virtual int marginLeft() const; + virtual int marginRight() const; + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed); + + virtual VisiblePosition positionForPoint(const IntPoint&); + + IntRect linesBoundingBox() const; + + virtual IntRect borderBoundingBox() const + { + IntRect boundingBox = linesBoundingBox(); + return IntRect(0, 0, boundingBox.width(), boundingBox.height()); + } + + InlineFlowBox* createInlineFlowBox(); + void dirtyLineBoxes(bool fullLayout); + virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } + + RenderLineBoxList* lineBoxes() { return &m_lineBoxes; } + const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; } + + InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); } + InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } - void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; - virtual VisiblePosition positionForCoordinates(int x, int y); + RenderBoxModelObject* continuation() const { return m_continuation; } + RenderInline* inlineContinuation() const; + void setContinuation(RenderBoxModelObject* c) { m_continuation = c; } + + virtual void updateDragState(bool dragOn); + + virtual void childBecameNonInline(RenderObject* child); + virtual void updateHitTestResult(HitTestResult&, const IntPoint&); + + IntSize relativePositionedInlineOffset(const RenderBox* child) const; + + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + void paintOutline(GraphicsContext*, int tx, int ty); + + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + + int verticalPositionFromCache(bool firstLine) const; + void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } + +#if ENABLE(DASHBOARD_SUPPORT) + virtual void addDashboardRegions(Vector<DashboardRegionValue>&); +#endif + protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateBoxModelInfoFromStyle(); + virtual InlineFlowBox* createFlowBox(); // Subclassed by SVG + + static RenderInline* cloneInline(RenderInline* src); - static RenderInline* cloneInline(RenderFlow* src); +private: + void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine); + RenderBoxModelObject* continuationBefore(RenderObject* beforeChild); +protected: + RenderObjectChildList m_children; + RenderLineBoxList m_lineBoxes; // All of the line boxes created for this inline flow. For example, <i>Hello<br>world.</i> will have two <i> line boxes. + +private: + RenderBoxModelObject* m_continuation; // Can be either a block or an inline. <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as its continuation but the + // <b> will just have an inline as its continuation. + mutable int m_lineHeight; + mutable int m_verticalPosition; }; +inline RenderInline* toRenderInline(RenderObject* o) +{ + ASSERT(!o || o->isRenderInline()); + return static_cast<RenderInline*>(o); +} + +inline const RenderInline* toRenderInline(const RenderObject* o) +{ + ASSERT(!o || o->isRenderInline()); + return static_cast<const RenderInline*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderInline(const RenderInline*); + } // namespace WebCore #endif // RenderInline_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp index 9c9eff0..ba85f1a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp @@ -44,10 +44,14 @@ #include "config.h" #include "RenderLayer.h" +#include "CString.h" #include "CSSPropertyNames.h" +#include "CSSStyleDeclaration.h" +#include "CSSStyleSelector.h" #include "Document.h" #include "EventHandler.h" #include "EventNames.h" +#include "FloatPoint3D.h" #include "FloatRect.h" #include "FocusController.h" #include "Frame.h" @@ -59,6 +63,7 @@ #include "HitTestRequest.h" #include "HitTestResult.h" #include "OverflowEvent.h" +#include "OverlapTestRequestClient.h" #include "Page.h" #include "PlatformMouseEvent.h" #include "RenderArena.h" @@ -73,8 +78,16 @@ #include "Scrollbar.h" #include "ScrollbarTheme.h" #include "SelectionController.h" +#include "TransformationMatrix.h" +#include "TransformState.h" #include "TranslateTransformOperation.h" #include <wtf/StdLibExtras.h> +#include <wtf/UnusedParam.h> + +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerBacking.h" +#include "RenderLayerCompositor.h" +#endif #if ENABLE(SVG) #include "SVGNames.h" @@ -88,12 +101,6 @@ namespace WebCore { using namespace HTMLNames; -const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterIfNeeded = { RenderLayer::noScroll, RenderLayer::alignCenter, RenderLayer::alignToClosestEdge }; -const RenderLayer::ScrollAlignment RenderLayer::gAlignToEdgeIfNeeded = { RenderLayer::noScroll, RenderLayer::alignToClosestEdge, RenderLayer::alignToClosestEdge }; -const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterAlways = { RenderLayer::alignCenter, RenderLayer::alignCenter, RenderLayer::alignCenter }; -const RenderLayer::ScrollAlignment RenderLayer::gAlignTopAlways = { RenderLayer::alignTop, RenderLayer::alignTop, RenderLayer::alignTop }; -const RenderLayer::ScrollAlignment RenderLayer::gAlignBottomAlways = { RenderLayer::alignBottom, RenderLayer::alignBottom, RenderLayer::alignBottom }; - const int MinimumWidthWhileResizing = 100; const int MinimumHeightWhileResizing = 40; @@ -116,8 +123,8 @@ void ClipRects::destroy(RenderArena* renderArena) renderArena->free(*(size_t *)this, this); } -RenderLayer::RenderLayer(RenderObject* object) - : m_object(object) +RenderLayer::RenderLayer(RenderBoxModelObject* renderer) + : m_renderer(renderer) , m_parent(0) , m_previous(0) , m_next(0) @@ -138,15 +145,15 @@ RenderLayer::RenderLayer(RenderObject* object) , m_inResizeMode(false) , m_posZOrderList(0) , m_negZOrderList(0) - , m_overflowList(0) + , m_normalFlowList(0) , m_clipRects(0) #ifndef NDEBUG , m_clipRectsRoot(0) #endif , m_scrollDimensionsDirty(true) , m_zOrderListsDirty(true) - , m_overflowListDirty(true) - , m_isOverflowOnly(shouldBeOverflowOnly()) + , m_normalFlowListDirty(true) + , m_isNormalFlowOnly(shouldBeNormalFlowOnly()) , m_usedTransparency(false) , m_paintingInsideReflection(false) , m_inOverflowRelayout(false) @@ -156,17 +163,22 @@ RenderLayer::RenderLayer(RenderObject* object) , m_hasVisibleContent(false) , m_visibleDescendantStatusDirty(false) , m_hasVisibleDescendant(false) + , m_3DTransformedDescendantStatusDirty(true) + , m_has3DTransformedDescendant(false) +#if USE(ACCELERATED_COMPOSITING) + , m_hasCompositingDescendant(false) + , m_mustOverlayCompositedLayers(false) +#endif , m_marquee(0) , m_staticX(0) , m_staticY(0) - , m_transform(0) , m_reflection(0) , m_scrollCorner(0) , m_resizer(0) { - if (!object->firstChild() && object->style()) { + if (!renderer->firstChild() && renderer->style()) { m_visibleContentStatusDirty = false; - m_hasVisibleContent = object->style()->visibility() == VISIBLE; + m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; } } @@ -185,9 +197,13 @@ RenderLayer::~RenderLayer() delete m_posZOrderList; delete m_negZOrderList; - delete m_overflowList; + delete m_normalFlowList; delete m_marquee; +#if USE(ACCELERATED_COMPOSITING) + clearBacking(); +#endif + // Make sure we have no lingering clip rects. ASSERT(!m_clipRects); @@ -204,11 +220,53 @@ RenderLayer::~RenderLayer() m_resizer->destroy(); } +#if USE(ACCELERATED_COMPOSITING) +RenderLayerCompositor* RenderLayer::compositor() const +{ + ASSERT(renderer()->view()); + return renderer()->view()->compositor(); +} + +void RenderLayer::rendererContentChanged() +{ + // This can get called when video becomes accelerated, so the layers may change. + if (compositor()->updateLayerCompositingState(this)) + compositor()->setCompositingLayersNeedUpdate(); + + if (m_backing) + m_backing->rendererContentChanged(); +} +#endif // USE(ACCELERATED_COMPOSITING) + +bool RenderLayer::hasAcceleratedCompositing() const +{ +#if USE(ACCELERATED_COMPOSITING) + return compositor()->hasAcceleratedCompositing(); +#else + return false; +#endif +} + +void RenderLayer::setStaticY(int staticY) +{ + if (m_staticY == staticY) + return; + m_staticY = staticY; + renderer()->setChildNeedsLayout(true, false); +} + void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) { if (doFullRepaint) { - m_object->repaint(); + renderer()->repaint(); +#if USE(ACCELERATED_COMPOSITING) + checkForRepaint = false; + // We need the full repaint to propagate to child layers if we are hardware compositing. + if (!compositor()->inCompositingMode()) + doFullRepaint = false; +#else checkForRepaint = doFullRepaint = false; +#endif } updateLayerPosition(); // For relpositioned layers or non-positioned layers, @@ -225,22 +283,23 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) updateTransform(); if (m_hasVisibleContent) { - RenderView* view = m_object->view(); + RenderView* view = renderer()->view(); ASSERT(view); // FIXME: Optimize using LayoutState and remove the disableLayoutState() call // from updateScrollInfoAfterLayout(). - ASSERT(!view->layoutState()); + ASSERT(!view->layoutStateEnabled()); - IntRect newRect = m_object->absoluteClippedOverflowRect(); - IntRect newOutlineBox = m_object->absoluteOutlineBounds(); + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); + IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); + IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); if (checkForRepaint) { if (view && !view->printing()) { if (m_needsFullRepaint) { - view->repaintViewRectangle(m_repaintRect); + renderer()->repaintUsingContainer(repaintContainer, m_repaintRect); if (newRect != m_repaintRect) - view->repaintViewRectangle(newRect); + renderer()->repaintUsingContainer(repaintContainer, newRect); } else - m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox); + renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox); } } m_repaintRect = newRect; @@ -258,6 +317,11 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->updateLayerPositions(doFullRepaint, checkForRepaint); + +#if USE(ACCELERATED_COMPOSITING) + if (isComposited()) + backing()->updateAfterLayout(); +#endif // With all our children positioned, now update our marquee if we need to. if (m_marquee) @@ -266,7 +330,11 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) void RenderLayer::updateTransform() { - bool hasTransform = renderer()->hasTransform(); + // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, + // so check style too. + bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform(); + bool had3DTransform = has3DTransform(); + bool hadTransform = m_transform; if (hasTransform != hadTransform) { if (hasTransform) @@ -276,9 +344,33 @@ void RenderLayer::updateTransform() } if (hasTransform) { - m_transform->reset(); - renderer()->style()->applyTransform(*m_transform, renderer()->borderBox().size()); + RenderBox* box = renderBox(); + ASSERT(box); + m_transform->makeIdentity(); + box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); + makeMatrixRenderable(*m_transform, hasAcceleratedCompositing()); } + + if (had3DTransform != has3DTransform()) + dirty3DTransformedDescendantStatus(); +} + +TransformationMatrix RenderLayer::currentTransform() const +{ + if (!m_transform) + return TransformationMatrix(); + +#if USE(ACCELERATED_COMPOSITING) + if (renderer()->style()->isRunningAcceleratedAnimation()) { + TransformationMatrix currTransform; + RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer()); + style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); + makeMatrixRenderable(currTransform, hasAcceleratedCompositing()); + return currTransform; + } +#endif + + return *m_transform; } void RenderLayer::setHasVisibleContent(bool b) @@ -288,9 +380,10 @@ void RenderLayer::setHasVisibleContent(bool b) m_visibleContentStatusDirty = false; m_hasVisibleContent = b; if (m_hasVisibleContent) { - m_repaintRect = renderer()->absoluteClippedOverflowRect(); - m_outlineBox = renderer()->absoluteOutlineBounds(); - if (!isOverflowOnly()) + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); + m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); + m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); + if (!isNormalFlowOnly()) dirtyStackingContextZOrderLists(); } if (parent()) @@ -342,12 +435,12 @@ void RenderLayer::updateVisibilityStatus() } if (m_visibleContentStatusDirty) { - if (m_object->style()->visibility() == VISIBLE) + if (renderer()->style()->visibility() == VISIBLE) m_hasVisibleContent = true; else { // layer may be hidden but still have some visible content, check for this m_hasVisibleContent = false; - RenderObject* r = m_object->firstChild(); + RenderObject* r = renderer()->firstChild(); while (r) { if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { m_hasVisibleContent = true; @@ -360,7 +453,7 @@ void RenderLayer::updateVisibilityStatus() else { do { r = r->parent(); - if (r==m_object) + if (r==renderer()) r = 0; } while (r && !r->nextSibling()); if (r) @@ -372,83 +465,180 @@ void RenderLayer::updateVisibilityStatus() } } +void RenderLayer::dirty3DTransformedDescendantStatus() +{ + RenderLayer* curr = stackingContext(); + if (curr) + curr->m_3DTransformedDescendantStatusDirty = true; + + // This propagates up through preserve-3d hierarchies to the enclosing flattening layer. + // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts. + while (curr && curr->preserves3D()) { + curr->m_3DTransformedDescendantStatusDirty = true; + curr = curr->stackingContext(); + } +} + +// Return true if this layer or any preserve-3d descendants have 3d. +bool RenderLayer::update3DTransformedDescendantStatus() +{ + if (m_3DTransformedDescendantStatusDirty) { + m_has3DTransformedDescendant = false; + + // Transformed or preserve-3d descendants can only be in the z-order lists, not + // in the normal flow list, so we only need to check those. + if (m_posZOrderList) { + for (unsigned i = 0; i < m_posZOrderList->size(); ++i) + m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus(); + } + + // Now check our negative z-index children. + if (m_negZOrderList) { + for (unsigned i = 0; i < m_negZOrderList->size(); ++i) + m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus(); + } + + m_3DTransformedDescendantStatusDirty = false; + } + + // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs + // the m_has3DTransformedDescendant set. + if (preserves3D()) + return has3DTransform() || m_has3DTransformedDescendant; + + return has3DTransform(); +} + void RenderLayer::updateLayerPosition() { // Clear our cached clip rect information. clearClipRects(); - int x = m_object->xPos(); - int y = m_object->yPos() - m_object->borderTopExtra(); + RenderBox* rendererBox = renderBox(); + + int x = rendererBox ? rendererBox->x() : 0; + int y = rendererBox ? rendererBox->y() : 0; - if (!m_object->isPositioned() && m_object->parent()) { + if (!renderer()->isPositioned() && renderer()->parent()) { // We must adjust our position by walking up the render tree looking for the // nearest enclosing object with a layer. - RenderObject* curr = m_object->parent(); + RenderObject* curr = renderer()->parent(); while (curr && !curr->hasLayer()) { - if (!curr->isTableRow()) { + if (curr->isBox() && !curr->isTableRow()) { // Rows and cells share the same coordinate space (that of the section). // Omit them when computing our xpos/ypos. - x += curr->xPos(); - y += curr->yPos(); + RenderBox* currBox = toRenderBox(curr); + x += currBox->x(); + y += currBox->y(); } curr = curr->parent(); } - y += curr->borderTopExtra(); - if (curr->isTableRow()) { + if (curr->isBox() && curr->isTableRow()) { // Put ourselves into the row coordinate space. - x -= curr->xPos(); - y -= curr->yPos(); + RenderBox* currBox = toRenderBox(curr); + x -= currBox->x(); + y -= currBox->y(); } } m_relX = m_relY = 0; - if (m_object->isRelPositioned()) { - m_relX = static_cast<RenderBox*>(m_object)->relativePositionOffsetX(); - m_relY = static_cast<RenderBox*>(m_object)->relativePositionOffsetY(); + if (renderer()->isRelPositioned()) { + m_relX = renderer()->relativePositionOffsetX(); + m_relY = renderer()->relativePositionOffsetY(); x += m_relX; y += m_relY; } // Subtract our parent's scroll offset. - if (m_object->isPositioned() && enclosingPositionedAncestor()) { + if (renderer()->isPositioned() && enclosingPositionedAncestor()) { RenderLayer* positionedParent = enclosingPositionedAncestor(); // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. positionedParent->subtractScrolledContentOffset(x, y); - if (m_object->isPositioned()) { - IntSize offset = static_cast<RenderBox*>(m_object)->offsetForPositionedInContainer(positionedParent->renderer()); + 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); - setPos(x,y); + // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. - setWidth(m_object->width()); - setHeight(m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra()); + setLocation(x, y); - if (!m_object->hasOverflowClip()) { - if (m_object->overflowWidth() > m_object->width()) - setWidth(m_object->overflowWidth()); - if (m_object->overflowHeight() > m_object->height()) - setHeight(m_object->overflowHeight()); + if (renderer()->isRenderInline()) { + RenderInline* inlineFlow = toRenderInline(renderer()); + IntRect lineBox = inlineFlow->linesBoundingBox(); + setWidth(lineBox.width()); + setHeight(lineBox.height()); + } else if (RenderBox* box = renderBox()) { + setWidth(box->width()); + setHeight(box->height()); + + if (!box->hasOverflowClip()) { + if (box->overflowWidth() > box->width()) + setWidth(box->overflowWidth()); + if (box->overflowHeight() > box->height()) + setHeight(box->overflowHeight()); + } } } -RenderLayer *RenderLayer::stackingContext() const +TransformationMatrix RenderLayer::perspectiveTransform() const { - RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isRoot() && - curr->m_object->style()->hasAutoZIndex(); - curr = curr->parent()) { } - return curr; + if (!renderer()->hasTransform()) + return TransformationMatrix(); + + RenderStyle* style = renderer()->style(); + if (!style->hasPerspective()) + return TransformationMatrix(); + + // Maybe fetch the perspective from the backing? + const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); + const float boxWidth = borderBox.width(); + const float boxHeight = borderBox.height(); + + float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth); + float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight); + + // A perspective origin of 0,0 makes the vanishing point in the center of the element. + // We want it to be in the top-left, so subtract half the height and width. + perspectiveOriginX -= boxWidth / 2.0f; + perspectiveOriginY -= boxHeight / 2.0f; + + TransformationMatrix t; + t.translate(perspectiveOriginX, perspectiveOriginY); + t.applyPerspective(style->perspective()); + t.translate(-perspectiveOriginX, -perspectiveOriginY); + + return t; +} + +FloatPoint RenderLayer::perspectiveOrigin() const +{ + if (!renderer()->hasTransform()) + return FloatPoint(); + + const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); + RenderStyle* style = renderer()->style(); + + return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()), + style->perspectiveOriginY().calcFloatValue(borderBox.height())); +} + +RenderLayer* RenderLayer::stackingContext() const +{ + RenderLayer* layer = parent(); + while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex()) + layer = layer->parent(); + return layer; } RenderLayer* RenderLayer::enclosingPositionedAncestor() const { RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned() && !curr->hasTransform(); + for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isPositioned() && !curr->renderer()->isRelPositioned() && !curr->hasTransform(); curr = curr->parent()) { } return curr; } @@ -456,11 +646,32 @@ RenderLayer* RenderLayer::enclosingPositionedAncestor() const RenderLayer* RenderLayer::enclosingTransformedAncestor() const { RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->transform(); curr = curr->parent()) + for ( ; curr && !curr->renderer()->isRenderView() && !curr->transform(); curr = curr->parent()) { } return curr; } +#if USE(ACCELERATED_COMPOSITING) +RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const +{ + if (includeSelf && isComposited()) + return const_cast<RenderLayer*>(this); + + // Compositing layers are parented according to stacking order and overflow list, + // so we have to check whether the parent is a stacking context, or whether + // the child is overflow-only. + bool inNormalFlowList = isNormalFlowOnly(); + for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { + if (curr->isComposited() && (inNormalFlowList || curr->isStackingContext())) + return curr; + + inNormalFlowList = curr->isNormalFlowOnly(); + } + + return 0; +} +#endif + IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const { // We don't use convertToLayerCoords because it doesn't know about transforms @@ -479,18 +690,24 @@ bool RenderLayer::requiresSlowRepaints() const bool RenderLayer::isTransparent() const { #if ENABLE(SVG) - if (m_object->node()->namespaceURI() == SVGNames::svgNamespaceURI) + if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI) return false; #endif - return m_object->isTransparent() || m_object->hasMask(); + return renderer()->isTransparent() || renderer()->hasMask(); } -RenderLayer* -RenderLayer::transparentAncestor() +RenderLayer* RenderLayer::transparentPaintingAncestor() { - RenderLayer* curr = parent(); - for ( ; curr && !curr->isTransparent(); curr = curr->parent()) { } - return curr; + if (isComposited()) + return 0; + + for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { + if (curr->isComposited()) + return 0; + if (curr->isTransparent()) + return curr; + } + return 0; } static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer) @@ -499,16 +716,16 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor // paintDirtyRect, and that should cut down on the amount we have to paint. Still it // would be better to respect clips. - TransformationMatrix* t = l->transform(); - if (t && rootLayer != l) { + 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 = *t * transform; + transform = *l->transform() * transform; transform = transform * enclosingTransform; // We now have a transform that will produce a rectangle in our view's space. @@ -542,14 +759,14 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer) { - if (p->paintingDisabled() || (isTransparent() && m_usedTransparency)) + if (p->paintingDisabled() || (paintsWithTransparency() && m_usedTransparency)) return; - RenderLayer* ancestor = transparentAncestor(); + RenderLayer* ancestor = transparentPaintingAncestor(); if (ancestor) ancestor->beginTransparencyLayers(p, rootLayer); - if (isTransparent()) { + if (paintsWithTransparency()) { m_usedTransparency = true; p->save(); p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer)); @@ -569,7 +786,7 @@ void RenderLayer::operator delete(void* ptr, size_t sz) } void RenderLayer::destroy(RenderArena* renderArena) -{ +{ delete this; // Recover the size left there for us by operator delete and free the memory. @@ -593,10 +810,10 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) child->setParent(this); - if (child->isOverflowOnly()) - dirtyOverflowList(); + if (child->isNormalFlowOnly()) + dirtyNormalFlowList(); - if (!child->isOverflowOnly() || child->firstChild()) { + if (!child->isNormalFlowOnly() || child->firstChild()) { // Dirty the z-order list in which we are contained. The stackingContext() can be null in the // case where we're building up generated content layers. This is ok, since the lists will start // off dirty in that case anyway. @@ -606,10 +823,19 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) child->updateVisibilityStatus(); if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) childVisibilityChanged(true); + +#if USE(ACCELERATED_COMPOSITING) + compositor()->layerWasAdded(this, child); +#endif } RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) { +#if USE(ACCELERATED_COMPOSITING) + if (!renderer()->documentBeingDestroyed()) + compositor()->layerWillBeRemoved(this, oldChild); +#endif + // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); @@ -621,9 +847,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) if (m_last == oldChild) m_last = oldChild->previousSibling(); - if (oldChild->isOverflowOnly()) - dirtyOverflowList(); - if (!oldChild->isOverflowOnly() || oldChild->firstChild()) { + if (oldChild->isNormalFlowOnly()) + dirtyNormalFlowList(); + if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) { // Dirty the z-order list in which we are contained. When called via the // reattachment process in removeOnlyThisLayer, the layer may already be disconnected // from the main layer tree, so we need to null-check the |stackingContext| value. @@ -645,7 +871,15 @@ void RenderLayer::removeOnlyThisLayer() { if (!m_parent) return; - + + // Mark that we are about to lose our layer. This makes render tree + // walks ignore this layer while we're removing it. + m_renderer->setHasLayer(false); + +#if USE(ACCELERATED_COMPOSITING) + compositor()->layerWillBeRemoved(m_parent, this); +#endif + // Dirty the clip rects. clearClipRectsIncludingDescendants(); @@ -663,11 +897,11 @@ void RenderLayer::removeOnlyThisLayer() RenderLayer* next = current->nextSibling(); removeChild(current); parent->addChild(current, nextSib); - current->updateLayerPositions(); + current->updateLayerPositions(); // Depends on hasLayer() already being false for proper layout. current = next; } - - destroy(renderer()->renderArena()); + + m_renderer->destroyLayer(); } void RenderLayer::insertOnlyThisLayer() @@ -676,46 +910,46 @@ void RenderLayer::insertOnlyThisLayer() // We need to connect ourselves when our renderer() has a parent. // Find our enclosingLayer and add ourselves. RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); + ASSERT(parentLayer); RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0; - if (parentLayer) - parentLayer->addChild(this, beforeChild); + parentLayer->addChild(this, beforeChild); } - + // Remove all descendant layers from the hierarchy and add them to the new position. for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) curr->moveLayers(m_parent, this); - + // Clear out all the clip rects. clearClipRectsIncludingDescendants(); } void -RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const +RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, int& yPos) const { if (ancestorLayer == this) return; - if (m_object->style()->position() == FixedPosition) { + if (renderer()->style()->position() == FixedPosition) { // Add in the offset of the view. We can obtain this by calling // localToAbsolute() on the RenderView. - FloatPoint absPos = m_object->localToAbsolute(FloatPoint(), true); - x += absPos.x(); - y += absPos.y(); + FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true); + xPos += absPos.x(); + yPos += absPos.y(); return; } RenderLayer* parentLayer; - if (m_object->style()->position() == AbsolutePosition) + if (renderer()->style()->position() == AbsolutePosition) parentLayer = enclosingPositionedAncestor(); else parentLayer = parent(); if (!parentLayer) return; - parentLayer->convertToLayerCoords(ancestorLayer, x, y); + parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos); - x += xPos(); - y += yPos(); + xPos += x(); + yPos += y(); } void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) @@ -724,7 +958,6 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) const int shortDistanceLimit = 100; // We delimit a 200 pixels long square enclosing the original point const int speedReducer = 2; // Within this square we divide the scrolling speed by 2 - const int iconRadius = 10; Frame* frame = renderer()->document()->frame(); if (!frame) return; @@ -741,9 +974,9 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) int xDelta = currentMousePosition.x() - sourcePoint.x(); int yDelta = currentMousePosition.y() - sourcePoint.y(); - if (abs(xDelta) < iconRadius) // at the center we let the space for the icon + if (abs(xDelta) < ScrollView::noPanScrollRadius) // at the center we let the space for the icon xDelta = 0; - if (abs(yDelta) < iconRadius) + if (abs(yDelta) < ScrollView::noPanScrollRadius) yDelta = 0; // Let's attenuate the speed for the short distances @@ -758,10 +991,10 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) void RenderLayer::scrollByRecursively(int xDelta, int yDelta) { bool restrictedByLineClamp = false; - if (m_object->parent()) - restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0; + if (renderer()->parent()) + restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; - if (m_object->hasOverflowClip() && !restrictedByLineClamp) { + if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { int newOffsetX = scrollXOffset() + xDelta; int newOffsetY = scrollYOffset() + yDelta; scrollToOffset(newOffsetX, newOffsetY); @@ -769,14 +1002,14 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) // If this layer can't do the scroll we ask its parent int leftToScrollX = newOffsetX - scrollXOffset(); int leftToScrollY = newOffsetY - scrollYOffset(); - if ((leftToScrollX || leftToScrollY) && m_object->parent()) { - m_object->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY); + if ((leftToScrollX || leftToScrollY) && renderer()->parent()) { + renderer()->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY); Frame* frame = renderer()->document()->frame(); if (frame) frame->eventHandler()->updateAutoscrollRenderer(); } - } else if (m_object->view()->frameView()) - m_object->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); + } else if (renderer()->view()->frameView()) + renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); } @@ -796,14 +1029,18 @@ RenderLayer::subtractScrolledContentOffset(int& x, int& y) const void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint) { - if (renderer()->style()->overflowX() != OMARQUEE) { + RenderBox* box = renderBox(); + if (!box) + return; + + if (box->style()->overflowX() != OMARQUEE) { if (x < 0) x = 0; if (y < 0) y = 0; // Call the scrollWidth/Height functions so that the dimensions will be computed if they need // to be (for overflow:hidden blocks). - int maxX = scrollWidth() - m_object->clientWidth(); - int maxY = scrollHeight() - m_object->clientHeight(); + int maxX = scrollWidth() - box->clientWidth(); + int maxY = scrollHeight() - box->clientHeight(); if (x > maxX) x = maxX; if (y > maxY) y = maxY; @@ -823,6 +1060,13 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai // Update the positions of our child layers. for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->updateLayerPositions(false, false); + +#if USE(ACCELERATED_COMPOSITING) + if (compositor()->inCompositingMode()) { + if (RenderLayer* compositingAncestor = ancestorCompositingLayer()) + compositingAncestor->backing()->updateAfterLayout(); + } +#endif RenderView* view = renderer()->view(); @@ -845,7 +1089,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai // Just schedule a full repaint of our object. if (repaint) - m_object->repaint(); + renderer()->repaint(); if (updateScrollbars) { if (m_hBar) @@ -857,7 +1101,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai // Schedule the scroll DOM event. if (view) { if (FrameView* frameView = view->frameView()) - frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), EventTargetNodeCast(renderer()->element())); + frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), renderer()->node()); } } @@ -868,24 +1112,26 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, int xOffset = 0, yOffset = 0; // We may end up propagating a scroll event. It is important that we suspend events until - // the end of the function since they could delete the layer or the layer's m_object. - FrameView* frameView = m_object->document()->view(); + // the end of the function since they could delete the layer or the layer's renderer(). + FrameView* frameView = renderer()->document()->view(); if (frameView) frameView->pauseScheduledEvents(); bool restrictedByLineClamp = false; - if (m_object->parent()) { - parentLayer = m_object->parent()->enclosingLayer(); - restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0; + if (renderer()->parent()) { + parentLayer = renderer()->parent()->enclosingLayer(); + restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; } - if (m_object->hasOverflowClip() && !restrictedByLineClamp) { + if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. // This will prevent us from revealing text hidden by the slider in Safari RSS. - FloatPoint absPos = m_object->localToAbsolute(); - absPos.move(m_object->borderLeft(), m_object->borderTop()); + RenderBox* box = renderBox(); + ASSERT(box); + FloatPoint absPos = box->localToAbsolute(); + absPos.move(box->borderLeft(), box->borderTop()); - IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), m_object->clientWidth(), m_object->clientHeight()); + IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight()); IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height()); IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY); @@ -904,9 +1150,9 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, newRect.setX(rect.x() - diffX); newRect.setY(rect.y() - diffY); } - } else if (!parentLayer && renderer()->canBeProgramaticallyScrolled(scrollToAnchor)) { + } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled(scrollToAnchor)) { if (frameView) { - if (m_object->document() && m_object->document()->ownerElement() && m_object->document()->ownerElement()->renderer()) { + if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) { IntRect viewRect = frameView->visibleContentRect(); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); @@ -917,7 +1163,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, yOffset = max(0, min(frameView->contentsHeight(), yOffset)); frameView->setScrollPosition(IntPoint(xOffset, yOffset)); - parentLayer = m_object->document()->ownerElement()->renderer()->enclosingLayer(); + parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer(); newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); } else { @@ -948,17 +1194,17 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & // If the rectangle is fully visible, use the specified visible behavior. // If the rectangle is partially visible, but over a certain threshold, // then treat it as fully visible to avoid unnecessary horizontal scrolling - scrollX = getVisibleBehavior(alignX); + scrollX = ScrollAlignment::getVisibleBehavior(alignX); else if (intersectWidth == visibleRect.width()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. - scrollX = getVisibleBehavior(alignX); + scrollX = ScrollAlignment::getVisibleBehavior(alignX); if (scrollX == alignCenter) scrollX = noScroll; } else if (intersectWidth > 0) // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior - scrollX = getPartialBehavior(alignX); + scrollX = ScrollAlignment::getPartialBehavior(alignX); else - scrollX = getHiddenBehavior(alignX); + scrollX = ScrollAlignment::getHiddenBehavior(alignX); // If we're trying to align to the closest edge, and the exposeRect is further right // than the visibleRect, and not bigger than the visible area, then align with the right. if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width()) @@ -981,17 +1227,17 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & int intersectHeight = intersection(visibleRect, exposeRectY).height(); if (intersectHeight == exposeRect.height()) // If the rectangle is fully visible, use the specified visible behavior. - scrollY = getVisibleBehavior(alignY); + scrollY = ScrollAlignment::getVisibleBehavior(alignY); else if (intersectHeight == visibleRect.height()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. - scrollY = getVisibleBehavior(alignY); + scrollY = ScrollAlignment::getVisibleBehavior(alignY); if (scrollY == alignCenter) scrollY = noScroll; } else if (intersectHeight > 0) // If the rectangle is partially visible, use the specified partial behavior - scrollY = getPartialBehavior(alignY); + scrollY = ScrollAlignment::getPartialBehavior(alignY); else - scrollY = getHiddenBehavior(alignY); + scrollY = ScrollAlignment::getHiddenBehavior(alignY); // If we're trying to align to the closest edge, and the exposeRect is further down // than the visibleRect, and not bigger than the visible area, then align with the bottom. if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height()) @@ -1024,18 +1270,19 @@ void RenderLayer::autoscroll() frame->eventHandler()->updateSelectionForMouseDrag(); IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition()); - scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, gAlignToEdgeIfNeeded, gAlignToEdgeIfNeeded); + scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); } void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset) { - if (!inResizeMode() || !m_object->hasOverflowClip()) + // FIXME: This should be possible on generated content but is not right now. + if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node()) return; // Set the width and height of the shadow ancestor node if there is one. // This is necessary for textarea elements since the resizable layer is in the shadow content. - Element* element = static_cast<Element*>(m_object->node()->shadowAncestorNode()); - RenderBox* renderer = static_cast<RenderBox*>(element->renderer()); + Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode()); + RenderBox* renderer = toRenderBox(element->renderer()); EResize resize = renderer->style()->resize(); if (resize == RESIZE_NONE) @@ -1064,8 +1311,8 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset ExceptionCode ec; - if (difference.width()) { - if (element && element->isControl()) { + if (resize != RESIZE_VERTICAL && difference.width()) { + if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec); @@ -1076,8 +1323,8 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec); } - if (difference.height()) { - if (element && element->isControl()) { + if (resize != RESIZE_HORIZONTAL && difference.height()) { + if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec); @@ -1164,6 +1411,7 @@ static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds) static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds) { + ASSERT(layer->renderer()->isBox()); if (layer->renderer()->style()->resize() == RESIZE_NONE) return IntRect(); return cornerRect(layer, bounds); @@ -1171,28 +1419,32 @@ static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds bool RenderLayer::scrollbarCornerPresent() const { - return !scrollCornerRect(this, m_object->borderBox()).isEmpty(); + ASSERT(renderer()->isBox()); + return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty(); } void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) { IntRect scrollRect = rect; + RenderBox* box = renderBox(); + ASSERT(box); if (scrollbar == m_vBar.get()) - scrollRect.move(renderer()->width() - renderer()->borderRight() - scrollbar->width(), renderer()->borderTop()); + scrollRect.move(box->width() - box->borderRight() - scrollbar->width(), box->borderTop()); else - scrollRect.move(renderer()->borderLeft(), renderer()->height() - renderer()->borderBottom() - scrollbar->height()); + scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height()); renderer()->repaintRectangle(scrollRect); } PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = m_object->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); + bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) - widget = RenderScrollbar::createCustomScrollbar(this, orientation, m_object->node()->shadowAncestorNode()->renderer()); + widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer)); else widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); - m_object->document()->view()->addChild(widget.get()); + renderer()->document()->view()->addChild(widget.get()); return widget.release(); } @@ -1224,8 +1476,8 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif } @@ -1247,8 +1499,8 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif } @@ -1276,28 +1528,32 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const void RenderLayer::positionOverflowControls(int tx, int ty) { - if (!m_hBar && !m_vBar && (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE)) + if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) return; - IntRect borderBox = m_object->borderBox(); + RenderBox* box = renderBox(); + if (!box) + return; + + IntRect borderBox = box->borderBoxRect(); IntRect scrollCorner(scrollCornerRect(this, borderBox)); IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); if (m_vBar) - m_vBar->setFrameRect(IntRect(absBounds.right() - m_object->borderRight() - m_vBar->width(), - absBounds.y() + m_object->borderTop(), + m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(), + absBounds.y() + box->borderTop(), m_vBar->width(), - absBounds.height() - (m_object->borderTop() + m_object->borderBottom()) - scrollCorner.height())); + absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height())); if (m_hBar) - m_hBar->setFrameRect(IntRect(absBounds.x() + m_object->borderLeft(), - absBounds.bottom() - m_object->borderBottom() - m_hBar->height(), - absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) - scrollCorner.width(), + m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(), + absBounds.bottom() - box->borderBottom() - m_hBar->height(), + absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), m_hBar->height())); if (m_scrollCorner) - m_scrollCorner->setRect(scrollCorner); + m_scrollCorner->setFrameRect(scrollCorner); if (m_resizer) - m_resizer->setRect(resizerCornerRect(this, borderBox)); + m_resizer->setFrameRect(resizerCornerRect(this, borderBox)); } int RenderLayer::scrollWidth() @@ -1316,19 +1572,22 @@ int RenderLayer::scrollHeight() void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) { + RenderBox* box = renderBox(); + ASSERT(box); + m_scrollDimensionsDirty = false; - bool ltr = m_object->style()->direction() == LTR; + bool ltr = renderer()->style()->direction() == LTR; - int clientWidth = m_object->clientWidth(); - int clientHeight = m_object->clientHeight(); + int clientWidth = box->clientWidth(); + int clientHeight = box->clientHeight(); - m_scrollLeftOverflow = ltr ? 0 : min(0, m_object->leftmostPosition(true, false) - m_object->borderLeft()); + m_scrollLeftOverflow = ltr ? 0 : min(0, box->leftmostPosition(true, false) - box->borderLeft()); int rightPos = ltr ? - m_object->rightmostPosition(true, false) - m_object->borderLeft() : + box->rightmostPosition(true, false) - box->borderLeft() : clientWidth - m_scrollLeftOverflow; - int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop(); + int bottomPos = box->lowestPosition(true, false) - box->borderTop(); m_scrollWidth = max(rightPos, clientWidth); m_scrollHeight = max(bottomPos, clientHeight); @@ -1358,9 +1617,9 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve m_horizontalOverflow = horizontalOverflow; m_verticalOverflow = verticalOverflow; - if (FrameView* frameView = m_object->document()->view()) { + if (FrameView* frameView = renderer()->document()->view()) { frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow), - EventTargetNodeCast(m_object->element())); + renderer()->node()); } } } @@ -1368,18 +1627,22 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve void RenderLayer::updateScrollInfoAfterLayout() { + RenderBox* box = renderBox(); + if (!box) + return; + m_scrollDimensionsDirty = true; bool horizontalOverflow, verticalOverflow; computeScrollDimensions(&horizontalOverflow, &verticalOverflow); - if (m_object->style()->overflowX() != OMARQUEE) { + if (box->style()->overflowX() != OMARQUEE) { // Layout may cause us to be in an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). - int newX = max(0, min(scrollXOffset(), scrollWidth() - m_object->clientWidth())); - int newY = max(0, min(m_scrollY, scrollHeight() - m_object->clientHeight())); + int newX = max(0, min(scrollXOffset(), scrollWidth() - box->clientWidth())); + int newY = max(0, min(m_scrollY, scrollHeight() - box->clientHeight())); if (newX != scrollXOffset() || newY != m_scrollY) { - RenderView* view = m_object->view(); + RenderView* view = renderer()->view(); ASSERT(view); // scrollToOffset() may call updateLayerPositions(), which doesn't work // with LayoutState. @@ -1396,58 +1659,58 @@ RenderLayer::updateScrollInfoAfterLayout() bool haveVerticalBar = m_vBar; // overflow:scroll should just enable/disable. - if (m_object->style()->overflowX() == OSCROLL) + if (renderer()->style()->overflowX() == OSCROLL) m_hBar->setEnabled(horizontalOverflow); - if (m_object->style()->overflowY() == OSCROLL) + if (renderer()->style()->overflowY() == OSCROLL) m_vBar->setEnabled(verticalOverflow); // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any // scrollbars that may be present. - if (m_object->style()->overflowX() == OHIDDEN && haveHorizontalBar) + if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar) setHasHorizontalScrollbar(false); - if (m_object->style()->overflowY() == OHIDDEN && haveVerticalBar) + if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar) setHasVerticalScrollbar(false); // overflow:auto may need to lay out again if scrollbars got added/removed. - bool scrollbarsChanged = (m_object->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || - (m_object->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); + bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || + (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); if (scrollbarsChanged) { - if (m_object->hasAutoHorizontalScrollbar()) + if (box->hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(horizontalOverflow); - if (m_object->hasAutoVerticalScrollbar()) + if (box->hasAutoVerticalScrollbar()) setHasVerticalScrollbar(verticalOverflow); #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif - m_object->repaint(); + renderer()->repaint(); - if (m_object->style()->overflowX() == OAUTO || m_object->style()->overflowY() == OAUTO) { + if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; - m_object->setNeedsLayout(true); - if (m_object->isRenderBlock()) - static_cast<RenderBlock*>(m_object)->layoutBlock(true); + renderer()->setNeedsLayout(true, false); + if (renderer()->isRenderBlock()) + toRenderBlock(renderer())->layoutBlock(true); else - m_object->layout(); + renderer()->layout(); m_inOverflowRelayout = false; } } } // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985). - if (m_hBar && m_object->hasAutoHorizontalScrollbar()) + if (m_hBar && box->hasAutoHorizontalScrollbar()) m_hBar->setEnabled(true); - if (m_vBar && m_object->hasAutoVerticalScrollbar()) + if (m_vBar && box->hasAutoVerticalScrollbar()) m_vBar->setEnabled(true); // Set up the range (and page step/line step). if (m_hBar) { - int clientWidth = m_object->clientWidth(); + int clientWidth = box->clientWidth(); int pageStep = (clientWidth - cAmountToKeepWhenPaging); if (pageStep < 0) pageStep = clientWidth; m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); @@ -1455,21 +1718,21 @@ RenderLayer::updateScrollInfoAfterLayout() m_hBar->setValue(scrollXOffset()); } if (m_vBar) { - int clientHeight = m_object->clientHeight(); + int clientHeight = box->clientHeight(); int pageStep = (clientHeight - cAmountToKeepWhenPaging); if (pageStep < 0) pageStep = clientHeight; m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); m_vBar->setProportion(clientHeight, m_scrollHeight); } - if (m_object->element() && m_object->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) + if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) updateOverflowStatus(horizontalOverflow, verticalOverflow); } void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { // Don't do anything if we have no overflow. - if (!m_object->hasOverflowClip()) + if (!renderer()->hasOverflowClip()) return; // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes @@ -1493,7 +1756,10 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { - IntRect cornerRect = scrollCornerRect(this, m_object->borderBox()); + RenderBox* box = renderBox(); + ASSERT(box); + + IntRect cornerRect = scrollCornerRect(this, box->borderBoxRect()); IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); if (!absRect.intersects(damageRect)) return; @@ -1513,10 +1779,13 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { - if (m_object->style()->resize() == RESIZE_NONE) + if (renderer()->style()->resize() == RESIZE_NONE) return; - IntRect cornerRect = resizerCornerRect(this, m_object->borderBox()); + RenderBox* box = renderBox(); + ASSERT(box); + + IntRect cornerRect = resizerCornerRect(this, box->borderBoxRect()); IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); if (!absRect.intersects(damageRect)) return; @@ -1540,6 +1809,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I // Clipping will exclude the right and bottom edges of this frame. if (m_hBar || m_vBar) { context->save(); + context->clip(absRect); IntRect largerCorner = absRect; largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1)); context->setStrokeColor(Color(makeRGB(217, 217, 217))); @@ -1552,12 +1822,15 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const { - if (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE) + if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE) return false; + RenderBox* box = renderBox(); + ASSERT(box); + IntPoint localPoint = absoluteToContents(absolutePoint); - IntRect localBounds(0, 0, m_object->width(), m_object->height()); + IntRect localBounds(0, 0, box->width(), box->height()); return resizerCornerRect(this, localBounds).contains(localPoint); } @@ -1566,10 +1839,13 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result) if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) return false; + RenderBox* box = renderBox(); + ASSERT(box); + int x = 0; int y = 0; convertToLayerCoords(root(), x, y); - IntRect absBounds(x, y, renderer()->width(), renderer()->height()); + IntRect absBounds(x, y, box->width(), box->height()); IntRect resizeControlRect; if (renderer()->style()->resize() != RESIZE_NONE) { @@ -1581,7 +1857,10 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result) int resizeControlSize = max(resizeControlRect.height(), 0); if (m_vBar) { - IntRect vBarRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), absBounds.y() + renderer()->borderTop(), m_vBar->width(), absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); + IntRect vBarRect(absBounds.right() - box->borderRight() - m_vBar->width(), + absBounds.y() + box->borderTop(), + m_vBar->width(), + absBounds.height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); if (vBarRect.contains(result.point())) { result.setScrollbar(m_vBar.get()); return true; @@ -1590,7 +1869,10 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result) resizeControlSize = max(resizeControlRect.width(), 0); if (m_hBar) { - IntRect hBarRect(absBounds.x() + renderer()->borderLeft(), absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height()); + IntRect hBarRect(absBounds.x() + box->borderLeft(), + absBounds.bottom() - box->borderBottom() - m_hBar->height(), + absBounds.width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), + m_hBar->height()); if (hBarRect.contains(result.point())) { result.setScrollbar(m_hBar.get()); return true; @@ -1620,10 +1902,13 @@ 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, PaintRestriction paintRestriction, RenderObject *paintingRoot) { - paintLayer(this, p, damageRect, false, paintRestriction, paintingRoot); + RenderObject::OverlapTestRequestMap overlapTestRequests; + paintLayer(this, p, damageRect, paintRestriction, paintingRoot, &overlapTestRequests); + RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); + for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) + it->first->setOverlapTestResult(false); } static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) @@ -1641,11 +1926,46 @@ static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const p->restore(); } -void -RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, - const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction, - RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects) +static void performOverlapTests(RenderObject::OverlapTestRequestMap& overlapTestRequests, const IntRect& layerBounds) +{ + Vector<OverlapTestRequestClient*> overlappedRequestClients; + RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); + for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) { + if (!layerBounds.intersects(it->second)) + continue; + + it->first->setOverlapTestResult(true); + overlappedRequestClients.append(it->first); + } + for (size_t i = 0; i < overlappedRequestClients.size(); ++i) + overlapTestRequests.remove(overlappedRequestClients[i]); +} + +#if USE(ACCELERATED_COMPOSITING) +static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection) { + return paintingReflection && !layer->has3DTransform(); +} +#endif + +void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, + const IntRect& paintDirtyRect, PaintRestriction paintRestriction, + RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, + PaintLayerFlags paintFlags) +{ +#if USE(ACCELERATED_COMPOSITING) + 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()) + 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(). + return; + } + } +#endif + // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC. // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document // will do a full repaint(). @@ -1653,34 +1973,29 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, return; // If this layer is totally invisible then there is nothing to paint. - if (!m_object->opacity()) + if (!renderer()->opacity()) return; - if (isTransparent()) - haveTransparency = true; + if (paintsWithTransparency()) + 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 (m_transform && !appliedTransform) { + if (paintsWithTransform() && !(paintFlags & PaintLayerAppliedTransform)) { // If the transform can't be inverted, then don't paint anything. if (!m_transform->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 (haveTransparency) + if (paintFlags & PaintLayerHaveTransparency) parent()->beginTransparencyLayers(p, rootLayer); // Make sure the parent's clip rects have been calculated. IntRect clipRect = paintDirtyRect; if (parent()) { - if (temporaryClipRects) { - ClipRects parentClipRects; - parent()->calculateClipRects(rootLayer, parentClipRects); - clipRect = parentClipRects.overflowClipRect(); - } else { - parent()->updateClipRects(rootLayer); - clipRect = parent()->clipRects()->overflowClipRect(); - } + ClipRects parentRects; + parentClipRects(rootLayer, parentRects, paintFlags & PaintLayerTemporaryClipRects); + clipRect = parentRects.overflowClipRect(); clipRect.intersect(paintDirtyRect); } @@ -1701,8 +2016,8 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, p->concatCTM(transform); // Now do a paint with the root layer shifted to be us. - paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects); - + paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintRestriction, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform); + p->restore(); // Restore the clip. @@ -1711,25 +2026,27 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, return; } + PaintLayerFlags localPaintFlags = paintFlags & ~PaintLayerAppliedTransform; + bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency; + // Paint the reflection first if we have one. - if (m_reflection && !m_paintingInsideReflection && (!m_transform || appliedTransform)) { + if (m_reflection && !m_paintingInsideReflection) { // Mark that we are now inside replica painting. m_paintingInsideReflection = true; - reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); + reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); m_paintingInsideReflection = false; } // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; - calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects); + calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects); int x = layerBounds.x(); int y = layerBounds.y(); - int tx = x - renderer()->xPos(); - int ty = y - renderer()->yPos() + renderer()->borderTopExtra(); + int tx = x - renderBoxX(); + int ty = y - renderBoxY(); // Ensure our lists are up-to-date. - updateZOrderLists(); - updateOverflowList(); + updateLayerListsIfNeeded(); bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; @@ -1739,11 +2056,14 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // 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. RenderObject* paintingRootForRenderer = 0; - if (paintingRoot && !m_object->isDescendantOf(paintingRoot)) + if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) paintingRootForRenderer = paintingRoot; + if (overlapTestRequests) + performOverlapTests(*overlapTestRequests, layerBounds); + // We want to paint our layer, but only if we intersect the damage rect. - bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent; + bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent && isSelfPaintingLayer(); if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) @@ -1757,11 +2077,6 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); renderer()->paint(paintInfo, tx, 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. - paintOverflowControls(p, x, y, damageRect); - // Restore the clip. restoreClip(p, paintDirtyRect, damageRect); } @@ -1769,7 +2084,7 @@ 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, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); // Now establish the appropriate clip and paint our child RenderObjects. if (shouldPaint && !clipRectToApply.isEmpty()) { @@ -1787,6 +2102,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, paintInfo.phase = PaintPhaseFloat; renderer()->paint(paintInfo, tx, ty); paintInfo.phase = PaintPhaseForeground; + paintInfo.overlapTestRequests = overlapTestRequests; renderer()->paint(paintInfo, tx, ty); paintInfo.phase = PaintPhaseChildOutlines; renderer()->paint(paintInfo, tx, ty); @@ -1796,7 +2112,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, restoreClip(p, paintDirtyRect, clipRectToApply); } - if (!outlineRect.isEmpty()) { + if (!outlineRect.isEmpty() && isSelfPaintingLayer()) { // Paint our own outline RenderObject::PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0); setClip(p, paintDirtyRect, outlineRect); @@ -1805,14 +2121,14 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, } // Paint any child layers that have overflow. - if (m_overflowList) - for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); - + 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); + // 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, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { setClip(p, paintDirtyRect, damageRect); @@ -1826,7 +2142,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, } // End our transparency layer - if (isTransparent() && m_usedTransparency) { + if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) { p->endTransparencyLayer(); p->restore(); m_usedTransparency = false; @@ -1847,9 +2163,19 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) renderer()->document()->updateLayout(); IntRect boundsRect(m_x, m_y, width(), height()); - boundsRect.intersect(frameVisibleRect(renderer())); - - RenderLayer* insideLayer = hitTestLayer(this, request, result, boundsRect, result.point()); + if (!request.ignoreClipping()) + boundsRect.intersect(frameVisibleRect(renderer())); + + RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, boundsRect, result.point(), false); + if (!insideLayer) { + // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, + // return ourselves. We do this so mouse events continue getting delivered after a drag has + // exited the WebView, and so hit testing over a scrollbar hits the content document. + if ((request.active() || request.mouseUp()) && renderer()->isRenderView()) { + renderer()->updateHitTestResult(result, result.point()); + insideLayer = this; + } + } // 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. @@ -1872,135 +2198,306 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) Node* RenderLayer::enclosingElement() const { for (RenderObject* r = renderer(); r; r = r->parent()) { - if (Node* e = r->element()) + if (Node* e = r->node()) return e; } ASSERT_NOT_REACHED(); return 0; } -RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform) +// Compute the z-offset of the point in the transformState. +// This is effectively projecting a ray normal to the plane of ancestor, finding where that +// ray intersects target, and computing the z delta between those two points. +static double computeZOffset(const HitTestingTransformState& transformState) { + // We got an affine transform, so no z-offset + if (transformState.m_accumulatedTransform.isAffine()) + return 0; + + // Flatten the point into the target plane + FloatPoint targetPoint = transformState.mappedPoint(); + + // Now map the point back through the transform, which computes Z. + FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint)); + return backmappedPoint.z(); +} + +PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, + const HitTestingTransformState* containerTransformState) const +{ + RefPtr<HitTestingTransformState> transformState; + int offsetX = 0; + int offsetY = 0; + if (containerTransformState) { + // If we're already computing transform state, then it's relative to the container (which we know is non-null). + transformState = HitTestingTransformState::create(*containerTransformState); + convertToLayerCoords(containerLayer, offsetX, offsetY); + } else { + // If this is the first time we need to make transform state, then base it off of hitTestPoint, + // which is relative to rootLayer. + transformState = HitTestingTransformState::create(hitTestPoint, FloatQuad(hitTestRect)); + convertToLayerCoords(rootLayer, offsetX, offsetY); + } + + RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0; + if (renderer()->shouldUseTransformFromContainer(containerRenderer)) { + TransformationMatrix containerTransform; + renderer()->getTransformFromContainer(containerRenderer, IntSize(offsetX, offsetY), containerTransform); + transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform); + } else { + transformState->translate(offsetX, offsetY, HitTestingTransformState::AccumulateTransform); + } + + return transformState; +} + + +static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState) +{ + if (!hitLayer) + return false; + + // The hit layer is depth-sorting with other layers, so just say that it was hit. + if (canDepthSort) + return true; + + // We need to look at z-depth to decide if this layer was hit. + if (zOffset) { + ASSERT(transformState); + // This is actually computing our z, but that's OK because the hitLayer is coplanar with us. + double childZOffset = computeZOffset(*transformState); + if (childZOffset > *zOffset) { + *zOffset = childZOffset; + return true; + } + return false; + } + + return true; +} + +// hitTestPoint and hitTestRect are relative to rootLayer. +// A 'flattening' layer is one preserves3D() == false. +// transformState.m_accumulatedTransform holds the transform from the containing flattening layer. +// transformState.m_lastPlanarPoint is the hitTestPoint in the plane of the containing flattening layer. +// transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer. +// +// If zOffset is non-null (which indicates that the caller wants z offset information), +// *zOffset on return is the z offset of the hit point relative to the containing flattening layer. +RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, + const HitTestingTransformState* transformState, double* zOffset) +{ + // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. + + bool useTemporaryClipRects = false; +#if USE(ACCELERATED_COMPOSITING) + useTemporaryClipRects = compositor()->inCompositingMode(); +#endif + // Apply a transform if we have one. - if (m_transform && !appliedTransform) { - // If the transform can't be inverted, then don't hit test this layer at all. - if (!m_transform->isInvertible()) - return 0; - + if (transform() && !appliedTransform) { // Make sure the parent's clip rects have been calculated. if (parent()) { - parent()->updateClipRects(rootLayer); - + ClipRects parentRects; + parentClipRects(rootLayer, parentRects, useTemporaryClipRects); + IntRect clipRect = parentRects.overflowClipRect(); // Go ahead and test the enclosing clip now. - IntRect clipRect = parent()->clipRects()->overflowClipRect(); if (!clipRect.contains(hitTestPoint)) return 0; } - // Adjust the transform such that the renderer's upper left corner is at (0,0) in user space. - // This involves subtracting out the position of the layer in our current coordinate space. - int x = 0; - int y = 0; - convertToLayerCoords(rootLayer, x, y); - TransformationMatrix transform; - transform.translate(x, y); - transform = *m_transform * transform; - - // Map the hit test point into the transformed space and then do a hit test with the root layer shifted to be us. - return hitTestLayer(this, request, result, transform.inverse().mapRect(hitTestRect), transform.inverse().mapPoint(hitTestPoint), true); + // Create a transform state to accumulate this transform. + RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); + + // If the transform can't be inverted, then don't hit test this layer at all. + if (!newTransformState->m_accumulatedTransform.isInvertible()) + return 0; + + // Compute the point and the hit test rect in the coords of this layer by using the values + // from the transformState, which store the point and quad in the coords of the last flattened + // layer, and the accumulated transform which lets up map through preserve-3d layers. + // + // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z) + // by our container. + IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint()); + IntRect localHitTestRect; +#if USE(ACCELERATED_COMPOSITING) + if (isComposited()) { + // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting. + localHitTestRect = backing()->compositedBounds(); + } else +#endif + localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox(); + + // Now do a hit test with the root layer shifted to be us. + return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset); + } + + // Ensure our lists and 3d status are up-to-date. + updateLayerListsIfNeeded(); + update3DTransformedDescendantStatus(); + + RefPtr<HitTestingTransformState> localTransformState; + if (appliedTransform) { + // We computed the correct state in the caller (above code), so just reference it. + ASSERT(transformState); + localTransformState = const_cast<HitTestingTransformState*>(transformState); + } else if (transformState || m_has3DTransformedDescendant || preserves3D()) { + // We need transform state for the first time, or to offset the container state, so create it here. + localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); } + // Check for hit test on backface if backface-visibility is 'hidden' + if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) { + TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse(); + // If the z-vector of the matrix is negative, the back is facing towards the viewer. + if (invertedMatrix.m33() < 0) + return 0; + } + + RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState; + if (localTransformState && !preserves3D()) { + // Keep a copy of the pre-flattening state, for computing z-offsets for the container + unflattenedTransformState = HitTestingTransformState::create(*localTransformState); + // This layer is flattening, so flatten the state passed to descendants. + localTransformState->flatten(); + } + // Calculate the clip rects we should use. IntRect layerBounds; IntRect bgRect; IntRect fgRect; IntRect outlineRect; - calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect); - - // Ensure our lists are up-to-date. - updateZOrderLists(); - updateOverflowList(); - - // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer, - // we are done and can return it. - RenderLayer* insideLayer = 0; - - // Begin by walking our list of positive layers from highest z-index down to the lowest - // z-index. + calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects); + + // The following are used for keeping track of the z-depth of the hit point of 3d-transformed + // descendants. + double localZOffset = -numeric_limits<double>::infinity(); + double* zOffsetForDescendantsPtr = 0; + double* zOffsetForContentsPtr = 0; + + bool depthSortDescendants = false; + if (preserves3D()) { + depthSortDescendants = true; + // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down. + zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; + zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; + } else if (m_has3DTransformedDescendant) { + // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground. + depthSortDescendants = true; + zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; + zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; + } else if (zOffset) { + zOffsetForDescendantsPtr = 0; + // Container needs us to give back a z offset for the hit layer. + zOffsetForContentsPtr = zOffset; + } + + // This variable tracks which layer the mouse ends up being inside. + RenderLayer* candidateLayer = 0; + + // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. if (m_posZOrderList) { for (int i = m_posZOrderList->size() - 1; i >= 0; --i) { - insideLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); - if (insideLayer) - return insideLayer; + HitTestResult tempResult(result.point()); + RenderLayer* hitLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); + if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { + result = tempResult; + if (!depthSortDescendants) + return hitLayer; + + candidateLayer = hitLayer; + } } } // Now check our overflow objects. - if (m_overflowList) { - for (int i = m_overflowList->size() - 1; i >= 0; --i) { - insideLayer = m_overflowList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); - if (insideLayer) - return insideLayer; + if (m_normalFlowList) { + for (int i = m_normalFlowList->size() - 1; i >= 0; --i) { + RenderLayer* currLayer = m_normalFlowList->at(i); + HitTestResult tempResult(result.point()); + RenderLayer* hitLayer = currLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); + if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { + result = tempResult; + if (!depthSortDescendants) + return hitLayer; + + candidateLayer = hitLayer; + } } } // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. - if (fgRect.contains(hitTestPoint) && - renderer()->hitTest(request, result, hitTestPoint, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), - HitTestDescendants)) { - // For positioned generated content, we might still not have a - // node by the time we get to the layer level, since none of - // the content in the layer has an element. So just walk up - // the tree. - if (!result.innerNode() || !result.innerNonSharedNode()) { - Node* e = enclosingElement(); - if (!result.innerNode()) - result.setInnerNode(e); - if (!result.innerNonSharedNode()) - result.setInnerNonSharedNode(e); + 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. + HitTestResult tempResult(result.point()); + if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && + isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { + result = tempResult; + if (!depthSortDescendants) + return this; + // Foreground can depth-sort with descendant layers, so keep this as a candidate. + candidateLayer = this; } - - return this; } - + // Now check our negative z-index children. if (m_negZOrderList) { for (int i = m_negZOrderList->size() - 1; i >= 0; --i) { - insideLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint); - if (insideLayer) - return insideLayer; + HitTestResult tempResult(result.point()); + RenderLayer* hitLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr); + if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) { + result = tempResult; + if (!depthSortDescendants) + return hitLayer; + + candidateLayer = hitLayer; + } } } + + // If we found a layer, return. Child layers, and foreground always render in front of background. + if (candidateLayer) + return candidateLayer; - // Next we want to see if the mouse is inside this layer but not any of its children. - if (bgRect.contains(hitTestPoint) && - renderer()->hitTest(request, result, hitTestPoint, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), - HitTestSelf)) { - if (!result.innerNode() || !result.innerNonSharedNode()) { - Node* e = enclosingElement(); - if (!result.innerNode()) - result.setInnerNode(e); - if (!result.innerNonSharedNode()) - result.setInnerNonSharedNode(e); + if (bgRect.contains(hitTestPoint) && isSelfPaintingLayer()) { + HitTestResult tempResult(result.point()); + if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) && + isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { + result = tempResult; + return this; } - - return this; } + + return 0; +} - // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, - // return ourselves. We do this so mouse events continue getting delivered after a drag has - // exited the WebView, and so hit testing over a scrollbar hits the content document. - if ((request.active || request.mouseUp) && renderer()->isRenderView()) { - renderer()->updateHitTestResult(result, hitTestPoint); - return this; +bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const IntRect& layerBounds, const IntPoint& hitTestPoint, HitTestFilter hitTestFilter) const +{ + if (!renderer()->hitTest(request, result, hitTestPoint, + layerBounds.x() - renderBoxX(), + layerBounds.y() - renderBoxY(), + hitTestFilter)) { + // It's wrong to set innerNode, but then claim that you didn't hit anything. + ASSERT(!result.innerNode()); + return false; } - return 0; + // For positioned generated content, we might still not have a + // node by the time we get to the layer level, since none of + // the content in the layer has an element. So just walk up + // the tree. + if (!result.innerNode() || !result.innerNonSharedNode()) { + Node* e = enclosingElement(); + if (!result.innerNode()) + result.setInnerNode(e); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(e); + } + + return true; } void RenderLayer::updateClipRects(const RenderLayer* rootLayer) @@ -2022,7 +2519,7 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer) if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects()) m_clipRects = parentLayer->clipRects(); else - m_clipRects = new (m_object->renderArena()) ClipRects(clipRects); + m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects); m_clipRects->ref(); #ifndef NDEBUG m_clipRectsRoot = rootLayer; @@ -2031,10 +2528,9 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer) void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const { - IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); if (!parent()) { // The root layer's clip rect is always infinite. - clipRects.reset(infiniteRect); + clipRects.reset(ClipRects::infiniteRect()); return; } @@ -2050,22 +2546,22 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl parentLayer->calculateClipRects(rootLayer, clipRects); } else - clipRects.reset(infiniteRect); + clipRects.reset(ClipRects::infiniteRect()); // A fixed object is essentially the root of its containing block hierarchy, so when // we encounter such an object, we reset our clip rects to the fixedClipRect. - if (m_object->style()->position() == FixedPosition) { + if (renderer()->style()->position() == FixedPosition) { clipRects.setPosClipRect(clipRects.fixedClipRect()); clipRects.setOverflowClipRect(clipRects.fixedClipRect()); clipRects.setFixed(true); } - else if (m_object->style()->position() == RelativePosition) + else if (renderer()->style()->position() == RelativePosition) clipRects.setPosClipRect(clipRects.overflowClipRect()); - else if (m_object->style()->position() == AbsolutePosition) + else if (renderer()->style()->position() == AbsolutePosition) clipRects.setOverflowClipRect(clipRects.posClipRect()); // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { + if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. int x = 0; int y = 0; @@ -2077,14 +2573,14 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl y -= view->frameView()->scrollY(); } - if (m_object->hasOverflowClip()) { - IntRect newOverflowClip = m_object->getOverflowClipRect(x,y); + if (renderer()->hasOverflowClip()) { + IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x,y); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); - if (m_object->isPositioned() || m_object->isRelPositioned()) + if (renderer()->isPositioned() || renderer()->isRelPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } - if (m_object->hasClip()) { - IntRect newPosClip = m_object->getClipRect(x,y); + if (renderer()->hasClip()) { + IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y); clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); @@ -2092,24 +2588,30 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl } } +void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects) const +{ + ASSERT(parent()); + if (temporaryClipRects) { + parent()->calculateClipRects(rootLayer, clipRects); + return; + } + + parent()->updateClipRects(rootLayer); + clipRects = *parent()->clipRects(); +} + void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds, IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const { if (rootLayer != this && parent()) { - ClipRects parentClipRects; - if (temporaryClipRects) - parent()->calculateClipRects(rootLayer, parentClipRects); - else { - parent()->updateClipRects(rootLayer); - parentClipRects = *parent()->clipRects(); - } - - backgroundRect = m_object->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() : - (m_object->isPositioned() ? parentClipRects.posClipRect() : - parentClipRects.overflowClipRect()); + ClipRects parentRects; + parentClipRects(rootLayer, parentRects, temporaryClipRects); + backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() : + (renderer()->isPositioned() ? parentRects.posClipRect() : + parentRects.overflowClipRect()); RenderView* view = renderer()->view(); ASSERT(view); - if (view && parentClipRects.fixed() && rootLayer->renderer() == view) + if (view && parentRects.fixed() && rootLayer->renderer() == view) backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY()); backgroundRect.intersect(paintDirtyRect); @@ -2122,16 +2624,16 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); - layerBounds = IntRect(x,y,width(),height()); + layerBounds = IntRect(x, y, width(), height()); // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { + if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. - if (m_object->hasOverflowClip()) - foregroundRect.intersect(m_object->getOverflowClipRect(x,y)); - if (m_object->hasClip()) { + if (renderer()->hasOverflowClip()) + foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x,y)); + if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. - IntRect newPosClip = m_object->getClipRect(x,y); + IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y); backgroundRect.intersect(newPosClip); foregroundRect.intersect(newPosClip); outlineRect.intersect(newPosClip); @@ -2156,7 +2658,7 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa IntRect RenderLayer::childrenClipRect() const { - RenderLayer* rootLayer = renderer()->document()->renderer()->layer(); + RenderLayer* rootLayer = renderer()->view()->layer(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); return foregroundRect; @@ -2164,7 +2666,7 @@ IntRect RenderLayer::childrenClipRect() const IntRect RenderLayer::selfClipRect() const { - RenderLayer* rootLayer = renderer()->document()->renderer()->layer(); + RenderLayer* rootLayer = renderer()->view()->layer(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); return backgroundRect; @@ -2182,7 +2684,7 @@ bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect // can go ahead and return true. RenderView* view = renderer()->view(); ASSERT(view); - if (view && !renderer()->isInlineFlow()) { + if (view && !renderer()->isRenderInline()) { IntRect b = layerBounds; b.inflate(view->maximalOutlineSize()); if (b.intersects(damageRect)) @@ -2194,7 +2696,7 @@ bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect return boundingBox(rootLayer).intersects(damageRect); } -IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const +IntRect RenderLayer::localBoundingBox() const { // There are three special cases we need to consider. // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the @@ -2206,64 +2708,66 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those // floats. IntRect result; - if (renderer()->isInlineFlow()) { + if (renderer()->isRenderInline()) { // Go from our first line box to our last line box. - RenderInline* inlineFlow = static_cast<RenderInline*>(renderer()); + RenderInline* inlineFlow = toRenderInline(renderer()); InlineFlowBox* firstBox = inlineFlow->firstLineBox(); if (!firstBox) return result; int top = firstBox->root()->topOverflow(); int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow(); - int left = firstBox->xPos(); + int left = firstBox->x(); for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) - left = min(left, curr->xPos()); - result = IntRect(m_x + left, m_y + (top - renderer()->yPos()), width(), bottom - top); + left = min(left, curr->x()); + result = IntRect(left, top, width(), bottom - top); } else if (renderer()->isTableRow()) { // Our bounding box is just the union of all of our cells' border/overflow rects. for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { - IntRect bbox = child->borderBox(); - bbox.move(0, child->borderTopExtra()); + IntRect bbox = toRenderBox(child)->borderBoxRect(); result.unite(bbox); - IntRect overflowRect = renderer()->overflowRect(false); - overflowRect.move(0, child->borderTopExtra()); + IntRect overflowRect = renderBox()->overflowRect(false); if (bbox != overflowRect) result.unite(overflowRect); } } - result.move(m_x, m_y); } else { - if (renderer()->hasMask()) - result = renderer()->maskClipRect(); + RenderBox* box = renderBox(); + ASSERT(box); + if (box->hasMask()) + result = box->maskClipRect(); else { - IntRect bbox = renderer()->borderBox(); + IntRect bbox = box->borderBoxRect(); result = bbox; - IntRect overflowRect = renderer()->overflowRect(false); + IntRect overflowRect = box->overflowRect(false); if (bbox != overflowRect) result.unite(overflowRect); } - - // We have to adjust the x/y of this result so that it is in the coordinate space of the layer. - // We also have to add in borderTopExtra here, since borderBox(), in order to play well with methods like - // floatRect that deal with child content, uses an origin of (0,0) that is at the child content box (so - // border box returns a y coord of -borderTopExtra(). The layer, however, uses the outer box. This is all - // really confusing. - result.move(m_x, m_y + renderer()->borderTopExtra()); } - - // Convert the bounding box to an absolute position. We can do this easily by looking at the delta - // between the bounding box's xpos and our layer's xpos and then applying that to the absolute layerBounds - // passed in. - int absX = 0, absY = 0; - convertToLayerCoords(rootLayer, absX, absY); - result.move(absX - m_x, absY - m_y); + RenderView* view = renderer()->view(); ASSERT(view); if (view) - result.inflate(view->maximalOutlineSize()); + result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables. + + return result; +} + +IntRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const +{ + IntRect result = localBoundingBox(); + + int deltaX = 0, deltaY = 0; + convertToLayerCoords(ancestorLayer, deltaX, deltaY); + result.move(deltaX, deltaY); return result; } +IntRect RenderLayer::absoluteBoundingBox() const +{ + return boundingBox(root()); +} + void RenderLayer::clearClipRectsIncludingDescendants() { if (!m_clipRects) @@ -2278,7 +2782,7 @@ void RenderLayer::clearClipRectsIncludingDescendants() void RenderLayer::clearClipRects() { if (m_clipRects) { - m_clipRects->deref(m_object->renderArena()); + m_clipRects->deref(renderer()->renderArena()); m_clipRects = 0; #ifndef NDEBUG m_clipRectsRoot = 0; @@ -2286,6 +2790,38 @@ void RenderLayer::clearClipRects() } } +#if USE(ACCELERATED_COMPOSITING) +RenderLayerBacking* RenderLayer::ensureBacking() +{ + if (!m_backing) + m_backing.set(new RenderLayerBacking(this)); + return m_backing.get(); +} + +void RenderLayer::clearBacking() +{ + m_backing.clear(); +} +#endif + +void RenderLayer::setParent(RenderLayer* parent) +{ + if (parent == m_parent) + return; + +#if USE(ACCELERATED_COMPOSITING) + if (m_parent && !renderer()->documentBeingDestroyed()) + compositor()->layerWillBeRemoved(m_parent, this); +#endif + + m_parent = parent; + +#if USE(ACCELERATED_COMPOSITING) + if (m_parent && !renderer()->documentBeingDestroyed()) + compositor()->layerWasAdded(m_parent, this); +#endif +} + static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2) { if (!obj1 || !obj2) @@ -2301,28 +2837,28 @@ static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2) void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result) { - // We don't update :hover/:active state when the result is marked as readonly. - if (request.readonly) + // We don't update :hover/:active state when the result is marked as readOnly. + if (request.readOnly()) return; Document* doc = renderer()->document(); Node* activeNode = doc->activeNode(); - if (activeNode && !request.active) { + if (activeNode && !request.active()) { // We are clearing the :active chain because the mouse has been released. for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) { - if (curr->element() && !curr->isText()) - curr->element()->setInActiveChain(false); + if (curr->node() && !curr->isText()) + curr->node()->setInActiveChain(false); } doc->setActiveNode(0); } else { Node* newActiveNode = result.innerNode(); - if (!activeNode && newActiveNode && request.active) { + if (!activeNode && newActiveNode && request.active()) { // We are setting the :active chain and freezing it. If future moves happen, they // will need to reference this chain. for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) { - if (curr->element() && !curr->isText()) { - curr->element()->setInActiveChain(true); + if (curr->node() && !curr->isText()) { + curr->node()->setInActiveChain(true); } } doc->setActiveNode(newActiveNode); @@ -2332,7 +2868,7 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR // If the mouse is down and if this is a mouse move event, we want to restrict changes in // :hover/:active to only apply to elements that are in the :active chain that we froze // at the time the mouse went down. - bool mustBeInActiveChain = request.active && request.mouseMove; + bool mustBeInActiveChain = request.active() && request.mouseMove(); // Check to see if the hovered node has changed. If not, then we don't need to // do anything. @@ -2352,18 +2888,18 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR if (oldHoverObj != newHoverObj) { // The old hover path only needs to be cleared up to (and not including) the common ancestor; for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { - if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) { - curr->element()->setActive(false); - curr->element()->setHovered(false); + if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { + curr->node()->setActive(false); + curr->node()->setHovered(false); } } } // Now set the hover state for our new object up to the root. for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { - if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) { - curr->element()->setActive(request.active); - curr->element()->setHovered(true); + if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { + curr->node()->setActive(request.active()); + curr->node()->setHovered(true); } } } @@ -2381,6 +2917,11 @@ void RenderLayer::dirtyZOrderLists() if (m_negZOrderList) m_negZOrderList->clear(); m_zOrderListsDirty = true; + +#if USE(ACCELERATED_COMPOSITING) + if (!renderer()->documentBeingDestroyed()) + compositor()->setCompositingLayersNeedUpdate(); +#endif } void RenderLayer::dirtyStackingContextZOrderLists() @@ -2390,18 +2931,23 @@ void RenderLayer::dirtyStackingContextZOrderLists() sc->dirtyZOrderLists(); } -void RenderLayer::dirtyOverflowList() +void RenderLayer::dirtyNormalFlowList() { - if (m_overflowList) - m_overflowList->clear(); - m_overflowListDirty = true; + if (m_normalFlowList) + m_normalFlowList->clear(); + m_normalFlowListDirty = true; + +#if USE(ACCELERATED_COMPOSITING) + if (!renderer()->documentBeingDestroyed()) + compositor()->setCompositingLayersNeedUpdate(); +#endif } void RenderLayer::updateZOrderLists() { if (!isStackingContext() || !m_zOrderListsDirty) return; - + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) if (!m_reflection || reflectionLayer() != child) child->collectLayers(m_posZOrderList, m_negZOrderList); @@ -2409,27 +2955,28 @@ void RenderLayer::updateZOrderLists() // Sort the two lists. if (m_posZOrderList) std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex); + if (m_negZOrderList) std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); m_zOrderListsDirty = false; } -void RenderLayer::updateOverflowList() +void RenderLayer::updateNormalFlowList() { - if (!m_overflowListDirty) + if (!m_normalFlowListDirty) return; for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { // Ignore non-overflow layers and reflections. - if (child->isOverflowOnly() && (!m_reflection || reflectionLayer() != child)) { - if (!m_overflowList) - m_overflowList = new Vector<RenderLayer*>; - m_overflowList->append(child); + if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) { + if (!m_normalFlowList) + m_normalFlowList = new Vector<RenderLayer*>; + m_normalFlowList->append(child); } } - m_overflowListDirty = false; + m_normalFlowListDirty = false; } void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer) @@ -2437,7 +2984,7 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL updateVisibilityStatus(); // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. - if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) { + if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isNormalFlowOnly()) { // Determine which buffer the child should be in. Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; @@ -2460,34 +3007,97 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL } } +void RenderLayer::updateLayerListsIfNeeded() +{ +#if USE(ACCELERATED_COMPOSITING) + if (compositor()->inCompositingMode()) { + if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty) + compositor()->updateCompositingLayers(this); + return; + } +#endif + updateZOrderLists(); + updateNormalFlowList(); +} + void RenderLayer::repaintIncludingDescendants() { - m_object->repaint(); + renderer()->repaint(); for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) curr->repaintIncludingDescendants(); } -bool RenderLayer::shouldBeOverflowOnly() const +#if USE(ACCELERATED_COMPOSITING) +void RenderLayer::setBackingNeedsRepaint() +{ + ASSERT(isComposited()); + if (backing()->paintingGoesToWindow()) { + // If we're trying to repaint the placeholder document layer, propagate the + // repaint to the native view system. + RenderView* view = renderer()->view(); + if (view) + view->repaintViewRectangle(absoluteBoundingBox()); + } else + backing()->setContentsNeedDisplay(); +} + +void RenderLayer::setBackingNeedsRepaintInRect(const IntRect& r) +{ + ASSERT(isComposited()); + if (backing()->paintingGoesToWindow()) { + // If we're trying to repaint the placeholder document layer, propagate the + // repaint to the native view system. + IntRect absRect(r); + int x = 0; + int y = 0; + convertToLayerCoords(root(), x, y); + absRect.move(x, y); + + RenderView* view = renderer()->view(); + if (view) + view->repaintViewRectangle(absRect); + } else + backing()->setContentsNeedDisplayInRect(r); +} + +// Since we're only painting non-composited layers, we know that they all share the same repaintContainer. +void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer) +{ + renderer()->repaintUsingContainer(repaintContainer, renderer()->clippedOverflowRectForRepaint(repaintContainer)); + + for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isComposited()) + curr->repaintIncludingNonCompositingDescendants(repaintContainer); + } +} +#endif + +bool RenderLayer::shouldBeNormalFlowOnly() const { - return (renderer()->hasOverflowClip() || renderer()->hasReflection()) && + return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo()) && !renderer()->isPositioned() && !renderer()->isRelPositioned() && !renderer()->hasTransform() && !isTransparent(); } -void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*) +bool RenderLayer::isSelfPaintingLayer() const { - bool isOverflowOnly = shouldBeOverflowOnly(); - if (isOverflowOnly != m_isOverflowOnly) { - m_isOverflowOnly = isOverflowOnly; + return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo(); +} + +void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) +{ + bool isNormalFlowOnly = shouldBeNormalFlowOnly(); + if (isNormalFlowOnly != m_isNormalFlowOnly) { + m_isNormalFlowOnly = isNormalFlowOnly; RenderLayer* p = parent(); if (p) - p->dirtyOverflowList(); + p->dirtyNormalFlowList(); dirtyStackingContextZOrderLists(); } - if (m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) { + if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) { if (!m_marquee) m_marquee = new RenderMarquee(this); m_marquee->updateMarqueeStyle(); @@ -2514,16 +3124,30 @@ void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*) updateScrollCornerStyle(); updateResizerStyle(); + +#if USE(ACCELERATED_COMPOSITING) + updateTransform(); + + if (compositor()->updateLayerCompositingState(this)) + compositor()->setCompositingLayersNeedUpdate(); + else if (m_backing) + m_backing->updateGraphicsLayerGeometry(); + + if (m_backing && diff >= StyleDifferenceRepaint) + m_backing->setContentsNeedDisplay(); +#else + UNUSED_PARAM(diff); +#endif } void RenderLayer::updateScrollCornerStyle() { - RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object; - RefPtr<RenderStyle> corner = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0; + RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); + RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : 0; if (corner) { if (!m_scrollCorner) { - m_scrollCorner = new (m_object->renderArena()) RenderScrollbarPart(m_object->document()); - m_scrollCorner->setParent(m_object); + m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); + m_scrollCorner->setParent(renderer()); } m_scrollCorner->setStyle(corner.release()); } else if (m_scrollCorner) { @@ -2534,12 +3158,12 @@ void RenderLayer::updateScrollCornerStyle() void RenderLayer::updateResizerStyle() { - RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object; - RefPtr<RenderStyle> resizer = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0; + RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); + RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : 0; if (resizer) { if (!m_resizer) { - m_resizer = new (m_object->renderArena()) RenderScrollbarPart(m_object->document()); - m_resizer->setParent(m_object); + m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); + m_resizer->setParent(renderer()); } m_resizer->setStyle(resizer.release()); } else if (m_resizer) { @@ -2597,13 +3221,4 @@ void RenderLayer::updateReflectionStyle() m_reflection->setStyle(newStyle.release()); } -void RenderLayer::suspendMarquees() -{ - if (m_marquee) - m_marquee->suspend(); - - for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) - curr->suspendMarquees(); -} - } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h index b2ba48c..4feede8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Apple Computer, Inc. + * Copyright (C) 2003, 2009 Apple Inc. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -44,19 +44,20 @@ #ifndef RenderLayer_h #define RenderLayer_h +#include "RenderBox.h" +#include "ScrollBehavior.h" #include "ScrollbarClient.h" -#include "RenderObject.h" #include "Timer.h" #include <wtf/OwnPtr.h> namespace WebCore { -class TransformationMatrix; class CachedResource; +class HitTestRequest; class HitTestResult; +class HitTestingTransformState; class RenderFrameSet; class RenderMarquee; -class RenderObject; class RenderReplica; class RenderScrollbarPart; class RenderStyle; @@ -64,8 +65,12 @@ class RenderTable; class RenderText; class RenderView; class Scrollbar; +class TransformationMatrix; -struct HitTestRequest; +#if USE(ACCELERATED_COMPOSITING) +class RenderLayerBacking; +class RenderLayerCompositor; +#endif class ClipRects { public: @@ -140,7 +145,9 @@ public: m_fixed = other.fixed(); return *this; } - + + static IntRect infiniteRect() { return IntRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); } + private: // The normal operator new is disallowed on all render objects. void* operator new(size_t) throw(); @@ -155,38 +162,13 @@ private: class RenderLayer : public ScrollbarClient { public: - enum ScrollBehavior { - noScroll, - alignCenter, - alignTop, - alignBottom, - alignLeft, - alignRight, - alignToClosestEdge - }; - - struct ScrollAlignment { - ScrollBehavior m_rectVisible; - ScrollBehavior m_rectHidden; - ScrollBehavior m_rectPartial; - }; - friend class RenderReplica; - static const ScrollAlignment gAlignCenterIfNeeded; - static const ScrollAlignment gAlignToEdgeIfNeeded; - static const ScrollAlignment gAlignCenterAlways; - static const ScrollAlignment gAlignTopAlways; - static const ScrollAlignment gAlignBottomAlways; - - static ScrollBehavior getVisibleBehavior(const ScrollAlignment& s) { return s.m_rectVisible; } - static ScrollBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; } - static ScrollBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; } - - RenderLayer(RenderObject*); + RenderLayer(RenderBoxModelObject*); ~RenderLayer(); - RenderObject* renderer() const { return m_object; } + RenderBoxModelObject* renderer() const { return m_renderer; } + RenderBox* renderBox() const { return m_renderer && m_renderer->isBox() ? toRenderBox(m_renderer) : 0; } RenderLayer* parent() const { return m_parent; } RenderLayer* previousSibling() const { return m_previous; } RenderLayer* nextSibling() const { return m_next; } @@ -201,20 +183,28 @@ public: void repaintIncludingDescendants(); - void styleChanged(RenderStyle::Diff, const RenderStyle*); +#if USE(ACCELERATED_COMPOSITING) + // Indicate that the layer contents need to be repainted. Only has an effect + // if layer compositing is being used, + void setBackingNeedsRepaint(); + void setBackingNeedsRepaintInRect(const IntRect& r); // r is in the coordinate space of the layer's render object + void repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer); +#endif + + void styleChanged(StyleDifference, const RenderStyle*); RenderMarquee* marquee() const { return m_marquee; } - void suspendMarquees(); - bool isOverflowOnly() const { return m_isOverflowOnly; } + bool isNormalFlowOnly() const { return m_isNormalFlowOnly; } + bool isSelfPaintingLayer() const; bool requiresSlowRepaints() const; bool isTransparent() const; - RenderLayer* transparentAncestor(); + RenderLayer* transparentPaintingAncestor(); void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer); - bool hasReflection() const { return m_object->hasReflection(); } + bool hasReflection() const { return renderer()->hasReflection(); } RenderReplica* reflection() const { return m_reflection; } RenderLayer* reflectionLayer() const; @@ -226,12 +216,12 @@ public: return curr; } - int xPos() const { return m_x; } - int yPos() const { return m_y; } - void setPos(int xPos, int yPos) + int x() const { return m_x; } + int y() const { return m_y; } + void setLocation(int x, int y) { - m_x = xPos; - m_y = yPos; + m_x = x; + m_y = y; } int width() const { return m_width; } @@ -256,9 +246,9 @@ public: void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true); void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); } void scrollToYOffset(int y) { scrollToOffset(m_scrollX + m_scrollOriginX, y); } - void scrollRectToVisible(const IntRect&, bool scrollToAnchor = false, const ScrollAlignment& alignX = gAlignCenterIfNeeded, const ScrollAlignment& alignY = gAlignCenterIfNeeded); + void scrollRectToVisible(const IntRect&, bool scrollToAnchor = false, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded); - IntRect getRectToExpose(const IntRect& visibleRect, const IntRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY); + IntRect getRectToExpose(const IntRect& visibleRect, const IntRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY); void setHasHorizontalScrollbar(bool); void setHasVerticalScrollbar(bool); @@ -289,6 +279,19 @@ public: void resize(const PlatformMouseEvent&, const IntSize&); bool inResizeMode() const { return m_inResizeMode; } void setInResizeMode(bool b) { m_inResizeMode = b; } + + bool isRootLayer() const { return renderer()->isRenderView(); } + +#if USE(ACCELERATED_COMPOSITING) + RenderLayerCompositor* compositor() const; + + // Notification from the renderer that its content changed (e.g. current frame of image changed). + // Allows updates of layer content without repainting. + void rendererContentChanged(); +#endif + + // Returns true if the accelerated compositing is enabled + bool hasAcceleratedCompositing() const; void updateLayerPosition(); void updateLayerPositions(bool doFullRepaint = false, bool checkForRepaint = true); @@ -312,9 +315,9 @@ public: Vector<RenderLayer*>* posZOrderList() const { return m_posZOrderList; } Vector<RenderLayer*>* negZOrderList() const { return m_negZOrderList; } - void dirtyOverflowList(); - void updateOverflowList(); - Vector<RenderLayer*>* overflowList() const { return m_overflowList; } + void dirtyNormalFlowList(); + void updateNormalFlowList(); + Vector<RenderLayer*>* normalFlowList() const { return m_normalFlowList; } bool hasVisibleContent() const { return m_hasVisibleContent; } void setHasVisibleContent(bool); @@ -324,6 +327,13 @@ public: // the <html> layer and the root layer). RenderLayer* enclosingPositionedAncestor() const; +#if USE(ACCELERATED_COMPOSITING) + // Enclosing compositing layer; if includeSelf is true, may return this. + RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const; + // Ancestor compositing layer, excluding this. + RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(false); } +#endif + void convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const; bool hasAutoZIndex() const { return renderer()->style()->hasAutoZIndex(); } @@ -354,23 +364,39 @@ public: bool intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const; - // Returns a bounding box for this layer only. + // Bounding box relative to some ancestor layer. IntRect boundingBox(const RenderLayer* rootLayer) const; + // Bounding box in the coordinates of this layer. + IntRect localBoundingBox() const; + // Bounding box relative to the root. + IntRect absoluteBoundingBox() const; void updateHoverActiveState(const HitTestRequest&, HitTestResult&); + // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint. IntRect repaintRect() const { return m_repaintRect; } void setNeedsFullRepaint(bool f = true) { m_needsFullRepaint = f; } int staticX() const { return m_staticX; } int staticY() const { return m_staticY; } void setStaticX(int staticX) { m_staticX = staticX; } - void setStaticY(int staticY) { m_staticY = staticY; } + void setStaticY(int staticY); - bool hasTransform() const { return m_object->hasTransform(); } + bool hasTransform() const { return renderer()->hasTransform(); } + // Note that this transform has the transform-origin baked in. TransformationMatrix* transform() const { return m_transform.get(); } - - void destroy(RenderArena*); + // currentTransform computes a transform which takes accelerated animations into account. The + // resulting transform has transform-origin baked in. If the layer does not have a transform, + // returns the identity matrix. + TransformationMatrix currentTransform() const; + + // Get the perspective transform, which is applied to transformed sublayers. + // Returns true if the layer has a -webkit-perspective. + // Note that this transform has the perspective-origin baked in. + TransformationMatrix perspectiveTransform() const; + FloatPoint perspectiveOrigin() const; + bool preserves3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; } + bool has3DTransform() const { return m_transform && !m_transform->isAffine(); } // Overloaded new operator. Derived classes must override operator new // in order to allocate out of the RenderArena. @@ -379,6 +405,25 @@ public: // Overridden to prevent the normal delete from being called. void operator delete(void*, size_t); +#if USE(ACCELERATED_COMPOSITING) + bool isComposited() const { return m_backing != 0; } + RenderLayerBacking* backing() const { return m_backing.get(); } + RenderLayerBacking* ensureBacking(); + void clearBacking(); +#else + bool isComposited() const { return false; } +#endif + + bool paintsWithTransparency() const + { + return isTransparent() && !isComposited(); + } + + bool paintsWithTransform() const + { + return transform() && !isComposited(); + } + private: // The normal operator new is disallowed on all render objects. void* operator new(size_t) throw(); @@ -386,19 +431,43 @@ private: private: void setNextSibling(RenderLayer* next) { m_next = next; } void setPreviousSibling(RenderLayer* prev) { m_previous = prev; } - void setParent(RenderLayer* parent) { m_parent = parent; } + void setParent(RenderLayer* parent); void setFirstChild(RenderLayer* first) { m_first = first; } void setLastChild(RenderLayer* last) { m_last = last; } + int renderBoxX() const { return renderer()->isBox() ? toRenderBox(renderer())->x() : 0; } + int renderBoxY() const { return renderer()->isBox() ? toRenderBox(renderer())->y() : 0; } + void collectLayers(Vector<RenderLayer*>*&, Vector<RenderLayer*>*&); + void updateLayerListsIfNeeded(); + + enum PaintLayerFlag { + PaintLayerHaveTransparency = 1, + PaintLayerAppliedTransform = 1 << 1, + PaintLayerTemporaryClipRects = 1 << 2, + PaintLayerPaintingReflection = 1 << 3 + }; + + typedef unsigned PaintLayerFlags; + void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - bool haveTransparency, PaintRestriction, RenderObject* paintingRoot, - bool appliedTransform = false, bool temporaryClipRects = false); - RenderLayer* hitTestLayer(RenderLayer* rootLayer, const HitTestRequest&, HitTestResult&, const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform = false); + PaintRestriction, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0, + PaintLayerFlags paintFlags = 0); + + RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, + const HitTestingTransformState* transformState = 0, double* zOffset = 0); + + PassRefPtr<HitTestingTransformState> createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, + const HitTestingTransformState* containerTransformState) const; + + bool hitTestContents(const HitTestRequest&, HitTestResult&, const IntRect& layerBounds, const IntPoint& hitTestPoint, HitTestFilter) const; + void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0); - bool shouldBeOverflowOnly() const; + bool shouldBeNormalFlowOnly() const; virtual void valueChanged(Scrollbar*); virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); @@ -411,11 +480,22 @@ private: void dirtyVisibleDescendantStatus(); void updateVisibilityStatus(); + // This flag is computed by RenderLayerCompositor, which knows more about 3d hierarchies than we do. + void setHas3DTransformedDescendant(bool b) { m_has3DTransformedDescendant = b; } + bool has3DTransformedDescendant() const { return m_has3DTransformedDescendant; } + + void dirty3DTransformedDescendantStatus(); + // Both updates the status, and returns true if descendants of this have 3d. + bool update3DTransformedDescendantStatus(); + Node* enclosingElement() const; void createReflection(); void updateReflectionStyle(); bool paintingInsideReflection() const { return m_paintingInsideReflection; } + void setPaintingInsideReflection(bool b) { m_paintingInsideReflection = b; } + + void parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false) const; RenderLayer* enclosingTransformedAncestor() const; @@ -425,8 +505,24 @@ private: void updateScrollCornerStyle(); void updateResizerStyle(); -protected: - RenderObject* m_object; +#if USE(ACCELERATED_COMPOSITING) + bool hasCompositingDescendant() const { return m_hasCompositingDescendant; } + void setHasCompositingDescendant(bool b) { m_hasCompositingDescendant = b; } + + bool mustOverlayCompositedLayers() const { return m_mustOverlayCompositedLayers; } + void setMustOverlayCompositedLayers(bool b) { m_mustOverlayCompositedLayers = b; } +#endif + +private: + friend class RenderLayerBacking; + friend class RenderLayerCompositor; + friend class RenderBoxModelObject; + + // Only safe to call from RenderBoxModelObject::destroyLayer(RenderArena*) + void destroy(RenderArena*); + +protected: + RenderBoxModelObject* m_renderer; RenderLayer* m_parent; RenderLayer* m_previous; @@ -475,7 +571,7 @@ protected: // This list contains child layers that cannot create stacking contexts. For now it is just // overflow layers, but that may change in the future. - Vector<RenderLayer*>* m_overflowList; + Vector<RenderLayer*>* m_normalFlowList; ClipRects* m_clipRects; // Cached clip rects used when painting and hit testing. #ifndef NDEBUG @@ -484,8 +580,8 @@ protected: bool m_scrollDimensionsDirty : 1; bool m_zOrderListsDirty : 1; - bool m_overflowListDirty: 1; - bool m_isOverflowOnly : 1; + bool m_normalFlowListDirty: 1; + bool m_isNormalFlowOnly : 1; bool m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether // we ended up painting this layer or any descendants (and therefore need to @@ -502,6 +598,14 @@ protected: bool m_visibleDescendantStatusDirty : 1; bool m_hasVisibleDescendant : 1; + bool m_3DTransformedDescendantStatusDirty : 1; + bool m_has3DTransformedDescendant : 1; // Set on a stacking context layer that has 3D descendants anywhere + // in a preserves3D hierarchy. Hint to do 3D-aware hit testing. +#if USE(ACCELERATED_COMPOSITING) + bool m_hasCompositingDescendant : 1; + bool m_mustOverlayCompositedLayers : 1; +#endif + RenderMarquee* m_marquee; // Used by layers with overflow:marquee // Cached normal flow values for absolute positioned elements with static left/top values. @@ -516,6 +620,10 @@ protected: // Renderers to hold our custom scroll corner and resizer. RenderScrollbarPart* m_scrollCorner; RenderScrollbarPart* m_resizer; + +#if USE(ACCELERATED_COMPOSITING) + OwnPtr<RenderLayerBacking> m_backing; +#endif }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp new file mode 100644 index 0000000..1c6d43c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.cpp @@ -0,0 +1,1082 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "AnimationController.h" +#include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "RenderBox.h" +#include "RenderImage.h" +#include "RenderLayerCompositor.h" +#include "RenderVideo.h" +#include "RenderView.h" + +#include "RenderLayerBacking.h" + +using namespace std; + +namespace WebCore { + +static bool hasBorderOutlineOrShadow(const RenderStyle*); +static bool hasBoxDecorations(const RenderStyle*); +static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle*); + +RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) + : m_owningLayer(layer) + , m_ancestorClippingLayer(0) + , m_graphicsLayer(0) + , m_contentsLayer(0) + , m_clippingLayer(0) + , m_hasDirectlyCompositedContent(false) +{ + createGraphicsLayer(); +} + +RenderLayerBacking::~RenderLayerBacking() +{ + updateClippingLayers(false, false); + updateContentsLayer(false); + destroyGraphicsLayer(); +} + +void RenderLayerBacking::createGraphicsLayer() +{ + m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this); + +#ifndef NDEBUG + if (renderer()->node()) { + if (renderer()->node()->isDocumentNode()) + m_graphicsLayer->setName("Document Node"); + else { + if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID()) + m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->id()); + else + m_graphicsLayer->setName(renderer()->renderName()); + } + } else + m_graphicsLayer->setName("Anonymous Node"); +#endif // NDEBUG + + updateLayerOpacity(); + updateLayerTransform(); +} + +void RenderLayerBacking::destroyGraphicsLayer() +{ + if (m_graphicsLayer) + m_graphicsLayer->removeFromParent(); + + delete m_graphicsLayer; + m_graphicsLayer = 0; + + delete m_contentsLayer; + m_contentsLayer = 0; + + delete m_clippingLayer; + m_clippingLayer = 0; +} + +void RenderLayerBacking::updateLayerOpacity() +{ + m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity()), 0, 0); +} + +void RenderLayerBacking::updateLayerTransform() +{ + RenderStyle* style = renderer()->style(); + + // FIXME: This could use m_owningLayer->transform(), but that currently has transform-origin + // baked into it, and we don't want that. + TransformationMatrix t; + if (m_owningLayer->hasTransform()) { + style->applyTransform(t, toRenderBox(renderer())->borderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); + makeMatrixRenderable(t, compositor()->hasAcceleratedCompositing()); + } + + m_graphicsLayer->setTransform(t); +} + +void RenderLayerBacking::updateAfterLayout() +{ + RenderLayerCompositor* layerCompositor = compositor(); + if (!layerCompositor->compositingLayersNeedUpdate()) { + // Calling updateGraphicsLayerGeometry() here gives incorrect results, because the + // position of this layer's GraphicsLayer depends on the position of our compositing + // ancestor's GraphicsLayer. That cannot be determined until all the descendant + // RenderLayers of that ancestor have been processed via updateLayerPositions(). + // + // The solution is to update compositing children of this layer here, + // via updateCompositingChildrenGeometry(). + setCompositedBounds(layerCompositor->calculateCompositedBounds(m_owningLayer, m_owningLayer)); + layerCompositor->updateCompositingChildrenGeometry(m_owningLayer, m_owningLayer); + + if (!m_owningLayer->parent()) + layerCompositor->updateRootLayerPosition(); + } +} + +bool RenderLayerBacking::updateGraphicsLayerConfiguration() +{ + RenderLayerCompositor* compositor = this->compositor(); + + bool layerConfigChanged = false; + if (updateContentsLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) + layerConfigChanged = true; + + if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer))) + layerConfigChanged = true; + + m_hasDirectlyCompositedContent = false; + if (canUseDirectCompositing()) { + if (renderer()->isImage()) { + updateImageContents(); + m_hasDirectlyCompositedContent = true; + m_graphicsLayer->setDrawsContent(false); + } + + if (rendererHasBackground()) + m_graphicsLayer->setBackgroundColor(rendererBackgroundColor()); + else + m_graphicsLayer->clearBackgroundColor(); + } + + return layerConfigChanged; +} + +void RenderLayerBacking::updateGraphicsLayerGeometry() +{ + // If we haven't built z-order lists yet, wait until later. + if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty) + return; + + // Set transform property, if it is not animating. We have to do this here because the transform + // is affected by the layer dimensions. + if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyWebkitTransform)) + updateLayerTransform(); + + // Set opacity, if it is not animating. + if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyOpacity)) + updateLayerOpacity(); + + RenderStyle* style = renderer()->style(); + m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D); + m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); + + RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); + + // We compute everything relative to the enclosing compositing layer. + IntRect ancestorCompositingBounds; + if (compAncestor) { + ASSERT(compAncestor->backing()); + ancestorCompositingBounds = compAncestor->backing()->compositedBounds(); + } + + IntRect localCompositingBounds = compositedBounds(); + + IntRect relativeCompositingBounds(localCompositingBounds); + int deltaX = 0, deltaY = 0; + m_owningLayer->convertToLayerCoords(compAncestor, deltaX, deltaY); + relativeCompositingBounds.move(deltaX, deltaY); + + IntPoint graphicsLayerParentLocation; + if (compAncestor && compAncestor->backing()->hasClippingLayer()) { + // If the compositing ancestor has a layer to clip children, we parent in that, and therefore + // position relative to it. + graphicsLayerParentLocation = toRenderBox(compAncestor->renderer())->overflowClipRect(0, 0).location(); + } else + graphicsLayerParentLocation = ancestorCompositingBounds.location(); + + if (compAncestor && m_ancestorClippingLayer) { + // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this + // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects + // for a compositing layer, rootLayer is the layer itself. + ClipRects parentRects; + m_owningLayer->parentClipRects(compAncestor, parentRects, true); + IntRect parentClipRect = parentRects.overflowClipRect(); + + m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); + m_ancestorClippingLayer->setSize(parentClipRect.size()); + + // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords. + IntSize rendererOffset(parentClipRect.location().x() - deltaX, parentClipRect.location().y() - deltaY); + m_ancestorClippingLayer->setOffsetFromRenderer(rendererOffset); + + // The primary layer is then parented in, and positioned relative to this clipping layer. + graphicsLayerParentLocation = parentClipRect.location(); + } + + m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation)); + m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint()); + + FloatSize oldSize = m_graphicsLayer->size(); + FloatSize newSize = relativeCompositingBounds.size(); + if (oldSize != newSize) { + m_graphicsLayer->setSize(newSize); + // A bounds change will almost always require redisplay. Usually that redisplay + // will happen because of a repaint elsewhere, but not always: + // e.g. see RenderView::setMaximalOutlineSize() + m_graphicsLayer->setNeedsDisplay(); + } + + // If we have a layer that clips children, position it. + if (m_clippingLayer) { + IntRect clippingBox = toRenderBox(renderer())->overflowClipRect(0, 0); + m_clippingLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location())); + m_clippingLayer->setSize(clippingBox.size()); + m_clippingLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint()); + } + + if (m_owningLayer->hasTransform()) { + const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); + + // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds. + IntRect layerBounds = IntRect(deltaX, deltaY, borderBox.width(), borderBox.height()); + + // Update properties that depend on layer dimensions + FloatPoint3D transformOrigin = computeTransformOrigin(borderBox); + // Compute the anchor point, which is in the center of the renderer box unless transform-origin is set. + FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f, + relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f, + transformOrigin.z()); + m_graphicsLayer->setAnchorPoint(anchor); + + RenderStyle* style = renderer()->style(); + if (style->hasPerspective()) { + TransformationMatrix t = owningLayer()->perspectiveTransform(); + + if (m_clippingLayer) { + m_clippingLayer->setChildrenTransform(t); + m_graphicsLayer->setChildrenTransform(TransformationMatrix()); + } + else + m_graphicsLayer->setChildrenTransform(t); + } else { + if (m_clippingLayer) + m_clippingLayer->setChildrenTransform(TransformationMatrix()); + else + m_graphicsLayer->setChildrenTransform(TransformationMatrix()); + } + } else { + m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); + } + + if (m_contentsLayer) { + // The contents layer is always coincidental with the graphicsLayer for now. + m_contentsLayer->setPosition(IntPoint(0, 0)); + m_contentsLayer->setSize(newSize); + m_contentsLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); + } + + m_graphicsLayer->updateContentsRect(); + if (!m_hasDirectlyCompositedContent) + m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow()); +} + +void RenderLayerBacking::updateInternalHierarchy() +{ + // m_contentsLayer has to be inserted in the correct order with child layers, + // so it's not inserted here. + if (m_ancestorClippingLayer) { + m_ancestorClippingLayer->removeAllChildren(); + m_graphicsLayer->removeFromParent(); + m_ancestorClippingLayer->addChild(m_graphicsLayer); + } + + if (m_clippingLayer) { + m_clippingLayer->removeFromParent(); + m_graphicsLayer->addChild(m_clippingLayer); + } +} + +// Return true if the layers changed. +bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) +{ + bool layersChanged = false; + + if (needsAncestorClip) { + if (!m_ancestorClippingLayer) { + m_ancestorClippingLayer = GraphicsLayer::createGraphicsLayer(this); +#ifndef NDEBUG + m_ancestorClippingLayer->setName("Ancestor clipping Layer"); +#endif + m_ancestorClippingLayer->setMasksToBounds(true); + layersChanged = true; + } + } else if (m_ancestorClippingLayer) { + m_ancestorClippingLayer->removeFromParent(); + delete m_ancestorClippingLayer; + m_ancestorClippingLayer = 0; + layersChanged = true; + } + + if (needsDescendantClip) { + if (!m_clippingLayer) { + m_clippingLayer = GraphicsLayer::createGraphicsLayer(0); +#ifndef NDEBUG + m_clippingLayer->setName("Child clipping Layer"); +#endif + m_clippingLayer->setMasksToBounds(true); + layersChanged = true; + } + } else if (m_clippingLayer) { + m_clippingLayer->removeFromParent(); + delete m_clippingLayer; + m_clippingLayer = 0; + layersChanged = true; + } + + if (layersChanged) + updateInternalHierarchy(); + + return layersChanged; +} + +bool RenderLayerBacking::updateContentsLayer(bool needsContentsLayer) +{ + bool layerChanged = false; + if (needsContentsLayer) { + if (!m_contentsLayer) { + m_contentsLayer = GraphicsLayer::createGraphicsLayer(this); +#ifndef NDEBUG + m_contentsLayer->setName("Contents"); +#endif + m_contentsLayer->setDrawsContent(true); + m_contentsLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask); + m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintBackgroundMask); + layerChanged = true; + } + } else if (m_contentsLayer) { + m_contentsLayer->removeFromParent(); + delete m_contentsLayer; + m_contentsLayer = 0; + m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintAllMask); + layerChanged = true; + } + return layerChanged; +} + +float RenderLayerBacking::compositingOpacity(float rendererOpacity) const +{ + float finalOpacity = rendererOpacity; + + for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) { + // We only care about parents that are stacking contexts. + // Recall that opacity creates stacking context. + if (!curr->isStackingContext()) + continue; + + // If we found a compositing layer, we want to compute opacity + // relative to it. So we can break here. + if (curr->isComposited()) + break; + + finalOpacity *= curr->renderer()->opacity(); + } + + return finalOpacity; +} + +static bool hasBorderOutlineOrShadow(const RenderStyle* style) +{ + return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow(); +} + +static bool hasBoxDecorations(const RenderStyle* style) +{ + return hasBorderOutlineOrShadow(style) || style->hasBackground(); +} + +static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style) +{ + return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage(); +} + +bool RenderLayerBacking::rendererHasBackground() const +{ + // FIXME: share more code here + if (renderer()->node() && renderer()->node()->isDocumentNode()) { + RenderObject* htmlObject = renderer()->firstChild(); + if (!htmlObject) + return false; + + RenderStyle* style = htmlObject->style(); + if (style->hasBackground()) + return true; + + RenderObject* bodyObject = htmlObject->firstChild(); + if (!bodyObject) + return false; + + style = bodyObject->style(); + return style->hasBackground(); + } + + return renderer()->style()->hasBackground(); +} + +const Color& RenderLayerBacking::rendererBackgroundColor() const +{ + // FIXME: share more code here + if (renderer()->node() && renderer()->node()->isDocumentNode()) { + RenderObject* htmlObject = renderer()->firstChild(); + RenderStyle* style = htmlObject->style(); + if (style->hasBackground()) + return style->backgroundColor(); + + RenderObject* bodyObject = htmlObject->firstChild(); + style = bodyObject->style(); + return style->backgroundColor(); + } + + return renderer()->style()->backgroundColor(); +} + +// A "simple container layer" is a RenderLayer which has no visible content to render. +// It may have no children, or all its children may be themselves composited. +// This is a useful optimization, because it allows us to avoid allocating backing store. +bool RenderLayerBacking::isSimpleContainerCompositingLayer() const +{ + RenderObject* renderObject = renderer(); + if (renderObject->isReplaced() || // replaced objects are not containers + renderObject->hasMask()) // masks require special treatment + return false; + + RenderStyle* style = renderObject->style(); + + // 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)) + return false; + + // If we have got this far and the renderer has no children, then we're ok. + if (!renderObject->firstChild()) + return true; + + if (renderObject->node() && renderObject->node()->isDocumentNode()) { + // Look to see if the root object has a non-simple backgound + RenderObject* rootObject = renderObject->document()->documentElement()->renderer(); + if (!rootObject) + return false; + + style = rootObject->style(); + + // 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)) + return false; + + // Now look at the body's renderer. + HTMLElement* body = renderObject->document()->body(); + RenderObject* bodyObject = (body && body->hasLocalName(HTMLNames::bodyTag)) ? body->renderer() : 0; + if (!bodyObject) + return false; + + style = bodyObject->style(); + + if (hasBoxDecorationsWithBackgroundImage(style)) + return false; + + // Ceck to see if all the body's children are compositing layers. + if (hasNonCompositingContent()) + return false; + + return true; + } + + // Check to see if all the renderer's children are compositing layers. + if (hasNonCompositingContent()) + return false; + + return true; +} + +bool RenderLayerBacking::hasNonCompositingContent() const +{ + // Conservative test for having no rendered children. + + // Some HTML can cause whitespace text nodes to have renderers, like: + // <div> + // <img src=...> + // </div> + // so test for 0x0 RenderTexts here + for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { + if (!child->hasLayer()) { + if (child->isRenderInline() || !child->isBox()) + return true; + + if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0) + return true; + } + } + + // FIXME: test for overflow controls. + if (m_owningLayer->isStackingContext()) { + // Use the m_hasCompositingDescendant bit to optimize? + if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + if (!curLayer->isComposited()) + return true; + } + } + + if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + if (!curLayer->isComposited()) + return true; + } + } + } + + if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + if (!curLayer->isComposited()) + return true; + } + } + + 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 +{ + RenderObject* renderObject = renderer(); + + // Reject anything that isn't an image + if (!renderObject->isImage() && !renderObject->isVideo()) + return false; + + if (renderObject->hasMask() || renderObject->hasReflection()) + 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()); +} + +void RenderLayerBacking::rendererContentChanged() +{ + if (canUseDirectCompositing() && renderer()->isImage()) + updateImageContents(); +} + +void RenderLayerBacking::updateImageContents() +{ + ASSERT(renderer()->isImage()); + RenderImage* imageRenderer = static_cast<RenderImage*>(renderer()); + + CachedImage* cachedImage = imageRenderer->cachedImage(); + if (!cachedImage) + return; + + Image* image = cachedImage->image(); + if (!image) + return; + + // We have to wait until the image is fully loaded before setting it on the layer. + if (!cachedImage->isLoaded()) + return; + + // This is a no-op if the layer doesn't have an inner layer for the image. + m_graphicsLayer->setContentsToImage(image); + + // Image animation is "lazy", in that it automatically stops unless someone is drawing + // the image. So we have to kick the animation each time; this has the downside that the + // image will keep animating, even if its layer is not visible. + image->startAnimation(); +} + +FloatPoint3D RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox) const +{ + RenderStyle* style = renderer()->style(); + + FloatPoint3D origin; + origin.setX(style->transformOriginX().calcFloatValue(borderBox.width())); + origin.setY(style->transformOriginY().calcFloatValue(borderBox.height())); + origin.setZ(style->transformOriginZ()); + + return origin; +} + +FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox) const +{ + RenderStyle* style = renderer()->style(); + + float boxWidth = borderBox.width(); + float boxHeight = borderBox.height(); + + FloatPoint origin; + origin.setX(style->perspectiveOriginX().calcFloatValue(boxWidth)); + origin.setY(style->perspectiveOriginY().calcFloatValue(boxHeight)); + + return origin; +} + +// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. +IntSize RenderLayerBacking::contentOffsetInCompostingLayer() +{ + return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y()); +} + +IntRect RenderLayerBacking::contentsBox(const GraphicsLayer*) +{ + if (!renderer()->isBox()) + return IntRect(); + + IntRect contentsRect; +#if ENABLE(VIDEO) + if (renderer()->isVideo()) { + RenderVideo* videoRenderer = static_cast<RenderVideo*>(renderer()); + contentsRect = videoRenderer->videoBox(); + } else +#endif + contentsRect = toRenderBox(renderer())->contentBoxRect(); + + IntSize contentOffset = contentOffsetInCompostingLayer(); + contentsRect.move(contentOffset); + return contentsRect; +} + +// Map the given point from coordinates in the GraphicsLayer to RenderLayer coordinates. +FloatPoint RenderLayerBacking::graphicsLayerToContentsCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point) +{ + return point + FloatSize(graphicsLayer->offsetFromRenderer()); +} + +// Map the given point from coordinates in the RenderLayer to GraphicsLayer coordinates. +FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point) +{ + return point - FloatSize(graphicsLayer->offsetFromRenderer()); +} + +bool RenderLayerBacking::paintingGoesToWindow() const +{ + return m_owningLayer->isRootLayer(); +} + +void RenderLayerBacking::setContentsNeedDisplay() +{ + bool needViewUpdate = false; + + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { + m_graphicsLayer->setNeedsDisplay(); + needViewUpdate = true; + } + + if (m_contentsLayer && m_contentsLayer->drawsContent()) { + m_contentsLayer->setNeedsDisplay(); + needViewUpdate = true; + } + + // Make sure layout happens before we get rendered again. + if (needViewUpdate) + compositor()->scheduleViewUpdate(); +} + +// r is in the coordinate space of the layer's render object +void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) +{ + bool needViewUpdate = false; + + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { + FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer, FloatPoint(r.x(), r.y())); + FloatRect dirtyRect(dirtyOrigin, r.size()); + FloatRect bounds(FloatPoint(), m_graphicsLayer->size()); + if (bounds.intersects(dirtyRect)) { + m_graphicsLayer->setNeedsDisplayInRect(dirtyRect); + needViewUpdate = true; + } + } + + if (m_contentsLayer && m_contentsLayer->drawsContent()) { + // FIXME: do incremental repaint + m_contentsLayer->setNeedsDisplay(); + needViewUpdate = true; + } + + // Make sure layout happens before we get rendered again. + if (needViewUpdate) + compositor()->scheduleViewUpdate(); +} + +static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) +{ + if (paintDirtyRect == clipRect) + return; + p->save(); + p->clip(clipRect); +} + +static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) +{ + if (paintDirtyRect == clipRect) + return; + p->restore(); +} + +// 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, + RenderObject* paintingRoot) +{ + if (paintingGoesToWindow()) { + ASSERT_NOT_REACHED(); + return; + } + + 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); + + int x = layerBounds.x(); // layerBounds is computed relative to rootLayer + int y = layerBounds.y(); + int tx = x - m_owningLayer->renderBoxX(); + int ty = y - m_owningLayer->renderBoxY(); + + // 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. + RenderObject *paintingRootForRenderer = 0; + if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) + paintingRootForRenderer = paintingRoot; + + bool shouldPaint = m_owningLayer->hasVisibleContent() && m_owningLayer->isSelfPaintingLayer(); + + if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackgroundMask)) { + // If this is the root then we need to send in a bigger bounding box + // because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()). + IntRect paintBox = clipRectToApply; + + // FIXME: do we need this code? + if (renderer()->node() && renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) { + RenderBox* box = toRenderBox(renderer()); + int w = box->width(); + int h = box->height(); + + int rw; + int rh; + if (box->view()->frameView()) { + rw = box->view()->frameView()->contentsWidth(); + rh = box->view()->frameView()->contentsHeight(); + } else { + rw = box->view()->width(); + rh = box->view()->height(); + } + + int bx = tx - box->marginLeft(); + int by = ty - box->marginTop(); + int bw = max(w + box->marginLeft() + box->marginRight() + box->borderLeft() + box->borderRight(), rw); + int bh = max(h + box->marginTop() + box->marginBottom() + box->borderTop() + box->borderBottom(), rh); + paintBox = IntRect(bx, by, bw, bh); + } + + // Paint our background first, before painting any child layers. + // Establish the clip used to paint our background. + setClip(context, paintDirtyRect, damageRect); + + RenderObject::PaintInfo info(context, paintBox, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); + renderer()->paint(info, tx, 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. + m_owningLayer->paintOverflowControls(context, x, y, damageRect); + + // Restore the clip. + restoreClip(context, paintDirtyRect, damageRect); + } + + if (shouldPaint && (paintingPhase & GraphicsLayerPaintForegroundMask)) { + // Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint. + // FIXME: should these be painted as background? + 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); + } + + bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; + bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; + + // Set up the clip used when painting our children. + setClip(context, paintDirtyRect, clipRectToApply); + RenderObject::PaintInfo paintInfo(context, clipRectToApply, + selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, + forceBlackText, paintingRootForRenderer, 0); + renderer()->paint(paintInfo, tx, ty); + + if (!selectionOnly) { + paintInfo.phase = PaintPhaseFloat; + renderer()->paint(paintInfo, tx, ty); + + paintInfo.phase = PaintPhaseForeground; + renderer()->paint(paintInfo, tx, ty); + + paintInfo.phase = PaintPhaseChildOutlines; + renderer()->paint(paintInfo, tx, ty); + } + + // Now restore our clip. + restoreClip(context, paintDirtyRect, clipRectToApply); + + if (!outlineRect.isEmpty()) { + // Paint our own outline + RenderObject::PaintInfo paintInfo(context, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0); + setClip(context, paintDirtyRect, outlineRect); + renderer()->paint(paintInfo, tx, ty); + restoreClip(context, paintDirtyRect, outlineRect); + } + + // Paint any child layers that have overflow. + 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); + } + + // 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); + } + + if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) { + setClip(context, paintDirtyRect, damageRect); + + // Paint the mask. + RenderObject::PaintInfo paintInfo(context, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0); + renderer()->paint(paintInfo, tx, ty); + + // Restore the clip. + restoreClip(context, paintDirtyRect, damageRect); + } + } + + ASSERT(!m_owningLayer->m_usedTransparency); +} + +// Up-call from compositing layer drawing callback. +void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase drawingPhase, const IntRect& clip) +{ + // We have to use the same root as for hit testing, because both methods + // can compute and cache clipRects. + IntRect enclosingBBox = compositedBounds(); + + IntRect clipRect(clip); + + // Set up the coordinate space to be in the layer's rendering coordinates. + context.translate(-enclosingBBox.x(), -enclosingBBox.y()); + + // Offset the clip. + clipRect.move(enclosingBBox.x(), enclosingBBox.y()); + + // The dirtyRect is in the coords of the painting root. + IntRect dirtyRect = enclosingBBox; + dirtyRect.intersect(clipRect); + + paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintRestrictionNone, drawingPhase, renderer()); +} + +bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes) +{ + bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); + bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform); + + if (!hasOpacity && !hasTransform) + return false; + + GraphicsLayer::TransformValueList transformVector; + GraphicsLayer::FloatValueList opacityVector; + + for (Vector<KeyframeValue>::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) { + const RenderStyle* keyframeStyle = it->style(); + float key = it->key(); + + if (!keyframeStyle) + continue; + + // get timing function + const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0; + + if (hasTransform) + transformVector.insert(key, &(keyframeStyle->transform()), tf); + + if (hasOpacity) + opacityVector.insert(key, keyframeStyle->opacity(), tf); + } + + bool didAnimateTransform = !hasTransform; + bool didAnimateOpacity = !hasOpacity; + + if (hasTransform && m_graphicsLayer->animateTransform(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, beginTime, false)) + didAnimateTransform = true; + + if (hasOpacity && m_graphicsLayer->animateFloat(AnimatedPropertyOpacity, opacityVector, anim, beginTime)) + didAnimateOpacity = true; + + return didAnimateTransform && didAnimateOpacity; +} + +bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) +{ + bool didAnimate = false; + ASSERT(property != cAnimateAll); + + if (property == (int)CSSPropertyOpacity) { + const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); + if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { + // If beginTime is not 0, we are restarting this transition, so first set the from value + // in case it was smashed by a previous animation. + if (beginTime > 0) + m_graphicsLayer->setOpacity(compositingOpacity(fromStyle->opacity()), 0, 0); + + if (m_graphicsLayer->setOpacity(compositingOpacity(toStyle->opacity()), opacityAnim, beginTime)) + didAnimate = true; + } + } + + if (property == (int)CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { + // We get a TransformOperation, which is a linked list of primitive operations and their arguments. + // Arguments can be floats or Length values, which need to be converted to numbers using + // val.calcFloatValue(renderer()->width()) (or height()). + const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); + if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { + GraphicsLayer::TransformValueList transformVector; + transformVector.insert(0, &fromStyle->transform(), 0); + transformVector.insert(1, &toStyle->transform(), 0); + if (m_graphicsLayer->animateTransform(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, beginTime, true)) + didAnimate = true; + } + } + + return didAnimate; +} + +void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double time) +{ + renderer()->animation()->notifyAnimationStarted(renderer(), time); +} + +void RenderLayerBacking::animationFinished(const String& name, int index, bool reset) +{ + m_graphicsLayer->removeFinishedAnimations(name, index, reset); +} + +void RenderLayerBacking::transitionFinished(int property) +{ + AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); + if (animatedProperty != AnimatedPropertyInvalid) + m_graphicsLayer->removeFinishedTransitions(animatedProperty); +} + +void RenderLayerBacking::suspendAnimations() +{ + m_graphicsLayer->suspendAnimations(); +} + +void RenderLayerBacking::resumeAnimations() +{ + m_graphicsLayer->resumeAnimations(); +} + +IntRect RenderLayerBacking::compositedBounds() const +{ + return m_compositedBounds; +} + +void RenderLayerBacking::setCompositedBounds(const IntRect& bounds) +{ + m_compositedBounds = bounds; + +} +int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) +{ + int cssProperty = CSSPropertyInvalid; + switch (property) { + case AnimatedPropertyWebkitTransform: + cssProperty = CSSPropertyWebkitTransform; + break; + case AnimatedPropertyOpacity: + cssProperty = CSSPropertyOpacity; + break; + case AnimatedPropertyBackgroundColor: + cssProperty = CSSPropertyBackgroundColor; + break; + case AnimatedPropertyInvalid: + ASSERT_NOT_REACHED(); + } + return cssProperty; +} + +AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(int cssProperty) +{ + switch (cssProperty) { + case CSSPropertyWebkitTransform: + return AnimatedPropertyWebkitTransform; + case CSSPropertyOpacity: + return AnimatedPropertyOpacity; + case CSSPropertyBackgroundColor: + return AnimatedPropertyBackgroundColor; + // It's fine if we see other css properties here; they are just not accelerated. + } + return AnimatedPropertyInvalid; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h new file mode 100644 index 0000000..50a77db --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerBacking.h @@ -0,0 +1,176 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderLayerBacking_h +#define RenderLayerBacking_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerClient.h" +#include "RenderLayer.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class KeyframeList; +class RenderLayerCompositor; + +// RenderLayerBacking controls the compositing behavior for a single RenderLayer. +// It holds the various GraphicsLayers, and makes decisions about intra-layer rendering +// optimizations. +// +// There is one RenderLayerBacking for each RenderLayer that is composited. + +class RenderLayerBacking : public GraphicsLayerClient { +public: + RenderLayerBacking(RenderLayer*); + ~RenderLayerBacking(); + + RenderLayer* owningLayer() const { return m_owningLayer; } + + void updateAfterLayout(); + + // Returns true if layer configuration changed. + bool updateGraphicsLayerConfiguration(); + // Update graphics layer position and bounds. + void updateGraphicsLayerGeometry(); // make private + // Update contents and clipping structure. + void updateInternalHierarchy(); // make private + + GraphicsLayer* graphicsLayer() const { return m_graphicsLayer; } + + // Layer to clip children + bool hasClippingLayer() const { return m_clippingLayer != 0; } + GraphicsLayer* clippingLayer() const { return m_clippingLayer; } + + // Layer to get clipped by ancestor + bool hasAncestorClippingLayer() const { return m_ancestorClippingLayer != 0; } + GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer; } + + bool hasContentsLayer() const { return m_contentsLayer != 0; } + GraphicsLayer* contentsLayer() const { return m_contentsLayer; } + + GraphicsLayer* parentForSublayers() const { return m_clippingLayer ? m_clippingLayer : m_graphicsLayer; } + GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer : m_graphicsLayer; } + + // RenderLayers with backing normally short-circuit paintLayer() because + // their content is rendered via callbacks from GraphicsLayer. However, the document + // layer is special, because it has a GraphicsLayer to act as a container for the GraphicsLayers + // for descendants, but its contents usually render into the window (in which case this returns true). + // This returns false for other layers, and when the document layer actually needs to paint into its backing store + // for some reason. + bool paintingGoesToWindow() const; + + void setContentsNeedDisplay(); + // r is in the coordinate space of the layer's render object + void setContentsNeedDisplayInRect(const IntRect& r); + + // Notification from the renderer that its content changed; used by RenderImage. + 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); + void animationFinished(const String& name, int index, bool reset); + void transitionFinished(int property); + + void suspendAnimations(); + void resumeAnimations(); + + IntRect compositedBounds() const; + void setCompositedBounds(const IntRect&); + + FloatPoint graphicsLayerToContentsCoordinates(const GraphicsLayer*, const FloatPoint&); + FloatPoint contentsToGraphicsLayerCoordinates(const GraphicsLayer*, const FloatPoint&); + + // GraphicsLayerClient interface + virtual void notifyAnimationStarted(const GraphicsLayer*, double startTime); + + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clip); + + virtual IntRect contentsBox(const GraphicsLayer*); + +private: + void createGraphicsLayer(); + void destroyGraphicsLayer(); + + RenderBoxModelObject* renderer() const { return m_owningLayer->renderer(); } + RenderLayerCompositor* compositor() const { return m_owningLayer->compositor(); } + + bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip); + bool updateContentsLayer(bool needsContentsLayer); + + IntSize contentOffsetInCompostingLayer(); + // Result is transform origin in pixels. + FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const; + // Result is perspective origin in pixels. + FloatPoint computePerspectiveOrigin(const IntRect& borderBox) const; + + void updateLayerOpacity(); + void updateLayerTransform(); + + // 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). + bool isSimpleContainerCompositingLayer() const; + // Returns true if we can optimize the RenderLayer to draw the replaced content + // directly into a compositing buffer + bool canUseDirectCompositing() const; + void updateImageContents(); + + bool rendererHasBackground() const; + const Color& rendererBackgroundColor() const; + + bool hasNonCompositingContent() const; + + void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, + PaintRestriction paintRestriction, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); + + static int graphicsLayerToCSSProperty(AnimatedPropertyID); + static AnimatedPropertyID cssToGraphicsLayerProperty(int); + +private: + RenderLayer* m_owningLayer; + + GraphicsLayer* m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context + GraphicsLayer* m_graphicsLayer; + GraphicsLayer* m_contentsLayer; // only used in cases where we need to draw the foreground separately + GraphicsLayer* m_clippingLayer; // only used if we have clipping on a stacking context, with compositing children + + IntRect m_compositedBounds; + + bool m_hasDirectlyCompositedContent; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // RenderLayerBacking_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp new file mode 100644 index 0000000..8b07ca9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.cpp @@ -0,0 +1,914 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" + +#include "AnimationController.h" +#include "ChromeClient.h" +#include "CSSPropertyNames.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsLayer.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "Page.h" +#include "RenderLayerBacking.h" +#include "RenderVideo.h" +#include "RenderView.h" +#include "Settings.h" + +#if PROFILE_LAYER_REBUILD +#include <wtf/CurrentTime.h> +#endif + +#ifndef NDEBUG +#include "CString.h" +#include "RenderTreeAsText.h" +#endif + +#if ENABLE(3D_RENDERING) +// This symbol is used to determine from a script whether 3D rendering is enabled (via 'nm'). +bool WebCoreHas3DRendering = true; +#endif + +namespace WebCore { + +struct CompositingState { + CompositingState(RenderLayer* compAncestor) + : m_compositingAncestor(compAncestor) + , m_subtreeIsCompositing(false) +#ifndef NDEBUG + , m_depth(0) +#endif + { + } + + RenderLayer* m_compositingAncestor; + bool m_subtreeIsCompositing; +#ifndef NDEBUG + int m_depth; +#endif +}; + +static TransformationMatrix flipTransform() +{ + TransformationMatrix flipper; + flipper.flipY(); + return flipper; +} + +RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) + : m_renderView(renderView) + , m_rootPlatformLayer(0) + , m_compositing(false) + , m_rootLayerAttached(false) + , m_compositingLayersNeedUpdate(false) + , m_hasAcceleratedCompositing(true) +#if PROFILE_LAYER_REBUILD + , m_rootLayerUpdateCount(0) +#endif // PROFILE_LAYER_REBUILD +{ +} + +RenderLayerCompositor::~RenderLayerCompositor() +{ + ASSERT(!m_rootLayerAttached); + delete m_rootPlatformLayer; +} + +void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) +{ + if (enable != m_compositing) { + m_compositing = enable; + + // We never go out of compositing mode for a given page, + // but if all the layers disappear, we'll just be left with + // the empty root layer, which has minimal overhead. + if (m_compositing) + ensureRootPlatformLayer(); + else + destroyRootPlatformLayer(); + } +} + +void RenderLayerCompositor::cacheAcceleratedCompositingEnabledFlag() +{ + bool hasAcceleratedCompositing = false; + if (Settings* settings = m_renderView->document()->settings()) + hasAcceleratedCompositing = settings-> acceleratedCompositingEnabled(); + + if (hasAcceleratedCompositing != m_hasAcceleratedCompositing) + setCompositingLayersNeedUpdate(); + + m_hasAcceleratedCompositing = hasAcceleratedCompositing; +} + +void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate) +{ + if (inCompositingMode()) { + if (!m_compositingLayersNeedUpdate && needUpdate) + scheduleViewUpdate(); + + m_compositingLayersNeedUpdate = needUpdate; + } +} + +void RenderLayerCompositor::scheduleViewUpdate() +{ + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; + + page->chrome()->client()->scheduleViewUpdate(); +} + +void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) +{ + if (!m_compositingLayersNeedUpdate) + return; + + ASSERT(inCompositingMode()); + + if (!updateRoot) { + // Only clear the flag if we're updating the entire hierarchy + m_compositingLayersNeedUpdate = false; + updateRoot = rootRenderLayer(); + } + +#if PROFILE_LAYER_REBUILD + ++m_rootLayerUpdateCount; + + 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. + { + CompositingState compState(updateRoot); + computeCompositingRequirements(updateRoot, compState); + } + + // Now create and parent the compositing layers. + { + CompositingState compState(updateRoot); + rebuildCompositingLayerTree(updateRoot, compState); + } + +#if PROFILE_LAYER_REBUILD + double endTime = WTF::currentTime(); + if (updateRoot == rootRenderLayer()) + fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n", + m_rootLayerUpdateCount, 1000.0 * (endTime - startTime)); +#endif + ASSERT(updateRoot || !m_compositingLayersNeedUpdate); + + if (!hasAcceleratedCompositing()) + enableCompositingMode(false); +} + +bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) +{ + bool layerChanged = false; + + if (needsToBeComposited(layer)) { + enableCompositingMode(); + if (!layer->backing()) { + + // If we need to repaint, do so before making backing + if (shouldRepaint == CompositingChangeRepaintNow) + repaintOnCompositingChange(layer); + + layer->ensureBacking(); + layerChanged = true; + } + } else { + if (layer->backing()) { + layer->clearBacking(); + layerChanged = true; + + // If we need to repaint, do so now that we've removed the backing + if (shouldRepaint == CompositingChangeRepaintNow) + repaintOnCompositingChange(layer); + } + } + +#if ENABLE(VIDEO) + if (layerChanged && layer->renderer()->isVideo()) { + // If it's a video, give the media player a chance to hook up to the layer. + RenderVideo* video = static_cast<RenderVideo*>(layer->renderer()); + video->acceleratedRenderingStateChanged(); + } +#endif + return layerChanged; +} + +bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) +{ + bool layerChanged = updateBacking(layer, shouldRepaint); + + // See if we need content or clipping layers. Methods called here should assume + // that the compositing state of descendant layers has not been updated yet. + if (layer->backing() && layer->backing()->updateGraphicsLayerConfiguration()) + layerChanged = true; + + return layerChanged; +} + +void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) +{ + RenderBoxModelObject* repaintContainer = layer->renderer()->containerForRepaint(); + if (!repaintContainer) + repaintContainer = m_renderView; + + layer->repaintIncludingNonCompositingDescendants(repaintContainer); + if (repaintContainer == m_renderView) { + // The contents of this layer may be moving between the window + // and a GraphicsLayer, so we need to make sure the window system + // synchronizes those changes on the screen. + m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); + } +} + +// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant +// RenderLayers that are rendered by the composited RenderLayer. +IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) +{ + IntRect boundingBoxRect, unionBounds; + boundingBoxRect = unionBounds = layer->localBoundingBox(); + + ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0)); + + if (!layer->isSelfPaintingLayer()) + return IntRect(); + + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + if (!curLayer->isComposited()) { + IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); + unionBounds.unite(childUnionBounds); + } + } + } + + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + if (!curLayer->isComposited()) { + IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); + unionBounds.unite(childUnionBounds); + } + } + } + + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + if (!curLayer->isComposited()) { + IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer); + unionBounds.unite(curAbsBounds); + } + } + } + + if (layer->paintsWithTransform()) { + TransformationMatrix* affineTrans = layer->transform(); + boundingBoxRect = affineTrans->mapRect(boundingBoxRect); + unionBounds = affineTrans->mapRect(unionBounds); + } + + int ancestorRelX = 0, ancestorRelY = 0; + layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY); + unionBounds.move(ancestorRelX, ancestorRelY); + + return unionBounds; +} + +void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) +{ + setCompositingLayersNeedUpdate(); +} + +void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) +{ + if (!child->isComposited() || parent->renderer()->documentBeingDestroyed()) + return; + + setCompositingParent(child, 0); + + RenderLayer* compLayer = parent->enclosingCompositingLayer(); + if (compLayer) { + ASSERT(compLayer->backing()); + IntRect compBounds = child->backing()->compositedBounds(); + + int offsetX = 0, offsetY = 0; + child->convertToLayerCoords(compLayer, offsetX, offsetY); + compBounds.move(offsetX, offsetY); + + compLayer->setBackingNeedsRepaintInRect(compBounds); + + // The contents of this layer may be moving from a GraphicsLayer to the window, + // so we need to make sure the window system synchronizes those changes on the screen. + m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); + } + + setCompositingLayersNeedUpdate(); +} + +RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const +{ + for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) { + if (curr->isStackingContext()) + return 0; + + if (curr->renderer()->hasOverflowClip()) + return curr; + } + return 0; +} + +// Recurse through the layers in z-index and overflow order (which is equivalent to painting order) +// For the z-order children of a compositing layer: +// If a child layers has a compositing layer, then all subsequent layers must +// be compositing in order to render above that layer. +// +// If a child in the negative z-order list is compositing, then the layer itself +// must be compositing so that its contents render over that child. +// This implies that its positive z-index children must also be compositing. +// +void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, struct CompositingState& compositingState) +{ + layer->updateLayerPosition(); + layer->updateZOrderLists(); + layer->updateNormalFlowList(); + + // Clear the flag + layer->setHasCompositingDescendant(false); + layer->setMustOverlayCompositedLayers(compositingState.m_subtreeIsCompositing); + + // The children of this layer don't need to composite, unless there is + // a compositing layer among them, so start by inheriting the compositing + // ancestor with m_subtreeIsCompositing set to false. + CompositingState childState(compositingState.m_compositingAncestor); +#ifndef NDEBUG + ++childState.m_depth; +#endif + + const bool willBeComposited = needsToBeComposited(layer); + if (willBeComposited) { + // Tell the parent it has compositing descendants. + compositingState.m_subtreeIsCompositing = true; + // This layer now acts as the ancestor for kids. + childState.m_compositingAncestor = layer; + } + +#if ENABLE(VIDEO) + // Video is special. It's a replaced element with a content layer, but has shadow content + // for the controller that must render in front. Without this, the controls fail to show + // when the video element is a stacking context (e.g. due to opacity or transform). + if (willBeComposited && layer->renderer()->isVideo()) + childState.m_subtreeIsCompositing = true; +#endif + + 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) { + RenderLayer* curLayer = negZOrderList->at(i); + computeCompositingRequirements(curLayer, childState); + + // 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) { + // make layer compositing + layer->setMustOverlayCompositedLayers(true); + childState.m_compositingAncestor = layer; + } + } + } + } + + ASSERT(!layer->m_normalFlowListDirty); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + computeCompositingRequirements(curLayer, childState); + } + } + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + computeCompositingRequirements(curLayer, childState); + } + } + } + + // 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 && + (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) + layer->setMustOverlayCompositedLayers(true); + + // 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); + + // Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree(). + updateBacking(layer, CompositingChangeRepaintNow); +} + +void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) +{ + ASSERT(childLayer->isComposited()); + + // It's possible to be called with a parent that isn't yet composited when we're doing + // partial updates as required by painting or hit testing. Just bail in that case; + // we'll do a full layer update soon. + if (!parentLayer || !parentLayer->isComposited()) + return; + + if (parentLayer) { + GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers(); + GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers(); + + hostingLayer->addChild(hostedLayer); + } else + childLayer->backing()->childForSuperlayers()->removeFromParent(); +} + +void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) +{ + ASSERT(layer->isComposited()); + + GraphicsLayer* hostingLayer = layer->backing()->parentForSublayers(); + hostingLayer->removeAllChildren(); +} + +void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) +{ + ASSERT(layer->isComposited()); + + GraphicsLayer* layerAnchor = layer->backing()->childForSuperlayers(); + + if (layerAnchor->parent() != m_rootPlatformLayer) { + layerAnchor->removeFromParent(); + if (m_rootPlatformLayer) + m_rootPlatformLayer->addChild(layerAnchor); + } +} + +#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->hasMask() || o->hasReflection() || !m_hasAcceleratedCompositing) + return false; + + return o->supportsAcceleratedRendering(); +} +#endif + +void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& compositingState) +{ + // 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->setCompositedBounds(calculateCompositedBounds(layer, layer)); + + layerBacking->updateGraphicsLayerConfiguration(); + layerBacking->updateGraphicsLayerGeometry(); + + if (!layer->parent()) + updateRootLayerPosition(); + + // FIXME: make this more incremental + layerBacking->parentForSublayers()->removeAllChildren(); + } + + // host the document layer in the RenderView's root layer + if (layer->isRootLayer() && layer->isComposited()) + parentInRootLayer(layer); + + CompositingState childState = compositingState; + if (layer->isComposited()) + childState.m_compositingAncestor = layer; + +#ifndef NDEBUG + ++childState.m_depth; +#endif + + // The children of this stacking context don't need to composite, unless there is + // a compositing layer among them, so start by assuming false. + childState.m_subtreeIsCompositing = false; + + 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) { + RenderLayer* curLayer = negZOrderList->at(i); + rebuildCompositingLayerTree(curLayer, childState); + if (curLayer->isComposited()) + setCompositingParent(curLayer, childState.m_compositingAncestor); + } + } + + if (layerBacking && layerBacking->contentsLayer()) { + // we only have a contents layer if we have an m_layer + layerBacking->contentsLayer()->removeFromParent(); + + GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer(); + hostingLayer->addChild(layerBacking->contentsLayer()); + } + } + + ASSERT(!layer->m_normalFlowListDirty); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + rebuildCompositingLayerTree(curLayer, childState); + if (curLayer->isComposited()) + setCompositingParent(curLayer, childState.m_compositingAncestor); + } + } + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + rebuildCompositingLayerTree(curLayer, childState); + if (curLayer->isComposited()) + setCompositingParent(curLayer, childState.m_compositingAncestor); + } + } + } +} + + +// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. +void RenderLayerCompositor::updateCompositingChildrenGeometry(RenderLayer* compositingAncestor, RenderLayer* layer) +{ + if (layer != compositingAncestor) { + if (RenderLayerBacking* layerBacking = layer->backing()) { + layerBacking->setCompositedBounds(calculateCompositedBounds(layer, layer)); + layerBacking->updateGraphicsLayerGeometry(); + return; + } + } + + if (!layer->hasCompositingDescendant()) + return; + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) + updateCompositingChildrenGeometry(compositingAncestor, negZOrderList->at(i)); + } + } + + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) + updateCompositingChildrenGeometry(compositingAncestor, 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) + updateCompositingChildrenGeometry(compositingAncestor, posZOrderList->at(i)); + } + } +} + + +void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& absRect) +{ + recursiveRepaintLayerRect(rootRenderLayer(), absRect); +} + +void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect) +{ + if (layer->isComposited()) + layer->setBackingNeedsRepaintInRect(rect); + + if (layer->hasCompositingDescendant()) { + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + int x = 0, y = 0; + curLayer->convertToLayerCoords(layer, x, y); + IntRect childRect(rect); + childRect.move(-x, -y); + recursiveRepaintLayerRect(curLayer, childRect); + } + } + + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + int x = 0, y = 0; + curLayer->convertToLayerCoords(layer, x, y); + IntRect childRect(rect); + childRect.move(-x, -y); + recursiveRepaintLayerRect(curLayer, childRect); + } + } + } + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + int x = 0, y = 0; + curLayer->convertToLayerCoords(layer, x, y); + IntRect childRect(rect); + childRect.move(-x, -y); + recursiveRepaintLayerRect(curLayer, childRect); + } + } +} + +RenderLayer* RenderLayerCompositor::rootRenderLayer() const +{ + return m_renderView->layer(); +} + +GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const +{ + return m_rootPlatformLayer; +} + +void RenderLayerCompositor::didMoveOnscreen() +{ + if (!m_rootPlatformLayer) + return; + + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; + + page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer); + m_rootLayerAttached = true; +} + +void RenderLayerCompositor::willMoveOffscreen() +{ + if (!m_rootPlatformLayer || !m_rootLayerAttached) + return; + + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; + + page->chrome()->client()->attachRootGraphicsLayer(frame, 0); + m_rootLayerAttached = false; +} + +void RenderLayerCompositor::updateRootLayerPosition() +{ + if (m_rootPlatformLayer) + m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight())); +} + +bool RenderLayerCompositor::has3DContent() const +{ + return layerHas3DContent(rootRenderLayer()); +} + +bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const +{ + if (!m_hasAcceleratedCompositing || !layer->isSelfPaintingLayer()) + return false; + + return requiresCompositingLayer(layer) || layer->mustOverlayCompositedLayers(); +} + +// 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 +{ + // The root layer always has a compositing layer, but it may not have backing. + return (inCompositingMode() && layer->isRootLayer()) || + requiresCompositingForTransform(layer->renderer()) || + requiresCompositingForVideo(layer->renderer()) || + layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden || + clipsCompositingDescendants(layer) || + requiresCompositingForAnimation(layer->renderer()); +} + +// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips, +// up to the enclosing compositing ancestor. This is required because compositing layers are parented +// according to the z-order hierarchy, yet clipping goes down the renderer hierarchy. +// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, +// but a sibling in the z-order hierarchy. +bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const +{ + if (!layer->isComposited() || !layer->parent()) + return false; + + RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); + if (!compositingAncestor) + return false; + + // If the compositingAncestor clips, that will be taken care of by clipsCompositingDescendants(), + // so we only care about clipping between its first child that is our ancestor (the computeClipRoot), + // and layer. + RenderLayer* computeClipRoot = 0; + RenderLayer* curr = layer; + while (curr) { + RenderLayer* next = curr->parent(); + if (next == compositingAncestor) { + computeClipRoot = curr; + break; + } + curr = next; + } + + if (!computeClipRoot || computeClipRoot == layer) + return false; + + ClipRects parentRects; + layer->parentClipRects(computeClipRoot, parentRects, true); + + return parentRects.overflowClipRect() != ClipRects::infiniteRect(); +} + +// Return true if the given layer is a stacking context and has compositing child +// layers that it needs to clip. In this case we insert a clipping GraphicsLayer +// into the hierarchy between this layer and its children in the z-order hierarchy. +bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const +{ + // FIXME: need to look at hasClip() too eventually + return layer->hasCompositingDescendant() && + layer->renderer()->hasOverflowClip(); +} + +bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) const +{ + RenderStyle* style = renderer->style(); + // Note that we ask the renderer if it has a transform, because the style may have transforms, + // but the renderer may be an inline that doesn't suppport them. + return renderer->hasTransform() && (style->transform().has3DOperation() || style->transformStyle3D() == TransformStyle3DPreserve3D || style->hasPerspective()); +} + +bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer) const +{ +#if ENABLE(VIDEO) + if (renderer->isVideo()) { + RenderVideo* video = static_cast<RenderVideo*>(renderer); + return canAccelerateVideoRendering(video); + } +#endif + return false; +} + +bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const +{ + if (AnimationController* animController = renderer->animation()) { + return (animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) + || animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyWebkitTransform); + } + return false; +} + +// If an element has negative z-index children, those children render in front of the +// layer background, so we need an extra 'contents' layer for the foreground of the layer +// object. +bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const +{ + return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0); +} + +void RenderLayerCompositor::ensureRootPlatformLayer() +{ + if (m_rootPlatformLayer) + return; + + m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0); + m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight())); + m_rootPlatformLayer->setPosition(FloatPoint(0, 0)); + + if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp) + m_rootPlatformLayer->setChildrenTransform(flipTransform()); + + // Need to clip to prevent transformed content showing outside this frame + m_rootPlatformLayer->setMasksToBounds(true); + + didMoveOnscreen(); +} + +void RenderLayerCompositor::destroyRootPlatformLayer() +{ + if (!m_rootPlatformLayer) + return; + + willMoveOffscreen(); + delete m_rootPlatformLayer; + m_rootPlatformLayer = 0; +} + +bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const +{ + const RenderStyle* style = layer->renderer()->style(); + + if (style && + (style->transformStyle3D() == TransformStyle3DPreserve3D || + style->hasPerspective() || + style->transform().has3DOperation())) + return true; + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + if (layerHas3DContent(curLayer)) + return true; + } + } + + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + if (layerHas3DContent(curLayer)) + return true; + } + } + } + + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + if (layerHas3DContent(curLayer)) + return true; + } + } + return false; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h new file mode 100644 index 0000000..bcd6a3f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayerCompositor.h @@ -0,0 +1,169 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderLayerCompositor_h +#define RenderLayerCompositor_h + +#include "RenderLayer.h" + +namespace WebCore { + +#define PROFILE_LAYER_REBUILD 0 + +class GraphicsLayer; +#if ENABLE(VIDEO) +class RenderVideo; +#endif + +// RenderLayerCompositor manages the hierarchy of +// composited RenderLayers. It determines which RenderLayers +// become compositing, and creates and maintains a hierarchy of +// GraphicsLayers based on the RenderLayer painting order. +// +// There is one RenderLayerCompositor per RenderView. + +class RenderLayerCompositor { +public: + + RenderLayerCompositor(RenderView*); + ~RenderLayerCompositor(); + + // Return true if this RenderView is in "compositing mode" (i.e. has one or more + // composited RenderLayers) + bool inCompositingMode() const { return m_compositing; } + // This will make a compositing layer at the root automatically, and hook up to + // the native view/window system. + void enableCompositingMode(bool enable = true); + + // Returns true if the accelerated compositing is enabled + bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; } + + // Copy the acceleratedCompositingEnabledFlag from Settings + void cacheAcceleratedCompositingEnabledFlag(); + + void setCompositingLayersNeedUpdate(bool needUpdate = true); + bool compositingLayersNeedUpdate() const { return m_compositingLayersNeedUpdate; } + + void scheduleViewUpdate(); + + // Rebuild the tree of compositing layers + void updateCompositingLayers(RenderLayer* updateRoot = 0); + + // Update the compositing state of the given layer. Returns true if that state changed. + enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater }; + bool updateLayerCompositingState(RenderLayer*, CompositingChangeRepaint = CompositingChangeRepaintNow); + + // Update the geometry for compositing children of compositingAncestor. + void updateCompositingChildrenGeometry(RenderLayer* compositingAncestor, RenderLayer* layer); + + // Whether layer's backing needs a graphics layer to do clipping by an ancestor (non-stacking-context parent with overflow). + bool clippedByAncestor(RenderLayer*) const; + // Whether layer's backing needs a graphics layer to clip z-order children of the given layer. + bool clipsCompositingDescendants(const RenderLayer*) const; + + // Whether the given layer needs an extra 'contents' layer. + bool needsContentsCompositingLayer(const RenderLayer*) const; + // Return the bounding box required for compositing layer and its childern, relative to ancestorLayer. + // If layerBoundingBox is not 0, on return it contains the bounding box of this layer only. + IntRect calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer); + + // Repaint the appropriate layers when the given RenderLayer starts or stops being composited. + void repaintOnCompositingChange(RenderLayer*); + + // Notify us that a layer has been added or removed + void layerWasAdded(RenderLayer* parent, RenderLayer* child); + void layerWillBeRemoved(RenderLayer* parent, RenderLayer* child); + + // Get the nearest ancestor layer that has overflow or clip, but is not a stacking context + RenderLayer* enclosingNonStackingClippingLayer(const RenderLayer* layer) const; + + // Repaint parts of all composited layers that intersect the given absolute rectangle. + void repaintCompositedLayersAbsoluteRect(const IntRect&); + + RenderLayer* rootRenderLayer() const; + GraphicsLayer* rootPlatformLayer() const; + + void didMoveOnscreen(); + void willMoveOffscreen(); + + void updateRootLayerPosition(); + +#if ENABLE(VIDEO) + // Use by RenderVideo to ask if it should try to use accelerated compositing. + bool canAccelerateVideoRendering(RenderVideo*) const; +#endif + + // Walk the tree looking for layers with 3d transforms. Useful in case you need + // to know if there is non-affine content, e.g. for drawing into an image. + bool has3DContent() const; + +private: + // Whether the given RL needs a compositing layer. + bool needsToBeComposited(const RenderLayer*) const; + // Whether the layer has an intrinsic need for compositing layer. + bool requiresCompositingLayer(const RenderLayer*) const; + + // Make or destroy the backing for this layer; returns true if backing changed. + bool updateBacking(RenderLayer*, CompositingChangeRepaint shouldRepaint); + + // Repaint the given rect (which is layer's coords), and regions of child layers that intersect that rect. + void recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect); + + void computeCompositingRequirements(RenderLayer*, struct CompositingState&); + void rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState&); + + // Hook compositing layers together + void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); + void removeCompositedChildren(RenderLayer*); + + void parentInRootLayer(RenderLayer*); + + bool layerHas3DContent(const RenderLayer*) const; + + void ensureRootPlatformLayer(); + void destroyRootPlatformLayer(); + + // Whether a running transition or animation enforces the need for a compositing layer. + bool requiresCompositingForAnimation(RenderObject*) const; + bool requiresCompositingForTransform(RenderObject*) const; + bool requiresCompositingForVideo(RenderObject*) const; + +private: + RenderView* m_renderView; + GraphicsLayer* m_rootPlatformLayer; + bool m_compositing; + bool m_rootLayerAttached; + bool m_compositingLayersNeedUpdate; + bool m_hasAcceleratedCompositing; + +#if PROFILE_LAYER_REBUILD + int m_rootLayerUpdateCount; +#endif +}; + + +} // namespace WebCore + +#endif // RenderLayerCompositor_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp deleted file mode 100644 index 1fac53f..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "RenderLegend.h" - -namespace WebCore { - -RenderLegend::RenderLegend(Node* element) - : RenderBlock(element) -{ -} - -} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h deleted file mode 100644 index 649f132..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the DOM implementation for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 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 RenderLegend_h -#define RenderLegend_h - -#include "RenderBlock.h" - -namespace WebCore { - - class RenderLegend : public RenderBlock { - public: - RenderLegend(Node*); - - virtual const char* renderName() const { return "RenderLegend"; } - }; - -} // namespace WebCore - -#endif // RenderLegend_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp new file mode 100644 index 0000000..00566b8 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderLineBoxList.h" + +#include "InlineTextBox.h" +#include "RenderArena.h" +#include "RenderInline.h" +#include "RenderView.h" +#include "RootInlineBox.h" + +using namespace std; + +namespace WebCore { + +#ifndef NDEBUG +RenderLineBoxList::~RenderLineBoxList() +{ + ASSERT(!m_firstLineBox); + ASSERT(!m_lastLineBox); +} +#endif + +void RenderLineBoxList::appendLineBox(InlineFlowBox* box) +{ + checkConsistency(); + + if (!m_firstLineBox) + m_firstLineBox = m_lastLineBox = box; + else { + m_lastLineBox->setNextLineBox(box); + box->setPreviousLineBox(m_lastLineBox); + m_lastLineBox = box; + } + + checkConsistency(); +} + +void RenderLineBoxList::deleteLineBoxTree(RenderArena* arena) +{ + InlineFlowBox* line = m_firstLineBox; + InlineFlowBox* nextLine; + while (line) { + nextLine = line->nextFlowBox(); + line->deleteLine(arena); + line = nextLine; + } + m_firstLineBox = m_lastLineBox = 0; +} + +void RenderLineBoxList::extractLineBox(InlineFlowBox* box) +{ + checkConsistency(); + + m_lastLineBox = box->prevFlowBox(); + 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()) + curr->setExtracted(); + + checkConsistency(); +} + +void RenderLineBoxList::attachLineBox(InlineFlowBox* box) +{ + checkConsistency(); + + if (m_lastLineBox) { + m_lastLineBox->setNextLineBox(box); + box->setPreviousLineBox(m_lastLineBox); + } else + m_firstLineBox = box; + InlineFlowBox* last = box; + for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) { + curr->setExtracted(false); + last = curr; + } + m_lastLineBox = last; + + checkConsistency(); +} + +void RenderLineBoxList::removeLineBox(InlineFlowBox* box) +{ + checkConsistency(); + + if (box == m_firstLineBox) + m_firstLineBox = box->nextFlowBox(); + if (box == m_lastLineBox) + m_lastLineBox = box->prevFlowBox(); + if (box->nextLineBox()) + box->nextLineBox()->setPreviousLineBox(box->prevLineBox()); + if (box->prevLineBox()) + box->prevLineBox()->setNextLineBox(box->nextLineBox()); + + checkConsistency(); +} + +void RenderLineBoxList::deleteLineBoxes(RenderArena* arena) +{ + if (m_firstLineBox) { + InlineRunBox* next; + for (InlineRunBox* curr = m_firstLineBox; curr; curr = next) { + next = curr->nextLineBox(); + curr->destroy(arena); + } + m_firstLineBox = 0; + m_lastLineBox = 0; + } +} + +void RenderLineBoxList::dirtyLineBoxes() +{ + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + curr->dirtyLineBoxes(); +} + +void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::PaintInfo& paintInfo, int tx, int ty) const +{ + // Only paint during the foreground/selection phases. + if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseOutline + && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines && paintInfo.phase != PaintPhaseTextClip + && paintInfo.phase != PaintPhaseMask) + return; + + ASSERT(renderer->isRenderBlock() || (renderer->isRenderInline() && renderer->hasLayer())); // The only way an inline could paint like this is if it has a layer. + + // If we have no lines then we have no work to do. + if (!firstLineBox()) + return; + + // We can check the first box and last box and avoid painting if we don't + // intersect. This is a quick short-circuit that we can take to avoid walking any lines. + // FIXME: This check is flawed in the following extremely obscure way: + // if some line in the middle has a huge overflow, it might actually extend below the last line. + int yPos = firstLineBox()->root()->topOverflow() - renderer->maximalOutlineSize(paintInfo.phase); + int h = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBox()->root()->bottomOverflow() - yPos; + yPos += ty; + if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) + return; + + RenderObject::PaintInfo info(paintInfo); + ListHashSet<RenderInline*> outlineObjects; + info.outlineObjects = &outlineObjects; + + // See if our root lines intersect with the dirty rect. If so, then we paint + // them. 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. + RenderView* v = renderer->view(); + bool usePrintRect = !v->printRect().isEmpty(); + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { + 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. + // The whole way objects break across pages needs to be redone. + // Try to avoid splitting a line vertically, but only if it's less than the height + // of the entire page. + if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= v->printRect().height()) { + if (ty + curr->root()->bottomOverflow() > v->printRect().bottom()) { + if (ty + curr->root()->topOverflow() < v->truncatedAt()) + v->setBestTruncatedAt(ty + curr->root()->topOverflow(), renderer); + // If we were able to truncate, don't paint. + if (ty + curr->root()->topOverflow() >= v->truncatedAt()) + break; + } + } + } + + int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - renderer->maximalOutlineSize(info.phase); + int bottom = curr->root()->bottomOverflow() + renderer->maximalOutlineSize(info.phase); + h = bottom - top; + yPos = ty + top; + if (yPos < info.rect.bottom() && yPos + h > info.rect.y()) + curr->paint(info, tx, ty); + } + + if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) { + ListHashSet<RenderInline*>::iterator end = info.outlineObjects->end(); + for (ListHashSet<RenderInline*>::iterator it = info.outlineObjects->begin(); it != end; ++it) { + RenderInline* flow = *it; + flow->paintOutline(info.context, tx, ty); + } + info.outlineObjects->clear(); + } +} + + +bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) const +{ + if (hitTestAction != HitTestForeground) + return false; + + ASSERT(renderer->isRenderBlock() || (renderer->isRenderInline() && renderer->hasLayer())); // The only way an inline could hit test like this is if it has a layer. + + // If we have no lines then we have no work to do. + if (!firstLineBox()) + return false; + + // We can check the first box and last box and avoid hit testing if we don't + // contain the point. This is a quick short-circuit that we can take to avoid walking any lines. + // FIXME: This check is flawed in the following extremely obscure way: + // if some line in the middle has a huge overflow, it might actually extend below the last line. + if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow())) + return false; + + // 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()) { + if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) { + bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty); + if (inside) { + renderer->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + return true; + } + } + } + + return false; +} + +void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, RenderObject* child) +{ + if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow()))) + return; + + // If we have no first line box, then just bail early. + if (!firstLineBox()) { + // For an empty inline, go ahead and propagate the check up to our parent, unless the parent + // is already dirty. + if (container->isInline() && !container->parent()->selfNeedsLayout()) + container->parent()->dirtyLinesFromChangedChild(container); + return; + } + + // Try to figure out which line box we belong in. First try to find a previous + // line box by examining our siblings. If we didn't find a line box, then use our + // parent's first line box. + RootInlineBox* box = 0; + RenderObject* curr = 0; + for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + if (curr->isReplaced()) { + InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper(); + if (wrapper) + box = wrapper->root(); + } else if (curr->isText()) { + InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); + if (textBox) + box = textBox->root(); + } else if (curr->isRenderInline()) { + InlineRunBox* runBox = toRenderInline(curr)->lastLineBox(); + if (runBox) + box = runBox->root(); + } + + if (box) + break; + } + if (!box) + box = firstLineBox()->root(); + + // If we found a line box, then dirty it. + if (box) { + RootInlineBox* adjacentBox; + box->markDirty(); + + // dirty the adjacent lines that might be affected + // NOTE: we dirty the previous line because RootInlineBox objects cache + // the address of the first object on the next line after a BR, which we may be + // invalidating here. For more info, see how RenderBlock::layoutInlineChildren + // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, + // despite the name, actually returns the first RenderObject after the BR. + // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." + adjacentBox = box->prevRootBox(); + if (adjacentBox) + adjacentBox->markDirty(); + if (child->isBR() || (curr && curr->isBR())) { + adjacentBox = box->nextRootBox(); + if (adjacentBox) + adjacentBox->markDirty(); + } + } +} + +#ifndef NDEBUG + +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); + prev = child; + } + ASSERT(prev == m_lastLineBox); +#endif +} + +#endif + +} diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.h b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.h new file mode 100644 index 0000000..52d7542 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderLineBoxList.h @@ -0,0 +1,86 @@ +/* + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderLineBoxList_h +#define RenderLineBoxList_h + +#include "RenderBox.h" + +namespace WebCore { + +class RenderLineBoxList { +public: + RenderLineBoxList() + : m_firstLineBox(0) + , m_lastLineBox(0) + { + } + +#ifndef NDEBUG + ~RenderLineBoxList(); +#endif + + InlineFlowBox* firstLineBox() const { return m_firstLineBox; } + InlineFlowBox* lastLineBox() const { return m_lastLineBox; } + + void checkConsistency() const; + + void appendLineBox(InlineFlowBox*); + + void deleteLineBoxTree(RenderArena*); + void deleteLineBoxes(RenderArena*); + + void extractLineBox(InlineFlowBox*); + void attachLineBox(InlineFlowBox*); + void removeLineBox(InlineFlowBox*); + + void dirtyLineBoxes(); + void dirtyLinesFromChangedChild(RenderObject* parent, RenderObject* child); + + void paint(RenderBoxModelObject*, RenderObject::PaintInfo&, int x, int y) const; + bool hitTest(RenderBoxModelObject*, const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction) const; + +private: + // For block flows, each box represents the root inline box for a line in the + // paragraph. + // For inline flows, each box represents a portion of that inline. + InlineFlowBox* m_firstLineBox; + InlineFlowBox* m_lastLineBox; +}; + + +#ifdef NDEBUG +inline void RenderLineBoxList::checkConsistency() const +{ +} +#endif + +} // namespace WebCore + +#endif // RenderFlow_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp index 35b9451..83c569e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp @@ -2,6 +2,7 @@ * This file is part of the select element renderer in WebCore. * * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,15 +42,15 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOptGroupElement.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" #include "HitTestResult.h" +#include "OptionGroupElement.h" +#include "OptionElement.h" #include "Page.h" #include "RenderScrollbar.h" #include "RenderTheme.h" #include "RenderView.h" #include "Scrollbar.h" +#include "SelectElement.h" #include "SelectionController.h" #include "NodeRenderStyle.h" #include <math.h> @@ -71,7 +72,7 @@ const int maxDefaultSize = 10; // widget, but I'm not sure this is right for the new control. const int baselineAdjustment = 7; -RenderListBox::RenderListBox(HTMLSelectElement* element) +RenderListBox::RenderListBox(Element* element) : RenderBlock(element) , m_optionsChanged(true) , m_scrollToRevealSelectionAfterLayout(false) @@ -86,7 +87,7 @@ RenderListBox::~RenderListBox() setHasVerticalScrollbar(false); } -void RenderListBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderListBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); setReplaced(isInline()); @@ -95,18 +96,18 @@ void RenderListBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* ol void RenderListBox::updateFromElement() { if (m_optionsChanged) { - const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node())->listItems(); + const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems(); int size = numItems(); float width = 0; for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; + Element* element = listItems[i]; String text; Font itemFont = style()->font(); - if (element->hasTagName(optionTag)) - text = static_cast<HTMLOptionElement*>(element)->optionText(); - else if (element->hasTagName(optgroupTag)) { - text = static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); + if (OptionElement* optionElement = toOptionElement(element)) + text = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) { + text = optionGroupElement->groupLabelText(); FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); @@ -150,7 +151,7 @@ void RenderListBox::layout() void RenderListBox::scrollToRevealSelection() { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); m_scrollToRevealSelectionAfterLayout = false; @@ -196,7 +197,7 @@ void RenderListBox::calcPrefWidths() int RenderListBox::size() const { - int specifiedSize = static_cast<HTMLSelectElement*>(node())->size(); + int specifiedSize = toSelectElement(static_cast<Element*>(node()))->size(); if (specifiedSize > 1) return max(minSize, specifiedSize); return min(max(minSize, numItems()), maxDefaultSize); @@ -210,7 +211,7 @@ int RenderListBox::numVisibleItems() const int RenderListBox::numItems() const { - return static_cast<HTMLSelectElement*>(node())->listItems().size(); + return toSelectElement(static_cast<Element*>(node()))->listItems().size(); } int RenderListBox::listHeight() const @@ -223,7 +224,7 @@ void RenderListBox::calcHeight() int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom(); int itemHeight = RenderListBox::itemHeight(); - m_height = itemHeight * size() - rowSpacing + toAdd; + setHeight(itemHeight * size() - rowSpacing + toAdd); RenderBlock::calcHeight(); @@ -292,16 +293,17 @@ void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty) void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - const Vector<HTMLElement*>& listItems = select->listItems(); - HTMLElement* element = listItems[listIndex]; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); + Element* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); String itemText; - if (element->hasTagName(optionTag)) - itemText = static_cast<HTMLOptionElement*>(element)->optionText(); - else if (element->hasTagName(optgroupTag)) - itemText = static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); - + if (optionElement) + itemText = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) + itemText = optionGroupElement->groupLabelText(); + // Determine where the item text should be placed IntRect r = itemBoundingBoxRect(tx, ty, listIndex); r.move(optionsSpacingHorizontal, style()->font().ascent()); @@ -311,7 +313,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in itemStyle = style(); Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color(); - if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) { + if (optionElement && optionElement->selected()) { if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) textColor = theme()->activeListBoxSelectionForegroundColor(); // Honor the foreground color for disabled items @@ -322,31 +324,31 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in paintInfo.context->setFillColor(textColor); Font itemFont = style()->font(); - if (element->hasTagName(optgroupTag)) { + if (isOptionGroupElement(element)) { FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(document()->styleSelector()->fontSelector()); } - paintInfo.context->setFont(itemFont); - + unsigned length = itemText.length(); const UChar* string = itemText.characters(); TextRun textRun(string, length, 0, 0, 0, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, false, false); // Draw the item text if (itemStyle->visibility() != HIDDEN) - paintInfo.context->drawBidiText(textRun, r.location()); + paintInfo.context->drawBidiText(itemFont, textRun, r.location()); } void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, int listIndex) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - const Vector<HTMLElement*>& listItems = select->listItems(); - HTMLElement* element = listItems[listIndex]; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); + Element* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); Color backColor; - if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) { + if (optionElement && optionElement->selected()) { if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) backColor = theme()->activeListBoxSelectionBackgroundColor(); else @@ -368,9 +370,9 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int return false; IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(), - _ty + borderTop() - borderTopExtra(), - m_vBar->width(), - height() + borderTopExtra() + borderBottomExtra() - borderTop() - borderBottom()); + _ty, + m_vBar->width(), + height() - borderTop() - borderBottom()); if (vertRect.contains(_x, _y)) { result.setScrollbar(m_vBar.get()); @@ -436,7 +438,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) return; m_inAutoscroll = true; - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); select->updateListBoxSelection(!select->multiple()); m_inAutoscroll = false; } @@ -466,7 +468,7 @@ void RenderListBox::autoscroll() int endIndex = scrollToward(pos); if (endIndex >= 0) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); m_inAutoscroll = true; if (!select->multiple()) @@ -480,7 +482,7 @@ void RenderListBox::autoscroll() void RenderListBox::stopAutoscroll() { - static_cast<HTMLSelectElement*>(node())->listBoxOnChange(); + toSelectElement(static_cast<Element*>(node()))->listBoxOnChange(); } bool RenderListBox::scrollToRevealElementAtListIndex(int index) @@ -513,9 +515,10 @@ bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granular void RenderListBox::valueChanged(unsigned listIndex) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + Element* element = static_cast<Element*>(node()); + SelectElement* select = toSelectElement(element); select->setSelectedIndex(select->listToOptionIndex(listIndex)); - select->onChange(); + element->dispatchFormControlChangeEvent(); } void RenderListBox::valueChanged(Scrollbar*) @@ -525,7 +528,7 @@ void RenderListBox::valueChanged(Scrollbar*) m_indexOffset = newOffset; repaint(); // Fire the scroll DOM event. - EventTargetNodeCast(node())->dispatchEventForType(eventNames().scrollEvent, false, false); + node()->dispatchEvent(eventNames().scrollEvent, false, false); } } @@ -577,9 +580,32 @@ void RenderListBox::setScrollTop(int newTop) m_vBar->setValue(index); } +bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +{ + if (!RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction)) + return false; + const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems(); + int size = numItems(); + tx += this->x(); + ty += this->y(); + for (int i = 0; i < size; ++i) { + if (itemBoundingBoxRect(tx, ty, i).contains(x, y)) { + if (Element* node = listItems[i]) { + result.setInnerNode(node); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(node); + result.setLocalPoint(IntPoint(x - tx, y - ty)); + break; + } + } + } + + return true; +} + IntRect RenderListBox::controlClipRect(int tx, int ty) const { - IntRect clipRect = contentBox(); + IntRect clipRect = contentBoxRect(); clipRect.move(tx, ty); return clipRect; } @@ -597,21 +623,14 @@ void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& repaintRectangle(scrollRect); } -bool RenderListBox::isScrollable() const -{ - if (numVisibleItems() < numItems()) - return true; - return RenderObject::isScrollable(); -} - PassRefPtr<Scrollbar> RenderListBox::createScrollbar() { RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this); else - widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, SmallScrollbar); + widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, theme()->scrollbarControlSizeForPart(ListboxPart)); document()->view()->addChild(widget.get()); return widget.release(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h index ccc6847..b8c0540 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h @@ -36,11 +36,9 @@ namespace WebCore { -class HTMLSelectElement; - class RenderListBox : public RenderBlock, private ScrollbarClient { public: - RenderListBox(HTMLSelectElement*); + RenderListBox(Element*); ~RenderListBox(); virtual const char* renderName() const { return "RenderListBox"; } @@ -58,7 +56,6 @@ public: virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty); virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool isScrollable() const; virtual void calcPrefWidths(); virtual int baselinePosition(bool firstLine, bool isRootLineBox) const; @@ -93,8 +90,10 @@ public: virtual void setScrollLeft(int); virtual void setScrollTop(int); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: // ScrollbarClient interface. diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp index f88f131..fb965d2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp @@ -49,7 +49,7 @@ RenderListItem::RenderListItem(Node* node) setInline(false); } -void RenderListItem::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -144,7 +144,7 @@ static RenderObject* getParentOfFirstLineBox(RenderBlock* curr, RenderObject* ma if (currChild == marker) continue; - if (currChild->isInline() && (!currChild->isInlineFlow() || curr->generatesLineBoxesForInlineChild(currChild))) + if (currChild->isInline() && (!currChild->isRenderInline() || curr->generatesLineBoxesForInlineChild(currChild))) return curr; if (currChild->isFloating() || currChild->isPositioned()) @@ -153,11 +153,11 @@ static RenderObject* getParentOfFirstLineBox(RenderBlock* curr, RenderObject* ma if (currChild->isTable() || !currChild->isRenderBlock()) break; - if (curr->isListItem() && currChild->style()->htmlHacks() && currChild->element() && - (currChild->element()->hasTagName(ulTag)|| currChild->element()->hasTagName(olTag))) + if (curr->isListItem() && currChild->style()->htmlHacks() && currChild->node() && + (currChild->node()->hasTagName(ulTag)|| currChild->node()->hasTagName(olTag))) break; - RenderObject* lineBox = getParentOfFirstLineBox(static_cast<RenderBlock*>(currChild), marker); + RenderObject* lineBox = getParentOfFirstLineBox(toRenderBlock(currChild), marker); if (lineBox) return lineBox; } @@ -235,12 +235,12 @@ void RenderListItem::layout() void RenderListItem::positionListMarker() { if (m_marker && !m_marker->isInside() && m_marker->inlineBoxWrapper()) { - int markerOldX = m_marker->xPos(); + int markerOldX = m_marker->x(); int yOffset = 0; int xOffset = 0; - for (RenderObject* o = m_marker->parent(); o != this; o = o->parent()) { - yOffset += o->yPos(); - xOffset += o->xPos(); + for (RenderBox* o = m_marker->parentBox(); o != this; o = o->parentBox()) { + yOffset += o->y(); + xOffset += o->x(); } bool adjustOverflow = false; @@ -248,7 +248,7 @@ void RenderListItem::positionListMarker() RootInlineBox* root = m_marker->inlineBoxWrapper()->root(); if (style()->direction() == LTR) { - int leftLineOffset = leftRelOffset(yOffset, leftOffset(yOffset)); + int leftLineOffset = leftRelOffset(yOffset, leftOffset(yOffset, false), false); markerXPos = leftLineOffset - xOffset - paddingLeft() - borderLeft() + m_marker->marginLeft(); m_marker->inlineBoxWrapper()->adjustPosition(markerXPos - markerOldX, 0); if (markerXPos < root->leftOverflow()) { @@ -256,7 +256,7 @@ void RenderListItem::positionListMarker() adjustOverflow = true; } } else { - int rightLineOffset = rightRelOffset(yOffset, rightOffset(yOffset)); + int rightLineOffset = rightRelOffset(yOffset, rightOffset(yOffset, false), false); markerXPos = rightLineOffset - xOffset + paddingRight() + borderRight() + m_marker->marginLeft(); m_marker->inlineBoxWrapper()->adjustPosition(markerXPos - markerOldX, 0); if (markerXPos + m_marker->width() > root->rightOverflow()) { @@ -267,12 +267,12 @@ void RenderListItem::positionListMarker() if (adjustOverflow) { IntRect markerRect(markerXPos + xOffset, yOffset, m_marker->width(), m_marker->height()); - RenderObject* o = m_marker; + RenderBox* o = m_marker; do { - o = o->parent(); + o = o->parentBox(); if (o->isRenderBlock()) - static_cast<RenderBlock*>(o)->addVisualOverflow(markerRect); - markerRect.move(-o->xPos(), -o->yPos()); + toRenderBlock(o)->addVisualOverflow(markerRect); + markerRect.move(-o->x(), -o->y()); } while (o != this); } } @@ -280,7 +280,7 @@ void RenderListItem::positionListMarker() void RenderListItem::paint(PaintInfo& paintInfo, int tx, int ty) { - if (!m_height) + if (!height()) return; RenderBlock::paint(paintInfo, tx, ty); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h index d4dd675..91844f7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h @@ -61,7 +61,7 @@ public: const String& markerText() const; protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: void updateMarkerLocation(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp index 4209906..9627711 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp @@ -28,7 +28,6 @@ #include "CharacterNames.h" #include "Document.h" #include "GraphicsContext.h" -#include "ListMarkerBox.h" #include "RenderLayer.h" #include "RenderListItem.h" #include "RenderView.h" @@ -159,7 +158,7 @@ static int toArmenianUnder10000(int number, bool upper, bool addCircumflex, UCha int lowerOffset = upper ? 0 : 0x0030; - if (int thousands = number / 1000) + if (int thousands = number / 1000) { if (thousands == 7) { letters[length++] = 0x0548 + lowerOffset; letters[length++] = 0x0552 + lowerOffset; @@ -170,6 +169,7 @@ static int toArmenianUnder10000(int number, bool upper, bool addCircumflex, UCha if (addCircumflex) letters[length++] = 0x0302; } + } if (int hundreds = (number / 100) % 10) { letters[length++] = (0x0543 - 1 + lowerOffset) + hundreds; @@ -472,7 +472,6 @@ String listMarkerText(EListStyleType type, int value) RenderListMarker::RenderListMarker(RenderListItem* item) : RenderBox(item->document()) , m_listItem(item) - , m_selectionState(SelectionNone) { // init RenderObject attributes setInline(true); // our object is Inline @@ -485,7 +484,7 @@ RenderListMarker::~RenderListMarker() m_image->removeClient(this); } -void RenderListMarker::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderListMarker::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { if (style() && (newStyle->listStylePosition() != style()->listStylePosition() || newStyle->listStyleType() != style()->listStyleType())) setNeedsLayoutAndPrefWidthsRecalc(); @@ -493,7 +492,7 @@ void RenderListMarker::styleWillChange(RenderStyle::Diff diff, const RenderStyle RenderBox::styleWillChange(diff, newStyle); } -void RenderListMarker::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderListMarker::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBox::styleDidChange(diff, oldStyle); @@ -506,12 +505,11 @@ void RenderListMarker::styleDidChange(RenderStyle::Diff diff, const RenderStyle* } } -InlineBox* RenderListMarker::createInlineBox(bool, bool isRootLineBox, bool) +InlineBox* RenderListMarker::createInlineBox() { - ASSERT(!isRootLineBox); - ListMarkerBox* box = new (renderArena()) ListMarkerBox(this); - m_inlineBoxWrapper = box; - return box; + InlineBox* result = RenderBox::createInlineBox(); + result->setIsText(isText()); + return result; } bool RenderListMarker::isImage() const @@ -530,7 +528,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) IntRect marker = getRelativeMarkerRect(); marker.move(tx, ty); - IntRect box(tx + m_x, ty + m_y, m_width, m_height); + IntRect box(tx + x(), ty + y(), width(), height()); if (box.y() > paintInfo.rect.bottom() || box.y() + box.height() < paintInfo.rect.y()) return; @@ -539,7 +537,6 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) paintBoxDecorations(paintInfo, box.x(), box.y()); GraphicsContext* context = paintInfo.context; - context->setFont(style()->font()); if (isImage()) { #if PLATFORM(MAC) @@ -547,8 +544,10 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) paintCustomHighlight(tx, ty, style()->highlight(), true); #endif context->drawImage(m_image->image(this, marker.size()), marker.location()); - if (selectionState() != SelectionNone) + if (selectionState() != SelectionNone) { + // FIXME: selectionRect() is in absolute, not painting coordinates. context->fillRect(selectionRect(), selectionBackgroundColor()); + } return; } @@ -558,8 +557,10 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) paintCustomHighlight(tx, ty, style()->highlight(), true); #endif - if (selectionState() != SelectionNone) + if (selectionState() != SelectionNone) { + // FIXME: selectionRect() is in absolute, not painting coordinates. context->fillRect(selectionRect(), selectionBackgroundColor()); + } const Color color(style()->color()); context->setStrokeColor(color); @@ -619,15 +620,15 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) const Font& font = style()->font(); if (style()->direction() == LTR) { int width = font.width(textRun); - context->drawText(textRun, marker.location()); + context->drawText(style()->font(), textRun, marker.location()); const UChar periodSpace[2] = { '.', ' ' }; - context->drawText(TextRun(periodSpace, 2), marker.location() + IntSize(width, 0)); + context->drawText(style()->font(), TextRun(periodSpace, 2), marker.location() + IntSize(width, 0)); } else { const UChar spacePeriod[2] = { ' ', '.' }; TextRun spacePeriodRun(spacePeriod, 2); int width = font.width(spacePeriodRun); - context->drawText(spacePeriodRun, marker.location()); - context->drawText(textRun, marker.location() + IntSize(width, 0)); + context->drawText(style()->font(), spacePeriodRun, marker.location()); + context->drawText(style()->font(), textRun, marker.location() + IntSize(width, 0)); } } @@ -637,11 +638,11 @@ void RenderListMarker::layout() ASSERT(!prefWidthsDirty()); if (isImage()) { - m_width = m_image->imageSize(this, style()->effectiveZoom()).width(); - m_height = m_image->imageSize(this, style()->effectiveZoom()).height(); + setWidth(m_image->imageSize(this, style()->effectiveZoom()).width()); + setHeight(m_image->imageSize(this, style()->effectiveZoom()).height()); } else { - m_width = minPrefWidth(); - m_height = style()->font().height(); + setWidth(minPrefWidth()); + setHeight(style()->font().height()); } m_marginLeft = m_marginRight = 0; @@ -662,7 +663,7 @@ void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*) if (o != m_image->data()) return; - if (m_width != m_image->imageSize(this, style()->effectiveZoom()).width() || m_height != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred()) + if (width() != m_image->imageSize(this, style()->effectiveZoom()).width() || height() != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred()) setNeedsLayoutAndPrefWidthsRecalc(); else repaint(); @@ -830,7 +831,7 @@ bool RenderListMarker::isInside() const IntRect RenderListMarker::getRelativeMarkerRect() { if (isImage()) - return IntRect(m_x, m_y, m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height()); + return IntRect(x(), y(), m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height()); switch (style()->listStyleType()) { case DISC: @@ -840,7 +841,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() const Font& font = style()->font(); int ascent = font.ascent(); int bulletWidth = (ascent * 2 / 3 + 1) / 2; - return IntRect(m_x + 1, m_y + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); + return IntRect(x() + 1, y() + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); } case LNONE: return IntRect(); @@ -867,7 +868,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() int itemWidth = font.width(m_text); const UChar periodSpace[2] = { '.', ' ' }; int periodSpaceWidth = font.width(TextRun(periodSpace, 2)); - return IntRect(m_x, m_y + font.ascent(), itemWidth + periodSpaceWidth, font.height()); + return IntRect(x(), y() + font.ascent(), itemWidth + periodSpaceWidth, font.height()); } return IntRect(); @@ -875,14 +876,14 @@ IntRect RenderListMarker::getRelativeMarkerRect() void RenderListMarker::setSelectionState(SelectionState state) { - m_selectionState = state; + RenderBox::setSelectionState(state); if (InlineBox* box = inlineBoxWrapper()) if (RootInlineBox* root = box->root()) root->setHasSelectedChildren(state != SelectionNone); containingBlock()->setSelectionState(state); } -IntRect RenderListMarker::selectionRect(bool clipToVisibleContent) +IntRect RenderListMarker::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); @@ -890,14 +891,12 @@ IntRect RenderListMarker::selectionRect(bool clipToVisibleContent) return IntRect(); RootInlineBox* root = inlineBoxWrapper()->root(); - IntRect rect(0, root->selectionTop() - yPos(), width(), root->selectionHeight()); + IntRect rect(0, root->selectionTop() - y(), width(), root->selectionHeight()); if (clipToVisibleContent) - computeAbsoluteRepaintRect(rect); - else { - FloatPoint absPos = localToAbsolute(); - rect.move(absPos.x(), absPos.y()); - } + computeRectForRepaint(repaintContainer, rect); + else + rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); return rect; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h index 738427c..57580a8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h @@ -49,7 +49,7 @@ public: virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - virtual InlineBox* createInlineBox(bool, bool, bool); + virtual InlineBox* createInlineBox(); virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; @@ -60,16 +60,15 @@ public: bool isInside() const; - virtual SelectionState selectionState() const { return m_selectionState; } virtual void setSelectionState(SelectionState); - virtual IntRect selectionRect(bool clipToVisibleContent = true); + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); virtual bool canBeSelectionLeaf() const { return true; } void updateMargins(); protected: - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: IntRect getRelativeMarkerRect(); @@ -77,7 +76,6 @@ private: String m_text; RefPtr<StyleImage> m_image; RenderListItem* m_listItem; - SelectionState m_selectionState; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp index 96d26ea..48659f7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp @@ -68,9 +68,9 @@ RenderMarquee::RenderMarquee(RenderLayer* l) int RenderMarquee::marqueeSpeed() const { int result = m_layer->renderer()->style()->marqueeSpeed(); - Node* elt = m_layer->renderer()->element(); - if (elt && elt->hasTagName(marqueeTag)) { - HTMLMarqueeElement* marqueeElt = static_cast<HTMLMarqueeElement*>(elt); + Node* n = m_layer->renderer()->node(); + if (n && n->hasTagName(marqueeTag)) { + HTMLMarqueeElement* marqueeElt = static_cast<HTMLMarqueeElement*>(n); result = max(result, marqueeElt->minimumDelay()); } return result; @@ -105,17 +105,18 @@ bool RenderMarquee::isHorizontal() const int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) { - RenderObject* o = m_layer->renderer(); - RenderStyle* s = o->style(); + RenderBox* box = m_layer->renderBox(); + ASSERT(box); + RenderStyle* s = box->style(); if (isHorizontal()) { bool ltr = s->direction() == LTR; - int clientWidth = o->clientWidth(); - int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false); + int clientWidth = box->clientWidth(); + int contentWidth = ltr ? box->rightmostPosition(true, false) : box->leftmostPosition(true, false); if (ltr) - contentWidth += (o->paddingRight() - o->borderLeft()); + contentWidth += (box->paddingRight() - box->borderLeft()); else { - contentWidth = o->width() - contentWidth; - contentWidth += (o->paddingLeft() - o->borderRight()); + contentWidth = box->width() - contentWidth; + contentWidth += (box->paddingLeft() - box->borderRight()); } if (dir == MRIGHT) { if (stopAtContentEdge) @@ -131,9 +132,9 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge } } else { - int contentHeight = m_layer->renderer()->lowestPosition(true, false) - - m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom(); - int clientHeight = m_layer->renderer()->clientHeight(); + int contentHeight = box->lowestPosition(true, false) - + box->borderTop() + box->paddingBottom(); + int clientHeight = box->clientHeight(); if (dir == MUP) { if (stopAtContentEdge) return min(contentHeight - clientHeight, 0); @@ -283,7 +284,7 @@ void RenderMarquee::timerFired(Timer<RenderMarquee>*) addIncrement = !addIncrement; } bool positive = range > 0; - int clientSize = (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight()); + int clientSize = (isHorizontal() ? m_layer->renderBox()->clientWidth() : m_layer->renderBox()->clientHeight()); int increment = max(1, abs(m_layer->renderer()->style()->marqueeIncrement().calcValue(clientSize))); int currentPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()); newPos = currentPos + (addIncrement ? increment : -increment); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h index d9d20cd..886c343 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h @@ -44,7 +44,8 @@ #ifndef RenderMarquee_h #define RenderMarquee_h -#include "RenderStyle.h" +#include "Length.h" +#include "RenderStyleConstants.h" #include "Timer.h" namespace WebCore { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp index a224136..b0eb097 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 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -28,25 +28,20 @@ #if ENABLE(VIDEO) #include "RenderMedia.h" -#include "CSSStyleSelector.h" -#include "Event.h" #include "EventNames.h" #include "FloatConversion.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLMediaElement.h" #include "HTMLNames.h" #include "MediaControlElements.h" #include "MouseEvent.h" -#include "MediaPlayer.h" -#include "RenderSlider.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> #include <wtf/MathExtras.h> using namespace std; namespace WebCore { +using namespace HTMLNames; + static const double cTimeUpdateRepeatDelay = 0.2; static const double cOpacityAnimationRepeatDelay = 0.05; // FIXME get this from style @@ -82,8 +77,14 @@ RenderMedia::~RenderMedia() void RenderMedia::destroy() { if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) { + + // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach() + // when display: style changes + m_panel->detach(); + removeChild(m_controlsShadowRoot->renderer()); m_controlsShadowRoot->detach(); + m_controlsShadowRoot = 0; } RenderReplaced::destroy(); } @@ -98,18 +99,40 @@ MediaPlayer* RenderMedia::player() const return mediaElement()->player(); } +void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderReplaced::styleDidChange(diff, oldStyle); + + if (m_controlsShadowRoot) { + if (m_panel->renderer()) + m_panel->renderer()->setStyle(getCachedPseudoStyle(MEDIA_CONTROLS_PANEL)); + + if (m_timelineContainer->renderer()) + m_timelineContainer->renderer()->setStyle(getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER)); + + m_muteButton->updateStyle(); + m_playButton->updateStyle(); + m_seekBackButton->updateStyle(); + m_seekForwardButton->updateStyle(); + m_timeline->updateStyle(); + m_fullscreenButton->updateStyle(); + m_currentTimeDisplay->updateStyle(); + m_timeRemainingDisplay->updateStyle(); + } +} + void RenderMedia::layout() { - IntSize oldSize = contentBox().size(); + IntSize oldSize = contentBoxRect().size(); RenderReplaced::layout(); - RenderObject* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0; + RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0; if (!controlsRenderer) return; - IntSize newSize = contentBox().size(); + IntSize newSize = contentBoxRect().size(); if (newSize != oldSize || controlsRenderer->needsLayout()) { - controlsRenderer->setPos(borderLeft() + paddingLeft(), borderTop() + paddingTop()); + controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); controlsRenderer->setNeedsLayout(true, false); @@ -118,34 +141,17 @@ void RenderMedia::layout() } } -RenderObject* RenderMedia::firstChild() const -{ - return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0; -} - -RenderObject* RenderMedia::lastChild() const -{ - return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0; -} - -void RenderMedia::removeChild(RenderObject* child) -{ - ASSERT(m_controlsShadowRoot); - ASSERT(child == m_controlsShadowRoot->renderer()); - child->removeLayers(enclosingLayer()); - static_cast<RenderMediaControlShadowRoot*>(child)->setParent(0); -} - void RenderMedia::createControlsShadowRoot() { ASSERT(!m_controlsShadowRoot); m_controlsShadowRoot = new MediaControlShadowRootElement(document(), mediaElement()); + addChild(m_controlsShadowRoot->renderer()); } void RenderMedia::createPanel() { ASSERT(!m_panel); - RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_PANEL); + RenderStyle* style = getCachedPseudoStyle(MEDIA_CONTROLS_PANEL); m_panel = new HTMLDivElement(HTMLNames::divTag, document()); RenderObject* renderer = m_panel->createRenderer(renderArena(), style); if (renderer) { @@ -186,27 +192,42 @@ void RenderMedia::createSeekForwardButton() m_seekForwardButton->attachToParent(m_panel.get()); } +void RenderMedia::createTimelineContainer() +{ + ASSERT(!m_timelineContainer); + RenderStyle* style = getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER); + m_timelineContainer = new HTMLDivElement(HTMLNames::divTag, document()); + RenderObject* renderer = m_timelineContainer->createRenderer(renderArena(), style); + if (renderer) { + m_timelineContainer->setRenderer(renderer); + renderer->setStyle(style); + m_timelineContainer->setAttached(); + m_timelineContainer->setInDocument(true); + m_panel->addChild(m_timelineContainer); + m_panel->renderer()->addChild(renderer); + } +} + void RenderMedia::createTimeline() { ASSERT(!m_timeline); m_timeline = new MediaControlTimelineElement(document(), mediaElement()); - m_timeline->attachToParent(m_panel.get()); + m_timeline->setAttribute(precisionAttr, "float"); + m_timeline->attachToParent(m_timelineContainer.get()); } -void RenderMedia::createTimeDisplay() +void RenderMedia::createCurrentTimeDisplay() { - ASSERT(!m_timeDisplay); - RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY); - m_timeDisplay = new HTMLDivElement(HTMLNames::divTag, document()); - RenderObject* renderer = m_timeDisplay->createRenderer(renderArena(), style); - if (renderer) { - m_timeDisplay->setRenderer(renderer); - renderer->setStyle(style); - m_timeDisplay->setAttached(); - m_timeDisplay->setInDocument(true); - m_panel->addChild(m_timeDisplay); - m_panel->renderer()->addChild(renderer); - } + ASSERT(!m_currentTimeDisplay); + m_currentTimeDisplay = new MediaTimeDisplayElement(document(), mediaElement(), true); + m_currentTimeDisplay->attachToParent(m_timelineContainer.get()); +} + +void RenderMedia::createTimeRemainingDisplay() +{ + ASSERT(!m_timeRemainingDisplay); + m_timeRemainingDisplay = new MediaTimeDisplayElement(document(), mediaElement(), false); + m_timeRemainingDisplay->attachToParent(m_timelineContainer.get()); } void RenderMedia::createFullscreenButton() @@ -230,10 +251,12 @@ void RenderMedia::updateControls() m_panel = 0; m_muteButton = 0; m_playButton = 0; + m_timelineContainer = 0; m_timeline = 0; m_seekBackButton = 0; m_seekForwardButton = 0; - m_timeDisplay = 0; + m_currentTimeDisplay = 0; + m_timeRemainingDisplay = 0; m_fullscreenButton = 0; m_controlsShadowRoot = 0; } @@ -246,19 +269,29 @@ void RenderMedia::updateControls() if (!m_controlsShadowRoot) { createControlsShadowRoot(); createPanel(); - createMuteButton(); - createPlayButton(); - createTimeline(); - createSeekBackButton(); - createSeekForwardButton(); - createTimeDisplay(); - createFullscreenButton(); + if (m_panel && m_panel->renderer()) { + createMuteButton(); + createPlayButton(); + createTimelineContainer(); + createSeekBackButton(); + createSeekForwardButton(); + createFullscreenButton(); + } + if (m_timelineContainer && m_timelineContainer->renderer()) { + createCurrentTimeDisplay(); + createTimeline(); + createTimeRemainingDisplay(); + } } - - if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA) - m_timeUpdateTimer.stop(); - else + + if (media->canPlay()) { + if (m_timeUpdateTimer.isActive()) + m_timeUpdateTimer.stop(); + } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE ) { m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay); + } + + m_previousVisible = style()->visibility(); if (m_muteButton) m_muteButton->update(); @@ -266,6 +299,10 @@ void RenderMedia::updateControls() m_playButton->update(); if (m_timeline) m_timeline->update(); + if (m_currentTimeDisplay) + m_currentTimeDisplay->update(); + if (m_timeRemainingDisplay) + m_timeRemainingDisplay->update(); if (m_seekBackButton) m_seekBackButton->update(); if (m_seekForwardButton) @@ -287,32 +324,47 @@ String RenderMedia::formatTime(float time) { if (!isfinite(time)) time = 0; - int seconds = (int)time; + int seconds = (int)fabsf(time); int hours = seconds / (60 * 60); int minutes = (seconds / 60) % 60; seconds %= 60; - return String::format("%02d:%02d:%02d", hours, minutes, seconds); + if (hours) { + if (hours > 9) + return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + else + return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + } + else + return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds); } void RenderMedia::updateTimeDisplay() { - if (!m_timeDisplay) + if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE) return; - String timeString = formatTime(mediaElement()->currentTime()); + float now = mediaElement()->currentTime(); + float duration = mediaElement()->duration(); + + String timeString = formatTime(now); ExceptionCode ec; - m_timeDisplay->setInnerText(timeString, ec); -} + m_currentTimeDisplay->setInnerText(timeString, ec); + timeString = formatTime(now - duration); + m_timeRemainingDisplay->setInnerText(timeString, ec); +} + void RenderMedia::updateControlVisibility() { if (!m_panel || !m_panel->renderer()) return; + // Don't fade for audio controls. HTMLMediaElement* media = mediaElement(); - if (player() && !player()->hasVideo() || !media->isVideo()) + if (!media->hasVideo()) return; + // do fading manually, css animations don't work well with shadow trees - bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA); + bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->canPlay()); if (visible == (m_opacityAnimationTo > 0)) return; @@ -320,7 +372,7 @@ void RenderMedia::updateControlVisibility() // don't fade gradually if it the element has just changed visibility m_previousVisible = style()->visibility(); m_opacityAnimationTo = m_previousVisible == VISIBLE ? 1.0f : 0; - changeOpacity(m_panel.get(), 0); + changeOpacity(m_panel.get(), m_opacityAnimationTo); return; } @@ -361,7 +413,7 @@ void RenderMedia::forwardEvent(Event* event) { if (event->isMouseEvent() && m_controlsShadowRoot) { MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - IntPoint point(mouseEvent->pageX(), mouseEvent->pageY()); + IntPoint point(mouseEvent->absoluteLocation()); if (m_muteButton && m_muteButton->hitTest(point)) m_muteButton->defaultEventHandler(event); @@ -385,8 +437,10 @@ void RenderMedia::forwardEvent(Event* event) updateControlVisibility(); } if (event->type() == eventNames().mouseoutEvent) { - // FIXME: moving over scrollbar thumb generates mouseout for the ancestor media element for some reason - m_mouseOver = absoluteBoundingBoxRect().contains(point); + // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant + Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0; + RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0; + m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this); updateControlVisibility(); } } @@ -398,7 +452,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return bottom; - return max(bottom, m_controlsShadowRoot->renderer()->yPos() + m_controlsShadowRoot->renderer()->lowestPosition(includeOverflowInterior, includeSelf)); + return max(bottom, m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf)); } int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const @@ -407,7 +461,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return right; - return max(right, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->rightmostPosition(includeOverflowInterior, includeSelf)); + return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf)); } int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const @@ -416,7 +470,7 @@ int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return left; - return min(left, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->leftmostPosition(includeOverflowInterior, includeSelf)); + return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf)); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h index 8f48caf..6013d7b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h @@ -40,6 +40,7 @@ class MediaControlPlayButtonElement; class MediaControlSeekButtonElement; class MediaControlTimelineElement; class MediaControlFullscreenButtonElement; +class MediaTimeDisplayElement; class MediaPlayer; class RenderMedia : public RenderReplaced { @@ -48,9 +49,11 @@ public: RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize); virtual ~RenderMedia(); - virtual RenderObject* firstChild() const; - virtual RenderObject* lastChild() const; - virtual void removeChild(RenderObject*); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + virtual void destroy(); virtual void layout(); @@ -66,6 +69,7 @@ public: void updateFromElement(); void updatePlayer(); void updateControls(); + void updateTimeDisplay(); void forwardEvent(Event*); @@ -75,22 +79,26 @@ public: private: void createControlsShadowRoot(); + void destroyControlsShadowRoot(); void createPanel(); void createMuteButton(); void createPlayButton(); void createSeekBackButton(); void createSeekForwardButton(); + void createTimelineContainer(); void createTimeline(); - void createTimeDisplay(); + void createCurrentTimeDisplay(); + void createTimeRemainingDisplay(); void createFullscreenButton(); void timeUpdateTimerFired(Timer<RenderMedia>*); - void updateTimeDisplay(); void updateControlVisibility(); void changeOpacity(HTMLElement*, float opacity); void opacityAnimationTimerFired(Timer<RenderMedia>*); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + RefPtr<HTMLElement> m_controlsShadowRoot; RefPtr<HTMLElement> m_panel; RefPtr<MediaControlMuteButtonElement> m_muteButton; @@ -99,9 +107,12 @@ private: RefPtr<MediaControlSeekButtonElement> m_seekForwardButton; RefPtr<MediaControlTimelineElement> m_timeline; RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton; - RefPtr<HTMLElement> m_timeDisplay; - EventTargetNode* m_lastUnderNode; - EventTargetNode* m_nodeUnderMouse; + RefPtr<HTMLElement> m_timelineContainer; + RefPtr<MediaTimeDisplayElement> m_currentTimeDisplay; + RefPtr<MediaTimeDisplayElement> m_timeRemainingDisplay; + RenderObjectChildList m_children; + Node* m_lastUnderNode; + Node* m_nodeUnderMouse; Timer<RenderMedia> m_timeUpdateTimer; Timer<RenderMedia> m_opacityAnimationTimer; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp new file mode 100644 index 0000000..06d901a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.cpp @@ -0,0 +1,150 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderMediaControls.h" + +#include "GraphicsContext.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "RenderThemeSafari.h" +#include "SoftLinking.h" +#include <CoreGraphics/CoreGraphics.h> + +using namespace std; + +namespace WebCore { + +#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME) +SOFT_LINK_DEBUG_LIBRARY(SafariTheme) +#else +SOFT_LINK_LIBRARY(SafariTheme) +#endif + +SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state)) +SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value)) + +#if ENABLE(VIDEO) + +static ThemeControlState determineState(RenderObject* o) +{ + ThemeControlState result = 0; + RenderTheme* theme = o->theme(); + if (theme->isActive(o)) + result |= SafariTheme::ActiveState; + if (theme->isEnabled(o) && !theme->isReadOnlyControl(o)) + result |= SafariTheme::EnabledState; + if (theme->isPressed(o)) + result |= SafariTheme::PressedState; + if (theme->isChecked(o)) + result |= SafariTheme::CheckedState; + if (theme->isIndeterminate(o)) + result |= SafariTheme::IndeterminateCheckedState; + if (theme->isFocused(o)) + result |= SafariTheme::FocusedState; + if (theme->isDefault(o)) + result |= SafariTheme::DefaultState; + return result; +} + +static const int mediaSliderThumbWidth = 13; +static const int mediaSliderThumbHeight = 14; + +void RenderMediaControls::adjustMediaSliderThumbSize(RenderObject* o) +{ + if (o->style()->appearance() != MediaSliderThumbPart) + return; + + float zoomLevel = o->style()->effectiveZoom(); + o->style()->setWidth(Length(static_cast<int>(mediaSliderThumbWidth * zoomLevel), Fixed)); + o->style()->setHeight(Length(static_cast<int>(mediaSliderThumbHeight * zoomLevel), Fixed)); +} + +static HTMLMediaElement* parentMediaElement(RenderObject* o) +{ + Node* node = o->node(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) + return 0; + + return static_cast<HTMLMediaElement*>(mediaNode); +} + +bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + ASSERT(SafariThemeLibrary()); + + switch (part) { + case MediaFullscreenButton: + paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + break; + case MediaMuteButton: + case MediaUnMuteButton: + if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) { + bool audioEnabled = btn->displayType() == MediaMuteButton; + paintThemePart(audioEnabled ? SafariTheme::MediaMuteButtonPart : SafariTheme::MediaUnMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + } + break; + case MediaPauseButton: + case MediaPlayButton: + if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) { + bool currentlyPlaying = btn->displayType() == MediaPlayButton; + paintThemePart(currentlyPlaying ? SafariTheme::MediaPauseButtonPart : SafariTheme::MediaPlayButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + } + break; + case MediaSeekBackButton: + paintThemePart(SafariTheme::MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + break; + case MediaSeekForwardButton: + paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + break; + case MediaSlider: { + if (HTMLMediaElement* mediaElement = parentMediaElement(o)) + STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, mediaElement->percentLoaded()); + break; + } + case MediaSliderThumb: + paintThemePart(SafariTheme::MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + break; + case MediaTimelineContainer: + ASSERT_NOT_REACHED(); + break; + case MediaCurrentTimeDisplay: + ASSERT_NOT_REACHED(); + break; + case MediaTimeRemainingDisplay: + ASSERT_NOT_REACHED(); + break; + case MediaControlsPanel: + ASSERT_NOT_REACHED(); + break; + } + return false; +} + +#endif // #if ENABLE(VIDEO) + +} // namespace WebCore + diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.h b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.h new file mode 100644 index 0000000..529dbac --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMediaControls.h @@ -0,0 +1,43 @@ +/* + * 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. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderMediaControls_h +#define RenderMediaControls_h + +#include "RenderObject.h" +#include "MediaControlElements.h" + +namespace WebCore { + +class HTMLMediaElement; +class RenderMediaControls { +public: + static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + static void adjustMediaSliderThumbSize(RenderObject*); +}; + +} // namespace WebCore + +#endif // RenderMediaControls_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp index baec309..4cd7b43 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. + * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,20 +25,16 @@ #include "RenderMenuList.h" #include "CSSStyleSelector.h" -#include "Document.h" -#include "FontSelector.h" #include "FrameView.h" -#include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLOptGroupElement.h" -#include "HTMLSelectElement.h" +#include "NodeRenderStyle.h" +#include "OptionElement.h" +#include "OptionGroupElement.h" #include "PopupMenu.h" #include "RenderBR.h" #include "RenderScrollbar.h" -#include "RenderText.h" #include "RenderTheme.h" -#include "NodeRenderStyle.h" +#include "SelectElement.h" #include <math.h> using namespace std; @@ -46,7 +43,7 @@ namespace WebCore { using namespace HTMLNames; -RenderMenuList::RenderMenuList(HTMLSelectElement* element) +RenderMenuList::RenderMenuList(Element* element) : RenderFlexibleBox(element) , m_buttonText(0) , m_innerBlock(0) @@ -64,12 +61,6 @@ RenderMenuList::~RenderMenuList() m_popup = 0; } -// this static cast is safe because RenderMenuLists are only created for HTMLSelectElements -HTMLSelectElement* RenderMenuList::selectElement() -{ - return static_cast<HTMLSelectElement*>(node()); -} - void RenderMenuList::createInnerBlock() { if (m_innerBlock) { @@ -118,7 +109,7 @@ void RenderMenuList::removeChild(RenderObject* oldChild) m_innerBlock->removeChild(oldChild); } -void RenderMenuList::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -137,15 +128,25 @@ void RenderMenuList::styleDidChange(RenderStyle::Diff diff, const RenderStyle* o void RenderMenuList::updateOptionsWidth() { float maxOptionWidth = 0; - const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node())->listItems(); + const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems(); int size = listItems.size(); for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; - if (element->hasTagName(optionTag)) { - String text = static_cast<HTMLOptionElement*>(element)->optionText(); + Element* element = listItems[i]; + OptionElement* optionElement = toOptionElement(element); + if (!optionElement) + continue; + + String text = optionElement->textIndentedToRespectGroupLabel(); + if (theme()->popupOptionSupportsTextIndent()) { + // Add in the option's text indent. We can't calculate percentage values for now. + float optionWidth = 0; + if (RenderStyle* optionStyle = element->renderStyle()) + optionWidth += optionStyle->textIndent().calcMinValue(0); if (!text.isEmpty()) - maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text)); - } + optionWidth += style()->font().floatWidth(text); + maxOptionWidth = max(maxOptionWidth, optionWidth); + } else if (!text.isEmpty()) + maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text)); } int width = static_cast<int>(ceilf(maxOptionWidth)); @@ -153,7 +154,8 @@ void RenderMenuList::updateOptionsWidth() return; m_optionsWidth = width; - setNeedsLayoutAndPrefWidthsRecalc(); + if (parent()) + setNeedsLayoutAndPrefWidthsRecalc(); } void RenderMenuList::updateFromElement() @@ -166,22 +168,22 @@ void RenderMenuList::updateFromElement() if (m_popupIsVisible) m_popup->updateFromElement(); else - setTextFromOption(static_cast<HTMLSelectElement*>(node())->selectedIndex()); + setTextFromOption(toSelectElement(static_cast<Element*>(node()))->selectedIndex()); } void RenderMenuList::setTextFromOption(int optionIndex) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - const Vector<HTMLElement*>& listItems = select->listItems(); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); int size = listItems.size(); int i = select->optionToListIndex(optionIndex); String text = ""; if (i >= 0 && i < size) { - HTMLElement* element = listItems[i]; - if (element->hasTagName(optionTag)) - text = static_cast<HTMLOptionElement*>(listItems[i])->optionText(); + if (OptionElement* optionElement = toOptionElement(listItems[i])) + text = optionElement->textIndentedToRespectGroupLabel(); } + setText(text.stripWhiteSpace()); } @@ -224,8 +226,8 @@ IntRect RenderMenuList::controlClipRect(int tx, int ty) const contentWidth(), contentHeight()); - IntRect innerBox(tx + m_innerBlock->xPos() + m_innerBlock->paddingLeft(), - ty + m_innerBlock->yPos() + m_innerBlock->paddingTop(), + IntRect innerBox(tx + m_innerBlock->x() + m_innerBlock->paddingLeft(), + ty + m_innerBlock->y() + m_innerBlock->paddingTop(), m_innerBlock->contentWidth(), m_innerBlock->contentHeight()); @@ -273,7 +275,7 @@ void RenderMenuList::showPopup() createInnerBlock(); if (!m_popup) m_popup = PopupMenu::create(this); - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); m_popupIsVisible = true; // Compute the top left taking transforms into account, but use @@ -294,46 +296,52 @@ void RenderMenuList::hidePopup() void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - select->setSelectedIndex(select->listToOptionIndex(listIndex), true, fireOnChange); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange); } String RenderMenuList::itemText(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; - if (element->hasTagName(optgroupTag)) - return static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); - else if (element->hasTagName(optionTag)) - return static_cast<HTMLOptionElement*>(element)->optionText(); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; + if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) + return optionGroupElement->groupLabelText(); + else if (OptionElement* optionElement = toOptionElement(element)) + return optionElement->textIndentedToRespectGroupLabel(); return String(); } bool RenderMenuList::itemIsEnabled(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; - if (!element->hasTagName(optionTag)) + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; + if (!isOptionElement(element)) return false; + bool groupEnabled = true; - if (element->parentNode() && element->parentNode()->hasTagName(optgroupTag)) - groupEnabled = element->parentNode()->isEnabled(); - return element->isEnabled() && groupEnabled; + if (Element* parentElement = element->parentElement()) { + if (isOptionGroupElement(parentElement)) + groupEnabled = parentElement->isEnabledFormControl(); + } + if (!groupEnabled) + return false; + + return element->isEnabledFormControl(); } PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle(); - return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE) : menuStyle(); + return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->textIndent(), style->direction()) : menuStyle(); } Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; Color backgroundColor; if (element->renderStyle()) @@ -355,7 +363,7 @@ PopupMenuStyle RenderMenuList::menuStyle() const { RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style(); - return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE); + return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE, s->textIndent(), s->direction()); } HostWindow* RenderMenuList::hostWindow() const @@ -366,7 +374,7 @@ HostWindow* RenderMenuList::hostWindow() const PassRefPtr<Scrollbar> RenderMenuList::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) { RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(client, orientation, this); else @@ -396,40 +404,42 @@ int RenderMenuList::clientPaddingRight() const int RenderMenuList::listSize() const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); return select->listItems().size(); } int RenderMenuList::selectedIndex() const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); return select->optionToListIndex(select->selectedIndex()); } bool RenderMenuList::itemIsSeparator(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; return element->hasTagName(hrTag); } bool RenderMenuList::itemIsLabel(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; - return element->hasTagName(optgroupTag); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; + return isOptionGroupElement(element); } bool RenderMenuList::itemIsSelected(unsigned listIndex) const { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); - HTMLElement* element = select->listItems()[listIndex]; - return element->hasTagName(optionTag)&& static_cast<HTMLOptionElement*>(element)->selected(); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; + if (OptionElement* optionElement = toOptionElement(element)) + return optionElement->selected(); + return false; } void RenderMenuList::setTextFromItem(unsigned listIndex) { - HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); + SelectElement* select = toSelectElement(static_cast<Element*>(node())); setTextFromOption(select->listToOptionIndex(listIndex)); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h index f31ef32..7966eff 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h @@ -23,8 +23,8 @@ #ifndef RenderMenuList_h #define RenderMenuList_h -#include "RenderFlexibleBox.h" #include "PopupMenuClient.h" +#include "RenderFlexibleBox.h" #if PLATFORM(MAC) #define POPUP_MENU_PULLS_DOWN 0 @@ -34,16 +34,15 @@ namespace WebCore { -class HTMLSelectElement; class PopupMenu; +class RenderText; class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient { public: - RenderMenuList(HTMLSelectElement*); + RenderMenuList(Element*); ~RenderMenuList(); - - HTMLSelectElement* selectElement(); +private: virtual bool isMenuList() const { return true; } virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); @@ -60,6 +59,7 @@ public: virtual void calcPrefWidths(); +public: bool popupIsVisible() const { return m_popupIsVisible; } void showPopup(); void hidePopup(); @@ -68,10 +68,9 @@ public: String text() const; -protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - private: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; virtual bool itemIsEnabled(unsigned listIndex) const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp index 3ef7af7..098932a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp @@ -26,26 +26,14 @@ #include "RenderObject.h" #include "AXObjectCache.h" -#include "TransformationMatrix.h" -#include "AnimationController.h" #include "CSSStyleSelector.h" -#include "CachedImage.h" -#include "Chrome.h" -#include "Document.h" -#include "Element.h" -#include "EventHandler.h" -#include "FloatRect.h" +#include "FloatQuad.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOListElement.h" -#include "HitTestRequest.h" #include "HitTestResult.h" -#include "KURL.h" #include "Page.h" -#include "PlatformScreen.h" -#include "Position.h" #include "RenderArena.h" #include "RenderCounter.h" #include "RenderFlexibleBox.h" @@ -55,14 +43,17 @@ #include "RenderTableCell.h" #include "RenderTableCol.h" #include "RenderTableRow.h" -#include "RenderText.h" #include "RenderTheme.h" #include "RenderView.h" -#include "SelectionController.h" -#include "TextResourceDecoder.h" +#include "TransformState.h" #include <algorithm> #include <stdio.h> #include <wtf/RefCountedLeakCounter.h> +#include <wtf/UnusedParam.h> + +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif #if ENABLE(WML) #include "WMLNames.h" @@ -102,10 +93,10 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) // Works only if we have exactly one piece of content and it's a URL. // Otherwise acts as if we didn't support this feature. const ContentData* contentData = style->contentData(); - if (contentData && !contentData->m_next && contentData->m_type == CONTENT_OBJECT && doc != node) { + if (contentData && !contentData->next() && contentData->isImage() && doc != node) { RenderImageGeneratedContent* image = new (arena) RenderImageGeneratedContent(node); image->setStyle(style); - if (StyleImage* styleImage = contentData->m_content.m_image) + if (StyleImage* styleImage = contentData->image()) image->setStyleImage(styleImage); return image; } @@ -175,8 +166,8 @@ RenderObject::RenderObject(Node* node) , m_next(0) #ifndef NDEBUG , m_hasAXObject(false) + , m_setNeedsLayoutForbidden(false) #endif - , m_verticalPosition(PositionUndefined) , m_needsLayout(false) , m_needsPositionedMovementLayout(false) , m_normalChildNeedsLayout(false) @@ -188,6 +179,7 @@ RenderObject::RenderObject(Node* node) , m_paintBackground(false) , m_isAnonymous(node == node->document()) , m_isText(false) + , m_isBox(false) , m_inline(true) , m_replaced(false) , m_isDragging(false) @@ -198,10 +190,19 @@ RenderObject::RenderObject(Node* node) , m_hasOverrideSize(false) , m_hasCounterNodeMap(false) , m_everHadLayout(false) + , m_childrenInline(false) + , m_topMarginQuirk(false) + , m_bottomMarginQuirk(false) + , m_hasMarkupTruncation(false) + , m_selectionState(SelectionNone) + , m_hasColumns(false) + , m_cellWidthChanged(false) + , m_replacedHasOverflow(false) { #ifndef NDEBUG renderObjectCounter.increment(); #endif + ASSERT(node); } RenderObject::~RenderObject() @@ -213,6 +214,13 @@ RenderObject::~RenderObject() #endif } +RenderTheme* RenderObject::theme() const +{ + ASSERT(document()->page()); + + return document()->page()->theme(); +} + bool RenderObject::isDescendantOf(const RenderObject* obj) const { for (const RenderObject* r = this; r; r = r->m_parent) { @@ -224,63 +232,95 @@ bool RenderObject::isDescendantOf(const RenderObject* obj) const bool RenderObject::isBody() const { - return node()->hasTagName(bodyTag); + return node() && node()->hasTagName(bodyTag); } bool RenderObject::isHR() const { - return element() && element()->hasTagName(hrTag); + return node() && node()->hasTagName(hrTag); } bool RenderObject::isHTMLMarquee() const { - return element() && element()->renderer() == this && element()->hasTagName(marqueeTag); -} - -bool RenderObject::canHaveChildren() const -{ - return false; -} - -RenderFlow* RenderObject::continuation() const -{ - return 0; + return node() && node()->renderer() == this && node()->hasTagName(marqueeTag); } -bool RenderObject::isInlineContinuation() const +static void updateListMarkerNumbers(RenderObject* child) { - return false; + for (RenderObject* r = child; r; r = r->nextSibling()) + if (r->isListItem()) + static_cast<RenderListItem*>(r)->updateValue(); } -void RenderObject::addChild(RenderObject*, RenderObject*) +void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) { - ASSERT_NOT_REACHED(); -} - -RenderObject* RenderObject::removeChildNode(RenderObject*, bool) -{ - ASSERT_NOT_REACHED(); - return 0; -} - -void RenderObject::removeChild(RenderObject*) -{ - ASSERT_NOT_REACHED(); -} + RenderObjectChildList* children = virtualChildren(); + ASSERT(children); + if (!children) + return; -void RenderObject::moveChildNode(RenderObject*) -{ - ASSERT_NOT_REACHED(); + bool needsTable = false; + + if (newChild->isListItem()) + updateListMarkerNumbers(beforeChild ? beforeChild : children->lastChild()); + else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) + needsTable = !isTable(); + else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) + needsTable = !isTable(); + else if (newChild->isTableSection()) + needsTable = !isTable(); + else if (newChild->isTableRow()) + needsTable = !isTableSection(); + else if (newChild->isTableCell()) { + needsTable = !isTableRow(); + // I'm not 100% sure this is the best way to fix this, but without this + // change we recurse infinitely when trying to render the CSS2 test page: + // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html. + // See Radar 2925291. + if (needsTable && isTableCell() && !children->firstChild() && !newChild->isTableCell()) + needsTable = false; + } + + if (needsTable) { + RenderTable* table; + RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children->lastChild(); + if (afterChild && afterChild->isAnonymous() && afterChild->isTable()) + table = static_cast<RenderTable*>(afterChild); + else { + table = new (renderArena()) RenderTable(document() /* is anonymous */); + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(style()); + newStyle->setDisplay(TABLE); + table->setStyle(newStyle.release()); + addChild(table, beforeChild); + } + table->addChild(newChild); + } else { + // Just add it... + children->insertChildNode(this, newChild, beforeChild); + } + + if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { + RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); + if (textToTransform) + toRenderText(newChild)->setText(textToTransform.release(), true); + } } -void RenderObject::appendChildNode(RenderObject*, bool) +void RenderObject::removeChild(RenderObject* oldChild) { - ASSERT_NOT_REACHED(); -} + RenderObjectChildList* children = virtualChildren(); + ASSERT(children); + if (!children) + return; -void RenderObject::insertChildNode(RenderObject*, RenderObject*, bool) -{ - ASSERT_NOT_REACHED(); + // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode + // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on + // layout anyway). + if (oldChild->isFloatingOrPositioned()) + toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists(); + + children->removeChildNode(this, oldChild); } RenderObject* RenderObject::nextInPreOrder() const @@ -352,20 +392,6 @@ RenderObject* RenderObject::childAt(unsigned index) const return child; } -bool RenderObject::isEditable() const -{ - RenderText* textRenderer = 0; - if (isText()) - textRenderer = static_cast<RenderText*>(const_cast<RenderObject*>(this)); - - return style()->visibility() == VISIBLE && - element() && element()->isContentEditable() && - ((isBlockFlow() && !firstChild()) || - isReplaced() || - isBR() || - (textRenderer && textRenderer->firstTextBox())); -} - RenderObject* RenderObject::firstLeafChild() const { RenderObject* r = firstChild(); @@ -403,7 +429,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject* beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject); newObject = 0; } - parentLayer->addChild(obj->layer(), beforeChild); + parentLayer->addChild(toRenderBoxModelObject(obj)->layer(), beforeChild); return; } @@ -427,7 +453,7 @@ void RenderObject::removeLayers(RenderLayer* parentLayer) return; if (hasLayer()) { - parentLayer->removeChild(layer()); + parentLayer->removeChild(toRenderBoxModelObject(this)->layer()); return; } @@ -441,9 +467,11 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) return; if (hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(this)->layer(); + ASSERT(oldParent == layer->parent()); if (oldParent) - oldParent->removeChild(layer()); - newParent->addChild(layer()); + oldParent->removeChild(layer); + newParent->addChild(layer); return; } @@ -459,7 +487,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* return 0; // Step 1: If our layer is a child of the desired parent, then return our layer. - RenderLayer* ourLayer = layer(); + RenderLayer* ourLayer = hasLayer() ? toRenderBoxModelObject(this)->layer() : 0; if (ourLayer && ourLayer->parent() == parentLayer) return ourLayer; @@ -491,7 +519,7 @@ RenderLayer* RenderObject::enclosingLayer() const { const RenderObject* curr = this; while (curr) { - RenderLayer* layer = curr->layer(); + RenderLayer* layer = curr->hasLayer() ? toRenderBoxModelObject(curr)->layer() : 0; if (layer) return layer; curr = curr->parent(); @@ -499,190 +527,34 @@ RenderLayer* RenderObject::enclosingLayer() const return 0; } -bool RenderObject::requiresLayer() +RenderLayer* RenderObject::enclosingSelfPaintingLayer() const { - return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); -} - -RenderBlock* RenderObject::firstLineBlock() const -{ - return 0; -} - -int RenderObject::offsetLeft() const -{ - RenderObject* offsetPar = offsetParent(); - if (!offsetPar) - return 0; - int x = xPos() - offsetPar->borderLeft(); - if (!isPositioned()) { - if (isRelPositioned()) - x += static_cast<const RenderBox*>(this)->relativePositionOffsetX(); - RenderObject* curr = parent(); - while (curr && curr != offsetPar) { - x += curr->xPos(); - curr = curr->parent(); - } - if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) - x += offsetPar->xPos(); - } - return x; -} - -int RenderObject::offsetTop() const -{ - RenderObject* offsetPar = offsetParent(); - if (!offsetPar) - return 0; - int y = yPos() - borderTopExtra() - offsetPar->borderTop(); - if (!isPositioned()) { - if (isRelPositioned()) - y += static_cast<const RenderBox*>(this)->relativePositionOffsetY(); - RenderObject* curr = parent(); - while (curr && curr != offsetPar) { - if (!curr->isTableRow()) - y += curr->yPos(); - curr = curr->parent(); - } - if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) - y += offsetPar->yPos(); + const RenderObject* curr = this; + while (curr) { + RenderLayer* layer = curr->hasLayer() ? toRenderBoxModelObject(curr)->layer() : 0; + if (layer && layer->isSelfPaintingLayer()) + return layer; + curr = curr->parent(); } - return y; + return 0; } -RenderObject* RenderObject::offsetParent() const +RenderBox* RenderObject::enclosingBox() const { - // FIXME: It feels like this function could almost be written using containing blocks. - if (isBody()) - return 0; - - bool skipTables = isPositioned() || isRelPositioned(); - float currZoom = style()->effectiveZoom(); - RenderObject* curr = parent(); - while (curr && (!curr->element() || - (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) { - Node* element = curr->element(); - if (!skipTables && element) { - bool isTableElement = element->hasTagName(tableTag) || - element->hasTagName(tdTag) || - element->hasTagName(thTag); - -#if ENABLE(WML) - if (!isTableElement && element->isWMLElement()) - isTableElement = element->hasTagName(WMLNames::tableTag) || - element->hasTagName(WMLNames::tdTag); -#endif - - if (isTableElement) - break; - } - - float newZoom = curr->style()->effectiveZoom(); - if (currZoom != newZoom) - break; - currZoom = newZoom; + RenderObject* curr = const_cast<RenderObject*>(this); + while (curr) { + if (curr->isBox()) + return toRenderBox(curr); curr = curr->parent(); } - return curr; -} - -int RenderObject::verticalScrollbarWidth() const -{ - return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0; -} - -int RenderObject::horizontalScrollbarHeight() const -{ - return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0; -} - -// More IE extensions. clientWidth and clientHeight represent the interior of an object -// excluding border and scrollbar. -int RenderObject::clientWidth() const -{ - return width() - borderLeft() - borderRight() - verticalScrollbarWidth(); -} - -int RenderObject::clientHeight() const -{ - return height() - borderTop() - borderBottom() - horizontalScrollbarHeight(); -} - -// scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the -// object has overflow:hidden/scroll/auto specified and also has overflow. -int RenderObject::scrollWidth() const -{ - return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth(); -} - -int RenderObject::scrollHeight() const -{ - return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight(); -} - -int RenderObject::scrollLeft() const -{ - return hasOverflowClip() ? layer()->scrollXOffset() : 0; -} - -int RenderObject::scrollTop() const -{ - return hasOverflowClip() ? layer()->scrollYOffset() : 0; -} - -void RenderObject::setScrollLeft(int newLeft) -{ - if (hasOverflowClip()) - layer()->scrollToXOffset(newLeft); -} - -void RenderObject::setScrollTop(int newTop) -{ - if (hasOverflowClip()) - layer()->scrollToYOffset(newTop); -} - -bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) -{ - RenderLayer* l = layer(); - if (l && l->scroll(direction, granularity, multiplier)) - return true; - RenderBlock* b = containingBlock(); - if (b && !b->isRenderView()) - return b->scroll(direction, granularity, multiplier); - return false; -} -bool RenderObject::canBeProgramaticallyScrolled(bool) const -{ - if (!layer()) - return false; - - return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode()); -} - -void RenderObject::autoscroll() -{ - layer()->autoscroll(); -} - -void RenderObject::panScroll(const IntPoint& source) -{ - layer()->panScrollFromPoint(source); -} - -bool RenderObject::hasStaticX() const -{ - return (style()->left().isAuto() && style()->right().isAuto()) || style()->left().isStatic() || style()->right().isStatic(); -} - -bool RenderObject::hasStaticY() const -{ - return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic(); + ASSERT_NOT_REACHED(); + return 0; } -void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*) +RenderBlock* RenderObject::firstLineBlock() const { + return 0; } void RenderObject::setPrefWidthsDirty(bool b, bool markParents) @@ -699,109 +571,25 @@ void RenderObject::invalidateContainerPrefWidths() // in the chain that we mark dirty (even though they're kind of irrelevant). RenderObject* o = isTableCell() ? containingBlock() : container(); while (o && !o->m_prefWidthsDirty) { + // Don't invalidate the outermost object of an unrooted subtree. That object will be + // invalidated when the subtree is added to the document. + RenderObject* container = o->isTableCell() ? o->containingBlock() : o->container(); + if (!container && !o->isRenderView()) + break; + o->m_prefWidthsDirty = true; if (o->style()->position() == FixedPosition || o->style()->position() == AbsolutePosition) // A positioned object has no effect on the min/max width of its containing block ever. // We can optimize this case and not go up any further. break; - o = o->isTableCell() ? o->containingBlock() : o->container(); + o = container; } } -void RenderObject::setNeedsLayout(bool b, bool markParents) +void RenderObject::setLayerNeedsFullRepaint() { - bool alreadyNeededLayout = m_needsLayout; - m_needsLayout = b; - if (b) { - if (!alreadyNeededLayout) { - if (markParents) - markContainingBlocksForLayout(); - if (hasLayer()) - layer()->setNeedsFullRepaint(); - } - } else { - m_everHadLayout = true; - m_posChildNeedsLayout = false; - m_normalChildNeedsLayout = false; - m_needsPositionedMovementLayout = false; - } -} - -void RenderObject::setChildNeedsLayout(bool b, bool markParents) -{ - bool alreadyNeededLayout = m_normalChildNeedsLayout; - m_normalChildNeedsLayout = b; - if (b) { - if (!alreadyNeededLayout && markParents) - markContainingBlocksForLayout(); - } else { - m_posChildNeedsLayout = false; - m_normalChildNeedsLayout = false; - m_needsPositionedMovementLayout = false; - } -} - -void RenderObject::setNeedsPositionedMovementLayout() -{ - bool alreadyNeededLayout = needsLayout(); - m_needsPositionedMovementLayout = true; - if (!alreadyNeededLayout) { - markContainingBlocksForLayout(); - if (hasLayer()) - layer()->setNeedsFullRepaint(); - } -} - -static inline bool objectIsRelayoutBoundary(const RenderObject *obj) -{ - // FIXME: In future it may be possible to broaden this condition in order to improve performance. - // Table cells are excluded because even when their CSS height is fixed, their height() - // may depend on their contents. - return obj->isTextField() || obj->isTextArea() - || obj->hasOverflowClip() && !obj->style()->width().isIntrinsicOrAuto() && !obj->style()->height().isIntrinsicOrAuto() && !obj->style()->height().isPercent() && !obj->isTableCell() -#if ENABLE(SVG) - || obj->isSVGRoot() -#endif - ; -} - -void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot) -{ - ASSERT(!scheduleRelayout || !newRoot); - - RenderObject* o = container(); - RenderObject* last = this; - - while (o) { - if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) { - if (last->hasStaticY()) { - RenderObject* parent = last->parent(); - if (!parent->normalChildNeedsLayout()) { - parent->setChildNeedsLayout(true, false); - if (parent != newRoot) - parent->markContainingBlocksForLayout(scheduleRelayout, newRoot); - } - } - if (o->m_posChildNeedsLayout) - return; - o->m_posChildNeedsLayout = true; - } else { - if (o->m_normalChildNeedsLayout) - return; - o->m_normalChildNeedsLayout = true; - } - - if (o == newRoot) - return; - - last = o; - if (scheduleRelayout && objectIsRelayoutBoundary(last)) - break; - o = o->container(); - } - - if (scheduleRelayout) - last->scheduleRelayout(); + ASSERT(hasLayer()); + toRenderBoxModelObject(this)->layer()->setNeedsFullRepaint(true); } RenderBlock* RenderObject::containingBlock() const @@ -814,7 +602,7 @@ RenderBlock* RenderObject::containingBlock() const } if (isRenderView()) - return const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this)); + return const_cast<RenderView*>(toRenderView(this)); RenderObject* o = parent(); if (!isText() && m_style->position() == FixedPosition) { @@ -844,19 +632,7 @@ RenderBlock* RenderObject::containingBlock() const if (!o || !o->isRenderBlock()) return 0; // Probably doesn't happen any more, but leave just in case. -dwh - return static_cast<RenderBlock*>(o); -} - -int RenderObject::containingBlockWidth() const -{ - // FIXME ? - return containingBlock()->availableWidth(); -} - -int RenderObject::containingBlockHeight() const -{ - // FIXME ? - return containingBlock()->contentHeight(); + return toRenderBlock(o); } static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer) @@ -867,13 +643,16 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* // Make sure we have a valid image. StyleImage* img = layer->image(); - bool shouldPaintBackgroundImage = img && img->canRender(renderer->style()->effectiveZoom()); + if (!img || !img->canRender(renderer->style()->effectiveZoom())) + return false; + + if (!layer->xPosition().isZero() || !layer->yPosition().isZero()) + return true; - // These are always percents or auto. - if (shouldPaintBackgroundImage && - (!layer->xPosition().isZero() || !layer->yPosition().isZero() || - layer->size().width().isPercent() || layer->size().height().isPercent())) - // The image will shift unpredictably if the size changes. + if (layer->isSizeSet()) { + if (layer->size().width().isPercent() || layer->size().height().isPercent()) + return true; + } else if (img->usesImageContainerSize()) return true; return false; @@ -905,97 +684,9 @@ bool RenderObject::mustRepaintBackgroundOrBorder() const return false; } -void RenderObject::drawBorderArc(GraphicsContext* graphicsContext, int x, int y, float thickness, IntSize radius, - int angleStart, int angleSpan, BorderSide s, Color c, const Color& textColor, - EBorderStyle style, bool firstCorner) -{ - if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2)) - style = SOLID; - - if (!c.isValid()) { - if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE) - c.setRGB(238, 238, 238); - else - c = textColor; - } - - switch (style) { - case BNONE: - case BHIDDEN: - return; - case DOTTED: - case DASHED: - graphicsContext->setStrokeColor(c); - graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke); - graphicsContext->setStrokeThickness(thickness); - graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); - break; - case DOUBLE: { - float third = thickness / 3.0f; - float innerThird = (thickness + 1.0f) / 6.0f; - int shiftForInner = static_cast<int>(innerThird * 2.5f); - - int outerY = y; - int outerHeight = radius.height() * 2; - int innerX = x + shiftForInner; - int innerY = y + shiftForInner; - int innerWidth = (radius.width() - shiftForInner) * 2; - int innerHeight = (radius.height() - shiftForInner) * 2; - if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) { - outerHeight += 2; - innerHeight += 2; - } - - graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); - graphicsContext->setStrokeThickness(third); - graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan); - graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird); - graphicsContext->strokeArc(IntRect(innerX, innerY, innerWidth, innerHeight), angleStart, angleSpan); - break; - } - case GROOVE: - case RIDGE: { - Color c2; - if ((style == RIDGE && (s == BSTop || s == BSLeft)) || - (style == GROOVE && (s == BSBottom || s == BSRight))) - c2 = c.dark(); - else { - c2 = c; - c = c.dark(); - } - - graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); - 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->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness); - graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2, - (radius.height() - shiftForInner) * 2), angleStart, angleSpan); - break; - } - case INSET: - if (s == BSTop || s == BSLeft) - c = c.dark(); - case OUTSET: - if (style == OUTSET && (s == BSBottom || s == BSRight)) - c = c.dark(); - case SOLID: - graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c); - graphicsContext->setStrokeThickness(thickness); - graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); - break; - } -} - -void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2, - BorderSide s, Color c, const Color& textcolor, EBorderStyle style, - int adjbw1, int adjbw2) +void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2, + BoxSide s, Color c, const Color& textcolor, EBorderStyle style, + int adjbw1, int adjbw2) { int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1); @@ -1058,34 +749,34 @@ void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, switch (s) { case BSTop: - drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), y1, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - max((adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); break; case BSLeft: - drawBorder(graphicsContext, x1, y1 + max((-adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1, y1 + max((-adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - max((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(graphicsContext, x2 - third, y1 + max((adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((adjbw1 * 2 + 1) / 3, 0), x2, y2 - max((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); break; case BSBottom: - drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), y1, x2 - max((adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); break; case BSRight: - drawBorder(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - max(( adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); - drawBorder(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0), + drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0), x2, y2 - max((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); break; @@ -1113,27 +804,27 @@ void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, switch (s) { case BSTop: - drawBorder(graphicsContext, x1 + max(-adjbw1, 0) / 2, y1, x2 - max(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2, + drawLineForBoxSide(graphicsContext, x1 + max(-adjbw1, 0) / 2, y1, x2 - max(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf); - drawBorder(graphicsContext, x1 + max(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjbw2 + 1, 0) / 2, y2, + drawLineForBoxSide(graphicsContext, x1 + max(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjbw2 + 1, 0) / 2, y2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2); break; case BSLeft: - drawBorder(graphicsContext, x1, y1 + max(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjbw2, 0) / 2, + drawLineForBoxSide(graphicsContext, x1, y1 + max(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjbw2, 0) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf); - drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjbw1 + 1, 0) / 2, x2, y2 - max(adjbw2 + 1, 0) / 2, + drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjbw1 + 1, 0) / 2, x2, y2 - max(adjbw2 + 1, 0) / 2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2); break; case BSBottom: - drawBorder(graphicsContext, x1 + max(adjbw1, 0) / 2, y1, x2 - max(adjbw2, 0) / 2, (y1 + y2 + 1) / 2, + drawLineForBoxSide(graphicsContext, x1 + max(adjbw1, 0) / 2, y1, x2 - max(adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf); - drawBorder(graphicsContext, x1 + max(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjbw2 + 1, 0) / 2, y2, + drawLineForBoxSide(graphicsContext, x1 + max(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjbw2 + 1, 0) / 2, y2, s, c, textcolor, s1, adjbw1/2, adjbw2/2); break; case BSRight: - drawBorder(graphicsContext, x1, y1 + max(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjbw2, 0) / 2, + drawLineForBoxSide(graphicsContext, x1, y1 + max(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjbw2, 0) / 2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf); - drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjbw1 + 1, 0) / 2, x2, y2 - max(-adjbw2 + 1, 0) / 2, + drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjbw1 + 1, 0) / 2, x2, y2 - max(-adjbw2 + 1, 0) / 2, s, c, textcolor, s1, adjbw1/2, adjbw2/2); break; } @@ -1189,536 +880,156 @@ void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, } } -bool RenderObject::paintNinePieceImage(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style, - const NinePieceImage& ninePieceImage, CompositeOperator op) +void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, int y, float thickness, IntSize radius, + int angleStart, int angleSpan, BoxSide s, Color c, const Color& textColor, + EBorderStyle style, bool firstCorner) { - StyleImage* styleImage = ninePieceImage.image(); - if (!styleImage || !styleImage->canRender(style->effectiveZoom())) - return false; - - if (!styleImage->isLoaded()) - return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either. - - // If we have a border radius, the image gets clipped to the rounded rect. - bool clipped = false; - if (style->hasBorderRadius()) { - IntRect clipRect(tx, ty, w, h); - graphicsContext->save(); - graphicsContext->addRoundedRectClip(clipRect, style->borderTopLeftRadius(), style->borderTopRightRadius(), - style->borderBottomLeftRadius(), style->borderBottomRightRadius()); - clipped = true; - } - - // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function - // doesn't have any understanding of the zoom that is in effect on the tile. - styleImage->setImageContainerSize(IntSize(w, h)); - IntSize imageSize = styleImage->imageSize(this, 1.0f); - int imageWidth = imageSize.width(); - int imageHeight = imageSize.height(); - - int topSlice = min(imageHeight, ninePieceImage.m_slices.top().calcValue(imageHeight)); - int bottomSlice = min(imageHeight, ninePieceImage.m_slices.bottom().calcValue(imageHeight)); - int leftSlice = min(imageWidth, ninePieceImage.m_slices.left().calcValue(imageWidth)); - int rightSlice = min(imageWidth, ninePieceImage.m_slices.right().calcValue(imageWidth)); - - ENinePieceImageRule hRule = ninePieceImage.horizontalRule(); - ENinePieceImageRule vRule = ninePieceImage.verticalRule(); - - bool fitToBorder = style->borderImage() == ninePieceImage; - - int leftWidth = fitToBorder ? style->borderLeftWidth() : leftSlice; - int topWidth = fitToBorder ? style->borderTopWidth() : topSlice; - int rightWidth = fitToBorder ? style->borderRightWidth() : rightSlice; - int bottomWidth = fitToBorder ? style->borderBottomWidth() : bottomSlice; - - bool drawLeft = leftSlice > 0 && leftWidth > 0; - bool drawTop = topSlice > 0 && topWidth > 0; - bool drawRight = rightSlice > 0 && rightWidth > 0; - bool drawBottom = bottomSlice > 0 && bottomWidth > 0; - bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - leftWidth - rightWidth) > 0 && - (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0; - - Image* image = styleImage->image(this, imageSize); - - if (drawLeft) { - // Paint the top and bottom left corners. - - // 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), - 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), - 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, - h - topWidth - bottomWidth), - IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice), - Image::StretchTile, (Image::TileRule)vRule, op); - } - - if (drawRight) { - // Paint the top and bottom right corners - // 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), - 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), - IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op); - - // Paint the right edge. - graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, - h - topWidth - bottomWidth), - IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice), - Image::StretchTile, (Image::TileRule)vRule, op); - } - - // Paint the top edge. - if (drawTop) - graphicsContext->drawTiledImage(image, 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, - 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, - h - topWidth - bottomWidth), - IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice), - (Image::TileRule)hRule, (Image::TileRule)vRule, op); - - // Clear the clip for the border radius. - if (clipped) - graphicsContext->restore(); - - return true; -} - -void RenderObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, - const RenderStyle* style, bool begin, bool end) -{ - if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage())) - return; - - const Color& tc = style->borderTopColor(); - const Color& bc = style->borderBottomColor(); - const Color& lc = style->borderLeftColor(); - const Color& rc = style->borderRightColor(); - - bool tt = style->borderTopIsTransparent(); - bool bt = style->borderBottomIsTransparent(); - bool rt = style->borderRightIsTransparent(); - bool lt = style->borderLeftIsTransparent(); - - EBorderStyle ts = style->borderTopStyle(); - EBorderStyle bs = style->borderBottomStyle(); - EBorderStyle ls = style->borderLeftStyle(); - EBorderStyle rs = style->borderRightStyle(); - - bool renderTop = ts > BHIDDEN && !tt; - bool renderLeft = ls > BHIDDEN && begin && !lt; - bool renderRight = rs > BHIDDEN && end && !rt; - bool renderBottom = bs > BHIDDEN && !bt; - - // Need sufficient width and height to contain border radius curves. Sanity check our border radii - // and our width/height values to make sure the curves can all fit. If not, then we won't paint - // any border radii. - bool renderRadii = false; - IntSize topLeft = style->borderTopLeftRadius(); - IntSize topRight = style->borderTopRightRadius(); - IntSize bottomLeft = style->borderBottomLeftRadius(); - IntSize bottomRight = style->borderBottomRightRadius(); - - if (style->hasBorderRadius() && - static_cast<unsigned>(w) >= static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) && - static_cast<unsigned>(w) >= static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) && - static_cast<unsigned>(h) >= static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) && - static_cast<unsigned>(h) >= static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height())) - renderRadii = true; - - // Clip to the rounded rectangle. - if (renderRadii) { - graphicsContext->save(); - graphicsContext->addRoundedRectClip(IntRect(tx, ty, w, h), topLeft, topRight, bottomLeft, bottomRight); - } - - int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan; - float thickness; - bool upperLeftBorderStylesMatch = renderLeft && (ts == ls) && (tc == lc); - bool upperRightBorderStylesMatch = renderRight && (ts == rs) && (tc == rc) && (ts != OUTSET) && (ts != RIDGE) && (ts != INSET) && (ts != GROOVE); - bool lowerLeftBorderStylesMatch = renderLeft && (bs == ls) && (bc == lc) && (bs != OUTSET) && (bs != RIDGE) && (bs != INSET) && (bs != GROOVE); - bool lowerRightBorderStylesMatch = renderRight && (bs == rs) && (bc == rc); - - if (renderTop) { - bool ignore_left = (renderRadii && topLeft.width() > 0) || - (tc == lc && tt == lt && ts >= OUTSET && - (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET)); - - bool ignore_right = (renderRadii && topRight.width() > 0) || - (tc == rc && tt == rt && ts >= OUTSET && - (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET)); - - int x = tx; - int x2 = tx + w; - if (renderRadii) { - x += topLeft.width(); - x2 -= topRight.width(); - } - - drawBorder(graphicsContext, x, ty, x2, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, - ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth()); - - if (renderRadii) { - int leftY = ty; - - // We make the arc double thick and let the clip rect take care of clipping the extra off. - // We're doing this because it doesn't seem possible to match the curve of the clip exactly - // with the arc-drawing function. - thickness = style->borderTopWidth() * 2; - - if (topLeft.width()) { - int leftX = tx; - // The inner clip clips inside the arc. This is especially important for 1px borders. - bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width()) - && (style->borderTopWidth() < topLeft.height()) - && (ts != DOUBLE || style->borderTopWidth() > 6); - if (applyLeftInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2), - style->borderTopWidth()); - } - - firstAngleStart = 90; - firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45; - - // Draw upper left arc - drawBorderArc(graphicsContext, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan, - BSTop, tc, style->color(), ts, true); - if (applyLeftInnerClip) - graphicsContext->restore(); - } - - if (topRight.width()) { - int rightX = tx + w - topRight.width() * 2; - bool applyRightInnerClip = (style->borderRightWidth() < topRight.width()) - && (style->borderTopWidth() < topRight.height()) - && (ts != DOUBLE || style->borderTopWidth() > 6); - if (applyRightInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2), - style->borderTopWidth()); - } - - if (upperRightBorderStylesMatch) { - secondAngleStart = 0; - secondAngleSpan = 90; - } else { - secondAngleStart = 45; - secondAngleSpan = 45; - } + if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2)) + style = SOLID; - // Draw upper right arc - drawBorderArc(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan, - BSTop, tc, style->color(), ts, false); - if (applyRightInnerClip) - graphicsContext->restore(); - } - } + if (!c.isValid()) { + if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE) + c.setRGB(238, 238, 238); + else + c = textColor; } - if (renderBottom) { - bool ignore_left = (renderRadii && bottomLeft.width() > 0) || - (bc == lc && bt == lt && bs >= OUTSET && - (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET)); - - bool ignore_right = (renderRadii && bottomRight.width() > 0) || - (bc == rc && bt == rt && bs >= OUTSET && - (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET)); - - int x = tx; - int x2 = tx + w; - if (renderRadii) { - x += bottomLeft.width(); - x2 -= bottomRight.width(); - } - - drawBorder(graphicsContext, x, ty + h - style->borderBottomWidth(), x2, ty + h, BSBottom, bc, style->color(), bs, - ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth()); - - if (renderRadii) { - thickness = style->borderBottomWidth() * 2; - - if (bottomLeft.width()) { - int leftX = tx; - int leftY = ty + h - bottomLeft.height() * 2; - bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width()) - && (style->borderBottomWidth() < bottomLeft.height()) - && (bs != DOUBLE || style->borderBottomWidth() > 6); - if (applyLeftInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2), - style->borderBottomWidth()); - } - - if (lowerLeftBorderStylesMatch) { - firstAngleStart = 180; - firstAngleSpan = 90; - } else { - firstAngleStart = 225; - firstAngleSpan = 45; - } - - // Draw lower left arc - drawBorderArc(graphicsContext, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan, - BSBottom, bc, style->color(), bs, true); - if (applyLeftInnerClip) - graphicsContext->restore(); - } - - if (bottomRight.width()) { - int rightY = ty + h - bottomRight.height() * 2; - int rightX = tx + w - bottomRight.width() * 2; - bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width()) - && (style->borderBottomWidth() < bottomRight.height()) - && (bs != DOUBLE || style->borderBottomWidth() > 6); - if (applyRightInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(rightX, rightY, bottomRight.width() * 2, bottomRight.height() * 2), - style->borderBottomWidth()); - } - - secondAngleStart = 270; - secondAngleSpan = lowerRightBorderStylesMatch ? 90 : 45; + switch (style) { + case BNONE: + case BHIDDEN: + return; + case DOTTED: + case DASHED: + graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke); + graphicsContext->setStrokeThickness(thickness); + graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); + break; + case DOUBLE: { + float third = thickness / 3.0f; + float innerThird = (thickness + 1.0f) / 6.0f; + int shiftForInner = static_cast<int>(innerThird * 2.5f); - // Draw lower right arc - drawBorderArc(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan, - BSBottom, bc, style->color(), bs, false); - if (applyRightInnerClip) - graphicsContext->restore(); + int outerY = y; + int outerHeight = radius.height() * 2; + int innerX = x + shiftForInner; + int innerY = y + shiftForInner; + int innerWidth = (radius.width() - shiftForInner) * 2; + int innerHeight = (radius.height() - shiftForInner) * 2; + if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) { + outerHeight += 2; + innerHeight += 2; } - } - } - - if (renderLeft) { - bool ignore_top = (renderRadii && topLeft.height() > 0) || - (tc == lc && tt == lt && ls >= OUTSET && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET)); - bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) || - (bc == lc && bt == lt && ls >= OUTSET && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET)); - - int y = ty; - int y2 = ty + h; - if (renderRadii) { - y += topLeft.height(); - y2 -= bottomLeft.height(); + graphicsContext->setStrokeStyle(SolidStroke); + graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeThickness(third); + graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan); + graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird); + graphicsContext->strokeArc(IntRect(innerX, innerY, innerWidth, innerHeight), angleStart, angleSpan); + break; } - - drawBorder(graphicsContext, tx, y, tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls, - ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); - - if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) { - int topX = tx; - thickness = style->borderLeftWidth() * 2; - - if (!upperLeftBorderStylesMatch && topLeft.width()) { - int topY = ty; - bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width()) - && (style->borderTopWidth() < topLeft.height()) - && (ls != DOUBLE || style->borderLeftWidth() > 6); - if (applyTopInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2), - style->borderLeftWidth()); - } - - firstAngleStart = 135; - firstAngleSpan = 45; - - // Draw top left arc - drawBorderArc(graphicsContext, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan, - BSLeft, lc, style->color(), ls, true); - if (applyTopInnerClip) - graphicsContext->restore(); + case GROOVE: + case RIDGE: { + Color c2; + if ((style == RIDGE && (s == BSTop || s == BSLeft)) || + (style == GROOVE && (s == BSBottom || s == BSRight))) + c2 = c.dark(); + else { + c2 = c; + c = c.dark(); } - if (!lowerLeftBorderStylesMatch && bottomLeft.width()) { - int bottomY = ty + h - bottomLeft.height() * 2; - bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width()) - && (style->borderBottomWidth() < bottomLeft.height()) - && (ls != DOUBLE || style->borderLeftWidth() > 6); - if (applyBottomInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2), - style->borderLeftWidth()); - } - - secondAngleStart = 180; - secondAngleSpan = 45; + graphicsContext->setStrokeStyle(SolidStroke); + graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeThickness(thickness); + graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); - // Draw bottom left arc - drawBorderArc(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan, - BSLeft, lc, style->color(), ls, false); - if (applyBottomInnerClip) - graphicsContext->restore(); - } + float halfThickness = (thickness + 1.0f) / 4.0f; + int shiftForInner = static_cast<int>(halfThickness * 1.5f); + graphicsContext->setStrokeColor(c2); + graphicsContext->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness); + graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2, + (radius.height() - shiftForInner) * 2), angleStart, angleSpan); + break; } + case INSET: + if (s == BSTop || s == BSLeft) + c = c.dark(); + case OUTSET: + if (style == OUTSET && (s == BSBottom || s == BSRight)) + c = c.dark(); + case SOLID: + graphicsContext->setStrokeStyle(SolidStroke); + graphicsContext->setStrokeColor(c); + graphicsContext->setStrokeThickness(thickness); + graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); + break; } +} - if (renderRight) { - bool ignore_top = (renderRadii && topRight.height() > 0) || - ((tc == rc) && (tt == rt) && - (rs >= DOTTED || rs == INSET) && - (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET)); - - bool ignore_bottom = (renderRadii && bottomRight.height() > 0) || - ((bc == rc) && (bt == rt) && - (rs >= DOTTED || rs == INSET) && - (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET)); - - int y = ty; - int y2 = ty + h; - if (renderRadii) { - y += topRight.height(); - y2 -= bottomRight.height(); - } - - drawBorder(graphicsContext, tx + w - style->borderRightWidth(), y, tx + w, y2, BSRight, rc, style->color(), rs, - ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); - - if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) { - thickness = style->borderRightWidth() * 2; - - if (!upperRightBorderStylesMatch && topRight.width()) { - int topX = tx + w - topRight.width() * 2; - int topY = ty; - bool applyTopInnerClip = (style->borderRightWidth() < topRight.width()) - && (style->borderTopWidth() < topRight.height()) - && (rs != DOUBLE || style->borderRightWidth() > 6); - if (applyTopInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2), - style->borderRightWidth()); - } +void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect) +{ + if (rect.isEmpty()) + return; + Node* n = node(); + if (!n || !n->isLink() || !n->isElementNode()) + return; + const AtomicString& href = static_cast<Element*>(n)->getAttribute(hrefAttr); + if (href.isNull()) + return; + context->setURLForRect(n->document()->completeURL(href), rect); +} - firstAngleStart = 0; - firstAngleSpan = 45; +void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style) +{ + if (!hasOutline()) + return; - // Draw top right arc - drawBorderArc(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan, - BSRight, rc, style->color(), rs, true); - if (applyTopInnerClip) - graphicsContext->restore(); - } + int ow = style->outlineWidth(); + EBorderStyle os = style->outlineStyle(); - if (!lowerRightBorderStylesMatch && bottomRight.width()) { - int bottomX = tx + w - bottomRight.width() * 2; - int bottomY = ty + h - bottomRight.height() * 2; - bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width()) - && (style->borderBottomWidth() < bottomRight.height()) - && (rs != DOUBLE || style->borderRightWidth() > 6); - if (applyBottomInnerClip) { - graphicsContext->save(); - graphicsContext->addInnerRoundedRectClip(IntRect(bottomX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2), - style->borderRightWidth()); - } + Color oc = style->outlineColor(); + if (!oc.isValid()) + oc = style->color(); - secondAngleStart = 315; - secondAngleSpan = 45; + int offset = style->outlineOffset(); - // Draw bottom right arc - drawBorderArc(graphicsContext, bottomX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan, - BSRight, rc, style->color(), rs, false); - if (applyBottomInnerClip) - graphicsContext->restore(); - } + 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); + if (style->outlineStyleIsAuto()) + graphicsContext->drawFocusRing(oc); + else + addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); + graphicsContext->clearFocusRing(); } } - if (renderRadii) - graphicsContext->restore(); -} - -void RenderObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end) -{ - // FIXME: Deal with border-image. Would be great to use border-image as a mask. - - IntRect rect(tx, ty, w, h); - bool hasBorderRadius = s->hasBorderRadius(); - bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255; - for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) { - context->save(); + if (style->outlineStyleIsAuto() || style->outlineStyle() == BNONE) + return; - IntSize shadowOffset(shadow->x, shadow->y); - int shadowBlur = shadow->blur; - IntRect fillRect(rect); + tx -= offset; + ty -= offset; + w += 2 * offset; + h += 2 * offset; - if (hasBorderRadius) { - IntRect shadowRect(rect); - shadowRect.inflate(shadowBlur); - shadowRect.move(shadowOffset); - context->clip(shadowRect); + if (h < 0 || w < 0) + return; - // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not - // bleed in (due to antialiasing) if the context is transformed. - IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0); - shadowOffset -= extraOffset; - fillRect.move(extraOffset); - } + drawLineForBoxSide(graphicsContext, tx - ow, ty - ow, tx, ty + h + ow, + BSLeft, Color(oc), style->color(), os, ow, ow); - context->setShadow(shadowOffset, shadowBlur, shadow->color); - if (hasBorderRadius) { - IntSize topLeft = begin ? s->borderTopLeftRadius() : IntSize(); - IntSize topRight = end ? s->borderTopRightRadius() : IntSize(); - IntSize bottomLeft = begin ? s->borderBottomLeftRadius() : IntSize(); - IntSize bottomRight = end ? s->borderBottomRightRadius() : IntSize(); - if (!hasOpaqueBackground) - context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); - } else { - if (!hasOpaqueBackground) - context->clipOut(rect); - context->fillRect(fillRect, Color::black); - } - context->restore(); - } -} + drawLineForBoxSide(graphicsContext, tx - ow, ty - ow, tx + w + ow, ty, + BSTop, Color(oc), style->color(), os, ow, ow); -void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned, unsigned, bool) -{ -} + drawLineForBoxSide(graphicsContext, tx + w, ty - ow, tx + w + ow, ty + h + ow, + BSRight, Color(oc), style->color(), os, ow, ow); -void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel) -{ - // 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 - // shape). - if (topLevel && continuation()) { - rects.append(IntRect(tx, ty - collapsedMarginTop(), - width(), height() + collapsedMarginTop() + collapsedMarginBottom())); - continuation()->absoluteRects(rects, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos(), topLevel); - } else - rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra())); + drawLineForBoxSide(graphicsContext, tx - ow, ty + h, tx + w + ow, ty + h + ow, + BSBottom, Color(oc), style->color(), os, ow, ow); } IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) @@ -1751,24 +1062,6 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) return result; } -void RenderObject::collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned, unsigned, bool) -{ -} - -void RenderObject::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel) -{ - // 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 - // shape). - if (topLevel && continuation()) { - FloatRect localRect(0, -collapsedMarginTop(), - width(), height() + collapsedMarginTop() + collapsedMarginBottom()); - quads.append(localToAbsoluteQuad(localRect)); - continuation()->absoluteQuads(quads, topLevel); - } else - quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height() + borderTopExtra() + borderBottomExtra()))); -} - void RenderObject::addAbsoluteRectForLayer(IntRect& result) { if (hasLayer()) @@ -1786,128 +1079,84 @@ IntRect RenderObject::paintingRootRect(IntRect& topLevelRect) return result; } -void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect) -{ - if (rect.isEmpty()) - return; - Node* node = element(); - if (!node || !node->isLink() || !node->isElementNode()) - return; - const AtomicString& href = static_cast<Element*>(node)->getAttribute(hrefAttr); - if (href.isNull()) - return; - context->setURLForRect(node->document()->completeURL(href), rect); -} - - -void RenderObject::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderObject::paint(PaintInfo& /*paintInfo*/, 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 - // shape). - if (continuation()) { - graphicsContext->addFocusRingRect(IntRect(tx, ty - collapsedMarginTop(), width(), height() + collapsedMarginTop() + collapsedMarginBottom())); - continuation()->addFocusRingRects(graphicsContext, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos()); - } else - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); } -void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style) +RenderBoxModelObject* RenderObject::containerForRepaint() const { - if (!hasOutline()) - return; - - int ow = style->outlineWidth(); - - EBorderStyle os = style->outlineStyle(); - - Color oc = style->outlineColor(); - if (!oc.isValid()) - oc = style->color(); - - int offset = style->outlineOffset(); - - 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); - if (style->outlineStyleIsAuto()) - addFocusRingRects(graphicsContext, tx, ty); - else - addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); - graphicsContext->drawFocusRing(oc); - graphicsContext->clearFocusRing(); +#if USE(ACCELERATED_COMPOSITING) + if (RenderView* v = view()) { + if (v->usesCompositing()) { + RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayer(); + return compLayer ? compLayer->renderer() : 0; } } - - if (style->outlineStyleIsAuto() || style->outlineStyle() == BNONE) - return; - - tx -= offset; - ty -= offset; - w += 2 * offset; - h += 2 * offset; - - if (h < 0 || w < 0) - return; - - drawBorder(graphicsContext, tx - ow, ty - ow, tx, ty + h + ow, - BSLeft, Color(oc), style->color(), os, ow, ow); - - drawBorder(graphicsContext, tx - ow, ty - ow, tx + w + ow, ty, - BSTop, Color(oc), style->color(), os, ow, ow); - - drawBorder(graphicsContext, tx + w, ty - ow, tx + w + ow, ty + h + ow, - BSRight, Color(oc), style->color(), os, ow, ow); - - drawBorder(graphicsContext, tx - ow, ty + h, tx + w + ow, ty + h + ow, - BSBottom, Color(oc), style->color(), os, ow, ow); +#endif + // Do root-relative repaint. + return 0; } -void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/) +void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, const IntRect& r, bool immediate) { + if (!repaintContainer || repaintContainer->isRenderView()) { + RenderView* v = repaintContainer ? toRenderView(repaintContainer) : view(); + v->repaintViewRectangle(r, immediate); + } else { +#if USE(ACCELERATED_COMPOSITING) + RenderView* v = view(); + if (v->usesCompositing()) { + ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->isComposited()); + repaintContainer->layer()->setBackingNeedsRepaintInRect(r); + } +#else + ASSERT_NOT_REACHED(); +#endif + } } void RenderObject::repaint(bool immediate) { - // Can't use view(), since we might be unrooted. - RenderObject* o = this; - while (o->parent()) - o = o->parent(); - if (!o->isRenderView()) + // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) + RenderView* view; + if (!isRooted(&view)) return; - RenderView* view = static_cast<RenderView*>(o); + if (view->printing()) return; // Don't repaint if we're printing. - view->repaintViewRectangle(absoluteClippedOverflowRect(), immediate); + + RenderBoxModelObject* repaintContainer = containerForRepaint(); + repaintUsingContainer(repaintContainer ? repaintContainer : view, clippedOverflowRectForRepaint(repaintContainer), immediate); } void RenderObject::repaintRectangle(const IntRect& r, bool immediate) { - // Can't use view(), since we might be unrooted. - RenderObject* o = this; - while (o->parent()) - o = o->parent(); - if (!o->isRenderView()) + // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) + RenderView* view; + if (!isRooted(&view)) return; - RenderView* view = static_cast<RenderView*>(o); + if (view->printing()) return; // Don't repaint if we're printing. - IntRect absRect(r); - absRect.move(view->layoutDelta()); - computeAbsoluteRepaintRect(absRect); - view->repaintViewRectangle(absRect, immediate); + + IntRect dirtyRect(r); + + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + dirtyRect.move(view->layoutDelta()); + + RenderBoxModelObject* repaintContainer = containerForRepaint(); + computeRectForRepaint(repaintContainer, dirtyRect); + repaintUsingContainer(repaintContainer ? repaintContainer : view, dirtyRect, immediate); } -bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldOutlineBox) +bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox) { RenderView* v = view(); if (v->printing()) return false; // Don't repaint if we're printing. - IntRect newBounds = absoluteClippedOverflowRect(); + IntRect newBounds = clippedOverflowRectForRepaint(repaintContainer); IntRect newOutlineBox; bool fullRepaint = selfNeedsLayout(); @@ -1915,14 +1164,18 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In if (!fullRepaint && style()->borderFit() == BorderFitLines) fullRepaint = true; if (!fullRepaint) { - newOutlineBox = absoluteOutlineBounds(); + newOutlineBox = outlineBoundsForRepaint(repaintContainer); if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) fullRepaint = true; } + + if (!repaintContainer) + repaintContainer = v; + if (fullRepaint) { - v->repaintViewRectangle(oldBounds); + repaintUsingContainer(repaintContainer, oldBounds); if (newBounds != oldBounds) - v->repaintViewRectangle(newBounds); + repaintUsingContainer(repaintContainer, newBounds); return true; } @@ -1931,34 +1184,34 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In int deltaLeft = newBounds.x() - oldBounds.x(); if (deltaLeft > 0) - v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height())); else if (deltaLeft < 0) - v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); int deltaRight = newBounds.right() - oldBounds.right(); if (deltaRight > 0) - v->repaintViewRectangle(IntRect(oldBounds.right(), newBounds.y(), deltaRight, newBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.right(), newBounds.y(), deltaRight, newBounds.height())); else if (deltaRight < 0) - v->repaintViewRectangle(IntRect(newBounds.right(), oldBounds.y(), -deltaRight, oldBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(newBounds.right(), oldBounds.y(), -deltaRight, oldBounds.height())); int deltaTop = newBounds.y() - oldBounds.y(); if (deltaTop > 0) - v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop)); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop)); else if (deltaTop < 0) - v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); + repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); int deltaBottom = newBounds.bottom() - oldBounds.bottom(); if (deltaBottom > 0) - v->repaintViewRectangle(IntRect(newBounds.x(), oldBounds.bottom(), newBounds.width(), deltaBottom)); + repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), oldBounds.bottom(), newBounds.width(), deltaBottom)); else if (deltaBottom < 0) - v->repaintViewRectangle(IntRect(oldBounds.x(), newBounds.bottom(), oldBounds.width(), -deltaBottom)); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.x(), newBounds.bottom(), oldBounds.width(), -deltaBottom)); if (newOutlineBox == oldOutlineBox) return false; // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly // two rectangles (but typically only one). - RenderStyle* outlineStyle = !isInline() && continuation() ? continuation()->style() : style(); + RenderStyle* outlineStyle = outlineStyleForRepaint(); int ow = outlineStyle->outlineSize(); ShadowData* boxShadow = style()->boxShadow(); int width = abs(newOutlineBox.width() - oldOutlineBox.width()); @@ -1967,7 +1220,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) shadowRight = max(shadow->x + shadow->blur, shadowRight); - int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight(), max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight); + int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0; + int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight, max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight); IntRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth, newOutlineBox.y(), width + borderWidth, @@ -1975,7 +1229,7 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In int right = min(newBounds.right(), oldBounds.right()); if (rightRect.x() < right) { rightRect.setWidth(min(rightRect.width(), right - rightRect.x())); - v->repaintViewRectangle(rightRect); + repaintUsingContainer(repaintContainer, rightRect); } } int height = abs(newOutlineBox.height() - oldOutlineBox.height()); @@ -1984,7 +1238,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) shadowBottom = max(shadow->y + shadow->blur, shadowBottom); - int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom(), max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom); + int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0; + int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom, max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom); IntRect bottomRect(newOutlineBox.x(), min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight, max(newOutlineBox.width(), oldOutlineBox.width()), @@ -1992,7 +1247,7 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In int bottom = min(newBounds.bottom(), oldBounds.bottom()); if (bottomRect.y() < bottom) { bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y())); - v->repaintViewRectangle(bottomRect); + repaintUsingContainer(repaintContainer, bottomRect); } } return false; @@ -2014,36 +1269,27 @@ bool RenderObject::checkForRepaintDuringLayout() const return !document()->view()->needsFullRepaint() && !hasLayer(); } -IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow) +IntRect RenderObject::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) { - IntRect r(absoluteClippedOverflowRect()); - r.inflate(ow); - - if (continuation() && !isInline()) - r.inflateY(collapsedMarginTop()); - - if (isInlineFlow()) { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) - r.unite(curr->getAbsoluteRepaintRectWithOutline(ow)); - } - } - + IntRect r(clippedOverflowRectForRepaint(repaintContainer)); + r.inflate(outlineWidth); return r; } -IntRect RenderObject::absoluteClippedOverflowRect() +IntRect RenderObject::clippedOverflowRectForRepaint(RenderBoxModelObject*) { - if (parent()) - return parent()->absoluteClippedOverflowRect(); + ASSERT_NOT_REACHED(); return IntRect(); } -void RenderObject::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) { + if (repaintContainer == this) + return; + if (RenderObject* o = parent()) { if (o->isBlockFlow()) { - RenderBlock* cb = static_cast<RenderBlock*>(o); + RenderBlock* cb = toRenderBlock(o); if (cb->hasColumns()) cb->adjustRectForColumns(rect); } @@ -2052,17 +1298,19 @@ void RenderObject::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) // o->height() is inaccurate if we're in the middle of a layout of |o|, 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. - IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height()); + RenderBox* boxParent = toRenderBox(o); + + IntRect boxRect(0, 0, boxParent->layer()->width(), boxParent->layer()->height()); int x = rect.x(); int y = rect.y(); - o->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. + 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; } - o->computeAbsoluteRepaintRect(rect, fixed); + o->computeRectForRepaint(repaintContainer, rect, fixed); } } @@ -2074,8 +1322,8 @@ void RenderObject::dirtyLinesFromChangedChild(RenderObject*) void RenderObject::showTreeForThis() const { - if (element()) - element()->showTreeForThis(); + if (node()) + node()->showTreeForThis(); } #endif // NDEBUG @@ -2084,7 +1332,7 @@ Color RenderObject::selectionBackgroundColor() const { Color color; if (style()->userSelect() != SELECT_NONE) { - RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION); + RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION); if (pseudoStyle && pseudoStyle->backgroundColor().isValid()) color = pseudoStyle->backgroundColor().blendWithWhite(); else @@ -2102,14 +1350,14 @@ Color RenderObject::selectionForegroundColor() const if (style()->userSelect() == SELECT_NONE) return color; - if (RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION)) { + if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION)) { color = pseudoStyle->textFillColor(); if (!color.isValid()) color = pseudoStyle->color(); } else color = document()->frame()->selection()->isFocusedAndActive() ? - theme()->platformActiveSelectionForegroundColor() : - theme()->platformInactiveSelectionForegroundColor(); + theme()->activeSelectionForegroundColor() : + theme()->inactiveSelectionForegroundColor(); return color; } @@ -2120,7 +1368,7 @@ Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& d return 0; for (const RenderObject* curr = this; curr; curr = curr->parent()) { - Node* elt = curr->element(); + Node* elt = curr->node(); if (elt && elt->nodeType() == Node::TEXT_NODE) { // Since there's no way for the author to address the -webkit-user-drag style for a text node, // we use our own judgement. @@ -2154,17 +1402,6 @@ void RenderObject::selectionStartEnd(int& spos, int& epos) const view()->selectionStartEnd(spos, epos); } -RenderBlock* RenderObject::createAnonymousBlock() -{ - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(m_style.get()); - newStyle->setDisplay(BLOCK); - - RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); - newBox->setStyle(newStyle.release()); - return newBox; -} - void RenderObject::handleDynamicFloatPositionChange() { // We have gone from not affecting the inline status of the parent flow to suddenly @@ -2172,30 +1409,14 @@ void RenderObject::handleDynamicFloatPositionChange() // childrenInline() state and our state. setInline(style()->isDisplayInlineType()); if (isInline() != parent()->childrenInline()) { - if (!isInline()) { - if (parent()->isRenderInline()) { - // We have to split the parent flow. - RenderInline* parentInline = static_cast<RenderInline*>(parent()); - RenderBlock* newBox = parentInline->createAnonymousBlock(); - - RenderFlow* oldContinuation = parent()->continuation(); - parentInline->setContinuation(newBox); - - RenderObject* beforeChild = nextSibling(); - parent()->removeChildNode(this); - parentInline->splitFlow(beforeChild, newBox, this, oldContinuation); - } else if (parent()->isRenderBlock()) { - RenderBlock* o = static_cast<RenderBlock*>(parent()); - o->makeChildrenNonInline(); - if (o->isAnonymousBlock() && o->parent()) - o->parent()->removeLeftoverAnonymousBlock(o); - // o may be dead here - } - } else { + if (!isInline()) + toRenderBoxModelObject(parent())->childBecameNonInline(this); + else { // An anonymous block must be made to wrap this inline. - RenderBlock* box = createAnonymousBlock(); - parent()->insertChildNode(box, this); - box->appendChildNode(parent()->removeChildNode(this)); + RenderBlock* block = toRenderBlock(parent())->createAnonymousBlock(); + RenderObjectChildList* childlist = parent()->virtualChildren(); + childlist->insertChildNode(parent(), block, this); + block->children()->appendChildNode(block, childlist->removeChildNode(parent(), this)); } } } @@ -2208,18 +1429,50 @@ void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style) setStyle(style); } +StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsigned contextSensitiveProperties) const +{ +#if USE(ACCELERATED_COMPOSITING) + // If transform changed, and we are not composited, need to do a layout. + if (contextSensitiveProperties & ContextSensitivePropertyTransform) { + // Text nodes share style with their parents but transforms don't apply to them, + // hence the !isText() check. + // FIXME: when transforms are taken into account for overflow, we will need to do a layout. + if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited())) + diff = StyleDifferenceLayout; + else if (diff < StyleDifferenceRecompositeLayer) + diff = StyleDifferenceRecompositeLayer; + } + + // If opacity changed, and we are not composited, need to repaint (also + // ignoring text nodes) + if (contextSensitiveProperties & ContextSensitivePropertyOpacity) { + if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited())) + diff = StyleDifferenceRepaintLayer; + else if (diff < StyleDifferenceRecompositeLayer) + diff = StyleDifferenceRecompositeLayer; + } +#else + UNUSED_PARAM(contextSensitiveProperties); +#endif + + // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint. + if (diff == StyleDifferenceRepaintLayer && !hasLayer()) + diff = StyleDifferenceRepaint; + + return diff; +} + void RenderObject::setStyle(PassRefPtr<RenderStyle> style) { if (m_style == style) return; - RenderStyle::Diff diff = RenderStyle::Equal; + StyleDifference diff = StyleDifferenceEqual; + unsigned contextSensitiveProperties = ContextSensitivePropertyNone; if (m_style) - diff = m_style->diff(style.get()); + diff = m_style->diff(style.get(), contextSensitiveProperties); - // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint. - if (diff == RenderStyle::RepaintLayer && !hasLayer()) - diff = RenderStyle::Repaint; + diff = adjustStyleDifference(diff, contextSensitiveProperties); styleWillChange(diff, style.get()); @@ -2232,7 +1485,32 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style) updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0); updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0); + // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen + // during styleDidChange (it's used by clippedOverflowRectForRepaint()). + if (m_style->outlineWidth() > 0 && m_style->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) + toRenderView(document()->renderer())->setMaximalOutlineSize(m_style->outlineSize()); + styleDidChange(diff, oldStyle.get()); + + if (!m_parent || isText()) + return; + + // Now that the layer (if any) has been updated, we need to adjust the diff again, + // check whether we should layout now, and decide if we need to repaint. + StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties); + + if (diff <= StyleDifferenceLayoutPositionedMovementOnly) { + if (updatedDiff == StyleDifferenceLayout) + setNeedsLayoutAndPrefWidthsRecalc(); + else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly) + setNeedsPositionedMovementLayout(); + } + + if (updatedDiff == StyleDifferenceRepaintLayer || updatedDiff == StyleDifferenceRepaint) { + // Do a repaint with the new style now, e.g., for example if we go from + // not having an outline to having an outline. + repaint(); + } } void RenderObject::setStyleInternal(PassRefPtr<RenderStyle> style) @@ -2240,120 +1518,53 @@ void RenderObject::setStyleInternal(PassRefPtr<RenderStyle> style) m_style = style; } -void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { if (m_style) { // If our z-index changes value or our visibility changes, // we need to dirty our stacking context's z-order list. if (newStyle) { + bool visibilityChanged = m_style->visibility() != newStyle->visibility() + || m_style->zIndex() != newStyle->zIndex() + || m_style->hasAutoZIndex() != newStyle->hasAutoZIndex(); #if ENABLE(DASHBOARD_SUPPORT) - if (m_style->visibility() != newStyle->visibility() || - m_style->zIndex() != newStyle->zIndex() || - m_style->hasAutoZIndex() != newStyle->hasAutoZIndex()) + if (visibilityChanged) document()->setDashboardRegionsDirty(true); #endif + if (visibilityChanged && AXObjectCache::accessibilityEnabled()) + document()->axObjectCache()->childrenChanged(this); - if ((m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - m_style->zIndex() != newStyle->zIndex() || - m_style->visibility() != newStyle->visibility()) && hasLayer()) { - layer()->dirtyStackingContextZOrderLists(); - if (m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - m_style->visibility() != newStyle->visibility()) - layer()->dirtyZOrderLists(); - } - // keep layer hierarchy visibility bits up to date if visibility changes + // Keep layer hierarchy visibility bits up to date if visibility changes. if (m_style->visibility() != newStyle->visibility()) { if (RenderLayer* l = enclosingLayer()) { if (newStyle->visibility() == VISIBLE) l->setHasVisibleContent(true); else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) { l->dirtyVisibleContentStatus(); - if (diff > RenderStyle::RepaintLayer) + if (diff > StyleDifferenceRepaintLayer) repaint(); } } } } - // The background of the root element or the body element could propagate up to - // the canvas. Just dirty the entire canvas when our style changes substantially. - if (diff >= RenderStyle::Repaint && element() && - (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag))) - view()->repaint(); - else if (m_parent && !isText()) { - // Do a repaint with the old style first, e.g., for example if we go from - // having an outline to not having an outline. - if (diff == RenderStyle::RepaintLayer) { - layer()->repaintIncludingDescendants(); - if (!(m_style->clip() == newStyle->clip())) - layer()->clearClipRectsIncludingDescendants(); - } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize()) - repaint(); - } - - if (diff == RenderStyle::Layout) { - // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could - // end up being destroyed. - if (hasLayer()) { - if (m_style->position() != newStyle->position() || - m_style->zIndex() != newStyle->zIndex() || - m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - !(m_style->clip() == newStyle->clip()) || - m_style->hasClip() != newStyle->hasClip() || - m_style->opacity() != newStyle->opacity() || - m_style->transform() != newStyle->transform()) - layer()->repaintIncludingDescendants(); - } else if (newStyle->hasTransform() || newStyle->opacity() < 1) { - // If we don't have a layer yet, but we are going to get one because of transform or opacity, - // then we need to repaint the old position of the object. - repaint(); - } - } - - // When a layout hint happens and an object's position style changes, we have to do a layout - // to dirty the render tree using the old position value now. - if (diff == RenderStyle::Layout && m_parent && m_style->position() != newStyle->position()) { - markContainingBlocksForLayout(); - if (m_style->position() == StaticPosition) - repaint(); - if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)) - removeFromObjectLists(); - if (isRenderBlock()) { - if (newStyle->position() == StaticPosition) - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. - removePositionedObjects(0); - else if (m_style->position() == StaticPosition) { - // Remove our absolutely positioned descendants from their current containing block. - // They will be inserted into our positioned objects list during layout. - RenderObject* cb = parent(); - while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { - if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { - cb = cb->containingBlock(); - break; - } - cb = cb->parent(); - } - cb->removePositionedObjects(static_cast<RenderBlock*>(this)); - } - } - } - + if (m_parent && (diff == StyleDifferenceRepaint || newStyle->outlineSize() < m_style->outlineSize())) + repaint(); if (isFloating() && (m_style->floating() != newStyle->floating())) // For changes in float styles, we need to conceivably remove ourselves // from the floating objects list. - removeFromObjectLists(); + toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); else if (isPositioned() && (newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition)) // For changes in positioning styles, we need to conceivably remove ourselves // from the positioned objects list. - removeFromObjectLists(); + toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); s_affectsParentBlock = isFloatingOrPositioned() && (!newStyle->isFloating() && newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition) - && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow()); + && parent() && (parent()->isBlockFlow() || parent()->isRenderInline()); // reset style flags - if (diff == RenderStyle::Layout || diff == RenderStyle::LayoutPositionedMovementOnly) { + if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) { m_floating = false; m_positioned = false; m_relPositioned = false; @@ -2379,25 +1590,21 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne } } -void RenderObject::styleDidChange(RenderStyle::Diff diff, const RenderStyle*) +void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*) { - setHasBoxDecorations(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance() || m_style->boxShadow()); - if (s_affectsParentBlock) handleDynamicFloatPositionChange(); - // No need to ever schedule repaints from a style change of a text run, since - // we already did this for the parent of the text run. - // We do have to schedule layouts, though, since a style change can force us to - // need to relayout. - if (diff == RenderStyle::Layout && m_parent) + if (!m_parent) + return; + + if (diff == StyleDifferenceLayout) setNeedsLayoutAndPrefWidthsRecalc(); - else if (diff == RenderStyle::LayoutPositionedMovementOnly && m_parent && !isText()) + else if (diff == StyleDifferenceLayoutPositionedMovementOnly) setNeedsPositionedMovementLayout(); - else if (m_parent && !isText() && (diff == RenderStyle::RepaintLayer || diff == RenderStyle::Repaint)) - // Do a repaint with the new style now, e.g., for example if we go from - // not having an outline to having an outline. - repaint(); + + // Don't check for repaint here; we need to wait until the layer has been + // updated by subclasses before we know if we have to repaint (in setStyle()). } void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers) @@ -2430,42 +1637,92 @@ IntRect RenderObject::viewRect() const FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const { + TransformState transformState(TransformState::ApplyTransformDirection, localPoint); + mapLocalToContainer(0, fixed, useTransforms, transformState); + transformState.flatten(); + + return transformState.lastPlanarPoint(); +} + +FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +{ + TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint); + mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); + transformState.flatten(); + + return transformState.lastPlanarPoint(); +} + +void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const +{ + if (repaintContainer == this) + return; + RenderObject* o = parent(); - if (o) { - localPoint.move(0.0f, static_cast<float>(o->borderTopExtra())); - if (o->hasOverflowClip()) - localPoint -= o->layer()->scrolledContentOffset(); - return o->localToAbsolute(localPoint, fixed, useTransforms); - } + if (!o) + return; - return FloatPoint(); + if (o->hasOverflowClip()) + transformState.move(-toRenderBox(o)->layer()->scrolledContentOffset()); + + o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); } -FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +void RenderObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { RenderObject* o = parent(); if (o) { - FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms); - localPoint.move(0.0f, -static_cast<float>(o->borderTopExtra())); + o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); if (o->hasOverflowClip()) - localPoint += o->layer()->scrolledContentOffset(); - return localPoint; + transformState.move(toRenderBox(o)->layer()->scrolledContentOffset()); } - return FloatPoint(); } -FloatQuad RenderObject::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const +bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const { - RenderObject* o = parent(); - if (o) { - FloatQuad quad = localQuad; - quad.move(0.0f, static_cast<float>(o->borderTopExtra())); - if (o->hasOverflowClip()) - quad -= o->layer()->scrolledContentOffset(); - return o->localToAbsoluteQuad(quad, fixed); +#if ENABLE(3D_RENDERING) + // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform, + // so check the layer's transform directly. + return (hasLayer() && toRenderBoxModelObject(this)->layer()->transform()) || (containerObject && containerObject->style()->hasPerspective()); +#else + UNUSED_PARAM(containerObject); + return hasTransform(); +#endif +} + +void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const IntSize& offsetInContainer, TransformationMatrix& transform) const +{ + transform.makeIdentity(); + transform.translate(offsetInContainer.width(), offsetInContainer.height()); + RenderLayer* layer; + if (hasLayer() && (layer = toRenderBoxModelObject(this)->layer()) && layer->transform()) + transform.multLeft(layer->currentTransform()); + +#if ENABLE(3D_RENDERING) + if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) { + // Perpsective on the container affects us, so we have to factor it in here. + ASSERT(containerObject->hasLayer()); + FloatPoint perspectiveOrigin = toRenderBox(containerObject)->layer()->perspectiveOrigin(); + + TransformationMatrix perspectiveMatrix; + perspectiveMatrix.applyPerspective(containerObject->style()->perspective()); + + transform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0); + transform.multiply(perspectiveMatrix); + transform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0); } +#else + UNUSED_PARAM(containerObject); +#endif +} - return FloatQuad(); +FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderBoxModelObject* repaintContainer, bool fixed) const +{ + TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint(), &localQuad); + mapLocalToContainer(repaintContainer, fixed, true, transformState); + transformState.flatten(); + + return transformState.lastPlanarQuad(); } IntSize RenderObject::offsetFromContainer(RenderObject* o) const @@ -2473,10 +1730,8 @@ IntSize RenderObject::offsetFromContainer(RenderObject* o) const ASSERT(o == container()); IntSize offset; - offset.expand(0, o->borderTopExtra()); - if (o->hasOverflowClip()) - offset -= o->layer()->scrolledContentOffset(); + offset -= toRenderBox(o)->layer()->scrolledContentOffset(); return offset; } @@ -2489,50 +1744,29 @@ IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine return IntRect(); } -int RenderObject::paddingTop() const +RenderView* RenderObject::view() const { - int w = 0; - Length padding = m_style->paddingTop(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); - return padding.calcMinValue(w); + return toRenderView(document()->renderer()); } -int RenderObject::paddingBottom() const +bool RenderObject::isRooted(RenderView** view) { - int w = 0; - Length padding = style()->paddingBottom(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); - return padding.calcMinValue(w); -} + RenderObject* o = this; + while (o->parent()) + o = o->parent(); -int RenderObject::paddingLeft() const -{ - int w = 0; - Length padding = style()->paddingLeft(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); - return padding.calcMinValue(w); -} + if (!o->isRenderView()) + return false; -int RenderObject::paddingRight() const -{ - int w = 0; - Length padding = style()->paddingRight(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); - return padding.calcMinValue(w); -} + if (view) + *view = toRenderView(o); -RenderView* RenderObject::view() const -{ - return static_cast<RenderView*>(document()->renderer()); + return true; } bool RenderObject::hasOutlineAnnotation() const { - return element() && element()->isLink() && document()->printing(); + return node() && node()->isLink() && document()->printing(); } RenderObject* RenderObject::container() const @@ -2559,6 +1793,8 @@ RenderObject* RenderObject::container() const // as we can. If we're in the tree, we'll get the root. If we // aren't we'll get the root of our little subtree (most likely // we'll just return 0). + // FIXME: The definition of view() has changed to not crawl up the render tree. It might + // be safe now to use it. while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) o = o->parent(); } else if (pos == AbsolutePosition) { @@ -2572,61 +1808,30 @@ RenderObject* RenderObject::container() const return o; } -// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated -// content (and perhaps XBL). That's why it uses the render tree and not the DOM tree. -RenderObject* RenderObject::hoverAncestor() const -{ - return (!isInline() && continuation()) ? continuation() : parent(); -} - bool RenderObject::isSelectionBorder() const { SelectionState st = selectionState(); return st == SelectionStart || st == SelectionEnd || st == SelectionBoth; } -void RenderObject::removeFromObjectLists() -{ - if (documentBeingDestroyed()) - return; - - if (isFloating()) { - RenderBlock* outermostBlock = containingBlock(); - for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) { - if (p->containsFloat(this)) - outermostBlock = p; - } - - if (outermostBlock) - outermostBlock->markAllDescendantsWithFloatsForLayout(this); - } - - if (isPositioned()) { - RenderObject* p; - for (p = parent(); p; p = p->parent()) { - if (p->isRenderBlock()) - static_cast<RenderBlock*>(p)->removePositionedObject(this); - } - } -} - -bool RenderObject::documentBeingDestroyed() const -{ - return !document()->renderer(); -} - void RenderObject::destroy() { + // Destroy any leftover anonymous children. + RenderObjectChildList* children = virtualChildren(); + if (children) + children->destroyLeftoverChildren(); + // If this renderer is being autoscrolled, stop the autoscroll timer - if (document()->frame() && document()->frame()->eventHandler()->autoscrollRenderer() == this) + if (document()->frame()->eventHandler()->autoscrollRenderer() == this) document()->frame()->eventHandler()->stopAutoscrollTimer(true); if (m_hasCounterNodeMap) RenderCounter::destroyCounterNodes(this); - if (AXObjectCache::accessibilityEnabled()) + if (AXObjectCache::accessibilityEnabled()) { + document()->axObjectCache()->childrenChanged(this->parent()); document()->axObjectCache()->remove(this); - + } animation()->cancelAnimations(this); // By default no ref-counting. RenderWidget::destroy() doesn't call @@ -2635,12 +1840,13 @@ void RenderObject::destroy() remove(); - RenderArena* arena = renderArena(); - - if (hasLayer()) - layer()->destroy(arena); - - arenaDelete(arena, this); + // FIXME: Would like to do this in RenderBoxModelObject, but the timing is so complicated that this can't easily + // be moved into RenderBoxModelObject::destroy. + if (hasLayer()) { + setHasLayer(false); + toRenderBoxModelObject(this)->destroyLayer(); + } + arenaDelete(renderArena(), this); } void RenderObject::arenaDelete(RenderArena* arena, void* base) @@ -2676,9 +1882,14 @@ void RenderObject::arenaDelete(RenderArena* arena, void* base) arena->free(*(size_t*)base, base); } -VisiblePosition RenderObject::positionForCoordinates(int, int) +VisiblePosition RenderObject::positionForCoordinates(int x, int y) { - return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); + return positionForPoint(IntPoint(x, y)); +} + +VisiblePosition RenderObject::positionForPoint(const IntPoint&) +{ + return createVisiblePosition(caretMinOffset(), DOWNSTREAM); } void RenderObject::updateDragState(bool dragOn) @@ -2686,11 +1897,9 @@ void RenderObject::updateDragState(bool dragOn) bool valueChanged = (dragOn != m_isDragging); m_isDragging = dragOn; if (valueChanged && style()->affectedByDragRules()) - element()->setChanged(); + node()->setNeedsStyleRecalc(); for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) curr->updateDragState(dragOn); - if (continuation()) - continuation()->updateDragState(dragOn); } bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const IntPoint& point, int tx, int ty, HitTestFilter hitTestFilter) @@ -2721,34 +1930,12 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const IntPoint& po if (result.innerNode()) return; - Node* node = element(); - IntPoint localPoint(point); - if (isRenderView()) - node = document()->documentElement(); - else if (!isInline() && continuation()) - // We are in the margins of block elements that are part of a continuation. In - // this case we're actually still inside the enclosing inline element that was - // split. Go ahead and set our inner node accordingly. - node = continuation()->element(); - - if (node) { - if (node->renderer() && node->renderer()->continuation() && node->renderer() != this) { - // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space - // of the principal renderer's containing block. This will end up being the innerNonSharedNode. - RenderObject* firstBlock = node->renderer()->containingBlock(); - - // Get our containing block. - RenderObject* block = this; - if (isInline()) - block = containingBlock(); - - localPoint.move(block->xPos() - firstBlock->xPos(), block->yPos() - firstBlock->yPos()); - } - - result.setInnerNode(node); + Node* n = node(); + if (n) { + result.setInnerNode(n); if (!result.innerNonSharedNode()) - result.setInnerNonSharedNode(node); - result.setLocalPoint(localPoint); + result.setInnerNonSharedNode(n); + result.setLocalPoint(point); } } @@ -2757,78 +1944,9 @@ bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int /*x*/, return false; } -int RenderObject::verticalPositionHint(bool firstLine) const -{ - if (firstLine) // We're only really a first-line style if the document actually uses first-line rules. - firstLine = document()->usesFirstLineRules(); - int vpos = m_verticalPosition; - if (m_verticalPosition == PositionUndefined || firstLine) { - vpos = getVerticalPosition(firstLine); - if (!firstLine) - m_verticalPosition = vpos; - } - - return vpos; -} - -int RenderObject::getVerticalPosition(bool firstLine) const -{ - if (!isInline()) - return 0; - - // This method determines the vertical position for inline elements. - int vpos = 0; - EVerticalAlign va = style()->verticalAlign(); - if (va == TOP) - vpos = PositionTop; - else if (va == BOTTOM) - vpos = PositionBottom; - else { - bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM; - vpos = checkParent ? parent()->verticalPositionHint(firstLine) : 0; - // don't allow elements nested inside text-top to have a different valignment. - if (va == BASELINE) - return vpos; - - const Font& f = parent()->style(firstLine)->font(); - int fontsize = f.pixelSize(); - - if (va == SUB) - vpos += fontsize / 5 + 1; - else if (va == SUPER) - vpos -= fontsize / 3 + 1; - else if (va == TEXT_TOP) - vpos += baselinePosition(firstLine) - f.ascent(); - else if (va == MIDDLE) - vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine) / 2 + baselinePosition(firstLine); - else if (va == TEXT_BOTTOM) { - vpos += f.descent(); - if (!isReplaced()) - vpos -= style(firstLine)->font().descent(); - } else if (va == BASELINE_MIDDLE) - vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine); - else if (va == LENGTH) - vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine)); - } - - return vpos; -} - int RenderObject::lineHeight(bool firstLine, bool /*isRootLineBox*/) const { - RenderStyle* s = style(firstLine); - - Length lh = s->lineHeight(); - - // its "unset", choose nice default - if (lh.isNegative()) - return s->font().lineSpacing(); - - if (lh.isPercent()) - return lh.calcMinValue(s->fontSize()); - - // its fixed - return lh.value(); + return style(firstLine)->computedLineHeight(); } int RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const @@ -2840,7 +1958,7 @@ int RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const void RenderObject::scheduleRelayout() { if (isRenderView()) { - FrameView* view = static_cast<RenderView*>(this)->frameView(); + FrameView* view = toRenderView(this)->frameView(); if (view) view->scheduleRelayout(); } else if (parent()) { @@ -2850,59 +1968,42 @@ void RenderObject::scheduleRelayout() } } -void RenderObject::removeLeftoverAnonymousBlock(RenderBlock*) -{ -} - -InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool) -{ - ASSERT(!isRootLineBox); - return new (renderArena()) InlineBox(this); -} - -void RenderObject::dirtyLineBoxes(bool, bool) -{ -} - -InlineBox* RenderObject::inlineBoxWrapper() const -{ - return 0; -} - -void RenderObject::setInlineBoxWrapper(InlineBox*) -{ -} - -void RenderObject::deleteLineBoxWrapper() +void RenderObject::layout() { + ASSERT(needsLayout()); + RenderObject* child = firstChild(); + while (child) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); + child = child->nextSibling(); + } + setNeedsLayout(false); } -RenderStyle* RenderObject::firstLineStyle() const +RenderStyle* RenderObject::firstLineStyleSlowCase() const { - if (!document()->usesFirstLineRules()) - return m_style.get(); + ASSERT(document()->usesFirstLineRules()); - RenderStyle* s = m_style.get(); - const RenderObject* obj = isText() ? parent() : this; - if (obj->isBlockFlow()) { - RenderBlock* firstLineBlock = obj->firstLineBlock(); - if (firstLineBlock) - s = firstLineBlock->getCachedPseudoStyle(RenderStyle::FIRST_LINE, style()); - } else if (!obj->isAnonymous() && obj->isInlineFlow()) { - RenderStyle* parentStyle = obj->parent()->firstLineStyle(); - if (parentStyle != obj->parent()->style()) { - // A first-line style is in effect. We need to cache a first-line style - // for ourselves. - style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED); - s = obj->getCachedPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle); + RenderStyle* style = m_style.get(); + const RenderObject* renderer = isText() ? parent() : this; + if (renderer->isBlockFlow()) { + if (RenderBlock* firstLineBlock = renderer->firstLineBlock()) + style = firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style); + } else if (!renderer->isAnonymous() && renderer->isRenderInline()) { + RenderStyle* parentStyle = renderer->parent()->firstLineStyle(); + if (parentStyle != renderer->parent()->style()) { + // A first-line style is in effect. Cache a first-line style for ourselves. + style->setHasPseudoStyle(FIRST_LINE_INHERITED); + style = renderer->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle); } } - return s; + + return style; } -RenderStyle* RenderObject::getCachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const +RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const { - if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) + if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) return 0; RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo); @@ -2915,26 +2016,26 @@ RenderStyle* RenderObject::getCachedPseudoStyle(RenderStyle::PseudoId pseudo, Re return 0; } -PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const +PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const { - if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) + if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) return 0; if (!parentStyle) parentStyle = style(); - Node* node = element(); - while (node && !node->isElementNode()) - node = node->parentNode(); - if (!node) + Node* n = node(); + while (n && !n->isElementNode()) + n = n->parentNode(); + if (!n) return 0; RefPtr<RenderStyle> result; - if (pseudo == RenderStyle::FIRST_LINE_INHERITED) { - result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false); - result->setStyleType(RenderStyle::FIRST_LINE_INHERITED); + if (pseudo == FIRST_LINE_INHERITED) { + result = document()->styleSelector()->styleForElement(static_cast<Element*>(n), parentStyle, false); + result->setStyleType(FIRST_LINE_INHERITED); } else - result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle); + result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(n), parentStyle); return result.release(); } @@ -2977,10 +2078,10 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co } } curr = curr->parent(); - if (curr && curr->isRenderBlock() && curr->continuation()) - curr = curr->continuation(); - } while (curr && decorations && (!quirksMode || !curr->element() || - (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag)))); + if (curr && curr->isRenderBlock() && toRenderBlock(curr)->inlineContinuation()) + curr = toRenderBlock(curr)->inlineContinuation(); + } while (curr && decorations && (!quirksMode || !curr->node() || + (!curr->node()->hasTagName(aTag) && !curr->node()->hasTagName(fontTag)))); // If we bailed out, use the element we bailed out at (typically a <font> or <a> element). if (decorations && curr) { @@ -2993,24 +2094,22 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co } } -void RenderObject::updateWidgetPosition() -{ -} - #if ENABLE(DASHBOARD_SUPPORT) void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions) { // Convert the style regions to absolute coordinates. - if (style()->visibility() != VISIBLE) + if (style()->visibility() != VISIBLE || !isBox()) return; + + RenderBox* box = toRenderBox(this); const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions(); unsigned i, count = styleRegions.size(); for (i = 0; i < count; i++) { StyleDashboardRegion styleRegion = styleRegions[i]; - int w = width(); - int h = height(); + int w = box->width(); + int h = box->height(); DashboardRegionValue region; region.label = styleRegion.label; @@ -3056,32 +2155,6 @@ void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions } #endif -bool RenderObject::avoidsFloats() const -{ - return isReplaced() || hasOverflowClip() || isHR(); -} - -bool RenderObject::shrinkToAvoidFloats() const -{ - // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this - // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the - // current remaining width on a line. - if (isInline() && !isHTMLMarquee() || !avoidsFloats()) - return false; - - // All auto-width objects that avoid floats should always use lineWidth. - return style()->width().isAuto(); -} - -UChar RenderObject::backslashAsCurrencySymbol() const -{ - if (Node *node = element()) { - if (TextResourceDecoder* decoder = node->document()->decoder()) - return decoder->encoding().backslashAsCurrencySymbol(); - } - return '\\'; -} - bool RenderObject::willRenderImage(CachedImage*) { // Without visibility we won't render (and therefore don't care about animation). @@ -3097,7 +2170,7 @@ int RenderObject::maximalOutlineSize(PaintPhase p) const { if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines) return 0; - return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize(); + return toRenderView(document()->renderer())->maximalOutlineSize(); } int RenderObject::caretMinOffset() const @@ -3108,7 +2181,7 @@ int RenderObject::caretMinOffset() const int RenderObject::caretMaxOffset() const { if (isReplaced()) - return element() ? max(1U, element()->childNodeCount()) : 1; + return node() ? max(1U, node()->childNodeCount()) : 1; if (isHR()) return 1; return 0; @@ -3124,44 +2197,19 @@ int RenderObject::previousOffset(int current) const return current - 1; } -int RenderObject::nextOffset(int current) const +int RenderObject::previousOffsetForBackwardDeletion(int current) const { - return current + 1; -} - -int RenderObject::maxTopMargin(bool positive) const -{ - return positive ? max(0, marginTop()) : -min(0, marginTop()); -} - -int RenderObject::maxBottomMargin(bool positive) const -{ - return positive ? max(0, marginBottom()) : -min(0, marginBottom()); -} - -IntRect RenderObject::contentBox() const -{ - return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), - contentWidth(), contentHeight()); -} - -IntRect RenderObject::absoluteContentBox() const -{ - IntRect rect = contentBox(); - FloatPoint absPos = localToAbsoluteForContent(FloatPoint()); - rect.move(absPos.x(), absPos.y()); - return rect; + return current - 1; } -FloatQuad RenderObject::absoluteContentQuad() const +int RenderObject::nextOffset(int current) const { - IntRect rect = contentBox(); - return localToAbsoluteQuad(FloatRect(rect)); + return current + 1; } void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const { - int outlineSize = !isInline() && continuation() ? continuation()->style()->outlineSize() : style()->outlineSize(); + int outlineSize = outlineStyleForRepaint()->outlineSize(); if (ShadowData* boxShadow = style()->boxShadow()) { int shadowLeft = 0; int shadowRight = 0; @@ -3184,24 +2232,6 @@ void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const rect.inflate(outlineSize); } -IntRect RenderObject::absoluteOutlineBounds() const -{ - IntRect box = borderBox(); - adjustRectForOutlineAndShadow(box); - - FloatQuad absOutlineQuad = localToAbsoluteQuad(FloatRect(box)); - box = absOutlineQuad.enclosingBoundingBox(); - box.move(view()->layoutDelta()); - - return box; -} - -bool RenderObject::isScrollable() const -{ - RenderLayer* l = enclosingLayer(); - return l && (l->verticalScrollbar() || l->horizontalScrollbar()); -} - AnimationController* RenderObject::animation() const { return document()->frame()->animation(); @@ -3212,82 +2242,150 @@ void RenderObject::imageChanged(CachedImage* image, const IntRect* rect) imageChanged(static_cast<WrappedImagePtr>(image), rect); } -IntRect RenderObject::reflectionBox() const +RenderBoxModelObject* RenderObject::offsetParent() const { - IntRect result; - if (!m_style->boxReflect()) - return result; - IntRect box = borderBox(); - result = box; - switch (m_style->boxReflect()->direction()) { - case ReflectionBelow: - result.move(0, box.height() + reflectionOffset()); - break; - case ReflectionAbove: - result.move(0, -box.height() - reflectionOffset()); - break; - case ReflectionLeft: - result.move(-box.width() - reflectionOffset(), 0); - break; - case ReflectionRight: - result.move(box.width() + reflectionOffset(), 0); + // If any of the following holds true return null and stop this algorithm: + // A is the root element. + // A is the HTML body element. + // The computed value of the position property for element A is fixed. + if (isRoot() || isBody() || (isPositioned() && style()->position() == FixedPosition)) + return 0; + + // If A is an area HTML element which has a map HTML element somewhere in the ancestor + // chain return the nearest ancestor map HTML element and stop this algorithm. + // FIXME: Implement! + + // Return the nearest ancestor element of A for which at least one of the following is + // true and stop this algorithm if such an ancestor is found: + // * The computed value of the position property is not static. + // * It is the HTML body element. + // * The computed value of the position property of A is static and the ancestor + // is one of the following HTML elements: td, th, or table. + // * Our own extension: if there is a difference in the effective zoom + bool skipTables = isPositioned() || isRelPositioned(); + float currZoom = style()->effectiveZoom(); + RenderObject* curr = parent(); + while (curr && (!curr->node() || + (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) { + Node* element = curr->node(); + if (!skipTables && element) { + bool isTableElement = element->hasTagName(tableTag) || + element->hasTagName(tdTag) || + element->hasTagName(thTag); + +#if ENABLE(WML) + if (!isTableElement && element->isWMLElement()) + isTableElement = element->hasTagName(WMLNames::tableTag) || + element->hasTagName(WMLNames::tdTag); +#endif + + if (isTableElement) + break; + } + + float newZoom = curr->style()->effectiveZoom(); + if (currZoom != newZoom) break; + currZoom = newZoom; + curr = curr->parent(); } - return result; + return curr && curr->isBoxModelObject() ? toRenderBoxModelObject(curr) : 0; } -int RenderObject::reflectionOffset() const +VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity) { - if (!m_style->boxReflect()) - return 0; - if (m_style->boxReflect()->direction() == ReflectionLeft || m_style->boxReflect()->direction() == ReflectionRight) - return m_style->boxReflect()->offset().calcValue(borderBox().width()); - return m_style->boxReflect()->offset().calcValue(borderBox().height()); + // If this is a non-anonymous renderer, then it's simple. + if (Node* node = this->node()) + 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 + // extremely unlikely in any normal case because we stop as soon as we + // find a single non-anonymous renderer. + + // Find a nearby non-anonymous renderer. + RenderObject* child = this; + while (RenderObject* parent = child->parent()) { + // Find non-anonymous content after. + RenderObject* renderer = child; + while ((renderer = renderer->nextInPreOrder(parent))) { + if (Node* node = renderer->node()) + return VisiblePosition(node, 0, DOWNSTREAM); + } + + // Find non-anonymous content before. + renderer = child; + while ((renderer = renderer->previousInPreOrder())) { + if (renderer == parent) + break; + if (Node* node = renderer->node()) + return VisiblePosition(lastDeepEditingPositionForNode(node), DOWNSTREAM); + } + + // Use the parent itself unless it too is anonymous. + if (Node* node = parent->node()) + return VisiblePosition(node, 0, DOWNSTREAM); + + // Repeat at the next level up. + child = parent; + } + + // Everything was anonymous. Give up. + return VisiblePosition(); } -IntRect RenderObject::reflectedRect(const IntRect& r) const +VisiblePosition RenderObject::createVisiblePosition(const Position& position) { - if (!m_style->boxReflect()) - return IntRect(); + if (position.isNotNull()) + return VisiblePosition(position); - IntRect box = borderBox(); - IntRect result = r; - switch (m_style->boxReflect()->direction()) { - case ReflectionBelow: - result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom())); - break; - case ReflectionAbove: - result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom())); - break; - case ReflectionLeft: - result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right())); - break; - case ReflectionRight: - result.setX(box.right() + reflectionOffset() + (box.right() - r.right())); - break; - } - return result; + ASSERT(!node()); + return createVisiblePosition(0, DOWNSTREAM); } #if ENABLE(SVG) -FloatRect RenderObject::relativeBBox(bool) const +FloatRect RenderObject::objectBoundingBox() const { + ASSERT_NOT_REACHED(); + return FloatRect(); +} + +// Returns the smallest rectangle enclosing all of the painted content +// respecting clipping, masking, filters, opacity, stroke-width and markers +FloatRect RenderObject::repaintRectInLocalCoordinates() const +{ + ASSERT_NOT_REACHED(); return FloatRect(); } TransformationMatrix RenderObject::localTransform() const { - return TransformationMatrix(1, 0, 0, 1, xPos(), yPos()); + return TransformationMatrix(); +} + +TransformationMatrix 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(); } +bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + #endif // ENABLE(SVG) } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h index 70841b7..311ef9c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h @@ -3,7 +3,7 @@ * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,38 +27,30 @@ #include "CachedResourceClient.h" #include "Document.h" +#include "Element.h" #include "FloatQuad.h" +#include "RenderObjectChildList.h" #include "RenderStyle.h" -#include "ScrollTypes.h" -#include "VisiblePosition.h" -#include <wtf/HashMap.h> +#include "TextAffinity.h" +#include "TransformationMatrix.h" +#include <wtf/UnusedParam.h> namespace WebCore { -class TransformationMatrix; class AnimationController; -class Color; -class Document; -class Element; -class Event; -class FloatRect; -class FrameView; -class HTMLAreaElement; class HitTestResult; class InlineBox; class InlineFlowBox; +class OverlapTestRequestClient; class Position; -class RenderArena; +class RenderBoxModelObject; +class RenderInline; class RenderBlock; class RenderFlow; -class RenderFrameSet; class RenderLayer; -class RenderTable; -class RenderText; -class RenderView; -class String; - -struct HitTestRequest; +class RenderTheme; +class TransformState; +class VisiblePosition; /* * The painting of a layer occurs in three distinct phases. Each phase involves @@ -104,12 +96,17 @@ enum HitTestAction { HitTestForeground }; -enum VerticalPositionHint { - PositionTop = -0x7fffffff, - PositionBottom = 0x7fffffff, - PositionUndefined = static_cast<int>(0x80000000) +// Sides used when drawing borders and outlines. This is in RenderObject rather than RenderBoxModelObject since outlines can +// be drawn by SVG around bounding boxes. +enum BoxSide { + BSTop, + BSBottom, + BSLeft, + BSRight }; +const int caretWidth = 1; + #if ENABLE(DASHBOARD_SUPPORT) struct DashboardRegionValue { bool operator==(const DashboardRegionValue& o) const @@ -128,22 +125,22 @@ struct DashboardRegionValue { }; #endif -// FIXME: This should be a HashSequencedSet, but we don't have that data structure yet. -// This means the paint order of outlines will be wrong, although this is a minor issue. -typedef HashSet<RenderFlow*> RenderFlowSequencedSet; - // Base class for all rendering tree objects. class RenderObject : public CachedResourceClient { - friend class RenderContainer; - friend class RenderSVGContainer; + friend class RenderBlock; + friend class RenderBox; friend class RenderLayer; + friend class RenderObjectChildList; + friend class RenderSVGContainer; public: // Anonymous objects should pass the document as their node, and they will then automatically be // marked as anonymous in the constructor. RenderObject(Node*); virtual ~RenderObject(); - virtual const char* renderName() const { return "RenderObject"; } + RenderTheme* theme() const; + + virtual const char* renderName() const = 0; RenderObject* parent() const { return m_parent; } bool isDescendantOf(const RenderObject*) const; @@ -151,8 +148,20 @@ public: RenderObject* previousSibling() const { return m_previous; } RenderObject* nextSibling() const { return m_next; } - virtual RenderObject* firstChild() const { return 0; } - virtual RenderObject* lastChild() const { return 0; } + RenderObject* firstChild() const + { + if (const RenderObjectChildList* children = virtualChildren()) + return children->firstChild(); + return 0; + } + RenderObject* lastChild() const + { + if (const RenderObjectChildList* children = virtualChildren()) + return children->lastChild(); + return 0; + } + virtual RenderObjectChildList* virtualChildren() { return 0; } + virtual const RenderObjectChildList* virtualChildren() const { return 0; } RenderObject* nextInPreOrder() const; RenderObject* nextInPreOrder(RenderObject* stayWithin) const; @@ -164,30 +173,26 @@ public: RenderObject* firstLeafChild() const; RenderObject* lastLeafChild() const; - virtual RenderLayer* layer() const { return 0; } + // The following six functions are used when the render tree hierarchy changes to make sure layers get + // properly added and removed. Since containership can be implemented by any subclass, and since a hierarchy + // can contain a mixture of boxes and other object types, these functions need to be in the base class. RenderLayer* enclosingLayer() const; + RenderLayer* enclosingSelfPaintingLayer() const; void addLayers(RenderLayer* parentLayer, RenderObject* newObject); void removeLayers(RenderLayer* parentLayer); void moveLayers(RenderLayer* oldParent, RenderLayer* newParent); RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent = true); - virtual void positionChildLayers() { } - virtual bool requiresLayer(); - - virtual IntRect getOverflowClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); } - virtual IntRect getClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); } - bool hasClip() { return isPositioned() && style()->hasClip(); } - - virtual int getBaselineOfFirstLineBox() const { return -1; } - virtual int getBaselineOfLastLineBox() const { return -1; } + // Convenience function for getting to the nearest enclosing box of a RenderObject. + RenderBox* enclosingBox() const; + virtual bool isEmpty() const { return firstChild() == 0; } - virtual bool isEdited() const { return false; } - virtual void setEdited(bool) { } - #ifndef NDEBUG void setHasAXObject(bool flag) { m_hasAXObject = flag; } bool hasAXObject() const { return m_hasAXObject; } + bool isSetNeedsLayoutForbidden() const { return m_setNeedsLayoutForbidden; } + void setNeedsLayoutIsForbidden(bool flag) { m_setNeedsLayoutForbidden = flag; } #endif // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline @@ -198,35 +203,15 @@ public: // again. We have to make sure the render tree updates as needed to accommodate the new // normal flow object. void handleDynamicFloatPositionChange(); - - // This function is a convenience helper for creating an anonymous block that inherits its - // style from this RenderObject. - RenderBlock* createAnonymousBlock(); - - // Whether or not a positioned element requires normal flow x/y to be computed - // to determine its position. - bool hasStaticX() const; - bool hasStaticY() const; - virtual void setStaticX(int /*staticX*/) { } - virtual void setStaticY(int /*staticY*/) { } - virtual int staticX() const { return 0; } - virtual int staticY() const { return 0; } - + // RenderObject tree manipulation ////////////////////////////////////////// - virtual bool canHaveChildren() const; + virtual bool canHaveChildren() const { return virtualChildren(); } virtual bool isChildAllowed(RenderObject*, RenderStyle*) const { return true; } virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); + virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild = 0) { return addChild(newChild, beforeChild); } virtual void removeChild(RenderObject*); virtual bool createsAnonymousWrapper() const { return false; } - - // raw tree manipulation - virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true); - virtual void appendChildNode(RenderObject*, bool fullAppend = true); - virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true); - // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our - // change in parentage is not going to affect anything. - virtual void moveChildNode(RenderObject*); ////////////////////////////////////////// protected: @@ -238,6 +223,7 @@ protected: ////////////////////////////////////////// private: void addAbsoluteRectForLayer(IntRect& result); + void setLayerNeedsFullRepaint(); public: #ifndef NDEBUG @@ -263,20 +249,20 @@ public: virtual bool isApplet() const { return false; } virtual bool isBR() const { return false; } virtual bool isBlockFlow() const { return false; } + virtual bool isBoxModelObject() const { return false; } virtual bool isCounter() const { return false; } virtual bool isFieldset() const { return false; } virtual bool isFrame() const { return false; } virtual bool isFrameSet() const { return false; } virtual bool isImage() const { return false; } virtual bool isInlineBlockOrInlineTable() const { return false; } - virtual bool isInlineContinuation() const; - virtual bool isInlineFlow() const { return false; } virtual bool isListBox() const { return false; } virtual bool isListItem() const { return false; } virtual bool isListMarker() const { return false; } virtual bool isMedia() const { return false; } virtual bool isMenuList() const { return false; } 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; } @@ -287,50 +273,80 @@ public: virtual bool isTableCol() const { return false; } virtual bool isTableRow() const { return false; } virtual bool isTableSection() const { return false; } + virtual bool isTextControl() const { return false; } virtual bool isTextArea() const { return false; } virtual bool isTextField() const { return false; } + virtual bool isVideo() const { return false; } virtual bool isWidget() const { return false; } - - bool isRoot() const { return document()->documentElement() == node(); } + bool isRoot() const { return document()->documentElement() == m_node; } bool isBody() const; bool isHR() const; bool isHTMLMarquee() const; - virtual bool childrenInline() const { return false; } - virtual void setChildrenInline(bool) { } - - virtual RenderFlow* continuation() const; + bool childrenInline() const { return m_childrenInline; } + void setChildrenInline(bool b = true) { m_childrenInline = b; } + bool hasColumns() const { return m_hasColumns; } + void setHasColumns(bool b = true) { m_hasColumns = b; } + bool cellWidthChanged() const { return m_cellWidthChanged; } + void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; } #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. virtual bool isSVGRoot() const { return false; } virtual bool isSVGContainer() const { return false; } virtual bool isSVGHiddenContainer() const { return false; } virtual bool isRenderPath() const { return false; } virtual bool isSVGText() const { return false; } + virtual bool isSVGImage() const { return false; } + + // 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(). + // NOTE: Markers are not specifically ignored here by SVG 1.1 spec, but we ignore them + // since stroke-width is ignored (and marker size can depend on stroke-width). + // objectBoundingBox is returned local coordinates. + // The name objectBoundingBox is taken from the SVG 1.1 spec. + virtual FloatRect objectBoundingBox() const; + + // Returns the smallest rectangle enclosing all of the painted content + // respecting clipping, masking, filters, opacity, stroke-width and markers + virtual FloatRect repaintRectInLocalCoordinates() const; + + // 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 FloatRect relativeBBox(bool includeStroke = true) 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; - virtual TransformationMatrix localTransform() 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; -#endif - virtual bool isEditable() const; + // SVG uses FloatPoint precise hit testing, and passes the point in parent + // coordinates instead of in repaint container coordinates. Eventually the + // rest of the rendering tree will move to a similar model. + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); +#endif bool isAnonymous() const { return m_isAnonymous; } void setIsAnonymous(bool b) { m_isAnonymous = b; } bool isAnonymousBlock() const { - return m_isAnonymous && style()->display() == BLOCK && style()->styleType() == RenderStyle::NOPSEUDO && !isListMarker(); + return m_isAnonymous && style()->display() == BLOCK && style()->styleType() == NOPSEUDO && !isListMarker(); } - + bool isInlineContinuation() const { return (node() ? node()->renderer() != this : false) && isRenderInline(); } bool isFloating() const { return m_floating; } bool isPositioned() const { return m_positioned; } // absolute or fixed positioning bool isRelPositioned() const { return m_relPositioned; } // relative positioning bool isText() const { return m_isText; } + bool isBox() const { return m_isBox; } bool isInline() const { return m_inline; } // inline object - bool isCompact() const { return style()->display() == COMPACT; } // compact object bool isRunIn() const { return style()->display() == RUN_IN; } // run-in object bool isDragging() const { return m_isDragging; } bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS) @@ -340,9 +356,6 @@ public: bool hasBoxDecorations() const { return m_paintBackground; } bool mustRepaintBackgroundOrBorder() const; - bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; } - bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; } - bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; } bool selfNeedsLayout() const { return m_needsLayout; } bool needsPositionedMovementLayout() const { return m_needsPositionedMovementLayout; } @@ -354,43 +367,33 @@ public: bool isSelectionBorder() const; + bool hasClip() const { return isPositioned() && style()->hasClip(); } bool hasOverflowClip() const { return m_hasOverflowClip; } - virtual bool hasControlClip() const { return false; } - virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const { return IntRect(); } - - bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); } - bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); } - - bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } - bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } - bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } - virtual int verticalScrollbarWidth() const; - virtual int horizontalScrollbarHeight() const; - bool hasTransform() const { return m_hasTransform; } bool hasMask() const { return style() && style()->hasMask(); } - virtual IntRect maskClipRect() { return borderBox(); } -private: - bool includeVerticalScrollbarSize() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } - bool includeHorizontalScrollbarSize() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } + void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide, + Color, const Color& textcolor, EBorderStyle, int adjbw1, int adjbw2); + void drawArcForBoxSide(GraphicsContext*, int x, int y, float thickness, IntSize radius, int angleStart, + int angleSpan, BoxSide, Color, const Color& textcolor, EBorderStyle, bool firstCorner); public: // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect // any pseudo classes (and therefore has no concept of changing state). - RenderStyle* getCachedPseudoStyle(RenderStyle::PseudoId, RenderStyle* parentStyle = 0) const; - PassRefPtr<RenderStyle> getUncachedPseudoStyle(RenderStyle::PseudoId, RenderStyle* parentStyle = 0) const; + RenderStyle* getCachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0) const; + PassRefPtr<RenderStyle> getUncachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0) const; - void updateDragState(bool dragOn); + virtual void updateDragState(bool dragOn); RenderView* view() const; - // don't even think about making this method virtual! - Node* element() const { return m_isAnonymous ? 0 : m_node; } + // Returns true if this renderer is rooted, and optionally returns the hosting view (the root of the hierarchy). + bool isRooted(RenderView** = 0); + + Node* node() const { return m_isAnonymous ? 0 : m_node; } Document* document() const { return m_node->document(); } void setNode(Node* node) { m_node = node; } - Node* node() const { return m_node; } bool hasOutlineAnnotation() const; bool hasOutline() const { return style()->hasOutline() || hasOutlineAnnotation(); } @@ -400,16 +403,17 @@ public: * positioned elements */ RenderObject* container() const; - RenderObject* hoverAncestor() const; + virtual RenderObject* hoverAncestor() const { return parent(); } + + // IE Extension that can be called on any RenderObject. See the implementation for the details. + RenderBoxModelObject* offsetParent() const; - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0); void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0); void setNeedsLayout(bool b, bool markParents = true); void setChildNeedsLayout(bool b, bool markParents = true); void setNeedsPositionedMovementLayout(); void setPrefWidthsDirty(bool, bool markParents = true); void invalidateContainerPrefWidths(); - virtual void invalidateCounters() { } void setNeedsLayoutAndPrefWidthsRecalc() { @@ -422,7 +426,8 @@ public: void setFloating(bool b = true) { m_floating = b; } void setInline(bool b = true) { m_inline = b; } void setHasBoxDecorations(bool b = true) { m_paintBackground = b; } - void setRenderText() { m_isText = true; } + void setIsText() { m_isText = true; } + void setIsBox() { m_isBox = true; } void setReplaced(bool b = true) { m_replaced = b; } void setHasOverflowClip(bool b = true) { m_hasOverflowClip = b; } void setHasLayer(bool b = true) { m_hasLayer = b; } @@ -434,37 +439,29 @@ public: void updateFillImages(const FillLayer*, const FillLayer*); void updateImage(StyleImage*, StyleImage*); - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); - virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false); - - // For inline replaced elements, this function returns the inline box that owns us. Enables - // the replaced RenderObject to quickly determine what line it is contained on and to easily - // iterate over structures on the line. - virtual InlineBox* inlineBoxWrapper() const; - virtual void setInlineBoxWrapper(InlineBox*); - virtual void deleteLineBoxWrapper(); - // for discussion of lineHeight see CSS2 spec virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; // for the vertical-align property of inline elements - // the difference between this objects baseline position and the lines baseline position. - virtual int verticalPositionHint(bool firstLine) const; // the offset of baseline from the top of the object. virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; + typedef HashMap<OverlapTestRequestClient*, IntRect> OverlapTestRequestMap; + /* * Paint the object and its children, clipped by (x|y|w|h). * (tx|ty) is the calculated position of the parent */ struct PaintInfo { PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, bool newForceBlackText, - RenderObject* newPaintingRoot, RenderFlowSequencedSet* newOutlineObjects) + RenderObject* newPaintingRoot, ListHashSet<RenderInline*>* newOutlineObjects, + OverlapTestRequestMap* overlapTestRequests = 0) : context(newContext) , rect(newRect) , phase(newPhase) , forceBlackText(newForceBlackText) , paintingRoot(newPaintingRoot) , outlineObjects(newOutlineObjects) + , overlapTestRequests(overlapTestRequests) { } @@ -473,40 +470,14 @@ public: PaintPhase phase; bool forceBlackText; RenderObject* paintingRoot; // used to draw just one element and its visual kids - RenderFlowSequencedSet* outlineObjects; // used to list outlines that should be painted by a block with inline children + ListHashSet<RenderInline*>* outlineObjects; // used to list outlines that should be painted by a block with inline children + OverlapTestRequestMap* overlapTestRequests; }; virtual void paint(PaintInfo&, int tx, int ty); - 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 paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*); - void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true); - - // RenderBox implements this. - virtual void paintBoxDecorations(PaintInfo&, int /*tx*/, int /*ty*/) { } - virtual void paintMask(PaintInfo&, int /*tx*/, int /*ty*/) { } - virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, - int /*clipY*/, int /*clipH*/, int /*tx*/, int /*ty*/, int /*width*/, int /*height*/, - InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver) { } - - - /* - * Calculates the actual width of the object (only for non inline - * objects) - */ - virtual void calcWidth() { } - /* - * This function should cause the Element to calculate its - * width and height and the layout of its content - * - * when the Element calls setNeedsLayout(false), layout() is no - * longer called during relayouts, as long as there is no - * style sheet change. When that occurs, m_needsLayout will be - * set to true and the Element receives layout() calls - * again. - */ - virtual void layout() = 0; + // Recursive function that computes the size and position of this object and all its descendants. + virtual void layout(); /* This function performs a layout only if one is needed. */ void layoutIfNeeded() { if (needsLayout()) layout(); } @@ -519,24 +490,19 @@ public: // repaint and do not need a relayout virtual void updateFromElement() { } - // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) - virtual int availableWidth() const { return contentWidth(); } - - virtual int availableHeight() const { return 0; } - - virtual void updateWidgetPosition(); - #if ENABLE(DASHBOARD_SUPPORT) - void addDashboardRegions(Vector<DashboardRegionValue>&); + virtual void addDashboardRegions(Vector<DashboardRegionValue>&); void collectDashboardRegions(Vector<DashboardRegionValue>&); #endif bool hitTest(const HitTestRequest&, HitTestResult&, const IntPoint&, int tx, int ty, HitTestFilter = HitTestAll); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - void updateHitTestResult(HitTestResult&, const IntPoint&); + virtual void updateHitTestResult(HitTestResult&, const IntPoint&); - virtual VisiblePosition positionForCoordinates(int x, int y); - VisiblePosition positionForPoint(const IntPoint& point) { return positionForCoordinates(point.x(), point.y()); } + VisiblePosition positionForCoordinates(int x, int y); + virtual VisiblePosition positionForPoint(const IntPoint&); + VisiblePosition createVisiblePosition(int offset, EAffinity); + VisiblePosition createVisiblePosition(const Position&); virtual void dirtyLinesFromChangedChild(RenderObject*); @@ -555,186 +521,54 @@ public: // returns the containing block level element for this element. RenderBlock* containingBlock() const; - // return just the width of the containing block - virtual int containingBlockWidth() const; - // return just the height of the containing block - virtual int containingBlockHeight() const; - - // content area (box minus padding/border) - IntRect contentBox() const; - // absolute coords of content area. Ignores transforms. - IntRect absoluteContentBox() const; - // content rect converted to absolute coords, taking transforms into account - FloatQuad absoluteContentQuad() const; - - int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } - int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } - - // used by flexible boxes to impose a flexed width/height override - virtual int overrideSize() const { return 0; } - virtual int overrideWidth() const { return 0; } - virtual int overrideHeight() const { return 0; } - virtual void setOverrideSize(int /*overrideSize*/) { } - - // relative to parent node - virtual void setPos(int /*xPos*/, int /*yPos*/) { } - virtual void setWidth(int /*width*/) { } - virtual void setHeight(int /*height*/) { } - virtual void setRect(const IntRect& rect) { setPos(rect.x(), rect.y()); setWidth(rect.width()); setHeight(rect.height()); } - - virtual int xPos() const { return 0; } - virtual int yPos() const { return 0; } - // Convert the given local point to absolute coordinates // FIXME: Temporary. If useTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware. - virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; - virtual FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const; + FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; + FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const; - // This function is used to deal with the extra top space that can occur in table cells (called borderTopExtra). - // The children of the cell do not factor this space in, so we have to add it in. Any code that wants to - // accurately deal with the contents of a cell must call this function instad of absolutePosition. - FloatPoint localToAbsoluteForContent(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const + // Convert a local quad to absolute coordinates, taking transforms into account. + FloatQuad localToAbsoluteQuad(const FloatQuad& quad, bool fixed = false) const { - localPoint.move(0.0f, static_cast<float>(borderTopExtra())); - return localToAbsolute(localPoint, fixed, useTransforms); + return localToContainerQuad(quad, 0, fixed); } - - // Convert a local quad to an absolute quad, taking transforms into account. - virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const; + // 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; - - // width and height are without margins but include paddings and borders - virtual int width() const { return 0; } - virtual int height() const { return 0; } - - virtual IntRect borderBox() const { return IntRect(0, 0, width(), height()); } - // Bounds of the outline box in absolute coords. Respects transforms - IntRect absoluteOutlineBounds() const; - - // The height of a block when you include normal flow overflow spillage out of the bottom - // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside - // it would have an overflow height of borderTop() + paddingTop() + 100px. - virtual int overflowHeight(bool /*includeInterior*/ = true) const { return height(); } - virtual int overflowWidth(bool /*includeInterior*/ = true) const { return width(); } - virtual void setOverflowHeight(int) { } - virtual void setOverflowWidth(int) { } - virtual int overflowLeft(bool /*includeInterior*/ = true) const { return 0; } - virtual int overflowTop(bool /*includeInterior*/ = true) const { return 0; } - virtual IntRect overflowRect(bool /*includeInterior*/ = true) const { return borderBox(); } - - // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) - // to return the remaining width on a given line (and the height of a single line). - virtual int offsetWidth() const { return width(); } - virtual int offsetHeight() const { return height() + borderTopExtra() + borderBottomExtra(); } - - // IE extensions. Also supported by Gecko. We override in render flow to get the - // left and top correct. -dwh - virtual int offsetLeft() const; - virtual int offsetTop() const; - virtual RenderObject* offsetParent() const; - - // More IE extensions. clientWidth and clientHeight represent the interior of an object - // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth. - int clientLeft() const { return borderLeft(); } - int clientTop() const { return borderTop(); } - int clientWidth() const; - int clientHeight() const; - - // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the - // object has overflow:hidden/scroll/auto specified and also has overflow. - // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like - // textareas can scroll shadow content (but pretend that they are the objects that are - // scrolling). - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); - - virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool canBeProgramaticallyScrolled(bool) const; - virtual void autoscroll(); - virtual void stopAutoscroll() { } - - virtual void panScroll(const IntPoint&); - - virtual bool isScrollable() const; - - // The following seven functions are used to implement collapsing margins. - // All objects know their maximal positive and negative margins. The - // formula for computing a collapsed margin is |maxPosMargin|-|maxNegmargin|. - // For a non-collapsing, e.g., a leaf element, this formula will simply return - // the margin of the element. Blocks override the maxTopMargin and maxBottomMargin - // methods. - virtual bool isSelfCollapsingBlock() const { return false; } - virtual int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); } - virtual int collapsedMarginBottom() const { return maxBottomMargin(true) - maxBottomMargin(false); } - virtual bool isTopMarginQuirk() const { return false; } - virtual bool isBottomMarginQuirk() const { return false; } - - virtual int maxTopMargin(bool positive) const; - virtual int maxBottomMargin(bool positive) const; - - virtual int marginTop() const { return 0; } - virtual int marginBottom() const { return 0; } - virtual int marginLeft() const { return 0; } - virtual int marginRight() const { return 0; } - - // Virtual since table cells override - virtual int paddingTop() const; - virtual int paddingBottom() const; - virtual int paddingLeft() const; - virtual int paddingRight() const; - - virtual int borderTop() const { return style()->borderTopWidth(); } - virtual int borderBottom() const { return style()->borderBottomWidth(); } - virtual int borderTopExtra() const { return 0; } - virtual int borderBottomExtra() const { return 0; } - virtual int borderLeft() const { return style()->borderLeftWidth(); } - virtual int borderRight() const { return style()->borderRightWidth(); } - - virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + + virtual void absoluteRects(Vector<IntRect>&, int, int) { } // FIXME: useTransforms should go away eventually IntRect absoluteBoundingBoxRect(bool useTransforms = false); // Build an array of quads in absolute coords for line boxes - virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&) { } // the rect that will be painted if this object is passed as the paintingRoot IntRect paintingRootRect(IntRect& topLevelRect); - void addPDFURLRect(GraphicsContext*, const IntRect&); - - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - virtual int minPrefWidth() const { return 0; } virtual int maxPrefWidth() const { return 0; } RenderStyle* style() const { return m_style.get(); } - RenderStyle* firstLineStyle() const; + RenderStyle* firstLineStyle() const { return document()->usesFirstLineRules() ? firstLineStyleSlowCase() : style(); } RenderStyle* style(bool firstLine) const { return firstLine ? firstLineStyle() : style(); } - + + // Anonymous blocks that are part of of a continuation chain will return their inline continuation's outline style instead. + // This is typically only relevant when repainting. + virtual RenderStyle* outlineStyleForRepaint() const { return style(); } + void getTextDecorationColors(int decorations, Color& underline, Color& overline, Color& linethrough, bool quirksMode = false); - enum BorderSide { - BSTop, - BSBottom, - BSLeft, - BSRight - }; - - void drawBorderArc(GraphicsContext*, int x, int y, float thickness, IntSize radius, int angleStart, - int angleSpan, BorderSide, Color, const Color& textcolor, EBorderStyle, bool firstCorner); - void drawBorder(GraphicsContext*, int x1, int y1, int x2, int y2, BorderSide, - Color, const Color& textcolor, EBorderStyle, int adjbw1, int adjbw2); - + // Return the RenderBox in the container chain which is responsible for painting this object, or 0 + // if painting is root-relative. This is the container that should be passed to the 'forRepaint' + // methods. + RenderBoxModelObject* containerForRepaint() const; + // Actually do the repaint of rect r for this object which has been computed in the coordinate space + // of repaintContainer. If repaintContainer is 0, repaint via the view. + void repaintUsingContainer(RenderBoxModelObject* repaintContainer, const IntRect& r, bool immediate = false); + // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border // style changes. void repaint(bool immediate = false); @@ -743,7 +577,7 @@ public: void repaintRectangle(const IntRect&, bool immediate = false); // Repaint only if our old bounds and new bounds are different. - bool repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldOutlineBox); + bool repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const IntRect& oldBounds, const IntRect& oldOutlineBox); // Repaint only if the object moved. virtual void repaintDuringLayoutIfMoved(const IntRect& rect); @@ -755,42 +589,38 @@ public: // Returns the rect that should be repainted whenever this object changes. The rect is in the view's // coordinate space. This method deals with outlines and overflow. - virtual IntRect absoluteClippedOverflowRect(); - - IntRect getAbsoluteRepaintRectWithOutline(int ow); + IntRect absoluteClippedOverflowRect() + { + return clippedOverflowRectForRepaint(0); + } + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); - // Given a rect in the object's coordinate space, this method converts the rectangle to the view's - // coordinate space. - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); + // Given a rect in the object's coordinate space, compute a rect suitable for repainting + // that rect in view coordinates. + void computeAbsoluteRepaintRect(IntRect& r, bool fixed = false) + { + return computeRectForRepaint(0, r, fixed); + } + // Given a rect in the object's coordinate space, compute a rect suitable for repainting + // that rect in the coordinate space of repaintContainer. + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); virtual unsigned int length() const { return 1; } bool isFloatingOrPositioned() const { return (isFloating() || isPositioned()); } - virtual bool containsFloats() { return false; } - virtual bool containsFloat(RenderObject*) { return false; } - virtual bool hasOverhangingFloats() { return false; } - virtual bool expandsToEncloseOverhangingFloats() const { return isFloating() && style()->height().isAuto(); } - - virtual void removePositionedObjects(RenderBlock*) { } - - virtual bool avoidsFloats() const; - bool shrinkToAvoidFloats() const; - - // positioning of inline children (bidi) - virtual void position(InlineBox*) { } bool isTransparent() const { return style()->opacity() < 1.0f; } float opacity() const { return style()->opacity(); } bool hasReflection() const { return m_hasReflection; } - IntRect reflectionBox() const; - int reflectionOffset() const; - // Given a rect in the object's coordinate space, returns the corresponding rect in the reflection. - IntRect reflectedRect(const IntRect&) const; // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks. int maximalOutlineSize(PaintPhase) const; + void setHasMarkupTruncation(bool b = true) { m_hasMarkupTruncation = b; } + bool hasMarkupTruncation() const { return m_hasMarkupTruncation; } + enum SelectionState { SelectionNone, // The object is not selected. SelectionStart, // The object either contains the start of a selection run or is the start of a run @@ -801,20 +631,21 @@ public: // The current selection state for an object. For blocks, the state refers to the state of the leaf // descendants (as described above in the SelectionState enum declaration). - virtual SelectionState selectionState() const { return SelectionNone; } + SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState);; } // Sets the selection state for an object. - virtual void setSelectionState(SelectionState state) { if (parent()) parent()->setSelectionState(state); } + virtual void setSelectionState(SelectionState state) { m_selectionState = state; } // A single rectangle that encompasses all of the selected objects within this object. Used to determine the tightest // possible bounding box for the selection. - virtual IntRect selectionRect(bool) { return IntRect(); } + IntRect selectionRect(bool clipToVisibleContent = true) { return selectionRectForRepaint(0, clipToVisibleContent); } + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* /*repaintContainer*/, bool /*clipToVisibleContent*/ = true) { return IntRect(); } // Whether or not an object can be part of the leaf elements of the selection. virtual bool canBeSelectionLeaf() const { return false; } // Whether or not a block has selected children. - virtual bool hasSelectedChildren() const { return false; } + bool hasSelectedChildren() const { return m_selectionState != SelectionNone; } // Obtains the selection colors that should be used when painting a selection. Color selectionBackgroundColor() const; @@ -823,30 +654,6 @@ public: // Whether or not a given block needs to paint selection gaps. virtual bool shouldPaintSelectionGaps() const { return false; } - // This struct is used when the selection changes to cache the old and new state of the selection for each RenderObject. - struct SelectionInfo { - SelectionInfo() - : m_object(0) - , m_state(SelectionNone) - { - } - - SelectionInfo(RenderObject* o, bool clipToVisibleContent) - : m_object(o) - , m_rect(o->needsLayout() ? IntRect() : o->selectionRect(clipToVisibleContent)) - , m_state(o->selectionState()) - { - } - - RenderObject* object() const { return m_object; } - IntRect rect() const { return m_rect; } - SelectionState state() const { return m_state; } - - RenderObject* m_object; - IntRect m_rect; - SelectionState m_state; - }; - Node* draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const; /** @@ -857,12 +664,11 @@ public: */ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - virtual int lowestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; } - virtual int rightmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; } - virtual int leftmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; } - virtual void calcVerticalMargins() { } - void removeFromObjectLists(); + bool isTopMarginQuirk() const { return m_topMarginQuirk; } + bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; } + void setTopMarginQuirk(bool b = true) { m_topMarginQuirk = b; } + void setBottomMarginQuirk(bool b = true) { m_bottomMarginQuirk = b; } // When performing a global document tear-down, the renderer of the document is cleared. We use this // as a hook to detect the case of document destruction and don't waste time doing unnecessary work. @@ -875,21 +681,19 @@ public: virtual bool isFlexingChildren() const { return false; } virtual bool isStretchingChildren() const { return false; } - // Convenience, to avoid repeating the code to dig down to get this. - UChar backslashAsCurrencySymbol() const; - virtual int caretMinOffset() const; virtual int caretMaxOffset() const; virtual unsigned caretMaxRenderedOffset() const; virtual int previousOffset(int current) const; + virtual int previousOffsetForBackwardDeletion(int current) const; virtual int nextOffset(int current) const; virtual void imageChanged(CachedImage*, const IntRect* = 0); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) { } virtual bool willRenderImage(CachedImage*); - virtual void selectionStartEnd(int& spos, int& epos) const; + void selectionStartEnd(int& spos, int& epos) const; RenderObject* paintingRootForChildren(PaintInfo& paintInfo) const { @@ -907,33 +711,79 @@ public: void remove() { if (parent()) parent()->removeChild(this); } - void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } - - virtual void removeLeftoverAnonymousBlock(RenderBlock* child); - - virtual void capsLockStateMayHaveChanged() { } - AnimationController* animation() const; bool visibleToHitTesting() const { return style()->visibility() == VISIBLE && style()->pointerEvents() != PE_NONE; } + + // Map points and quads through elements, potentially via 3d transforms. You should never need to call these directly; use + // localToAbsolute/absoluteToLocal methods instead. + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; + + bool shouldUseTransformFromContainer(const RenderObject* container) const; + void getTransformFromContainer(const RenderObject* container, const IntSize& offsetInContainer, TransformationMatrix&) const; + + virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { }; + + IntRect absoluteOutlineBounds() const + { + return outlineBoundsForRepaint(0); + } + + bool replacedHasOverflow() const { return m_replacedHasOverflow; } + void setReplacedHasOverflow(bool b = true) { m_replacedHasOverflow = b; } protected: // Overrides should call the superclass at the end - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); // Overrides should call the superclass at the start - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - - virtual void printBoxDecorations(GraphicsContext*, int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*tx*/, int /*ty*/) { } + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual IntRect viewRect() const; + void paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*); + void addPDFURLRect(GraphicsContext*, const IntRect&); - int getVerticalPosition(bool firstLine) const; + virtual IntRect viewRect() const; void adjustRectForOutlineAndShadow(IntRect&) const; void arenaDelete(RenderArena*, void* objectBase); + virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const { return IntRect(); } + + class LayoutRepainter { + public: + LayoutRepainter(RenderObject& object, bool checkForRepaint, const IntRect* oldBounds = 0) + : m_object(object) + , m_repaintContainer(0) + , m_checkForRepaint(checkForRepaint) + { + if (m_checkForRepaint) { + m_repaintContainer = m_object.containerForRepaint(); + m_oldBounds = oldBounds ? *oldBounds : m_object.clippedOverflowRectForRepaint(m_repaintContainer); + m_oldOutlineBox = m_object.outlineBoundsForRepaint(m_repaintContainer); + } + } + + // Return true if it repainted. + bool repaintAfterLayout() + { + return m_checkForRepaint ? m_object.repaintAfterLayoutIfNeeded(m_repaintContainer, m_oldBounds, m_oldOutlineBox) : false; + } + + bool checkForRepaint() const { return m_checkForRepaint; } + + private: + RenderObject& m_object; + RenderBoxModelObject* m_repaintContainer; + IntRect m_oldBounds; + IntRect m_oldOutlineBox; + bool m_checkForRepaint; + }; + private: + RenderStyle* firstLineStyleSlowCase() const; + StyleDifference adjustStyleDifference(StyleDifference, unsigned contextSensitiveProperties) const; + RefPtr<RenderStyle> m_style; Node* m_node; @@ -944,9 +794,10 @@ private: #ifndef NDEBUG bool m_hasAXObject; + bool m_setNeedsLayoutForbidden : 1; #endif - mutable int m_verticalPosition; + // 32 bits have been used here. THERE ARE NO FREE BITS AVAILABLE. bool m_needsLayout : 1; bool m_needsPositionedMovementLayout :1; bool m_normalChildNeedsLayout : 1; @@ -961,6 +812,7 @@ private: bool m_isAnonymous : 1; bool m_isText : 1; + bool m_isBox : 1; bool m_inline : 1; bool m_replaced : 1; bool m_isDragging : 1; @@ -977,10 +829,147 @@ public: bool m_everHadLayout : 1; private: + // These bitfields are moved here from subclasses to pack them together + // from RenderBlock + bool m_childrenInline : 1; + bool m_topMarginQuirk : 1; + bool m_bottomMarginQuirk : 1; + bool m_hasMarkupTruncation : 1; + unsigned m_selectionState : 3; // SelectionState + bool m_hasColumns : 1; + + // from RenderTableCell + bool m_cellWidthChanged : 1; + + // from RenderReplaced + bool m_replacedHasOverflow : 1; + +private: // Store state between styleWillChange and styleDidChange static bool s_affectsParentBlock; }; +inline bool RenderObject::documentBeingDestroyed() const +{ + return !document()->renderer(); +} + +inline void RenderObject::setNeedsLayout(bool b, bool markParents) +{ + bool alreadyNeededLayout = m_needsLayout; + m_needsLayout = b; + if (b) { + ASSERT(!isSetNeedsLayoutForbidden()); + if (!alreadyNeededLayout) { + if (markParents) + markContainingBlocksForLayout(); + if (hasLayer()) + setLayerNeedsFullRepaint(); + } + } else { + m_everHadLayout = true; + m_posChildNeedsLayout = false; + m_normalChildNeedsLayout = false; + m_needsPositionedMovementLayout = false; + } +} + +inline void RenderObject::setChildNeedsLayout(bool b, bool markParents) +{ + bool alreadyNeededLayout = m_normalChildNeedsLayout; + m_normalChildNeedsLayout = b; + if (b) { + ASSERT(!isSetNeedsLayoutForbidden()); + if (!alreadyNeededLayout && markParents) + markContainingBlocksForLayout(); + } else { + m_posChildNeedsLayout = false; + m_normalChildNeedsLayout = false; + m_needsPositionedMovementLayout = false; + } +} + +inline void RenderObject::setNeedsPositionedMovementLayout() +{ + bool alreadyNeededLayout = needsLayout(); + m_needsPositionedMovementLayout = true; + if (!alreadyNeededLayout) { + markContainingBlocksForLayout(); + if (hasLayer()) + setLayerNeedsFullRepaint(); + } +} + +inline bool objectIsRelayoutBoundary(const RenderObject *obj) +{ + // FIXME: In future it may be possible to broaden this condition in order to improve performance. + // Table cells are excluded because even when their CSS height is fixed, their height() + // may depend on their contents. + return obj->isTextControl() + || (obj->hasOverflowClip() && !obj->style()->width().isIntrinsicOrAuto() && !obj->style()->height().isIntrinsicOrAuto() && !obj->style()->height().isPercent() && !obj->isTableCell()) +#if ENABLE(SVG) + || obj->isSVGRoot() +#endif + ; +} + +inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot) +{ + ASSERT(!scheduleRelayout || !newRoot); + + RenderObject* o = container(); + RenderObject* last = this; + + while (o) { + // Don't mark the outermost object of an unrooted subtree. That object will be + // marked when the subtree is added to the document. + RenderObject* container = o->container(); + if (!container && !o->isRenderView()) + return; + if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) { + if ((last->style()->top().isAuto() && last->style()->bottom().isAuto()) || last->style()->top().isStatic()) { + RenderObject* parent = last->parent(); + if (!parent->normalChildNeedsLayout()) { + parent->setChildNeedsLayout(true, false); + if (parent != newRoot) + parent->markContainingBlocksForLayout(scheduleRelayout, newRoot); + } + } + if (o->m_posChildNeedsLayout) + return; + o->m_posChildNeedsLayout = true; + ASSERT(!o->isSetNeedsLayoutForbidden()); + } else { + if (o->m_normalChildNeedsLayout) + return; + o->m_normalChildNeedsLayout = true; + ASSERT(!o->isSetNeedsLayoutForbidden()); + } + + if (o == newRoot) + return; + + last = o; + if (scheduleRelayout && objectIsRelayoutBoundary(last)) + break; + o = container; + } + + if (scheduleRelayout) + last->scheduleRelayout(); +} + +inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering) +{ +#if !ENABLE(3D_RENDERING) + UNUSED_PARAM(has3DRendering); + matrix.makeAffine(); +#else + if (!has3DRendering) + matrix.makeAffine(); +#endif +} + } // namespace WebCore #ifndef NDEBUG diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp new file mode 100644 index 0000000..32e856f --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderObjectChildList.h" + +#include "AXObjectCache.h" +#include "RenderBlock.h" +#include "RenderCounter.h" +#include "RenderImageGeneratedContent.h" +#include "RenderInline.h" +#include "RenderLayer.h" +#include "RenderListItem.h" +#include "RenderStyle.h" +#include "RenderTextFragment.h" +#include "RenderView.h" + +namespace WebCore { + +static void updateListMarkerNumbers(RenderObject* child) +{ + for (RenderObject* r = child; r; r = r->nextSibling()) { + if (r->isListItem()) + static_cast<RenderListItem*>(r)->updateValue(); + } +} + + +void RenderObjectChildList::destroyLeftoverChildren() +{ + while (firstChild()) { + if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText())) + firstChild()->remove(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment. + else { + // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields. + if (firstChild()->node()) + firstChild()->node()->setRenderer(0); + firstChild()->destroy(); + } + } +} + +RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) +{ + ASSERT(oldChild->parent() == owner); + + // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or + // that a positioned child got yanked). We also repaint, so that the area exposed when the child + // disappears gets repainted properly. + if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { + oldChild->setNeedsLayoutAndPrefWidthsRecalc(); + oldChild->repaint(); + } + + // If we have a line box wrapper, delete it. + if (oldChild->isBox()) + toRenderBox(oldChild)->deleteLineBoxWrapper(); + + if (!owner->documentBeingDestroyed() && fullRemove) { + // if we remove visible child from an invisible parent, we don't know the layer visibility any more + RenderLayer* layer = 0; + if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { + layer = owner->enclosingLayer(); + layer->dirtyVisibleContentStatus(); + } + + // Keep our layer hierarchy updated. + if (oldChild->firstChild() || oldChild->hasLayer()) { + if (!layer) + layer = owner->enclosingLayer(); + oldChild->removeLayers(layer); + } + + // renumber ordered lists + if (oldChild->isListItem()) + updateListMarkerNumbers(oldChild->nextSibling()); + + if (oldChild->isPositioned() && owner->childrenInline()) + owner->dirtyLinesFromChangedChild(oldChild); + } + + // If oldChild is the start or end of the selection, then clear the selection to + // avoid problems of invalid pointers. + // FIXME: The SelectionController should be responsible for this when it + // is notified of DOM mutations. + if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) + owner->view()->clearSelection(); + + // remove the child + if (oldChild->previousSibling()) + oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); + if (oldChild->nextSibling()) + oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); + + if (firstChild() == oldChild) + setFirstChild(oldChild->nextSibling()); + if (lastChild() == oldChild) + setLastChild(oldChild->previousSibling()); + + oldChild->setPreviousSibling(0); + oldChild->setNextSibling(0); + oldChild->setParent(0); + + if (AXObjectCache::accessibilityEnabled()) + owner->document()->axObjectCache()->childrenChanged(owner); + + return oldChild; +} + +void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend) +{ + ASSERT(newChild->parent() == 0); + ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); + + newChild->setParent(owner); + RenderObject* lChild = lastChild(); + + if (lChild) { + newChild->setPreviousSibling(lChild); + lChild->setNextSibling(newChild); + } else + setFirstChild(newChild); + + setLastChild(newChild); + + if (fullAppend) { + // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children + // and don't have a layer attached to ourselves. + RenderLayer* layer = 0; + if (newChild->firstChild() || newChild->hasLayer()) { + layer = owner->enclosingLayer(); + newChild->addLayers(layer, newChild); + } + + // if the new child is visible but this object was not, tell the layer it has some visible content + // that needs to be drawn and layer visibility optimization can't be used + if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) { + if (!layer) + layer = owner->enclosingLayer(); + if (layer) + layer->setHasVisibleContent(true); + } + + if (!newChild->isFloatingOrPositioned() && owner->childrenInline()) + owner->dirtyLinesFromChangedChild(newChild); + } + + newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. + if (!owner->normalChildNeedsLayout()) + owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. + + if (AXObjectCache::accessibilityEnabled()) + owner->document()->axObjectCache()->childrenChanged(owner); +} + +void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert) +{ + if (!beforeChild) { + appendChildNode(owner, child); + return; + } + + ASSERT(!child->parent()); + while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock()) + beforeChild = beforeChild->parent(); + ASSERT(beforeChild->parent() == owner); + + ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell())); + + if (beforeChild == firstChild()) + setFirstChild(child); + + RenderObject* prev = beforeChild->previousSibling(); + child->setNextSibling(beforeChild); + beforeChild->setPreviousSibling(child); + if (prev) + prev->setNextSibling(child); + child->setPreviousSibling(prev); + + child->setParent(owner); + + if (fullInsert) { + // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children + // and don't have a layer attached to ourselves. + RenderLayer* layer = 0; + if (child->firstChild() || child->hasLayer()) { + layer = owner->enclosingLayer(); + child->addLayers(layer, child); + } + + // if the new child is visible but this object was not, tell the layer it has some visible content + // that needs to be drawn and layer visibility optimization can't be used + if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) { + if (!layer) + layer = owner->enclosingLayer(); + if (layer) + layer->setHasVisibleContent(true); + } + + + if (!child->isFloating() && owner->childrenInline()) + owner->dirtyLinesFromChangedChild(child); + } + + child->setNeedsLayoutAndPrefWidthsRecalc(); + if (!owner->normalChildNeedsLayout()) + owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. + + if (AXObjectCache::accessibilityEnabled()) + owner->document()->axObjectCache()->childrenChanged(owner); +} + +static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type) +{ + if (type == BEFORE) { + RenderObject* first = container; + do { + // Skip list markers. + first = first->firstChild(); + while (first && first->isListMarker()) + first = first->nextSibling(); + } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO); + if (first && first->style()->styleType() != type) + return 0; + return first; + } + if (type == AFTER) { + RenderObject* last = container; + do { + last = last->lastChild(); + } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker()); + if (last && last->style()->styleType() != type) + return 0; + return last; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +static RenderObject* findBeforeAfterParent(RenderObject* object) +{ + // Only table parts need to search for the :before or :after parent + if (!(object->isTable() || object->isTableSection() || object->isTableRow())) + return object; + + RenderObject* beforeAfterParent = object; + while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())) + beforeAfterParent = beforeAfterParent->firstChild(); + return beforeAfterParent; +} + +static void invalidateCountersInContainer(RenderObject* container) +{ + if (!container) + return; + container = findBeforeAfterParent(container); + if (!container) + return; + for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) { + if (content->isCounter()) + static_cast<RenderCounter*>(content)->invalidate(); + } +} + +void RenderObjectChildList::invalidateCounters(RenderObject* owner) +{ + ASSERT(!owner->documentBeingDestroyed()); + invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE)); + invalidateCountersInContainer(beforeAfterContainer(owner, AFTER)); +} + +void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject) +{ + // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. + ASSERT(owner->document()->usesBeforeAfterRules()); + + // In CSS2, before/after pseudo-content cannot nest. Check this first. + if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER) + return; + + if (!styledObject) + styledObject = owner; + + RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); + RenderObject* child = beforeAfterContainer(owner, type); + + // Whether or not we currently have generated content attached. + bool oldContentPresent = child; + + // Whether or not we now want generated content. + bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE; + + // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate + // :after content and not :before content. + if (newContentWanted && type == BEFORE && owner->isRenderInline() && toRenderInline(owner)->isInlineContinuation()) + newContentWanted = false; + + // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, + // then we don't generate the :after content. + if (newContentWanted && type == AFTER && owner->isRenderInline() && toRenderInline(owner)->continuation()) + newContentWanted = false; + + // If we don't want generated content any longer, or if we have generated content, but it's no longer + // identical to the new content data we want to build render objects for, then we nuke all + // of the old generated content. + if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) { + // Nuke the child. + if (child && child->style()->styleType() == type) { + oldContentPresent = false; + child->destroy(); + child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild(); + } + } + + // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we + // have no generated content and can now return. + if (!newContentWanted) + return; + + if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && + !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) + // According to the CSS2 spec (the end of section 12.1), the only allowed + // display values for the pseudo style are NONE and INLINE for inline flows. + // FIXME: CSS2.1 lifted this restriction, but block display types will crash. + // For now we at least relax the restriction to allow all inline types like inline-block + // and inline-table. + pseudoElementStyle->setDisplay(INLINE); + + if (oldContentPresent) { + if (child && child->style()->styleType() == type) { + // We have generated content present still. We want to walk this content and update our + // style information with the new pseudo-element style. + child->setStyle(pseudoElementStyle); + + RenderObject* beforeAfterParent = findBeforeAfterParent(child); + if (!beforeAfterParent) + return; + + // Note that if we ever support additional types of generated content (which should be way off + // in the future), this code will need to be patched. + for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { + if (genChild->isText()) + // Generated text content is a child whose style also needs to be set to the pseudo-element style. + genChild->setStyle(pseudoElementStyle); + else if (genChild->isImage()) { + // Images get an empty style that inherits from the 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); + } + } + return; // We've updated the generated content. That's all we needed to do. + } + + RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0; + + // Generated content consists of a single container that houses multiple children (specified + // by the content property). This generated content container gets the pseudo-element style set on it. + RenderObject* generatedContentContainer = 0; + + // Walk our list of generated content and create render objects for each. + for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { + RenderObject* renderer = 0; + switch (content->type()) { + case CONTENT_NONE: + break; + case CONTENT_TEXT: + renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text()); + renderer->setStyle(pseudoElementStyle); + break; + case CONTENT_OBJECT: { + RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object + RefPtr<RenderStyle> style = RenderStyle::create(); + style->inheritFrom(pseudoElementStyle); + image->setStyle(style.release()); + if (StyleImage* styleImage = content->image()) + image->setStyleImage(styleImage); + renderer = image; + break; + } + case CONTENT_COUNTER: + renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter()); + renderer->setStyle(pseudoElementStyle); + break; + } + + if (renderer) { + if (!generatedContentContainer) { + // Make a generated box that might be any display type now that we are able to drill down into children + // to find the original content properly. + generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); + generatedContentContainer->setStyle(pseudoElementStyle); + owner->addChild(generatedContentContainer, insertBefore); + } + generatedContentContainer->addChild(renderer); + } + } +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h new file mode 100644 index 0000000..bf8800a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderObjectChildList.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderObjectChildList_h +#define RenderObjectChildList_h + +#include "RenderStyleConstants.h" + +namespace WebCore { + +class RenderObject; + +class RenderObjectChildList { +public: + RenderObjectChildList() + : m_firstChild(0) + , m_lastChild(0) + { + } + + RenderObject* firstChild() const { return m_firstChild; } + RenderObject* lastChild() const { return m_lastChild; } + + // FIXME: Temporary while RenderBox still exists. Eventually this will just happen during insert/append/remove methods on the child list, and nobody + // will need to manipulate firstChild or lastChild directly. + void setFirstChild(RenderObject* child) { m_firstChild = child; } + void setLastChild(RenderObject* child) { m_lastChild = child; } + + void destroyLeftoverChildren(); + + RenderObject* removeChildNode(RenderObject* owner, RenderObject*, bool fullRemove = true); + void appendChildNode(RenderObject* owner, RenderObject*, bool fullAppend = true); + void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool fullInsert = true); + + void updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject = 0); + void invalidateCounters(RenderObject* owner); + +private: + RenderObject* m_firstChild; + RenderObject* m_lastChild; +}; + +} // namespace WebCore + +#endif // RenderObjectChildList_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp index d840418..bcf9ef9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp @@ -1,10 +1,8 @@ -/** - * 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) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,22 +20,16 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "RenderPart.h" -#include "Document.h" #include "Frame.h" -#include "FrameTree.h" #include "FrameView.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLNames.h" -#include "Page.h" namespace WebCore { -using namespace HTMLNames; - -RenderPart::RenderPart(HTMLFrameOwnerElement* node) +RenderPart::RenderPart(Element* node) : RenderWidget(node) { // init RenderObject attributes @@ -46,71 +38,37 @@ RenderPart::RenderPart(HTMLFrameOwnerElement* node) RenderPart::~RenderPart() { - // Since deref ends up calling setWidget back on us, need to make sure - // that widget is already 0 so it won't do any work. - Widget* widget = m_widget; - m_widget = 0; - if (widget && widget->isFrameView()) - static_cast<FrameView*>(widget)->deref(); - else - delete widget; + clearWidget(); } void RenderPart::setWidget(Widget* widget) { - if (widget != m_widget) { - if (widget && widget->isFrameView()) - static_cast<FrameView*>(widget)->ref(); - RenderWidget::setWidget(widget); + if (widget == this->widget()) + return; - // make sure the scrollbars are set correctly for restore - // ### find better fix - viewCleared(); - } -} + if (widget && widget->isFrameView()) + static_cast<FrameView*>(widget)->ref(); + RenderWidget::setWidget(widget); -void RenderPart::viewCleared() -{ + // make sure the scrollbars are set correctly for restore + // ### find better fix + viewCleared(); } -void RenderPart::deleteWidget() +void RenderPart::viewCleared() { - if (m_widget && m_widget->isFrameView()) - static_cast<FrameView*>(m_widget)->deref(); - else - delete m_widget; } -// FIXME: This should not be necessary. Remove this once WebKit knows to properly schedule -// layouts using WebCore when objects resize. -void RenderPart::updateWidgetPosition() +void RenderPart::deleteWidget(Widget* widget) { - if (!m_widget) - return; - - int width, height; - FloatPoint absPos = localToAbsolute(); - absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); - width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); - IntRect newBounds(absPos.x(), absPos.y(), width, height); - bool boundsChanged = newBounds != m_widget->frameRect(); - if (boundsChanged) { - // The widget changed positions. Update the frame geometry. - RenderArena *arena = ref(); - element()->ref(); - m_widget->setFrameRect(newBounds); - element()->deref(); - deref(arena); - } + // Since deref ends up calling setWidget back on us, need to make sure + // that widget is already 0 so it won't do any work. + ASSERT(!this->widget()); - // 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 && m_widget->isFrameView()) { - FrameView* frameView = static_cast<FrameView*>(m_widget); - if (boundsChanged || frameView->needsLayout()) - frameView->layout(); - } + if (widget && widget->isFrameView()) + static_cast<FrameView*>(widget)->deref(); + else + delete widget; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.h b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h index e339468..e47ead0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPart.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h @@ -1,9 +1,7 @@ /* - * This file is part of the KDE project. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,32 +27,24 @@ namespace WebCore { -class Frame; -class HTMLFrameOwnerElement; - class RenderPart : public RenderWidget { public: - RenderPart(HTMLFrameOwnerElement*); + RenderPart(Element*); virtual ~RenderPart(); - virtual bool isRenderPart() const { return true; } - virtual const char* renderName() const { return "RenderPart"; } - - virtual void setWidget(Widget*); - - // FIXME: This should not be necessary. - // Remove this once WebKit knows to properly schedule layouts using WebCore when objects resize. - virtual void updateWidgetPosition(); - bool hasFallbackContent() const { return m_hasFallbackContent; } + virtual void setWidget(Widget*); virtual void viewCleared(); protected: bool m_hasFallbackContent; private: - virtual void deleteWidget(); + virtual bool isRenderPart() const { return true; } + virtual const char* renderName() const { return "RenderPart"; } + + virtual void deleteWidget(Widget*); }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp index e5200e2..7a3aa64 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp @@ -2,7 +2,7 @@ * 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 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,10 +25,7 @@ #include "RenderPartObject.h" #include "Frame.h" -#include "FrameLoader.h" #include "FrameLoaderClient.h" -#include "FrameTree.h" -#include "FrameView.h" #include "HTMLEmbedElement.h" #include "HTMLIFrameElement.h" #include "HTMLNames.h" @@ -40,11 +37,15 @@ #include "RenderView.h" #include "Text.h" +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) +#include "HTMLVideoElement.h" +#endif + namespace WebCore { using namespace HTMLNames; -RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element) +RenderPartObject::RenderPartObject(Element* element) : RenderPart(element) { // init RenderObject attributes @@ -57,8 +58,8 @@ RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element) RenderPartObject::~RenderPartObject() { - if (m_view) - m_view->removeWidgetToUpdate(this); + if (frameView()) + frameView()->removeWidgetToUpdate(this); } static bool isURLAllowed(Document* doc, const String& url) @@ -80,46 +81,83 @@ static bool isURLAllowed(Document* doc, const String& url) return true; } -static inline void mapClassIdToServiceType(const String& classId, String& serviceType, const PluginData* pluginData) +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"); +#if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER) + map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2"); + map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2"); +#endif + return map; +} + +static const String& activeXType() +{ + DEFINE_STATIC_LOCAL(String, activeXType, ("application/x-oleobject")); + return activeXType; +} + +static inline bool havePlugin(const PluginData* pluginData, const String& type) +{ + return pluginData && !type.isEmpty() && pluginData->supportsMimeType(type); +} + +static String serviceTypeForClassId(const String& classId, const PluginData* pluginData) { // 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; - - typedef HashMap<String, String, CaseFoldingHash> ServiceTypeHashMap; - static ServiceTypeHashMap* serviceTypeFallbackForClassId = 0; - if (!serviceTypeFallbackForClassId) { - serviceTypeFallbackForClassId = new ServiceTypeHashMap; - serviceTypeFallbackForClassId->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash"); - serviceTypeFallbackForClassId->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin"); - serviceTypeFallbackForClassId->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime"); - serviceTypeFallbackForClassId->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director"); -#if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER) - serviceTypeFallbackForClassId->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2"); - serviceTypeFallbackForClassId->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2"); -#endif - } + return String(); + + static ClassIdToTypeMap* map = createClassIdToTypeMap(); + String type = map->get(classId); - const String fallbackServiceType = serviceTypeFallbackForClassId->get(classId); - if (pluginData->supportsMimeType(fallbackServiceType)) - serviceType = fallbackServiceType; - else if (pluginData->supportsMimeType("application/x-oleobject")) - serviceType = "application/x-oleobject"; + // If we do have a plug-in that supports generic ActiveX content and don't have a plug-in + // for the MIME type we came up with, ignore the MIME type we came up with and just use + // the ActiveX type. + if (havePlugin(pluginData, activeXType()) && !havePlugin(pluginData, type)) + return activeXType(); + + return type; } -static bool shouldUseChildEmbedOfObject(HTMLObjectElement* o, const PluginData* pluginData) +static inline bool shouldUseEmbedDescendant(HTMLObjectElement* objectElement, const PluginData* pluginData) { - // An OBJECT tag with a classId is some kind of ActiveX control. The most - // common controls have parallel plugin versions and thus possibly nested - // EMBED tags. If this is the case, the OBJECT's classId should map to some - // known plugin MIME type. If it doesn't, either the control is unlikely to - // have a parallel plugin implementation (so there's no point looking - // inside), or we've purposefully disabled conversion for this classId, in - // which case we want to use the ActiveX OBJECT instead of the EMBED anyway. - String serviceType; - mapClassIdToServiceType(o->classId(), serviceType, pluginData); - return serviceType != "application/x-oleobject"; +#if PLATFORM(MAC) + UNUSED_PARAM(objectElement); + UNUSED_PARAM(pluginData); + // On Mac, we always want to use the embed descendant. + return true; +#else + // If we have both an <object> and <embed>, we always want to use the <embed> except when we have + // an ActiveX plug-in and plan to use it. + return !(havePlugin(pluginData, activeXType()) + && serviceTypeForClassId(objectElement->classId(), pluginData) == activeXType()); +#endif +} + +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 RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) @@ -128,10 +166,10 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) String serviceType; Vector<String> paramNames; Vector<String> paramValues; - Frame* frame = m_view->frame(); + Frame* frame = frameView()->frame(); - if (element()->hasTagName(objectTag)) { - HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element()); + if (node()->hasTagName(objectTag)) { + HTMLObjectElement* o = static_cast<HTMLObjectElement*>(node()); o->setNeedWidgetUpdate(false); if (!o->isFinishedParsingChildren()) @@ -140,8 +178,8 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) // Check for a child EMBED tag. HTMLEmbedElement* embed = 0; const PluginData* pluginData = frame->page()->pluginData(); - if (pluginData && shouldUseChildEmbedOfObject(o, pluginData)) { - for (Node* child = o->firstChild(); child;) { + if (shouldUseEmbedDescendant(o, pluginData)) { + for (Node* child = o->firstChild(); child; ) { if (child->hasTagName(embedTag)) { embed = static_cast<HTMLEmbedElement*>(child); break; @@ -206,7 +244,7 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) } // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. - NamedAttrMap* attributes = embedOrObject->attributes(); + NamedNodeMap* attributes = embedOrObject->attributes(); if (attributes) { for (unsigned i = 0; i < attributes->length(); ++i) { Attribute* it = attributes->attributeItem(i); @@ -218,9 +256,11 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) } } + mapDataParamToSrc(¶mNames, ¶mValues); + // If we still don't have a type, try to map from a specific CLASSID to a type. - if (pluginData && serviceType.isEmpty()) - mapClassIdToServiceType(o->classId(), serviceType, pluginData); + if (serviceType.isEmpty()) + serviceType = serviceTypeForClassId(o->classId(), pluginData); if (!isURLAllowed(document(), url)) return; @@ -245,8 +285,8 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues); if (!success && m_hasFallbackContent) o->renderFallbackContent(); - } else if (element()->hasTagName(embedTag)) { - HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element()); + } else if (node()->hasTagName(embedTag)) { + HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(node()); o->setNeedWidgetUpdate(false); url = o->url(); serviceType = o->serviceType(); @@ -257,7 +297,7 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) return; // add all attributes set on the embed object - NamedAttrMap* a = o->attributes(); + NamedNodeMap* a = o->attributes(); if (a) { for (unsigned i = 0; i < a->length(); ++i) { Attribute* it = a->attributeItem(i); @@ -278,6 +318,30 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) 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"; + frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues); + } +#endif } void RenderPartObject::layout() @@ -286,24 +350,24 @@ void RenderPartObject::layout() calcWidth(); calcHeight(); - adjustOverflowForBoxShadow(); + adjustOverflowForBoxShadowAndReflect(); RenderPart::layout(); - if (!m_widget && m_view) - m_view->addWidgetToUpdate(this); + if (!widget() && frameView()) + frameView()->addWidgetToUpdate(this); setNeedsLayout(false); } void RenderPartObject::viewCleared() { - if (element() && m_widget && m_widget->isFrameView()) { - FrameView* view = static_cast<FrameView*>(m_widget); + if (node() && widget() && widget()->isFrameView()) { + FrameView* view = static_cast<FrameView*>(widget()); int marginw = -1; int marginh = -1; - if (element()->hasTagName(iframeTag)) { - HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(element()); + if (node()->hasTagName(iframeTag)) { + HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node()); marginw = frame->getMarginWidth(); marginh = frame->getMarginHeight(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h index 98de5b9..2159d3c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h @@ -1,9 +1,7 @@ /* - * This file is part of the KDE project. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,13 +29,15 @@ namespace WebCore { class RenderPartObject : public RenderPart { public: - RenderPartObject(HTMLFrameOwnerElement*); + RenderPartObject(Element*); virtual ~RenderPartObject(); + void updateWidget(bool onlyCreateNonNetscapePlugins); + +private: virtual const char* renderName() const { return "RenderPartObject"; } virtual void layout(); - void updateWidget(bool onlyCreateNonNetscapePlugins); virtual void viewCleared(); }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp index e595745..4a7662f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp @@ -2,8 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2008 Rob Buis <buis@kde.org> 2005, 2007 Eric Seidel <eric@webkit.org> - - This file is part of the KDE project + 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 @@ -26,9 +25,8 @@ #if ENABLE(SVG) #include "RenderPath.h" -#include <math.h> - #include "FloatPoint.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" #include "RenderSVGContainer.h" @@ -41,7 +39,6 @@ #include "SVGStyledTransformableElement.h" #include "SVGTransformList.h" #include "SVGURIReference.h" - #include <wtf/MathExtras.h> namespace WebCore { @@ -66,16 +63,14 @@ private: RenderStyle* m_style; }; -// RenderPath -RenderPath::RenderPath(RenderStyle* style, SVGStyledTransformableElement* node) - : RenderObject(node) +RenderPath::RenderPath(SVGStyledTransformableElement* node) + : RenderSVGModelObject(node) { - ASSERT(style != 0); - ASSERT(static_cast<SVGElement*>(node)->isStyledTransformable()); } -RenderPath::~RenderPath() +TransformationMatrix RenderPath::localToParentTransform() const { + return m_localTransform; } TransformationMatrix RenderPath::localTransform() const @@ -83,16 +78,6 @@ TransformationMatrix RenderPath::localTransform() const return m_localTransform; } -FloatPoint RenderPath::mapAbsolutePointToLocal(const FloatPoint& point) const -{ - // FIXME: does it make sense to map incoming points with the inverse of the - // absolute transform? - double localX; - double localY; - absoluteTransform().inverse().map(point.x(), point.y(), &localX, &localY); - return FloatPoint::narrowPrecision(localX, localY); -} - bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const { if (m_path.isEmpty()) @@ -104,110 +89,74 @@ bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const return m_path.contains(point, style()->svgStyle()->fillRule()); } -FloatRect RenderPath::relativeBBox(bool includeStroke) const +bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) const { if (m_path.isEmpty()) - return FloatRect(); - - if (includeStroke) { - if (m_strokeBbox.isEmpty()) { - if (style()->svgStyle()->hasStroke()) { - BoundingRectStrokeStyleApplier strokeStyle(this, style()); - m_strokeBbox = m_path.strokeBoundingRect(&strokeStyle); - } else { - if (m_fillBBox.isEmpty()) - m_fillBBox = m_path.boundingRect(); - - m_strokeBbox = m_fillBBox; - } - } - - return m_strokeBbox; - } + return false; - if (m_fillBBox.isEmpty()) - m_fillBBox = m_path.boundingRect(); + if (requiresStroke && !SVGPaintServer::strokePaintServer(style(), this)) + return false; - return m_fillBBox; + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + return m_path.strokeContains(&strokeStyle, point); } -void RenderPath::setPath(const Path& newPath) +FloatRect RenderPath::objectBoundingBox() const { - m_path = newPath; - m_strokeBbox = FloatRect(); - m_fillBBox = FloatRect(); -} + if (m_path.isEmpty()) + return FloatRect(); -const Path& RenderPath::path() const -{ - return m_path; -} + if (m_cachedLocalFillBBox.isEmpty()) + m_cachedLocalFillBBox = m_path.boundingRect(); -bool RenderPath::calculateLocalTransform() -{ - TransformationMatrix oldTransform = m_localTransform; - m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); - return (m_localTransform != oldTransform); + return m_cachedLocalFillBBox; } -void RenderPath::layout() +FloatRect RenderPath::repaintRectInLocalCoordinates() const { - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); - if (checkForRepaint) { - oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBounds(); - } - - calculateLocalTransform(); - - setPath(static_cast<SVGStyledTransformableElement*>(element())->toPathData()); + if (m_path.isEmpty()) + return FloatRect(); - m_absoluteBounds = absoluteClippedOverflowRect(); + // If we already have a cached repaint rect, return that + if (!m_cachedLocalRepaintRect.isEmpty()) + return m_cachedLocalRepaintRect; - setWidth(m_absoluteBounds.width()); - setHeight(m_absoluteBounds.height()); + if (!style()->svgStyle()->hasStroke()) + m_cachedLocalRepaintRect = objectBoundingBox(); + else { + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + m_cachedLocalRepaintRect = m_path.strokeBoundingRect(&strokeStyle); + } - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + // Markers and filters can paint outside of the stroke path + m_cachedLocalRepaintRect.unite(m_markerBounds); + m_cachedLocalRepaintRect.unite(filterBoundingBoxForRenderer(this)); - setNeedsLayout(false); + return m_cachedLocalRepaintRect; } -IntRect RenderPath::absoluteClippedOverflowRect() +void RenderPath::setPath(const Path& newPath) { - FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true)); - - // Markers can expand the bounding box - repaintRect.unite(m_markerBounds); - -#if ENABLE(SVG_FILTERS) - // Filters can expand the bounding box - SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter()); - if (filter) - repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect)); -#endif - - if (!repaintRect.isEmpty()) - repaintRect.inflate(1); // inflate 1 pixel for antialiasing - - return enclosingIntRect(repaintRect); + m_path = newPath; + m_cachedLocalRepaintRect = FloatRect(); + m_cachedLocalFillBBox = FloatRect(); } -bool RenderPath::requiresLayer() +const Path& RenderPath::path() const { - return false; + return m_path; } -int RenderPath::lineHeight(bool, bool) const +void RenderPath::layout() { - return relativeBBox(true).height(); -} + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); -int RenderPath::baselinePosition(bool, bool) const -{ - return relativeBBox(true).height(); + SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node()); + m_localTransform = element->animatedLocalTransform(); + setPath(element->toPathData()); + + repainter.repaintAfterLayout(); + setNeedsLayout(false); } static inline void fillAndStrokePath(const Path& path, GraphicsContext* context, RenderStyle* style, RenderPath* object) @@ -233,23 +182,23 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) return; paintInfo.context->save(); - paintInfo.context->concatCTM(localTransform()); + paintInfo.context->concatCTM(localToParentTransform()); SVGResourceFilter* filter = 0; - FloatRect boundingBox = relativeBBox(true); + FloatRect boundingBox = repaintRectInLocalCoordinates(); if (paintInfo.phase == PaintPhaseForeground) { PaintInfo savedInfo(paintInfo); prepareToRenderSVGContent(this, paintInfo, boundingBox, filter); if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) - paintInfo.context->setUseAntialiasing(false); + paintInfo.context->setShouldAntialias(false); fillAndStrokePath(m_path, paintInfo.context, style(), this); - if (static_cast<SVGStyledElement*>(element())->supportsMarkers()) + if (static_cast<SVGStyledElement*>(node())->supportsMarkers()) m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path); - finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context); + finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) @@ -259,37 +208,28 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) paintInfo.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) { - graphicsContext->addFocusRingRect(enclosingIntRect(relativeBBox(true))); + graphicsContext->addFocusRingRect(enclosingIntRect(repaintRectInLocalCoordinates())); } -void RenderPath::absoluteRects(Vector<IntRect>& rects, int, int, bool) -{ - rects.append(absoluteClippedOverflowRect()); -} - -void RenderPath::absoluteQuads(Vector<FloatQuad>& quads, bool) -{ - quads.append(absoluteClippedOverflowRect()); -} - -bool RenderPath::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) +bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // We only draw in the forground phase, so we only hit-test then. if (hitTestAction != HitTestForeground) return false; - - IntPoint absolutePoint(_x, _y); + + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { - FloatPoint hitPoint = mapAbsolutePointToLocal(absolutePoint); - if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke) && strokeContains(hitPoint, hitRules.requireStroke)) - || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill) && fillContains(hitPoint, hitRules.requireFill))) { - updateHitTestResult(result, absolutePoint); + if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke)) + || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill))) { + updateHitTestResult(result, roundedIntPoint(localPoint)); return true; } } @@ -421,7 +361,7 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR { Document* doc = document(); - SVGElement* svgElement = static_cast<SVGElement*>(element()); + SVGElement* svgElement = static_cast<SVGElement*>(node()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.h b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h index e96439d..a4aefed 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderPath.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h @@ -3,8 +3,7 @@ 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> 2006 Apple Computer, Inc - - This file is part of the KDE project + 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 @@ -27,64 +26,51 @@ #if ENABLE(SVG) -#include "TransformationMatrix.h" #include "FloatRect.h" - -#include "RenderObject.h" +#include "RenderSVGModelObject.h" +#include "TransformationMatrix.h" namespace WebCore { class FloatPoint; -class Path; class RenderSVGContainer; class SVGStyledTransformableElement; -class RenderPath : public RenderObject -{ +class RenderPath : public RenderSVGModelObject { public: - RenderPath(RenderStyle*, SVGStyledTransformableElement*); - virtual ~RenderPath(); + RenderPath(SVGStyledTransformableElement*); // Hit-detection seperated for the fill and the stroke bool fillContains(const FloatPoint&, bool requiresFill = true) const; bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; - // Returns an unscaled bounding box (not even including localTransform()) for this vector path - virtual FloatRect relativeBBox(bool includeStroke = true) const; + virtual FloatRect objectBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; + + virtual TransformationMatrix localToParentTransform() const; const Path& path() const; - void setPath(const Path& newPath); + void setPath(const Path&); virtual bool isRenderPath() const { return true; } virtual const char* renderName() const { return "RenderPath"; } - - bool calculateLocalTransform(); - virtual TransformationMatrix localTransform() const; - + virtual void layout(); - virtual IntRect absoluteClippedOverflowRect(); - virtual bool requiresLayer(); - virtual int lineHeight(bool b, bool isRootLineBox = false) const; - virtual int baselinePosition(bool b, bool isRootLineBox = false) const; virtual void paint(PaintInfo&, int parentX, int parentY); - - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - 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); FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const; - + private: - FloatPoint mapAbsolutePointToLocal(const FloatPoint&) const; + virtual TransformationMatrix localTransform() const; mutable Path m_path; - mutable FloatRect m_fillBBox; - mutable FloatRect m_strokeBbox; + mutable FloatRect m_cachedLocalFillBBox; + mutable FloatRect m_cachedLocalRepaintRect; FloatRect m_markerBounds; TransformationMatrix m_localTransform; - IntRect m_absoluteBounds; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp index 79df0f1..e61ac8e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp @@ -28,6 +28,7 @@ #include "RenderLayer.h" #include "RenderTheme.h" #include "RenderView.h" +#include "VisiblePosition.h" using namespace std; @@ -42,8 +43,6 @@ const int cDefaultHeight = 150; RenderReplaced::RenderReplaced(Node* node) : RenderBox(node) , m_intrinsicSize(cDefaultWidth, cDefaultHeight) - , m_selectionState(SelectionNone) - , m_hasOverflow(false) { setReplaced(true); } @@ -51,19 +50,17 @@ RenderReplaced::RenderReplaced(Node* node) RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize) : RenderBox(node) , m_intrinsicSize(intrinsicSize) - , m_selectionState(SelectionNone) - , m_hasOverflow(false) { setReplaced(true); } RenderReplaced::~RenderReplaced() { - if (m_hasOverflow) + if (replacedHasOverflow()) gOverflowRectMap->remove(this); } -void RenderReplaced::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderReplaced::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBox::styleDidChange(diff, oldStyle); @@ -77,23 +74,16 @@ void RenderReplaced::layout() { ASSERT(needsLayout()); - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - m_height = minimumReplacedHeight(); + setHeight(minimumReplacedHeight()); calcWidth(); calcHeight(); - adjustOverflowForBoxShadow(); - - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + adjustOverflowForBoxShadowAndReflect(); + repainter.repaintAfterLayout(); + setNeedsLayout(false); } @@ -110,8 +100,8 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) if (!shouldPaint(paintInfo, tx, ty)) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); @@ -137,8 +127,25 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) drawSelectionTint = false; } + bool clipToBorderRadius = style()->overflowX() != OVISIBLE && style()->hasBorderRadius(); + if (clipToBorderRadius) { + // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. + paintInfo.context->save(); + + IntSize topLeft, topRight, bottomLeft, bottomRight; + IntRect borderRect = IntRect(tx, ty, width(), height()); + style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight); + + paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight); + } + paintReplaced(paintInfo, tx, ty); - + + if (clipToBorderRadius) + paintInfo.context->restore(); + + // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of + // surrounding content. if (drawSelectionTint) { IntRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.move(tx, ty); @@ -159,8 +166,8 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) if (style()->visibility() != VISIBLE) return false; - int currentTX = tx + m_x; - int currentTY = ty + m_y; + int currentTX = tx + x(); + int currentTY = ty + y(); // Early exit if the element touches the edges. int top = currentTY + overflowTop(); @@ -215,11 +222,11 @@ unsigned RenderReplaced::caretMaxRenderedOffset() const return 1; } -VisiblePosition RenderReplaced::positionForCoordinates(int x, int y) +VisiblePosition RenderReplaced::positionForPoint(const IntPoint& point) { InlineBox* box = inlineBoxWrapper(); if (!box) - return VisiblePosition(element(), 0, DOWNSTREAM); + return createVisiblePosition(0, DOWNSTREAM); // FIXME: This code is buggy if the replaced element is relative positioned. @@ -228,22 +235,22 @@ VisiblePosition RenderReplaced::positionForCoordinates(int x, int y) int top = root->topOverflow(); int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow(); - if (y + yPos() < top) - return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); // coordinates are above + if (point.y() + y() < top) + return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above - if (y + yPos() >= bottom) - return VisiblePosition(element(), caretMaxOffset(), DOWNSTREAM); // coordinates are below + if (point.y() + y() >= bottom) + return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below - if (element()) { - if (x <= width() / 2) - return VisiblePosition(element(), 0, DOWNSTREAM); - return VisiblePosition(element(), 1, DOWNSTREAM); + if (node()) { + if (point.x() <= width() / 2) + return createVisiblePosition(0, DOWNSTREAM); + return createVisiblePosition(1, DOWNSTREAM); } - return RenderBox::positionForCoordinates(x, y); + return RenderBox::positionForPoint(point); } -IntRect RenderReplaced::selectionRect(bool clipToVisibleContent) +IntRect RenderReplaced::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); @@ -252,11 +259,9 @@ IntRect RenderReplaced::selectionRect(bool clipToVisibleContent) IntRect rect = localSelectionRect(); if (clipToVisibleContent) - computeAbsoluteRepaintRect(rect); - else { - FloatPoint absPos = localToAbsoluteForContent(FloatPoint()); - rect.move(absPos.x(), absPos.y()); - } + computeRectForRepaint(repaintContainer, rect); + else + rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); return rect; } @@ -268,19 +273,19 @@ IntRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const if (!m_inlineBoxWrapper) // We're a block-level replaced element. Just return our own dimensions. - return IntRect(0, 0, width(), height() + borderTopExtra() + borderBottomExtra()); + return IntRect(0, 0, width(), height()); RenderBlock* cb = containingBlock(); if (!cb) return IntRect(); RootInlineBox* root = m_inlineBoxWrapper->root(); - return IntRect(0, root->selectionTop() - yPos(), width(), root->selectionHeight()); + return IntRect(0, root->selectionTop() - y(), width(), root->selectionHeight()); } void RenderReplaced::setSelectionState(SelectionState s) { - m_selectionState = s; + RenderBox::setSelectionState(s); if (m_inlineBoxWrapper) { RootInlineBox* line = m_inlineBoxWrapper->root(); if (line) @@ -303,7 +308,7 @@ bool RenderReplaced::isSelected() const if (s == SelectionStart) return selectionStart == 0; - int end = element()->hasChildNodes() ? element()->childNodeCount() : 1; + int end = node()->hasChildNodes() ? node()->childNodeCount() : 1; if (s == SelectionEnd) return selectionEnd == end; if (s == SelectionBoth) @@ -323,31 +328,39 @@ void RenderReplaced::setIntrinsicSize(const IntSize& size) m_intrinsicSize = size; } -void RenderReplaced::adjustOverflowForBoxShadow() +void RenderReplaced::adjustOverflowForBoxShadowAndReflect() { IntRect overflow; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - IntRect shadow = borderBox(); + IntRect shadow = borderBoxRect(); shadow.move(boxShadow->x, boxShadow->y); shadow.inflate(boxShadow->blur); overflow.unite(shadow); } + // Now that we have an overflow rect including shadow, let's make sure that + // the reflection (which can also include the shadow) is also included. + if (hasReflection()) { + if (overflow.isEmpty()) + overflow = borderBoxRect(); + overflow.unite(reflectedRect(overflow)); + } + if (!overflow.isEmpty()) { if (!gOverflowRectMap) gOverflowRectMap = new OverflowRectMap(); - overflow.unite(borderBox()); + overflow.unite(borderBoxRect()); gOverflowRectMap->set(this, overflow); - m_hasOverflow = true; - } else if (m_hasOverflow) { + setReplacedHasOverflow(true); + } else if (replacedHasOverflow()) { gOverflowRectMap->remove(this); - m_hasOverflow = false; + setReplacedHasOverflow(false); } } int RenderReplaced::overflowHeight(bool) const { - if (m_hasOverflow) { + if (replacedHasOverflow()) { IntRect *r = &gOverflowRectMap->find(this)->second; return r->height() + r->y(); } @@ -357,7 +370,7 @@ int RenderReplaced::overflowHeight(bool) const int RenderReplaced::overflowWidth(bool) const { - if (m_hasOverflow) { + if (replacedHasOverflow()) { IntRect *r = &gOverflowRectMap->find(this)->second; return r->width() + r->x(); } @@ -367,7 +380,7 @@ int RenderReplaced::overflowWidth(bool) const int RenderReplaced::overflowLeft(bool) const { - if (m_hasOverflow) + if (replacedHasOverflow()) return gOverflowRectMap->get(this).x(); return 0; @@ -375,7 +388,7 @@ int RenderReplaced::overflowLeft(bool) const int RenderReplaced::overflowTop(bool) const { - if (m_hasOverflow) + if (replacedHasOverflow()) return gOverflowRectMap->get(this).y(); return 0; @@ -383,24 +396,27 @@ int RenderReplaced::overflowTop(bool) const IntRect RenderReplaced::overflowRect(bool) const { - if (m_hasOverflow) + if (replacedHasOverflow()) return gOverflowRectMap->find(this)->second; - return borderBox(); + return borderBoxRect(); } -IntRect RenderReplaced::absoluteClippedOverflowRect() +IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return IntRect(); - // The selectionRect can project outside of the overflowRect, so use - // that for repainting to avoid selection painting glitches - IntRect r = localSelectionRect(false); + // The selectionRect can project outside of the overflowRect, so take their union + // for repainting to avoid selection painting glitches. + IntRect r = unionRect(localSelectionRect(false), overflowRect(false)); RenderView* v = view(); - if (v) + if (v) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); + } if (style()) { if (style()->hasAppearance()) @@ -409,7 +425,7 @@ IntRect RenderReplaced::absoluteClippedOverflowRect() if (v) r.inflate(style()->outlineSize()); } - computeAbsoluteRepaintRect(r); + computeRectForRepaint(repaintContainer, r); return r; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h index 3186718..4937446 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h @@ -34,6 +34,8 @@ public: virtual const char* renderName() const { return "RenderReplaced"; } + virtual bool canHaveChildren() const { return false; } + virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; @@ -53,33 +55,29 @@ public: virtual int overflowTop(bool includeInterior = true) const; virtual IntRect overflowRect(bool includeInterior = true) const; - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual unsigned caretMaxRenderedOffset() const; - virtual VisiblePosition positionForCoordinates(int x, int y); + virtual VisiblePosition positionForPoint(const IntPoint&); virtual bool canBeSelectionLeaf() const { return true; } - virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); } virtual void setSelectionState(SelectionState); - virtual IntRect selectionRect(bool clipToVisibleContent = true); + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); bool isSelected() const; protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); void setIntrinsicSize(const IntSize&); virtual void intrinsicSizeChanged(); bool shouldPaint(PaintInfo&, int& tx, int& ty); - void adjustOverflowForBoxShadow(); + void adjustOverflowForBoxShadowAndReflect(); IntRect localSelectionRect(bool checkWhetherSelected = true) const; private: IntSize m_intrinsicSize; - - unsigned m_selectionState : 3; // SelectionState - bool m_hasOverflow : 1; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp index 9556980..5fa3c62 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp @@ -35,24 +35,26 @@ namespace WebCore { RenderReplica::RenderReplica(Node* n) : RenderBox(n) -{} +{ + // This is a hack. Replicas are synthetic, and don't pick up the attributes of the + // renderers being replicated, so they always report that they are inline, non-replaced. + // However, we need transforms to be applied to replicas for reflections, so have to pass + // the if (!isInline() || isReplaced()) check before setHasTransform(). + setReplaced(true); +} RenderReplica::~RenderReplica() {} void RenderReplica::layout() { - IntRect box = parent()->borderBox(); - m_x = box.x(); - m_y = box.y(); - m_width = box.width(); - m_height = box.height(); + setFrameRect(parentBox()->borderBoxRect()); setNeedsLayout(false); } void RenderReplica::calcPrefWidths() { - m_minPrefWidth = parent()->width(); + m_minPrefWidth = parentBox()->width(); m_maxPrefWidth = m_minPrefWidth; setPrefWidthsDirty(false); } @@ -62,17 +64,16 @@ void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty) if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseMask) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (paintInfo.phase == PaintPhaseForeground) // Turn around and paint the parent layer. Use temporary clipRects, so that the layer doesn't end up caching clip rects // computing using the wrong rootLayer layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), paintInfo.context, paintInfo.rect, - true, PaintRestrictionNone, 0, - true, // appliedTransform - true); // temporaryClipRects + PaintRestrictionNone, 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 d3a9026..d5db3b7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h @@ -40,7 +40,7 @@ public: virtual const char* renderName() const { return "RenderReplica"; } - virtual bool requiresLayer() { return true; } + virtual bool requiresLayer() const { return true; } virtual void layout(); virtual void calcPrefWidths(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h index d545fd0..f8afd0f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h @@ -25,12 +25,13 @@ #if ENABLE(SVG) #include "RenderBlock.h" +#include "SVGRenderSupport.h" namespace WebCore { class SVGElement; -class RenderSVGBlock : public RenderBlock { +class RenderSVGBlock : public RenderBlock, protected SVGRenderBase { public: RenderSVGBlock(SVGElement*); virtual void setStyle(PassRefPtr<RenderStyle>); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp index 2d6b57f..8a77d2e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp @@ -2,8 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org> 2007 Eric Seidel <eric@webkit.org> - - This file is part of the KDE project + 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 @@ -27,6 +26,7 @@ #include "RenderSVGContainer.h" #include "AXObjectCache.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "RenderView.h" #include "SVGRenderSupport.h" @@ -37,157 +37,15 @@ namespace WebCore { RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) - : RenderObject(node) - , m_firstChild(0) - , m_lastChild(0) - , m_width(0) - , m_height(0) + : RenderSVGModelObject(node) , m_drawsContents(true) { - setReplaced(true); } RenderSVGContainer::~RenderSVGContainer() { } -bool RenderSVGContainer::canHaveChildren() const -{ - return true; -} - -void RenderSVGContainer::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - insertChildNode(newChild, beforeChild); -} - -void RenderSVGContainer::removeChild(RenderObject* oldChild) -{ - // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode - // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on - // layout anyway). - oldChild->removeFromObjectLists(); - - removeChildNode(oldChild); -} - -void RenderSVGContainer::destroy() -{ - destroyLeftoverChildren(); - RenderObject::destroy(); -} - -void RenderSVGContainer::destroyLeftoverChildren() -{ - while (m_firstChild) { - // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields. - if (m_firstChild->element()) - m_firstChild->element()->setRenderer(0); - - m_firstChild->destroy(); - } -} - -RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove) -{ - ASSERT(oldChild->parent() == this); - - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or - // that a positioned child got yanked). We also repaint, so that the area exposed when the child - // disappears gets repainted properly. - if (!documentBeingDestroyed() && fullRemove) { - oldChild->setNeedsLayoutAndPrefWidthsRecalc(); - oldChild->repaint(); - } - - // If we have a line box wrapper, delete it. - oldChild->deleteLineBoxWrapper(); - - if (!documentBeingDestroyed() && fullRemove) { - // If oldChild is the start or end of the selection, then clear the selection to - // avoid problems of invalid pointers. - // FIXME: The SelectionController should be responsible for this when it - // is notified of DOM mutations. - if (oldChild->isSelectionBorder()) - view()->clearSelection(); - } - - // remove the child - if (oldChild->previousSibling()) - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); - if (oldChild->nextSibling()) - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); - - if (m_firstChild == oldChild) - m_firstChild = oldChild->nextSibling(); - if (m_lastChild == oldChild) - m_lastChild = oldChild->previousSibling(); - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); - - return oldChild; -} - -void RenderSVGContainer::appendChildNode(RenderObject* newChild, bool) -{ - ASSERT(!newChild->parent()); - ASSERT(newChild->element()->isSVGElement()); - - newChild->setParent(this); - RenderObject* lChild = m_lastChild; - - if (lChild) { - newChild->setPreviousSibling(lChild); - lChild->setNextSibling(newChild); - } else - m_firstChild = newChild; - - m_lastChild = newChild; - - newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); -} - -void RenderSVGContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool) -{ - if (!beforeChild) { - appendChildNode(child); - return; - } - - ASSERT(!child->parent()); - ASSERT(beforeChild->parent() == this); - ASSERT(child->element()->isSVGElement()); - - if (beforeChild == m_firstChild) - m_firstChild = child; - - RenderObject* prev = beforeChild->previousSibling(); - child->setNextSibling(beforeChild); - beforeChild->setPreviousSibling(child); - if (prev) - prev->setNextSibling(child); - child->setPreviousSibling(prev); - - child->setParent(this); - - child->setNeedsLayoutAndPrefWidthsRecalc(); - if (!normalChildNeedsLayout()) - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. - - if (AXObjectCache::accessibilityEnabled()) - document()->axObjectCache()->childrenChanged(this); -} - bool RenderSVGContainer::drawsContents() const { return m_drawsContents; @@ -198,49 +56,15 @@ void RenderSVGContainer::setDrawsContents(bool drawsContents) m_drawsContents = drawsContents; } -TransformationMatrix RenderSVGContainer::localTransform() const -{ - return m_localTransform; -} - -bool RenderSVGContainer::requiresLayer() -{ - // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context - return false; -} - -int RenderSVGContainer::lineHeight(bool, bool) const -{ - return height() + marginTop() + marginBottom(); -} - -int RenderSVGContainer::baselinePosition(bool, bool) const -{ - return height() + marginTop() + marginBottom(); -} - -bool RenderSVGContainer::calculateLocalTransform() -{ - // subclasses can override this to add transform support - return false; -} - void RenderSVGContainer::layout() { ASSERT(needsLayout()); + ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - // Arbitrary affine transforms are incompatible with LayoutState. - view()->disableLayoutState(); + calcViewport(); // Allow RenderSVGViewportContainer to update its viewport - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint(); - if (checkForRepaint) { - oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBounds(); - } - - calculateLocalTransform(); + 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 @@ -253,67 +77,14 @@ void RenderSVGContainer::layout() child->layoutIfNeeded(); ASSERT(!child->needsLayout()); } + repainter.repaintAfterLayout(); - calcBounds(); - - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); - - view()->enableLayoutState(); setNeedsLayout(false); } -int RenderSVGContainer::calcReplacedWidth() const -{ - switch (style()->width().type()) { - case Fixed: - return max(0, style()->width().value()); - case Percent: - { - const int cw = containingBlockWidth(); - return cw > 0 ? max(0, style()->width().calcMinValue(cw)) : 0; - } - default: - return 0; - } -} - -int RenderSVGContainer::calcReplacedHeight() const -{ - switch (style()->height().type()) { - case Fixed: - return max(0, style()->height().value()); - case Percent: - { - RenderBlock* cb = containingBlock(); - return style()->height().calcValue(cb->availableHeight()); - } - default: - return 0; - } -} - -void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo) -{ - if (!localTransform().isIdentity()) - paintInfo.context->concatCTM(localTransform()); -} - -void RenderSVGContainer::applyAdditionalTransforms(PaintInfo&) -{ - // no-op -} - -void RenderSVGContainer::calcBounds() -{ - m_width = calcReplacedWidth(); - m_height = calcReplacedHeight(); - m_absoluteBounds = absoluteClippedOverflowRect(); -} - bool RenderSVGContainer::selfWillPaint() const { -#if ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) const SVGRenderStyle* svgStyle = style()->svgStyle(); SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter()); if (filter) @@ -330,98 +101,75 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) // Spec: groups w/o children still may render filter content. if (!firstChild() && !selfWillPaint()) return; - - paintInfo.context->save(); - applyContentTransforms(paintInfo); - SVGResourceFilter* filter = 0; - PaintInfo savedInfo(paintInfo); + PaintInfo childPaintInfo(paintInfo); - FloatRect boundingBox = relativeBBox(true); - if (paintInfo.phase == PaintPhaseForeground) - prepareToRenderSVGContent(this, paintInfo, boundingBox, filter); + childPaintInfo.context->save(); + + // Let the RenderSVGViewportContainer subclass clip if necessary + applyViewportClip(childPaintInfo); - applyAdditionalTransforms(paintInfo); + applyTransformToPaintInfo(childPaintInfo, localToParentTransform()); + + SVGResourceFilter* filter = 0; + FloatRect boundingBox = repaintRectInLocalCoordinates(); + if (childPaintInfo.phase == PaintPhaseForeground) + prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); - // default implementation. Just pass paint through to the children - PaintInfo childInfo(paintInfo); - childInfo.paintingRoot = paintingRootForChildren(paintInfo); + childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->paint(childInfo, 0, 0); + child->paint(childPaintInfo, 0, 0); if (paintInfo.phase == PaintPhaseForeground) - finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context); + finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); - paintInfo.context->restore(); - + childPaintInfo.context->restore(); + + // FIXME: This really should be drawn from local coordinates, but currently we hack it + // to avoid our clip killing our outline rect. Thus we translate our + // outline rect into parent coords before drawing. + // FIXME: This means our focus ring won't share our rotation like it should. + // We should instead disable our clip during PaintPhaseOutline + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) - paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style()); + paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height(), style()); } -TransformationMatrix RenderSVGContainer::viewportTransform() const +// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call +void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int) { - return TransformationMatrix(); + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); + graphicsContext->addFocusRingRect(paintRectInParent); } -IntRect RenderSVGContainer::absoluteClippedOverflowRect() +FloatRect RenderSVGContainer::objectBoundingBox() const { - FloatRect repaintRect; - - for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - repaintRect.unite(current->absoluteClippedOverflowRect()); - -#if ENABLE(SVG_FILTERS) - // Filters can expand the bounding box - SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter()); - if (filter) - repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect)); -#endif - - if (!repaintRect.isEmpty()) - repaintRect.inflate(1); // inflate 1 pixel for antialiasing - - return enclosingIntRect(repaintRect); + return computeContainerBoundingBox(this, false); } -void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int) +// 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 { - graphicsContext->addFocusRingRect(m_absoluteBounds); -} + FloatRect repaintRect = computeContainerBoundingBox(this, true); -void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool) -{ - rects.append(absoluteClippedOverflowRect()); -} + // A filter on this container can paint outside of the union of the child repaint rects + repaintRect.unite(filterBoundingBoxForRenderer(this)); -void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool) -{ - quads.append(absoluteClippedOverflowRect()); + return repaintRect; } -FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const +bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { - FloatRect rect; - - RenderObject* current = firstChild(); - for (; current != 0; current = current->nextSibling()) { - FloatRect childBBox = current->relativeBBox(includeStroke); - FloatRect mappedBBox = current->localTransform().mapRect(childBBox); - - // <svg> can have a viewBox contributing to the bbox - if (current->isSVGContainer()) - mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox); - - rect.unite(mappedBBox); - } + // Give RenderSVGViewportContainer a chance to apply its viewport clip + if (!pointIsInsideViewportClip(pointInParent)) + return false; - return rect; -} + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); -bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) -{ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) { - updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty)); + if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { + updateHitTestResult(result, roundedIntPoint(localPoint)); return true; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h index 48f5694..4bb7e44 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h @@ -1,8 +1,7 @@ /* Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> - - This file is part of the KDE project + 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,93 +24,52 @@ #if ENABLE(SVG) -#include "RenderPath.h" -#include "SVGPreserveAspectRatio.h" +#include "RenderSVGModelObject.h" namespace WebCore { class SVGElement; -class RenderSVGContainer : public RenderObject { +class RenderSVGContainer : public RenderSVGModelObject { public: RenderSVGContainer(SVGStyledElement*); ~RenderSVGContainer(); - virtual RenderObject* firstChild() const { return m_firstChild; } - virtual RenderObject* lastChild() const { return m_lastChild; } - - virtual int width() const { return m_width; } - virtual int height() const { return m_height; } - - virtual bool canHaveChildren() const; - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject*); - - virtual void destroy(); - void destroyLeftoverChildren(); - - virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true); - virtual void appendChildNode(RenderObject*, bool fullAppend = true); - virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true); - - // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our - // change in parentage is not going to affect anything. - virtual void moveChildNode(RenderObject* child) { appendChildNode(child->parent()->removeChildNode(child, false), false); } + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } - virtual void calcPrefWidths() { setPrefWidthsDirty(false); } - - // Some containers do not want it's children - // to be drawn, because they may be 'referenced' - // Example: <marker> children in SVG + // <marker> uses these methods to only allow drawing children during a special marker draw time void setDrawsContents(bool); bool drawsContents() const; virtual bool isSVGContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGContainer"; } - virtual bool requiresLayer(); - virtual int lineHeight(bool b, bool isRootLineBox = false) const; - virtual int baselinePosition(bool b, bool isRootLineBox = false) const; - virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - - virtual IntRect absoluteClippedOverflowRect(); - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - FloatRect relativeBBox(bool includeStroke = true) const; + virtual FloatRect objectBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; - virtual bool calculateLocalTransform(); - virtual TransformationMatrix localTransform() const; - virtual TransformationMatrix viewportTransform() const; - - 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); protected: - virtual void applyContentTransforms(PaintInfo&); - virtual void applyAdditionalTransforms(PaintInfo&); + // Allow RenderSVGTransformableContainer to hook in at the right time in layout() + virtual void calculateLocalTransform() { } - void calcBounds(); + // Allow RenderSVGViewportContainer to hook in at the right times in layout(), paint() and nodeAtFloatPoint() + virtual void calcViewport() { } + virtual void applyViewportClip(PaintInfo&) { } + virtual bool pointIsInsideViewportClip(const FloatPoint& /*pointInParent*/) { return true; } private: - int calcReplacedWidth() const; - int calcReplacedHeight() const; - - RenderObject* m_firstChild; - RenderObject* m_lastChild; - - int m_width; - int m_height; - bool selfWillPaint() const; + RenderObjectChildList m_children; bool m_drawsContents : 1; - -protected: - IntRect m_absoluteBounds; - TransformationMatrix m_localTransform; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp index d0dc881..b81e7f4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp @@ -42,7 +42,7 @@ RenderSVGGradientStop::~RenderSVGGradientStop() { } -void RenderSVGGradientStop::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderObject::styleDidChange(diff, oldStyle); @@ -61,7 +61,7 @@ void RenderSVGGradientStop::layout() SVGGradientElement* RenderSVGGradientStop::gradientElement() const { - Node* parentNode = element()->parent(); + Node* parentNode = node()->parent(); if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag)) return static_cast<SVGGradientElement*>(parentNode); return 0; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h index 86de6d0..1d0858d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h @@ -1,7 +1,6 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 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 @@ -41,14 +40,15 @@ namespace WebCore { virtual void layout(); - // This override is needed to prevent crashing on <svg><stop /></svg> - // RenderObject's default impl asks the parent Object and RenderSVGRoot - // asks all child RenderObjects for overflow rects, thus infinite loop. + // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> + // RenderObject's default implementations ASSERT_NOT_REACHED() // https://bugs.webkit.org/show_bug.cgi?id=20400 - virtual IntRect absoluteClippedOverflowRect() { return IntRect(); } - + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); } + virtual FloatRect objectBoundingBox() const { return FloatRect(); } + virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } + protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: SVGGradientElement* gradientElement() const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp index 4a7d6b2..f08c008 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp @@ -39,21 +39,6 @@ RenderSVGHiddenContainer::~RenderSVGHiddenContainer() { } -bool RenderSVGHiddenContainer::requiresLayer() -{ - return false; -} - -int RenderSVGHiddenContainer::lineHeight(bool, bool) const -{ - return 0; -} - -int RenderSVGHiddenContainer::baselinePosition(bool, bool) const -{ - return 0; -} - void RenderSVGHiddenContainer::layout() { ASSERT(needsLayout()); @@ -76,37 +61,32 @@ void RenderSVGHiddenContainer::paint(PaintInfo&, int, int) // This subtree does not paint. } -IntRect RenderSVGHiddenContainer::absoluteClippedOverflowRect() +IntRect RenderSVGHiddenContainer::clippedOverflowRectForRepaint(RenderBoxModelObject* /*repaintContainer*/) { return IntRect(); } -void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>&, int, int, bool) +void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>&, int, int) { // This subtree does not take up space or paint } -void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&, bool) +void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&) { // This subtree does not take up space or paint } -TransformationMatrix RenderSVGHiddenContainer::absoluteTransform() const -{ - return TransformationMatrix(); -} - -TransformationMatrix RenderSVGHiddenContainer::localTransform() const +bool RenderSVGHiddenContainer::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) { - return TransformationMatrix(); + return false; } -bool RenderSVGHiddenContainer::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +FloatRect RenderSVGHiddenContainer::objectBoundingBox() const { - return false; + return FloatRect(); } -FloatRect RenderSVGHiddenContainer::relativeBBox(bool) const +FloatRect RenderSVGHiddenContainer::repaintRectInLocalCoordinates() const { return FloatRect(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h index 24c7ddd..5a208d0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h @@ -37,29 +37,28 @@ namespace WebCore { public: RenderSVGHiddenContainer(SVGStyledElement*); virtual ~RenderSVGHiddenContainer(); - + virtual bool isSVGContainer() const { return true; } virtual bool isSVGHiddenContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } - - virtual bool requiresLayer(); - - virtual int lineHeight(bool b, bool isRootLineBox = false) const; - virtual int baselinePosition(bool b, bool isRootLineBox = false) const; - + + virtual bool requiresLayer() const { return false; } + virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual IntRect absoluteClippedOverflowRect(); - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - - virtual TransformationMatrix absoluteTransform() const; - virtual TransformationMatrix localTransform() const; + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + 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; - virtual FloatRect relativeBBox(bool includeStroke = true) const; - 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); }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp index 61f65a0..b38352e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp @@ -3,8 +3,7 @@ Copyright (C) 2006 Apple Computer, Inc. Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> - - This file is part of the WebKit project + Copyright (C) 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 @@ -29,8 +28,10 @@ #include "Attr.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" +#include "RenderLayer.h" #include "SVGImageElement.h" #include "SVGLength.h" #include "SVGPreserveAspectRatio.h" @@ -125,41 +126,25 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s } } -bool RenderSVGImage::calculateLocalTransform() -{ - TransformationMatrix oldTransform = m_localTransform; - m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); - return (m_localTransform != oldTransform); -} - void RenderSVGImage::layout() { ASSERT(needsLayout()); - - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } - - calculateLocalTransform(); + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + + SVGImageElement* image = static_cast<SVGImageElement*>(node()); + m_localTransform = image->animatedLocalTransform(); // minimum height - m_height = errorOccurred() ? intrinsicSize().height() : 0; + setHeight(errorOccurred() ? intrinsicSize().height() : 0); calcWidth(); calcHeight(); - SVGImageElement* image = static_cast<SVGImageElement*>(node()); m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); - calculateAbsoluteBounds(); - - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); - + repainter.repaintAfterLayout(); + setNeedsLayout(false); } @@ -169,7 +154,7 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) return; paintInfo.context->save(); - paintInfo.context->concatCTM(localTransform()); + paintInfo.context->concatCTM(localToParentTransform()); if (paintInfo.phase == PaintPhaseForeground) { SVGResourceFilter* filter = 0; @@ -186,14 +171,16 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio()); paintInfo.context->drawImage(image(), destRect, srcRect); - - finishRenderSVGContent(this, paintInfo, m_localBounds, filter, savedInfo.context); + finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); } - + + if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) + paintOutline(paintInfo.context, 0, 0, width(), height(), style()); + paintInfo.context->restore(); } -bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) +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. if (hitTestAction != HitTestForeground) @@ -203,12 +190,11 @@ bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult& result, i bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { - double localX, localY; - absoluteTransform().inverse().map(_x, _y, &localX, &localY); + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); if (hitRules.canHitFill) { - if (m_localBounds.contains(narrowPrecisionToFloat(localX), narrowPrecisionToFloat(localY))) { - updateHitTestResult(result, IntPoint(_x, _y)); + if (m_localBounds.contains(localPoint)) { + updateHitTestResult(result, roundedIntPoint(localPoint)); return true; } } @@ -217,60 +203,63 @@ bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult& result, i return false; } -bool RenderSVGImage::requiresLayer() +bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { + ASSERT_NOT_REACHED(); return false; } -FloatRect RenderSVGImage::relativeBBox(bool) const +FloatRect RenderSVGImage::objectBoundingBox() const { return m_localBounds; } +FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const +{ + FloatRect repaintRect = m_localBounds; + + // Filters can paint outside the image content + repaintRect.unite(filterBoundingBoxForRenderer(this)); + + return repaintRect; +} + void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) { RenderImage::imageChanged(image, rect); // We override to invalidate a larger rect, since SVG images can draw outside their "bounds" - repaintRectangle(absoluteClippedOverflowRect()); + repaintRectangle(absoluteClippedOverflowRect()); // FIXME: Isn't this just repaint()? } -void RenderSVGImage::calculateAbsoluteBounds() +IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { - // FIXME: broken with CSS transforms - FloatRect absoluteRect = absoluteTransform().mapRect(relativeBBox(true)); - -#if ENABLE(SVG_FILTERS) - // Filters can expand the bounding box - SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter()); - if (filter) - absoluteRect.unite(filter->filterBBoxForItemBBox(absoluteRect)); -#endif - - if (!absoluteRect.isEmpty()) - absoluteRect.inflate(1); // inflate 1 pixel for antialiasing + return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer); +} - m_absoluteBounds = enclosingIntRect(absoluteRect); +void RenderSVGImage::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); } -IntRect RenderSVGImage::absoluteClippedOverflowRect() +void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const { - return m_absoluteBounds; + SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); } void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int) { // this is called from paint() after the localTransform has already been applied - IntRect contentRect = enclosingIntRect(relativeBBox()); + IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); graphicsContext->addFocusRingRect(contentRect); } -void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int, bool) +void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int) { rects.append(absoluteClippedOverflowRect()); } -void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads, bool) +void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads) { quads.append(FloatRect(absoluteClippedOverflowRect())); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h index de8a2d3..01b8b65 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h @@ -2,8 +2,7 @@ Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> Copyright (C) 2006 Apple Computer, Inc. Copyright (C) 2007 Rob Buis <buis@kde.org> - - This file is part of the WebKit project. + Copyright (C) 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 @@ -29,23 +28,33 @@ #include "TransformationMatrix.h" #include "FloatRect.h" #include "RenderImage.h" +#include "SVGRenderSupport.h" namespace WebCore { class SVGImageElement; class SVGPreserveAspectRatio; - class RenderSVGImage : public RenderImage { + class RenderSVGImage : public RenderImage, SVGRenderBase { public: RenderSVGImage(SVGImageElement*); virtual ~RenderSVGImage(); - - virtual TransformationMatrix localTransform() const { return m_localTransform; } - - virtual FloatRect relativeBBox(bool includeStroke = true) const; - virtual IntRect absoluteClippedOverflowRect(); - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + virtual const char* renderName() const { return "RenderSVGImage"; } + virtual bool isSVGImage() const { return true; } + + virtual TransformationMatrix localToParentTransform() const { return m_localTransform; } + + virtual FloatRect objectBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; + + 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 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); @@ -54,17 +63,16 @@ namespace WebCore { virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - bool requiresLayer(); + 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); - bool calculateLocalTransform(); - private: - void calculateAbsoluteBounds(); + virtual TransformationMatrix localTransform() const { return m_localTransform; } + TransformationMatrix m_localTransform; FloatRect m_localBounds; - IntRect m_absoluteBounds; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp index 11da004..3c44dd8 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp @@ -2,7 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 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,7 +26,11 @@ #if ENABLE(SVG) #include "RenderSVGInline.h" +#include "FloatQuad.h" +#include "RenderBlock.h" #include "SVGInlineFlowBox.h" +#include "SVGInlineTextBox.h" +#include "SVGRootInlineBox.h" namespace WebCore { @@ -35,22 +39,49 @@ RenderSVGInline::RenderSVGInline(Node* n) { } -InlineBox* RenderSVGInline::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun) +InlineFlowBox* RenderSVGInline::createFlowBox() { - ASSERT(!(!isRootLineBox && (isReplaced() || makePlaceHolderBox))); - ASSERT(isInlineFlow()); + InlineFlowBox* box = new (renderArena()) SVGInlineFlowBox(this); + box->setIsSVG(true); + return box; +} + +void RenderSVGInline::absoluteRects(Vector<IntRect>& rects, int, int) +{ + InlineRunBox* firstBox = firstLineBox(); + + SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RenderBox* object = rootBox ? rootBox->block() : 0; + + if (!object) + return; + + int xRef = object->x(); + int yRef = object->y(); + + for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height()); + rects.append(enclosingIntRect(localToAbsoluteQuad(rect).boundingBox())); + } +} + +void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads) +{ + InlineRunBox* firstBox = firstLineBox(); + + SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RenderBox* object = rootBox ? rootBox->block() : 0; + + if (!object) + return; - InlineFlowBox* flowBox = new (renderArena()) SVGInlineFlowBox(this); + int xRef = object->x(); + int yRef = object->y(); - if (!m_firstLineBox) - m_firstLineBox = m_lastLineBox = flowBox; - else { - m_lastLineBox->setNextLineBox(flowBox); - flowBox->setPreviousLineBox(m_lastLineBox); - m_lastLineBox = flowBox; + for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height()); + quads.append(localToAbsoluteQuad(rect)); } - - return flowBox; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h index 42fdafc..1ff8d02 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h @@ -28,13 +28,21 @@ #include "RenderInline.h" namespace WebCore { + class RenderSVGInline : public RenderInline { public: - RenderSVGInline(Node*); - virtual const char* renderName() const { return "RenderSVGInline"; } - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); - virtual bool requiresLayer() { return false; } - }; + RenderSVGInline(Node*); + 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>&); + +private: + virtual InlineFlowBox* createFlowBox(); +}; + } #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp index 2212d78..b1a21d7 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp @@ -29,10 +29,12 @@ #include "RenderSVGInlineText.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "SVGInlineTextBox.h" #include "SVGRootInlineBox.h" +#include "VisiblePosition.h" namespace WebCore { @@ -53,27 +55,37 @@ RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> str) { } -void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int, bool) + +void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + // Skip RenderText's possible layout scheduling on style change + RenderObject::styleDidChange(diff, oldStyle); + + // FIXME: SVG text is apparently always transformed? + if (RefPtr<StringImpl> textToTransform = originalText()) + setText(textToTransform.release(), true); +} + +void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int) { - rects.append(computeAbsoluteRectForRange(0, textLength())); + rects.append(computeRepaintRectForRange(0, 0, textLength())); } -void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads, bool) +void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads) { - quads.append(FloatRect(computeAbsoluteRectForRange(0, textLength()))); + quads.append(computeRepaintQuadForRange(0, 0, textLength())); } -IntRect RenderSVGInlineText::selectionRect(bool) +IntRect RenderSVGInlineText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool /*clipToVisibleContent*/) { ASSERT(!needsLayout()); - IntRect rect; if (selectionState() == SelectionNone) - return rect; + return IntRect(); // Early exit if we're ie. a <text> within a <defs> section. if (isChildOfHiddenContainer(this)) - return rect; + return IntRect(); // Now calculate startPos and endPos for painting selection. // We include a selection while endPos > 0 @@ -91,79 +103,83 @@ IntRect RenderSVGInlineText::selectionRect(bool) } if (startPos == endPos) - return rect; + return IntRect(); - return computeAbsoluteRectForRange(startPos, endPos); + return computeRepaintRectForRange(repaintContainer, startPos, endPos); } -IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPos) +IntRect RenderSVGInlineText::computeRepaintRectForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos) { - IntRect rect; + FloatQuad repaintQuad = computeRepaintQuadForRange(repaintContainer, startPos, endPos); + return enclosingIntRect(repaintQuad.boundingBox()); +} +FloatQuad RenderSVGInlineText::computeRepaintQuadForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos) +{ RenderBlock* cb = containingBlock(); if (!cb || !cb->container()) - return rect; + return FloatQuad(); RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) - return rect; + return FloatQuad(); + IntRect rect; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) rect.unite(box->selectionRect(0, 0, startPos, endPos)); - // Mimic RenderBox::computeAbsoluteRepaintRect() functionality. But only the subset needed for SVG and respecting SVG transformations. - FloatPoint absPos = cb->container()->localToAbsolute(); - - // Remove HTML parent translation offsets here! These need to be retrieved from the RenderSVGRoot object. - // But do take the containingBlocks's container position into account, ie. SVG text in scrollable <div>. - TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); - - FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - xPos() - htmlParentCtm.e()), - narrowPrecisionToFloat(rect.y() + absPos.y() - yPos() - htmlParentCtm.f()), rect.width(), rect.height()); - // FIXME: broken with CSS transforms - return enclosingIntRect(absoluteTransform().mapRect(fixedRect)); + return localToContainerQuad(FloatQuad(rect), repaintContainer); } -InlineTextBox* RenderSVGInlineText::createInlineTextBox() +InlineTextBox* RenderSVGInlineText::createTextBox() { - return new (renderArena()) SVGInlineTextBox(this); + InlineTextBox* box = new (renderArena()) SVGInlineTextBox(this); + box->setIsSVG(true); + return box; } -IntRect RenderSVGInlineText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*) { - // SVG doesn't have any editable content where a caret rect would be needed + // SVG doesn't have any editable content where a caret rect would be needed. + // FIXME: That's not sufficient. The localCaretRect function is also used for selection. return IntRect(); } -VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y) +VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) { SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(firstTextBox()); if (!textBox || textLength() == 0) - return VisiblePosition(element(), 0, DOWNSTREAM); + return createVisiblePosition(0, DOWNSTREAM); SVGRootInlineBox* rootBox = textBox->svgRootInlineBox(); - RenderObject* object = rootBox ? rootBox->object() : 0; + RenderBlock* object = rootBox ? rootBox->block() : 0; if (!object) - return VisiblePosition(element(), 0, DOWNSTREAM); + return createVisiblePosition(0, DOWNSTREAM); - int offset = 0; + int closestOffsetInBox = 0; + // FIXME: This approach is wrong. The correct code would first find the + // closest SVGInlineTextBox to the point, and *then* ask only that inline box + // what the closest text offset to that point is. This code instead walks + // through all boxes in order, so when you click "near" a box, you'll actually + // end up returning the nearest offset in the last box, even if the + // nearest offset to your click is contained in another box. for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) { - if (box->svgCharacterHitsPosition(x + object->xPos(), y + object->yPos(), offset)) { + if (box->svgCharacterHitsPosition(point.x() + object->x(), point.y() + object->y(), closestOffsetInBox)) { // If we're not at the end/start of the box, stop looking for other selected boxes. if (box->direction() == LTR) { - if (offset <= (int) box->end() + 1) + if (closestOffsetInBox <= (int) box->end() + 1) break; } else { - if (offset > (int) box->start()) + if (closestOffsetInBox > (int) box->start()) break; } } } - return VisiblePosition(element(), offset, DOWNSTREAM); + return createVisiblePosition(closestOffsetInBox, DOWNSTREAM); } void RenderSVGInlineText::destroy() diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h index cc37166..c4a096d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h @@ -34,22 +34,25 @@ class RenderSVGInlineText : public RenderText { public: RenderSVGInlineText(Node*, PassRefPtr<StringImpl>); virtual const char* renderName() const { return "RenderSVGInlineText"; } + + virtual void styleDidChange(StyleDifference, const RenderStyle*); - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); - virtual bool requiresLayer() { return false; } - virtual IntRect selectionRect(bool clipToVisibleContent = true); + virtual bool requiresLayer() const { return false; } + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); virtual bool isSVGText() const { return true; } - virtual InlineTextBox* createInlineTextBox(); virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - virtual VisiblePosition positionForCoordinates(int x, int y); + virtual VisiblePosition positionForPoint(const IntPoint&); virtual void destroy(); private: - IntRect computeAbsoluteRectForRange(int startPos, int endPos); + virtual InlineTextBox* createTextBox(); + IntRect computeRepaintRectForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos); + FloatQuad computeRepaintQuadForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos); }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp new file mode 100644 index 0000000..3fab5a6 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.cpp @@ -0,0 +1,97 @@ +/* + * 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(SVG) +#include "RenderSVGModelObject.h" + +#include "GraphicsContext.h" +#include "RenderLayer.h" +#include "RenderView.h" +#include "SVGStyledElement.h" + +#if ENABLE(FILTERS) +#include "SVGResourceFilter.h" +#endif + +namespace WebCore { + +RenderSVGModelObject::RenderSVGModelObject(SVGStyledElement* node) + : RenderObject(node) +{ +} + +IntRect RenderSVGModelObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer); +} + +void RenderSVGModelObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); +} + +void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const +{ + SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); +} + +// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. +// FIXME: This may also need to move into SVGRenderBase as the RenderBox version depends +// on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. +IntRect RenderSVGModelObject::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const +{ + IntRect box = enclosingIntRect(repaintRectInLocalCoordinates()); + adjustRectForOutlineAndShadow(box); + + FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); + return containerRelativeQuad.enclosingBoundingBox(); +} + +void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, int, int) +{ + rects.append(absoluteClippedOverflowRect()); +} + +void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads) +{ + quads.append(absoluteClippedOverflowRect()); +} + +bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h new file mode 100644 index 0000000..0aa13ad --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGModelObject.h @@ -0,0 +1,71 @@ +/* + * 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 RenderSVGModelObject_h +#define RenderSVGModelObject_h + +#if ENABLE(SVG) + +#include "RenderObject.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +// Most renderers in the SVG rendering tree will inherit from this class +// but not all. (e.g. RenderSVGForeignObject, RenderSVGBlock, RenderSVGImage) thus methods +// required by SVG renders need to be declared on RenderObject, but shared +// logic can go in this class or in SVGRenderBase. + +class SVGStyledElement; + +class RenderSVGModelObject : public RenderObject, protected SVGRenderBase { +public: + RenderSVGModelObject(SVGStyledElement*); + + virtual bool requiresLayer() const { return false; } + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const; + + virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + +private: + // This method should never be called, SVG uses a different nodeAtPoint method + bool nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xInContainer, int yInContainer, int dxParentToContainer, int dyParentToContainer, HitTestAction hitTestAction); +}; + +} + +#endif // ENABLE(SVG) +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp index 457ac02..80c29dd 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp @@ -2,8 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org> 2007 Eric Seidel <eric@webkit.org> - - This file is part of the KDE project + 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 @@ -27,24 +26,24 @@ #include "RenderSVGRoot.h" #include "GraphicsContext.h" -#include "RenderPath.h" #include "RenderSVGContainer.h" #include "RenderView.h" #include "SVGLength.h" #include "SVGRenderSupport.h" -#include "SVGResourceClipper.h" -#include "SVGResourceFilter.h" -#include "SVGResourceMasker.h" #include "SVGSVGElement.h" #include "SVGStyledElement.h" -#include "SVGURIReference.h" +#include "TransformState.h" + +#if ENABLE(FILTERS) +#include "SVGResourceFilter.h" +#endif using namespace std; namespace WebCore { RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node) - : RenderContainer(node) + : RenderBox(node) { setReplaced(true); } @@ -86,69 +85,43 @@ void RenderSVGRoot::layout() { ASSERT(needsLayout()); - calcViewport(); - // Arbitrary affine transforms are incompatible with LayoutState. view()->disableLayoutState(); - IntRect oldBounds = m_absoluteBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); - if (checkForRepaint) - oldOutlineBox = absoluteOutlineBounds(); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); calcWidth(); calcHeight(); - m_absoluteBounds = absoluteClippedOverflowRect(); - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - m_width = static_cast<int>(m_width * svg->currentScale()); - m_height = static_cast<int>(m_height * svg->currentScale()); + 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); + child->setNeedsLayout(true, false); child->layoutIfNeeded(); ASSERT(!child->needsLayout()); } - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + repainter.repaintAfterLayout(); view()->enableLayoutState(); setNeedsLayout(false); } -void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, int parentY) +bool RenderSVGRoot::selfWillPaint() const { - // Translate from parent offsets (html renderers) to a relative transform (svg renderers) - IntPoint origin; - origin.move(parentX, parentY); - origin.move(m_x, m_y); - origin.move(borderLeft(), borderTop()); - origin.move(paddingLeft(), paddingTop()); - - if (origin.x() || origin.y()) { - paintInfo.context->concatCTM(TransformationMatrix().translate(origin.x(), origin.y())); - paintInfo.rect.move(-origin.x(), -origin.y()); - } - - // Respect scroll offset caused by html parents - TransformationMatrix ctm = RenderContainer::absoluteTransform(); - paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f())); - - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - paintInfo.context->concatCTM(TransformationMatrix().scale(svg->currentScale())); - - if (!viewport().isEmpty()) { - if (style()->overflowX() != OVISIBLE) - paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping - - paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y())); - } - - paintInfo.context->concatCTM(TransformationMatrix().translate(svg->currentTranslate().x(), svg->currentTranslate().y())); +#if ENABLE(FILTERS) + const SVGRenderStyle* svgStyle = style()->svgStyle(); + SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter()); + if (filter) + return true; +#endif + return false; } void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) @@ -156,141 +129,131 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) if (paintInfo.context->paintingDisabled()) return; - calcViewport(); + IntPoint parentOriginInContainer(parentX, parentY); + IntPoint borderBoxOriginInContainer = parentOriginInContainer + IntSize(x(), y()); + + if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) + paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()); - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - // A value of zero disables rendering of the element. - if (viewport().width() <= 0. || viewport().height() <= 0.) + // An empty viewport disables rendering. FIXME: Should we still render filters? + if (viewportSize().isEmpty()) return; - // This should only exist for <svg> renderers - if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) - paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY); - - if (!firstChild()) { -#if ENABLE(SVG_FILTERS) - // Spec: groups w/o children still may render filter content. - const SVGRenderStyle* svgStyle = style()->svgStyle(); - SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter()); - if (!filter) -#endif - return; - } + // Don't paint if we don't have kids, except if we have filters we should paint those. + if (!firstChild() && !selfWillPaint()) + return; + // Make a copy of the PaintInfo because applyTransformToPaintInfo will modify the damage rect. RenderObject::PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); - - applyContentTransforms(childPaintInfo, parentX, parentY); - SVGResourceFilter* filter = 0; + // SVG does not support independent x/y clipping + if (style()->overflowX() != OVISIBLE) + 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. + applyTransformToPaintInfo(childPaintInfo, localToRepaintContainerTransform(parentOriginInContainer)); - FloatRect boundingBox = relativeBBox(true); + SVGResourceFilter* filter = 0; + FloatRect boundingBox = repaintRectInLocalCoordinates(); if (childPaintInfo.phase == PaintPhaseForeground) - prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); + prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter); - childPaintInfo.context->concatCTM(svg->viewBoxToViewTransform(width(), height())); - RenderContainer::paint(childPaintInfo, 0, 0); + RenderBox::paint(childPaintInfo, 0, 0); if (childPaintInfo.phase == PaintPhaseForeground) - finishRenderSVGContent(this, childPaintInfo, boundingBox, filter, paintInfo.context); + finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context); childPaintInfo.context->restore(); - - if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) - paintOutline(childPaintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style()); + + if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) + paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height(), style()); } -FloatRect RenderSVGRoot::viewport() const +const FloatSize& RenderSVGRoot::viewportSize() const { - return m_viewport; + return m_viewportSize; } void RenderSVGRoot::calcViewport() { - SVGElement* svgelem = static_cast<SVGElement*>(element()); - if (svgelem->hasTagName(SVGNames::svgTag)) { - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); - if (!selfNeedsLayout() && !svg->hasRelativeValues()) - return; + if (!selfNeedsLayout() && !svg->hasRelativeValues()) + return; - float w, h; + if (!svg->hasSetContainerSize()) { + // 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(); - if (width.unitType() == LengthTypePercentage && svg->hasSetContainerSize()) - w = svg->relativeWidthValue(); - else - w = width.value(svg); - SVGLength height = svg->height(); - if (height.unitType() == LengthTypePercentage && svg->hasSetContainerSize()) - h = svg->relativeHeightValue(); - else - h = height.value(svg); - - m_viewport = FloatRect(0, 0, w, h); + 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); } } -IntRect RenderSVGRoot::absoluteClippedOverflowRect() +// 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 { - IntRect repaintRect; - - for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - repaintRect.unite(current->absoluteClippedOverflowRect()); - -#if ENABLE(SVG_FILTERS) - // Filters can expand the bounding box - SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter()); - if (filter) - repaintRect.unite(enclosingIntRect(filter->filterBBoxForItemBBox(repaintRect))); -#endif + 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; +} - return repaintRect; +IntSize RenderSVGRoot::parentOriginToBorderBox() const +{ + return IntSize(x(), y()); } -void RenderSVGRoot::addFocusRingRects(GraphicsContext* graphicsContext, int, int) +IntSize RenderSVGRoot::borderOriginToContentBox() const { - graphicsContext->addFocusRingRect(m_absoluteBounds); + return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop()); } -void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int) +TransformationMatrix RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const { - for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - current->absoluteRects(rects, 0, 0); + TransformationMatrix parentToContainer; + parentToContainer.translate(parentOriginInContainer.x(), parentOriginInContainer.y()); + return localToParentTransform() * parentToContainer; } -void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool) +TransformationMatrix RenderSVGRoot::localToParentTransform() const { - for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - current->absoluteQuads(quads); + IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); + + TransformationMatrix borderBoxOriginToParentOrigin; + borderBoxOriginToParentOrigin.translate(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); + + return localToBorderBoxTransform() * borderBoxOriginToParentOrigin; } +// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed. TransformationMatrix RenderSVGRoot::absoluteTransform() const { - TransformationMatrix ctm = RenderContainer::absoluteTransform(); - ctm.translate(m_x, m_y); - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - ctm.scale(svg->currentScale()); - ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y()); - ctm.translate(viewport().x(), viewport().y()); - return svg->viewBoxToViewTransform(width(), height()) * ctm; + // This would apply localTransform() twice if localTransform() were not the identity. + return localToParentTransform() * RenderBox::absoluteTransform(); } -FloatRect RenderSVGRoot::relativeBBox(bool includeStroke) const +FloatRect RenderSVGRoot::objectBoundingBox() const { - FloatRect rect; - - RenderObject* current = firstChild(); - for (; current != 0; current = current->nextSibling()) { - FloatRect childBBox = current->relativeBBox(includeStroke); - FloatRect mappedBBox = current->localTransform().mapRect(childBBox); - // <svg> can have a viewBox contributing to the bbox - if (current->isSVGContainer()) - mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox); - rect.unite(mappedBBox); - } + return computeContainerBoundingBox(this, false); +} - return rect; +FloatRect RenderSVGRoot::repaintRectInLocalCoordinates() const +{ + // FIXME: This does not include the border but it should! + return computeContainerBoundingBox(this, true); } TransformationMatrix RenderSVGRoot::localTransform() const @@ -298,48 +261,56 @@ TransformationMatrix RenderSVGRoot::localTransform() const return TransformationMatrix(); } +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 + repaintRect = localToBorderBoxTransform().mapRect(repaintRect); + RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed); +} + +void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const +{ + 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. + + // Transform to our border box and let RenderBox transform the rest of the way. + transformState.applyTransform(localToBorderBoxTransform()); + RenderBox::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); +} + bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - TransformationMatrix ctm = RenderContainer::absoluteTransform(); - - int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset - int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset - - if (!viewport().isEmpty() - && style()->overflowX() == OHIDDEN - && style()->overflowY() == OHIDDEN) { - int tx = m_x - _tx + sx; - int ty = m_y - _ty + sy; - - // Check if we need to do anything at all. - IntRect overflowBox = overflowRect(false); - overflowBox.move(tx, ty); - ctm.translate(viewport().x(), viewport().y()); - double localX, localY; - ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY); - if (!overflowBox.contains((int)localX, (int)localY)) + IntPoint pointInContainer(_x, _y); + IntSize containerToParentOffset(_tx, _ty); + + IntPoint pointInParent = pointInContainer - containerToParentOffset; + 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 localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - if (child->nodeAtPoint(request, result, _x - sx, _y - sy, 0, 0, hitTestAction)) { - updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty)); + if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { + // FIXME: CSS/HTML assumes the local point is relative to the border box, right? + updateHitTestResult(result, pointInBorderBox); return true; } } - - // Spec: Only graphical elements can be targeted by the mouse, period. + + // Spec: Only graphical elements can be targeted by the mouse, so we don't check self here. // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched." return false; } -void RenderSVGRoot::position(InlineBox* box) -{ - RenderContainer::position(box); - if (m_absoluteBounds.isEmpty()) - setNeedsLayout(true, false); -} - } #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h index acac78b..50866d2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h @@ -1,8 +1,7 @@ /* Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> - - This file is part of the KDE project + 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 @@ -24,54 +23,66 @@ #define RenderSVGRoot_h #if ENABLE(SVG) -#include "RenderContainer.h" +#include "RenderBox.h" #include "FloatRect.h" +#include "SVGRenderSupport.h" namespace WebCore { class SVGStyledElement; class TransformationMatrix; -class RenderSVGRoot : public RenderContainer { +class RenderSVGRoot : public RenderBox, SVGRenderBase { public: RenderSVGRoot(SVGStyledElement*); ~RenderSVGRoot(); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + virtual bool isSVGRoot() const { return true; } virtual const char* renderName() const { return "RenderSVGRoot"; } virtual int lineHeight(bool b, bool isRootLineBox = false) const; virtual int baselinePosition(bool b, bool isRootLineBox = false) const; virtual void calcPrefWidths(); - + virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - - virtual IntRect absoluteClippedOverflowRect(); - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - virtual TransformationMatrix absoluteTransform() const; + virtual TransformationMatrix localToParentTransform() const; bool fillContains(const FloatPoint&) const; bool strokeContains(const FloatPoint&) const; - FloatRect relativeBBox(bool includeStroke = true) const; - + + virtual FloatRect objectBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; + + // FIXME: Both of these overrides should be removed. virtual TransformationMatrix localTransform() const; - - FloatRect viewport() const; + virtual TransformationMatrix absoluteTransform() const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual void position(InlineBox*); - + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed); + + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + private: - void calcViewport(); - void applyContentTransforms(PaintInfo&, int parentX, int parentY); + void calcViewport(); + const FloatSize& viewportSize() const; + + bool selfWillPaint() const; + + IntSize parentOriginToBorderBox() const; + IntSize borderOriginToContentBox() const; + TransformationMatrix localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const; + TransformationMatrix localToBorderBoxTransform() const; - FloatRect m_viewport; - IntRect m_absoluteBounds; + RenderObjectChildList m_children; + FloatSize m_viewportSize; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp index fd2d3dd..90ff36c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp @@ -26,10 +26,6 @@ #if ENABLE(SVG) #include "RenderSVGTSpan.h" -#include "FloatRect.h" -#include "SVGInlineTextBox.h" -#include "SVGRootInlineBox.h" - namespace WebCore { RenderSVGTSpan::RenderSVGTSpan(Node* n) @@ -37,46 +33,6 @@ RenderSVGTSpan::RenderSVGTSpan(Node* n) { } -void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool) -{ - InlineRunBox* firstBox = firstLineBox(); - - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; - - if (!object) - return; - - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); - - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { - FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); - // FIXME: broken with CSS transforms - rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); - } -} - -void RenderSVGTSpan::absoluteQuads(Vector<FloatQuad>& quads, bool) -{ - InlineRunBox* firstBox = firstLineBox(); - - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; - - if (!object) - return; - - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); - - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { - FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); - // FIXME: broken with CSS transforms - quads.append(absoluteTransform().mapRect(rect)); - } -} - } #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h index d34cd2f..652c5e3 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h @@ -1,8 +1,7 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * (C) 2006 Apple Computer Inc. + * (C) 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 @@ -32,8 +31,12 @@ class RenderSVGTSpan : public RenderSVGInline { public: RenderSVGTSpan(Node*); virtual const char* renderName() const { return "RenderSVGTSpan"; } - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + // 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 1a1196b..9e9809d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp @@ -30,16 +30,19 @@ #include "RenderSVGText.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" +#include "RenderLayer.h" #include "RenderSVGRoot.h" -#include "SimpleFontData.h" #include "SVGLengthList.h" +#include "SVGRenderSupport.h" #include "SVGResourceFilter.h" #include "SVGRootInlineBox.h" #include "SVGTextElement.h" #include "SVGTransformList.h" #include "SVGURIReference.h" +#include "SimpleFontData.h" namespace WebCore { @@ -48,174 +51,145 @@ RenderSVGText::RenderSVGText(SVGTextElement* node) { } -IntRect RenderSVGText::absoluteClippedOverflowRect() +IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { - FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true)); - -#if ENABLE(SVG_FILTERS) - // Filters can expand the bounding box - SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter()); - if (filter) - repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect)); -#endif - - if (!repaintRect.isEmpty()) - repaintRect.inflate(1); // inflate 1 pixel for antialiasing - - return enclosingIntRect(repaintRect); + return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer); } -bool RenderSVGText::requiresLayer() +void RenderSVGText::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) { - return false; + SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); } -bool RenderSVGText::calculateLocalTransform() +void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const { - TransformationMatrix oldTransform = m_localTransform; - m_localTransform = static_cast<SVGTextElement*>(element())->animatedLocalTransform(); - return (oldTransform != m_localTransform); + SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); } 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); - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBounds(); - } + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); // Best guess for a relative starting point - SVGTextElement* text = static_cast<SVGTextElement*>(element()); + SVGTextElement* text = static_cast<SVGTextElement*>(node()); int xOffset = (int)(text->x()->getFirst().value(text)); int yOffset = (int)(text->y()->getFirst().value(text)); - setPos(xOffset, yOffset); - - calculateLocalTransform(); + setLocation(xOffset, yOffset); - RenderBlock::layout(); + m_localTransform = text->animatedLocalTransform(); - m_absoluteBounds = absoluteClippedOverflowRect(); + RenderBlock::layout(); - bool repainted = false; - if (checkForRepaint) - repainted = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); - + repainter.repaintAfterLayout(); setNeedsLayout(false); } -InlineBox* RenderSVGText::createInlineBox(bool, bool, bool) +RootInlineBox* RenderSVGText::createRootBox() { - ASSERT(!isInlineFlow()); - InlineFlowBox* flowBox = new (renderArena()) SVGRootInlineBox(this); - - if (!m_firstLineBox) - m_firstLineBox = m_lastLineBox = flowBox; - else { - m_lastLineBox->setNextLineBox(flowBox); - flowBox->setPreviousLineBox(m_lastLineBox); - m_lastLineBox = flowBox; - } - - return flowBox; + RootInlineBox* box = new (renderArena()) SVGRootInlineBox(this); + box->setIsSVG(true); + return box; } -bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) +bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) { - TransformationMatrix totalTransform = absoluteTransform(); - double localX, localY; - totalTransform.inverse().map(_x, _y, &localX, &localY); - FloatPoint hitPoint(_x, _y); - return RenderBlock::nodeAtPoint(request, result, (int)localX, (int)localY, _tx, _ty, hitTestAction); + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + return RenderBlock::nodeAtPoint(request, result, (int)localPoint.x(), (int)localPoint.y(), 0, 0, hitTestAction); } } return false; } -void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool) +bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int) { RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) return; - - FloatPoint absPos = localToAbsolute(); - - TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); - // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard + // 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()) { - FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height()); - boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f())); - // FIXME: broken with CSS transforms - rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect))); + 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. + rects.append(enclosingIntRect(localToAbsoluteQuad(boxRect).boundingBox())); } } } -void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool) +void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads) { RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) return; - - FloatPoint absPos = localToAbsolute(); - - TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); - // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard + // 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()) { - FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height()); - boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f())); - // FIXME: broken with CSS transforms - quads.append(absoluteTransform().mapRect(boxRect)); + 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. + quads.append(localToAbsoluteQuad(boxRect)); } } } void RenderSVGText::paint(PaintInfo& paintInfo, int, int) { - RenderObject::PaintInfo pi(paintInfo); - pi.rect = absoluteTransform().inverse().mapRect(pi.rect); + PaintInfo pi(paintInfo); + pi.context->save(); + applyTransformToPaintInfo(pi, localToParentTransform()); RenderBlock::paint(pi, 0, 0); + pi.context->restore(); } -FloatRect RenderSVGText::relativeBBox(bool includeStroke) const +FloatRect RenderSVGText::objectBoundingBox() const { - FloatRect repaintRect; + 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()) - repaintRect.unite(FloatRect(box->xPos(), box->yPos(), box->width(), box->height())); + boundingBox.unite(FloatRect(box->x(), box->y(), box->width(), box->height())); } + boundingBox.move(x(), y()); + return boundingBox; +} + +FloatRect RenderSVGText::repaintRectInLocalCoordinates() const +{ + FloatRect repaintRect = objectBoundingBox(); + // SVG needs to include the strokeWidth(), not the textStrokeWidth(). - if (includeStroke && style()->svgStyle()->hasStroke()) { + if (style()->svgStyle()->hasStroke()) { float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 0.0f); #if ENABLE(SVG_FONTS) @@ -231,7 +205,8 @@ FloatRect RenderSVGText::relativeBBox(bool includeStroke) const repaintRect.inflate(strokeWidth); } - repaintRect.move(xPos(), yPos()); + repaintRect.unite(filterBoundingBoxForRenderer(this)); + return repaintRect; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h index d76d451..c1f1430 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h @@ -38,29 +38,36 @@ public: RenderSVGText(SVGTextElement* node); virtual const char* renderName() const { return "RenderSVGText"; } - + virtual bool isSVGText() const { return true; } - - bool calculateLocalTransform(); - virtual TransformationMatrix localTransform() const { return m_localTransform; } - + + virtual TransformationMatrix 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); - - virtual bool requiresLayer(); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + + virtual bool requiresLayer() const { return false; } virtual void layout(); - - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - virtual IntRect absoluteClippedOverflowRect(); - virtual FloatRect relativeBBox(bool includeStroke = true) const; - - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + 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 FloatRect objectBoundingBox() const; + virtual FloatRect repaintRectInLocalCoordinates() const; private: + // FIXME: This can be removed when localTransform() is removed from RenderObject + virtual TransformationMatrix localTransform() const { return m_localTransform; } + + virtual RootInlineBox* createRootBox(); + TransformationMatrix m_localTransform; - IntRect m_absoluteBounds; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp index aa0209c..5d977f9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp @@ -25,7 +25,8 @@ #if ENABLE(SVG) #include "RenderSVGTextPath.h" -#include "FloatRect.h" +#include "FloatQuad.h" +#include "RenderBlock.h" #include "SVGInlineTextBox.h" #include "SVGPathElement.h" #include "SVGRootInlineBox.h" @@ -44,7 +45,7 @@ RenderSVGTextPath::RenderSVGTextPath(Node* n) Path RenderSVGTextPath::layoutPath() const { - SVGTextPathElement* textPathElement = static_cast<SVGTextPathElement*>(element()); + SVGTextPathElement* textPathElement = static_cast<SVGTextPathElement*>(node()); String pathId = SVGURIReference::getTarget(textPathElement->href()); Element* targetElement = textPathElement->document()->getElementById(pathId); if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag)) @@ -64,57 +65,17 @@ Path RenderSVGTextPath::layoutPath() const float RenderSVGTextPath::startOffset() const { - return static_cast<SVGTextPathElement*>(element())->startOffset().valueAsPercentage(); + return static_cast<SVGTextPathElement*>(node())->startOffset().valueAsPercentage(); } bool RenderSVGTextPath::exactAlignment() const { - return static_cast<SVGTextPathElement*>(element())->spacing() == SVG_TEXTPATH_SPACINGTYPE_EXACT; + return static_cast<SVGTextPathElement*>(node())->spacing() == SVG_TEXTPATH_SPACINGTYPE_EXACT; } bool RenderSVGTextPath::stretchMethod() const { - return static_cast<SVGTextPathElement*>(element())->method() == SVG_TEXTPATH_METHODTYPE_STRETCH; -} - -void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int) -{ - InlineRunBox* firstBox = firstLineBox(); - - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; - - if (!object) - return; - - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); - - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { - FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); - // FIXME: broken with CSS transforms - rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); - } -} - -void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool) -{ - InlineRunBox* firstBox = firstLineBox(); - - SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; - - if (!object) - return; - - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); - - for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { - FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); - // FIXME: broken with CSS transforms - quads.append(absoluteTransform().mapRect(rect)); - } + return static_cast<SVGTextPathElement*>(node())->method() == SVG_TEXTPATH_METHODTYPE_STRETCH; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h index 4fd4cc3..efab659 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h @@ -38,8 +38,6 @@ namespace WebCore { bool stretchMethod() const; virtual const char* renderName() const { return "RenderSVGTextPath"; } - virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); private: float m_startOffset; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp index 17d64f3..2324eee 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp @@ -1,8 +1,7 @@ /* Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> - 2004, 2005, 2006 Rob Buis <buis@kde.org> - - This file is part of the KDE project + 2004, 2005, 2006 Rob Buis <buis@kde.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 @@ -35,11 +34,19 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf { } -bool RenderSVGTransformableContainer::calculateLocalTransform() +TransformationMatrix RenderSVGTransformableContainer::localToParentTransform() const +{ + return m_localTransform; +} + +TransformationMatrix RenderSVGTransformableContainer::localTransform() const +{ + return m_localTransform; +} + +void RenderSVGTransformableContainer::calculateLocalTransform() { - TransformationMatrix oldTransform = m_localTransform; - m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); - return (m_localTransform != oldTransform); + m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform(); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h index 897cc63..c929761 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h @@ -1,5 +1,6 @@ /* - Copyright (C) 2007 Eric Seidel <eric@webkit.org + Copyright (C) 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 @@ -17,7 +18,6 @@ Boston, MA 02110-1301, USA. */ - #ifndef RenderSVGTransformableContainer_h #define RenderSVGTransformableContainer_h @@ -30,8 +30,15 @@ namespace WebCore { class RenderSVGTransformableContainer : public RenderSVGContainer { public: RenderSVGTransformableContainer(SVGStyledTransformableElement*); - - virtual bool calculateLocalTransform(); + + virtual TransformationMatrix localToParentTransform() const; + + private: + virtual void calculateLocalTransform(); + // FIXME: This can be made non-virtual once SVGRenderTreeAsText stops using localTransform() + virtual TransformationMatrix localTransform() const; + + TransformationMatrix m_localTransform; }; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp index f6ac424..d208621 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp @@ -2,8 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> 2007 Eric Seidel <eric@webkit.org> - - This file is part of the KDE project + 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 @@ -37,45 +36,12 @@ namespace WebCore { RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node) : RenderSVGContainer(node) { - setReplaced(true); } RenderSVGViewportContainer::~RenderSVGViewportContainer() { } -void RenderSVGViewportContainer::layout() -{ - ASSERT(needsLayout()); - - calcViewport(); - - // Arbitrary affine transforms are incompatible with LayoutState. - view()->disableLayoutState(); - - IntRect oldBounds = m_absoluteBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); - if (checkForRepaint) - oldOutlineBox = absoluteOutlineBounds(); - - calcBounds(); - - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (selfNeedsLayout()) - child->setNeedsLayout(true); - - child->layoutIfNeeded(); - ASSERT(!child->needsLayout()); - } - - if (checkForRepaint) - repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); - - view()->enableLayoutState(); - setNeedsLayout(false); -} - void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) { // A value of zero disables rendering of the element. @@ -85,22 +51,10 @@ void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int pa RenderSVGContainer::paint(paintInfo, parentX, parentY); } -void RenderSVGViewportContainer::applyContentTransforms(PaintInfo& paintInfo) -{ - if (!viewport().isEmpty()) { - if (style()->overflowX() != OVISIBLE) - paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping - - paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y())); - } - - RenderSVGContainer::applyContentTransforms(paintInfo); -} - -void RenderSVGViewportContainer::applyAdditionalTransforms(PaintInfo& paintInfo) +void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) { - paintInfo.context->concatCTM(viewportTransform()); - RenderSVGContainer::applyAdditionalTransforms(paintInfo); + if (style()->overflowX() != OVISIBLE) + paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping } FloatRect RenderSVGViewportContainer::viewport() const @@ -110,9 +64,9 @@ FloatRect RenderSVGViewportContainer::viewport() const void RenderSVGViewportContainer::calcViewport() { - SVGElement* svgelem = static_cast<SVGElement*>(element()); + SVGElement* svgelem = static_cast<SVGElement*>(node()); if (svgelem->hasTagName(SVGNames::svgTag)) { - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); if (!selfNeedsLayout() && !svg->hasRelativeValues()) return; @@ -126,7 +80,7 @@ void RenderSVGViewportContainer::calcViewport() if (!selfNeedsLayout()) return; - SVGMarkerElement* svg = static_cast<SVGMarkerElement*>(element()); + SVGMarkerElement* svg = static_cast<SVGMarkerElement*>(node()); float w = svg->markerWidth().value(svg); float h = svg->markerHeight().value(svg); m_viewport = FloatRect(0, 0, w, h); @@ -135,60 +89,42 @@ void RenderSVGViewportContainer::calcViewport() TransformationMatrix RenderSVGViewportContainer::viewportTransform() const { - if (element()->hasTagName(SVGNames::svgTag)) { - SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); + if (node()->hasTagName(SVGNames::svgTag)) { + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); return svg->viewBoxToViewTransform(viewport().width(), viewport().height()); - } else if (element()->hasTagName(SVGNames::markerTag)) { - SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(element()); + } else if (node()->hasTagName(SVGNames::markerTag)) { + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); return marker->viewBoxToViewTransform(viewport().width(), viewport().height()); } - - return TransformationMatrix(); + + return TransformationMatrix(); } +TransformationMatrix RenderSVGViewportContainer::localToParentTransform() const +{ + TransformationMatrix viewportTranslation; + viewportTranslation.translate(viewport().x(), viewport().y()); + return viewportTransform() * viewportTranslation; + // 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 { - TransformationMatrix ctm = RenderObject::absoluteTransform(); - ctm.translate(viewport().x(), viewport().y()); - return viewportTransform() * ctm; + // This would apply localTransform() twice if localTransform() were not the identity. + return localToParentTransform() * RenderSVGContainer::absoluteTransform(); } -bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) +bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent) { - if (!viewport().isEmpty() - && style()->overflowX() == OHIDDEN - && style()->overflowY() == OHIDDEN) { - // Check if we need to do anything at all. - IntRect overflowBox = overflowRect(false); - overflowBox.move(_tx, _ty); - TransformationMatrix ctm = RenderObject::absoluteTransform(); - ctm.translate(viewport().x(), viewport().y()); - double localX, localY; - ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY); - if (!overflowBox.contains((int)localX, (int)localY)) + // 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 (!viewport().contains(pointInParent)) return false; } - - int sx = 0; - int sy = 0; - - // Respect parent translation offset for non-outermost <svg> elements. - // Outermost <svg> element is handled by RenderSVGRoot. - if (element()->hasTagName(SVGNames::svgTag)) { - sx = _tx; - sy = _ty; - } - - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - if (child->nodeAtPoint(request, result, _x - sx, _y - sy, _tx, _ty, hitTestAction)) { - updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty)); - return true; - } - } - - // Spec: Only graphical elements can be targeted by the mouse, period. - // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched." - return false; + return true; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h index 2e4a49c..8657af4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h @@ -1,8 +1,7 @@ /* Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> - - This file is part of the KDE project + 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 @@ -29,6 +28,8 @@ namespace WebCore { +// This is used for non-root <svg> elements and <marker> elements, neither of which are SVGTransformable +// thus we inherit from RenderSVGContainer instead of RenderSVGTransformableContainer class RenderSVGViewportContainer : public RenderSVGContainer { public: RenderSVGViewportContainer(SVGStyledElement*); @@ -37,22 +38,24 @@ public: virtual bool isSVGContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGViewportContainer"; } - virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual TransformationMatrix absoluteTransform() const; - virtual TransformationMatrix viewportTransform() const; + virtual TransformationMatrix localToParentTransform() const; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + // FIXME: This override should be removed once callers of RenderBox::absoluteTransform() can be removed. + virtual TransformationMatrix absoluteTransform() const; FloatRect viewport() const; + // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed. + TransformationMatrix viewportTransform() const; + private: - void calcViewport(); + virtual void calcViewport(); + + virtual void applyViewportClip(PaintInfo&); + virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); - virtual void applyContentTransforms(PaintInfo&); - virtual void applyAdditionalTransforms(PaintInfo&); - FloatRect m_viewport; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp index b7045d6..db24a06 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp @@ -30,12 +30,12 @@ namespace WebCore { -PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer) +PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer) { return adoptRef(new RenderScrollbar(client, orientation, renderer)); } -RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer) +RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer) : Scrollbar(client, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme()) , m_owner(renderer) { @@ -50,7 +50,7 @@ void RenderScrollbar::setParent(ScrollView* parent) { Scrollbar::setParent(parent); if (!parent) { - // Destroy all of the scrollbar's RenderObjects. + // Destroy all of the scrollbar's RenderBoxes. updateScrollbarParts(true); } } @@ -117,7 +117,7 @@ ScrollbarPart RenderScrollbar::partForStyleResolve() return s_styleResolvePart; } -PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, RenderStyle::PseudoId pseudoId) +PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, PseudoId pseudoId) { s_styleResolvePart = partType; s_styleResolveScrollbar = this; @@ -158,23 +158,23 @@ void RenderScrollbar::updateScrollbarParts(bool destroy) } } -static RenderStyle::PseudoId pseudoForScrollbarPart(ScrollbarPart part) +static PseudoId pseudoForScrollbarPart(ScrollbarPart part) { switch (part) { case BackButtonStartPart: case ForwardButtonStartPart: case BackButtonEndPart: case ForwardButtonEndPart: - return RenderStyle::SCROLLBAR_BUTTON; + return SCROLLBAR_BUTTON; case BackTrackPart: case ForwardTrackPart: - return RenderStyle::SCROLLBAR_TRACK_PIECE; + return SCROLLBAR_TRACK_PIECE; case ThumbPart: - return RenderStyle::SCROLLBAR_THUMB; + return SCROLLBAR_THUMB; case TrackBGPart: - return RenderStyle::SCROLLBAR_TRACK; + return SCROLLBAR_TRACK; default: - return RenderStyle::SCROLLBAR; + return SCROLLBAR; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h index ad97001..245d750 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h @@ -26,23 +26,24 @@ #ifndef RenderScrollbar_h #define RenderScrollbar_h +#include "RenderStyleConstants.h" #include "Scrollbar.h" -#include "RenderStyle.h" #include <wtf/HashMap.h> namespace WebCore { -class RenderObject; +class RenderBox; +class RenderStyle; class RenderScrollbarPart; class RenderStyle; class RenderScrollbar : public Scrollbar { protected: - RenderScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*); + RenderScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderBox*); public: friend class Scrollbar; - static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*); + static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderBox*); virtual ~RenderScrollbar(); virtual void setParent(ScrollView*); @@ -60,7 +61,7 @@ public: virtual void styleChanged(); - RenderObject* owningRenderer() const { return m_owner; } + RenderBox* owningRenderer() const { return m_owner; } void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&); @@ -69,12 +70,13 @@ public: IntRect trackPieceRectWithMargins(ScrollbarPart, const IntRect&); int minimumThumbLength(); + virtual bool isCustomScrollbar() const { return true; } private: - PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, RenderStyle::PseudoId); + PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, PseudoId); void updateScrollbarPart(ScrollbarPart, bool destroy = false); - RenderObject* m_owner; + RenderBox* m_owner; HashMap<unsigned, RenderScrollbarPart*> m_parts; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp index 3f69ba6..0f29aeb 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp @@ -45,14 +45,14 @@ RenderScrollbarPart::~RenderScrollbarPart() void RenderScrollbarPart::layout() { - setPos(0, 0); // We don't worry about positioning ourselves. We're just determining our minimum width/height. + setLocation(IntPoint()); // We don't worry about positioning ourselves. We're just determining our minimum width/height. if (m_scrollbar->orientation() == HorizontalScrollbar) layoutHorizontalPart(); else layoutVerticalPart(); - m_overflowWidth = max(m_width, m_overflowWidth); - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowWidth = max(width(), m_overflowWidth); + m_overflowHeight = max(height(), m_overflowHeight); setNeedsLayout(false); } @@ -60,11 +60,11 @@ void RenderScrollbarPart::layout() void RenderScrollbarPart::layoutHorizontalPart() { if (m_part == ScrollbarBGPart) { - m_width = m_scrollbar->width(); + setWidth(m_scrollbar->width()); computeScrollbarHeight(); } else { computeScrollbarWidth(); - m_height = m_scrollbar->height(); + setHeight(m_scrollbar->height()); } } @@ -72,9 +72,9 @@ void RenderScrollbarPart::layoutVerticalPart() { if (m_part == ScrollbarBGPart) { computeScrollbarWidth(); - m_height = m_scrollbar->height(); + setHeight(m_scrollbar->height()); } else { - m_width = m_scrollbar->width(); + setWidth(m_scrollbar->width()); computeScrollbarHeight(); } } @@ -89,10 +89,10 @@ static int calcScrollbarThicknessUsing(const Length& l, int containingLength) void RenderScrollbarPart::computeScrollbarWidth() { int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight(); - int width = calcScrollbarThicknessUsing(style()->width(), visibleSize); + int w = calcScrollbarThicknessUsing(style()->width(), visibleSize); int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize); - int maxWidth = style()->maxWidth().isUndefined() ? width : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize); - m_width = max(minWidth, min(maxWidth, width)); + int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize); + setWidth(max(minWidth, min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginLeft = style()->marginLeft().calcMinValue(visibleSize); @@ -102,10 +102,10 @@ void RenderScrollbarPart::computeScrollbarWidth() void RenderScrollbarPart::computeScrollbarHeight() { int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom(); - int height = calcScrollbarThicknessUsing(style()->height(), visibleSize); + int h = calcScrollbarThicknessUsing(style()->height(), visibleSize); int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize); - int maxHeight = style()->maxHeight().isUndefined() ? height : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize); - m_height = max(minHeight, min(maxHeight, height)); + int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize); + setHeight(max(minHeight, min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginTop = style()->marginTop().calcMinValue(visibleSize); @@ -122,14 +122,20 @@ void RenderScrollbarPart::calcPrefWidths() setPrefWidthsDirty(false); } -void RenderScrollbarPart::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderScrollbarPart::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +{ + RenderBlock::styleWillChange(diff, newStyle); + setInline(false); +} + +void RenderScrollbarPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); setInline(false); setPositioned(false); setFloating(false); setHasOverflowClip(false); - if (oldStyle && m_scrollbar && m_part != NoPart && diff >= RenderStyle::Repaint) + if (oldStyle && m_scrollbar && m_part != NoPart && diff >= StyleDifferenceRepaint) m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); } @@ -144,7 +150,7 @@ void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rec void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, int tx, int ty, const IntRect& rect) { // Make sure our dimensions match the rect. - setPos(rect.x() - tx, rect.y() - ty); + setLocation(rect.x() - tx, rect.y() - ty); setWidth(rect.width()); setHeight(rect.height()); setOverflowWidth(max(rect.width(), overflowWidth())); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h index 2010f97..114bbff 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h @@ -40,7 +40,7 @@ public: virtual const char* renderName() const { return "RenderScrollbarPart"; } - virtual bool requiresLayer() { return false; } + virtual bool requiresLayer() const { return false; } virtual void layout(); virtual void calcPrefWidths(); @@ -48,7 +48,8 @@ public: void paintIntoRect(GraphicsContext*, int tx, int ty, const IntRect&); protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference diff, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); private: diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h b/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h new file mode 100644 index 0000000..e7b7b78 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSelectionInfo.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (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. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 SelectionInfo_h +#define SelectionInfo_h + +#include "IntRect.h" +#include "RenderBox.h" + +namespace WebCore { + +class RenderSelectionInfoBase { +public: + RenderSelectionInfoBase() + : m_object(0) + , m_repaintContainer(0) + , m_state(RenderObject::SelectionNone) + { + } + + RenderSelectionInfoBase(RenderObject* o) + : m_object(o) + , m_repaintContainer(o->containerForRepaint()) + , m_state(o->selectionState()) + { + } + + RenderObject* object() const { return m_object; } + RenderBoxModelObject* repaintContainer() const { return m_repaintContainer; } + RenderObject::SelectionState state() const { return m_state; } + +protected: + RenderObject* m_object; + RenderBoxModelObject* m_repaintContainer; + RenderObject::SelectionState m_state; +}; + +// This struct is used when the selection changes to cache the old and new state of the selection for each RenderObject. +class RenderSelectionInfo : public RenderSelectionInfoBase { +public: + RenderSelectionInfo(RenderObject* o, bool clipToVisibleContent) + : RenderSelectionInfoBase(o) + , m_rect(o->needsLayout() ? IntRect() : o->selectionRectForRepaint(m_repaintContainer, clipToVisibleContent)) + { + } + + void repaint() + { + m_object->repaintUsingContainer(m_repaintContainer, m_rect); + } + + IntRect rect() const { return m_rect; } + +private: + IntRect m_rect; // relative to repaint container +}; + + +// This struct is used when the selection changes to cache the old and new state of the selection for each RenderBlock. +class RenderBlockSelectionInfo : public RenderSelectionInfoBase { +public: + RenderBlockSelectionInfo(RenderBlock* b) + : RenderSelectionInfoBase(b) + , m_rects(b->needsLayout() ? GapRects() : block()->selectionGapRectsForRepaint(m_repaintContainer)) + { + } + + void repaint() + { + m_object->repaintUsingContainer(m_repaintContainer, m_rects); + } + + RenderBlock* block() const { return toRenderBlock(m_object); } + GapRects rects() const { return m_rects; } + +private: + GapRects m_rects; // relative to repaint container +}; + +} // namespace WebCore + + +#endif // SelectionInfo_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp index 040fa31..610a060 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp @@ -1,6 +1,5 @@ -/** - * - * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,8 +30,11 @@ #include "HTMLInputElement.h" #include "HTMLDivElement.h" #include "HTMLNames.h" +#include "MediaControlElements.h" #include "MouseEvent.h" +#include "RenderLayer.h" #include "RenderTheme.h" +#include "RenderView.h" #include <wtf/MathExtras.h> using std::min; @@ -41,44 +43,115 @@ namespace WebCore { using namespace HTMLNames; -const int defaultTrackLength = 129; +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; + + explicit SliderRange(HTMLInputElement*); + double clampValue(double value); + + // Map value into 0-1 range + double proportionFromValue(double value) + { + if (minimum == maximum) + return 0; -class HTMLSliderThumbElement : public HTMLDivElement { + 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"); + + // FIXME: This treats maximum strings that can't be parsed as 0, but perhaps 100 would be more appropriate. + const AtomicString& maxString = element->getAttribute(maxAttr); + maximum = maxString.isNull() ? 100.0 : maxString.toDouble(); + + // If the maximum is smaller, use it as the minimum. + minimum = min(element->getAttribute(minAttr).toDouble(), maximum); +} + +double SliderRange::clampValue(double value) +{ + double clampedValue = max(minimum, min(value, maximum)); + return isIntegral ? round(clampedValue) : clampedValue; +} + +double SliderRange::valueFromElement(HTMLInputElement* element, bool* wasClamped) +{ + String valueString = element->value(); + double oldValue = valueString.isNull() ? (minimum + maximum) / 2 : valueString.toDouble(); + double newValue = clampValue(oldValue); + + if (wasClamped) + *wasClamped = valueString.isNull() || 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); + return range.proportionFromValue(range.valueFromElement(element)); +} + +class SliderThumbElement : public HTMLDivElement { public: - HTMLSliderThumbElement(Document*, Node* shadowParent = 0); - + SliderThumbElement(Document*, Node* shadowParent); + + bool inDragMode() const { return m_inDragMode; } + virtual void defaultEventHandler(Event*); + +private: virtual bool isShadowNode() const { return true; } virtual Node* shadowParentNode() { return m_shadowParent; } - - bool inDragMode() const { return m_inDragMode; } -private: + Node* m_shadowParent; FloatPoint m_initialClickPoint; // initial click point in RenderSlider-local coordinates int m_initialPosition; bool m_inDragMode; }; -HTMLSliderThumbElement::HTMLSliderThumbElement(Document* doc, Node* shadowParent) - : HTMLDivElement(divTag, doc) +SliderThumbElement::SliderThumbElement(Document* document, Node* shadowParent) + : HTMLDivElement(divTag, document) , m_shadowParent(shadowParent) - , m_initialClickPoint(IntPoint()) , m_initialPosition(0) , m_inDragMode(false) { } -void HTMLSliderThumbElement::defaultEventHandler(Event* event) +void SliderThumbElement::defaultEventHandler(Event* event) { const AtomicString& eventType = event->type(); if (eventType == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); RenderSlider* slider; - if (document()->frame() && renderer() && renderer()->parent() && + if (document()->frame() && renderer() && (slider = static_cast<RenderSlider*>(renderer()->parent())) && slider->mouseEventIsInThumb(mouseEvent)) { + // Cache the initial point where the mouse down occurred, in slider coordinates - m_initialClickPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true); + m_initialClickPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true); // Cache the initial position of the thumb. m_initialPosition = slider->currentPosition(); m_inDragMode = true; @@ -101,16 +174,11 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event) // Move the slider MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent()); - FloatPoint curPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true); - int newPosition = slider->positionForOffset( - IntPoint(m_initialPosition + curPoint.x() - m_initialClickPoint.x() - + (renderer()->width() / 2), - m_initialPosition + curPoint.y() - m_initialClickPoint.y() - + (renderer()->height() / 2))); - if (slider->currentPosition() != newPosition) { - slider->setCurrentPosition(newPosition); - slider->valueChanged(); - } + + FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true); + IntPoint eventOffset(m_initialPosition + curPoint.x() - m_initialClickPoint.x() + renderBox()->width() / 2, + m_initialPosition + curPoint.y() - m_initialClickPoint.y() + renderBox()->height() / 2); + slider->setValueForPosition(slider->positionForOffset(eventOffset)); event->setDefaultHandled(); return; } @@ -121,7 +189,6 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event) RenderSlider::RenderSlider(HTMLInputElement* element) : RenderBlock(element) - , m_thumb(0) { } @@ -166,20 +233,20 @@ void RenderSlider::calcPrefWidths() setPrefWidthsDirty(false); } -void RenderSlider::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderSlider::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); - + if (m_thumb) - m_thumb->renderer()->setStyle(createThumbStyle(style(), m_thumb->renderer()->style())); - + m_thumb->renderer()->setStyle(createThumbStyle(style())); + setReplaced(isInline()); } -PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parentStyle, const RenderStyle* oldStyle) +PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parentStyle) { RefPtr<RenderStyle> style; - RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SLIDER_THUMB); + RenderStyle* pseudoStyle = getCachedPseudoStyle(SLIDER_THUMB); if (pseudoStyle) // We may be sharing style with another slider, but we must not share the thumb style. style = RenderStyle::clone(pseudoStyle); @@ -190,16 +257,11 @@ PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parent style->inheritFrom(parentStyle); style->setDisplay(BLOCK); - style->setPosition(RelativePosition); - if (oldStyle) { - style->setLeft(oldStyle->left()); - style->setTop(oldStyle->top()); - } if (parentStyle->appearance() == SliderVerticalPart) - style->setAppearance(SliderThumbVerticalPart); + style->setAppearance(SliderThumbVerticalPart); else if (parentStyle->appearance() == SliderHorizontalPart) - style->setAppearance(SliderThumbHorizontalPart); + style->setAppearance(SliderThumbHorizontalPart); else if (parentStyle->appearance() == MediaSliderPart) style->setAppearance(MediaSliderThumbPart); @@ -207,42 +269,97 @@ PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parent } void RenderSlider::layout() -{ - bool relayoutChildren = false; - - if (m_thumb && m_thumb->renderer()) { - - int oldWidth = m_width; - calcWidth(); - int oldHeight = m_height; - calcHeight(); - - if (oldWidth != m_width || oldHeight != m_height) - relayoutChildren = true; - - // Allow the theme to set the size of the thumb - if (m_thumb->renderer()->style()->hasAppearance()) - theme()->adjustSliderThumbSize(m_thumb->renderer()); +{ + ASSERT(needsLayout()); + + RenderBox* thumb = m_thumb ? toRenderBox(m_thumb->renderer()) : 0; + + IntSize baseSize(borderLeft() + paddingLeft() + paddingRight() + borderRight(), + borderTop() + paddingTop() + paddingBottom() + borderBottom()); + + if (thumb) { + // Allow the theme to set the size of the thumb. + if (thumb->style()->hasAppearance()) { + // FIXME: This should pass the style, not the renderer, to the theme. + theme()->adjustSliderThumbSize(thumb); + } + + baseSize.expand(thumb->style()->width().calcMinValue(0), thumb->style()->height().calcMinValue(0)); + } + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + + IntSize oldSize = size(); + + setSize(baseSize); + calcWidth(); + calcHeight(); + + IntRect overflowRect(IntPoint(), size()); + + if (thumb) { + if (oldSize != size()) + thumb->setChildNeedsLayout(true, false); + + LayoutStateMaintainer statePusher(view(), this, size()); + + IntRect oldThumbRect = thumb->frameRect(); + thumb->layoutIfNeeded(); + + IntRect thumbRect; + + thumbRect.setWidth(thumb->style()->width().calcMinValue(contentWidth())); + thumbRect.setHeight(thumb->style()->height().calcMinValue(contentHeight())); + + double fraction = sliderPosition(static_cast<HTMLInputElement*>(node())); + IntRect contentRect = contentBoxRect(); if (style()->appearance() == SliderVerticalPart) { - // FIXME: Handle percentage widths correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104 - m_thumb->renderer()->style()->setLeft(Length(contentWidth() / 2 - m_thumb->renderer()->style()->width().value() / 2, Fixed)); + thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2); + thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction))); } else { - // FIXME: Handle percentage heights correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104 - m_thumb->renderer()->style()->setTop(Length(contentHeight() / 2 - m_thumb->renderer()->style()->height().value() / 2, Fixed)); + thumbRect.setX(contentRect.x() + static_cast<int>(nextafter((contentRect.width() - thumbRect.width()) + 1, 0) * fraction)); + thumbRect.setY(contentRect.y() + (contentRect.height() - thumbRect.height()) / 2); } - if (relayoutChildren) - setPositionFromValue(true); + thumb->setFrameRect(thumbRect); + + if (thumb->checkForRepaintDuringLayout()) + thumb->repaintDuringLayoutIfMoved(oldThumbRect); + + statePusher.pop(); + + IntRect thumbOverflowRect = thumb->overflowRect(); + thumbOverflowRect.move(thumb->x(), thumb->y()); + overflowRect.unite(thumbOverflowRect); } - RenderBlock::layoutBlock(relayoutChildren); + // FIXME: m_overflowWidth and m_overflowHeight should be renamed + // m_overflowRight and m_overflowBottom. + m_overflowLeft = overflowRect.x(); + m_overflowTop = overflowRect.y(); + m_overflowWidth = overflowRect.right(); + m_overflowHeight = overflowRect.bottom(); + + repainter.repaintAfterLayout(); + + setNeedsLayout(false); } 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 HTMLSliderThumbElement(document(), node()); + m_thumb = new SliderThumbElement(document(), node()); RefPtr<RenderStyle> thumbStyle = createThumbStyle(style()); m_thumb->setRenderer(m_thumb->createRenderer(renderArena(), thumbStyle.get())); m_thumb->renderer()->setStyle(thumbStyle.release()); @@ -250,17 +367,23 @@ void RenderSlider::updateFromElement() m_thumb->setInDocument(true); addChild(m_thumb->renderer()); } - setPositionFromValue(); - setNeedsLayout(true, false); + setNeedsLayout(true); } bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt) { if (!m_thumb || !m_thumb->renderer()) return false; - - FloatPoint localPoint = m_thumb->renderer()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true); - IntRect thumbBounds = m_thumb->renderer()->borderBox(); + +#if ENABLE(VIDEO) + if (style()->appearance() == MediaSliderPart) { + MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node()); + return sliderThumb->hitTest(evt->absoluteLocation()); + } +#endif + + FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true); + IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect(); return thumbBounds.contains(roundedIntPoint(localPoint)); } @@ -268,135 +391,79 @@ void RenderSlider::setValueForPosition(int position) { if (!m_thumb || !m_thumb->renderer()) return; - - const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr); - const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr); - const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr); - - double minVal = minStr.isNull() ? 0.0 : minStr.toDouble(); - double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble(); - minVal = min(minVal, maxVal); // Make sure the range is sane. - - // Calculate the new value based on the position - double factor = (double)position / (double)trackSize(); - if (style()->appearance() == SliderVerticalPart) - factor = 1.0 - factor; - double val = minVal + factor * (maxVal - minVal); - - val = max(minVal, min(val, maxVal)); // Make sure val is within min/max. - // Force integer value if not float. - if (!equalIgnoringCase(precision, "float")) - val = lround(val); - - static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val)); - - if (position != currentPosition()) { - setCurrentPosition(position); - static_cast<HTMLInputElement*>(node())->onChange(); - } -} + HTMLInputElement* element = static_cast<HTMLInputElement*>(node()); -double RenderSlider::setPositionFromValue(bool inLayout) -{ - if (!m_thumb || !m_thumb->renderer()) - return 0; - - if (!inLayout) - document()->updateLayout(); - - String value = static_cast<HTMLInputElement*>(node())->value(); - const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr); - const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr); - const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr); - - double minVal = minStr.isNull() ? 0.0 : minStr.toDouble(); - double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble(); - minVal = min(minVal, maxVal); // Make sure the range is sane. - - double oldVal = value.isNull() ? (maxVal + minVal)/2.0 : value.toDouble(); - double val = max(minVal, min(oldVal, maxVal)); // Make sure val is within min/max. - - // Force integer value if not float. - if (!equalIgnoringCase(precision, "float")) - val = lround(val); - - // Calculate the new position based on the value - double factor = (val - minVal) / (maxVal - minVal); + // Calculate the new value based on the position, and send it to the element. + SliderRange range(element); + double fraction = static_cast<double>(position) / trackSize(); if (style()->appearance() == SliderVerticalPart) - factor = 1.0 - factor; + fraction = 1 - fraction; + double value = range.clampValue(range.valueFromProportion(fraction)); + element->setValueFromRenderer(String::number(value)); - setCurrentPosition((int)(factor * trackSize())); - - if (value.isNull() || val != oldVal) - static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val)); - - return val; + // Also update the position if appropriate. + if (position != currentPosition()) { + setNeedsLayout(true); + + // FIXME: It seems like this could send extra change events if the same value is set + // multiple times with no layout in between. + element->dispatchFormControlChangeEvent(); + } } int RenderSlider::positionForOffset(const IntPoint& p) { if (!m_thumb || !m_thumb->renderer()) return 0; - + int position; if (style()->appearance() == SliderVerticalPart) - position = p.y() - m_thumb->renderer()->height() / 2; + position = p.y() - m_thumb->renderBox()->height() / 2; else - position = p.x() - m_thumb->renderer()->width() / 2; + position = p.x() - m_thumb->renderBox()->width() / 2; return max(0, min(position, trackSize())); } -void RenderSlider::valueChanged() -{ - setValueForPosition(currentPosition()); - static_cast<HTMLInputElement*>(node())->onChange(); -} - int RenderSlider::currentPosition() { - if (!m_thumb || !m_thumb->renderer()) - return 0; - - if (style()->appearance() == SliderVerticalPart) - return m_thumb->renderer()->style()->top().value(); - return m_thumb->renderer()->style()->left().value(); -} - -void RenderSlider::setCurrentPosition(int pos) -{ - if (!m_thumb || !m_thumb->renderer()) - return; + ASSERT(m_thumb); + ASSERT(m_thumb->renderer()); if (style()->appearance() == SliderVerticalPart) - m_thumb->renderer()->style()->setTop(Length(pos, Fixed)); - else - m_thumb->renderer()->style()->setLeft(Length(pos, Fixed)); - - m_thumb->renderer()->layer()->updateLayerPosition(); - repaint(); - m_thumb->renderer()->repaint(); + return toRenderBox(m_thumb->renderer())->y() - contentBoxRect().y(); + return toRenderBox(m_thumb->renderer())->x() - contentBoxRect().x(); } int RenderSlider::trackSize() { - if (!m_thumb || !m_thumb->renderer()) - return 0; + ASSERT(m_thumb); + ASSERT(m_thumb->renderer()); if (style()->appearance() == SliderVerticalPart) - return contentHeight() - m_thumb->renderer()->height(); - return contentWidth() - m_thumb->renderer()->width(); + return contentHeight() - m_thumb->renderBox()->height(); + return contentWidth() - m_thumb->renderBox()->width(); } -void RenderSlider::forwardEvent(Event* evt) +void RenderSlider::forwardEvent(Event* event) { - m_thumb->defaultEventHandler(evt); + if (event->isMouseEvent()) { + MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); + if (event->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) { + if (!mouseEventIsInThumb(mouseEvent)) { + IntPoint eventOffset = roundedIntPoint(absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); + setValueForPosition(positionForOffset(eventOffset)); + } + } + } + + m_thumb->defaultEventHandler(event); } bool RenderSlider::inDragMode() const { - return m_thumb->inDragMode(); + return m_thumb && m_thumb->inDragMode(); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h index 2667672..f1eab9c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h @@ -1,6 +1,5 @@ -/** - * - * Copyright (C) 2006 Apple Computer, Inc. +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,16 +25,19 @@ namespace WebCore { - class HTMLDivElement; class HTMLInputElement; - class HTMLSliderThumbElement; class MouseEvent; + class SliderThumbElement; class RenderSlider : public RenderBlock { public: RenderSlider(HTMLInputElement*); - ~RenderSlider(); + virtual ~RenderSlider(); + + void forwardEvent(Event*); + bool inDragMode() const; + private: virtual const char* renderName() const { return "RenderSlider"; } virtual bool isSlider() const { return true; } @@ -43,30 +45,25 @@ namespace WebCore { virtual void calcPrefWidths(); virtual void layout(); virtual void updateFromElement(); - + bool mouseEventIsInThumb(MouseEvent*); void setValueForPosition(int position); - double setPositionFromValue(bool inLayout = false); + void setPositionFromValue(); int positionForOffset(const IntPoint&); - void valueChanged(); - int currentPosition(); - void setCurrentPosition(int pos); - - void forwardEvent(Event*); - bool inDragMode() const; - protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - - private: - PassRefPtr<RenderStyle> createThumbStyle(const RenderStyle* parentStyle, const RenderStyle* oldStyle = 0); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + PassRefPtr<RenderStyle> createThumbStyle(const RenderStyle* parentStyle); + int trackSize(); - RefPtr<HTMLSliderThumbElement> m_thumb; -}; + RefPtr<SliderThumbElement> m_thumb; + + friend class SliderThumbElement; + }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp index 4561d57..48b0d1c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp @@ -52,8 +52,6 @@ RenderTable::RenderTable(Node* node) , m_firstBody(0) , m_tableLayout(0) , m_currentBorder(0) - , m_frame(Void) - , m_rules(None) , m_hasColElements(false) , m_needsSectionRecalc(0) , m_hSpacing(0) @@ -70,7 +68,7 @@ RenderTable::~RenderTable() delete m_tableLayout; } -void RenderTable::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -110,8 +108,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) if (!beforeChild && isAfterContent(lastChild())) beforeChild = lastChild(); - bool wrapInAnonymousSection = true; - bool isTableElement = element() && element()->hasTagName(tableTag); + bool wrapInAnonymousSection = !child->isPositioned(); if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) { // First caption wins. @@ -123,7 +120,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) m_caption = 0; } if (!m_caption) - m_caption = static_cast<RenderBlock*>(child); + m_caption = toRenderBlock(child); wrapInAnonymousSection = false; } else if (child->isTableCol()) { m_hasColElements = true; @@ -131,56 +128,44 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) } else if (child->isTableSection()) { switch (child->style()->display()) { case TABLE_HEADER_GROUP: - if (child->isTableSection()) { - resetSectionPointerIfNotBefore(m_head, beforeChild); - if (!m_head) { - m_head = static_cast<RenderTableSection*>(child); - } else { - resetSectionPointerIfNotBefore(m_firstBody, beforeChild); - if (!m_firstBody) - m_firstBody = static_cast<RenderTableSection*>(child); - } + resetSectionPointerIfNotBefore(m_head, beforeChild); + if (!m_head) { + m_head = static_cast<RenderTableSection*>(child); + } else { + resetSectionPointerIfNotBefore(m_firstBody, beforeChild); + if (!m_firstBody) + m_firstBody = static_cast<RenderTableSection*>(child); } wrapInAnonymousSection = false; break; case TABLE_FOOTER_GROUP: - if (child->isTableSection()) { - resetSectionPointerIfNotBefore(m_foot, beforeChild); - if (!m_foot) { - m_foot = static_cast<RenderTableSection*>(child); - wrapInAnonymousSection = false; - break; - } + resetSectionPointerIfNotBefore(m_foot, beforeChild); + if (!m_foot) { + m_foot = static_cast<RenderTableSection*>(child); + wrapInAnonymousSection = false; + break; } // Fall through. case TABLE_ROW_GROUP: - if (child->isTableSection()) { - resetSectionPointerIfNotBefore(m_firstBody, beforeChild); - if (!m_firstBody) - m_firstBody = static_cast<RenderTableSection*>(child); - } + resetSectionPointerIfNotBefore(m_firstBody, beforeChild); + if (!m_firstBody) + m_firstBody = static_cast<RenderTableSection*>(child); wrapInAnonymousSection = false; break; default: ASSERT_NOT_REACHED(); } - } else if (child->isTableCell() || child->isTableRow()) { + } else if (child->isTableCell() || child->isTableRow()) + wrapInAnonymousSection = true; + else wrapInAnonymousSection = true; - } else { - // Allow a form to just sit at the top level. - wrapInAnonymousSection = !isTableElement || !child->element() || !(child->element()->hasTagName(formTag) && document()->isHTMLDocument()); - - // FIXME: Allow the delete button container element to sit at the top level. This is needed until http://bugs.webkit.org/show_bug.cgi?id=11363 is fixed. - if (wrapInAnonymousSection && child->element() && child->element()->isHTMLElement() && static_cast<HTMLElement*>(child->element())->id() == DeleteButtonController::containerElementIdentifier) - wrapInAnonymousSection = false; - } if (!wrapInAnonymousSection) { // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that. while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION) beforeChild = beforeChild->parent(); - RenderContainer::addChild(child, beforeChild); + RenderBox::addChild(child, beforeChild); return; } @@ -208,6 +193,12 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) section->addChild(child); } +void RenderTable::removeChild(RenderObject* oldChild) +{ + RenderBox::removeChild(oldChild); + setNeedsSectionRecalc(); +} + void RenderTable::calcWidth() { if (isPositioned()) @@ -219,12 +210,12 @@ void RenderTable::calcWidth() LengthType widthType = style()->width().type(); if (widthType > Relative && style()->width().isPositive()) { // Percent or fixed table - m_width = style()->width().calcMinValue(availableWidth); - m_width = max(minPrefWidth(), m_width); + setWidth(style()->width().calcMinValue(availableWidth)); + setWidth(max(minPrefWidth(), width())); } else { // An auto width table should shrink to fit within the line width if necessary in order to // avoid overlapping floats. - availableWidth = cb->lineWidth(m_y); + availableWidth = cb->lineWidth(y(), false); // Subtract out any fixed margins from our available width for auto width tables. int marginTotal = 0; @@ -237,10 +228,10 @@ void RenderTable::calcWidth() int availContentWidth = max(0, availableWidth - marginTotal); // Ensure we aren't bigger than our max width or smaller than our min width. - m_width = min(availContentWidth, maxPrefWidth()); + setWidth(min(availContentWidth, maxPrefWidth())); } - m_width = max(m_width, minPrefWidth()); + setWidth(max(width(), minPrefWidth())); // Finally, with our true width determined, compute our margins for real. m_marginRight = 0; @@ -257,32 +248,25 @@ void RenderTable::layout() recalcSectionsIfNeeded(); - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } - - LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y)); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); - m_height = 0; + setHeight(0); m_overflowHeight = 0; m_overflowTop = 0; initMaxMarginValues(); - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); - if (m_caption && m_width != oldWidth) + if (m_caption && width() != oldWidth) m_caption->setNeedsLayout(true, false); // FIXME: The optimisation below doesn't work since the internal table // layout could have changed. we need to add a flag to the table // layout that tells us if something has changed in the min max // calculations to do it correctly. -// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() ) +// if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) m_tableLayout->layout(); setCellWidths(); @@ -294,18 +278,24 @@ void RenderTable::layout() bool collapsing = collapseBorders(); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - // FIXME: What about a form that has a display value that makes it a table section? - if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag))) - child->layout(); if (child->isTableSection()) { + child->layoutIfNeeded(); RenderTableSection* section = static_cast<RenderTableSection*>(child); calculatedHeight += section->calcRowHeight(); if (collapsing) section->recalcOuterBorder(); + ASSERT(!section->needsLayout()); + } else if (child->isTableCol()) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); } } - m_overflowWidth = m_width + (collapsing ? outerBorderRight() - borderRight() : 0); + // Only lay out one caption, since it's the only one we're going to end up painting. + if (m_caption) + m_caption->layoutIfNeeded(); + + m_overflowWidth = width() + (collapsing ? outerBorderRight() - borderRight() : 0); m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0; // If any table section moved vertically, we will just repaint everything from that @@ -316,28 +306,28 @@ void RenderTable::layout() // FIXME: Collapse caption margin. if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { - IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height()); + IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - m_caption->setPos(m_caption->marginLeft(), m_height); + m_caption->setLocation(m_caption->marginLeft(), height()); if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) m_caption->repaintDuringLayoutIfMoved(captionRect); - m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom(); - m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false)); + setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); + m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, m_caption->y() + m_caption->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, m_caption->y() + m_caption->overflowHeight(false)); - if (m_height != oldTableTop) { + if (height() != oldTableTop) { sectionMoved = true; - movedSectionTop = min(m_height, oldTableTop); + movedSectionTop = min(height(), oldTableTop); } } int bpTop = borderTop() + (collapsing ? 0 : paddingTop()); int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom()); - m_height += bpTop; + setHeight(height() + bpTop); if (!isPositioned()) calcHeight(); @@ -352,16 +342,15 @@ void RenderTable::layout() th = max(0, th); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (!child->isTableSection()) - continue; - // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. - static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); + if (child->isTableSection()) + // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. + static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); } if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) { // Completely empty tables (with no sections or anything) should at least honor specified height // in strict mode. - m_height += th; + setHeight(height() + th); } int bl = borderLeft(); @@ -371,38 +360,38 @@ void RenderTable::layout() // position the table sections RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); while (section) { - if (!sectionMoved && section->yPos() != m_height) { + if (!sectionMoved && section->y() != height()) { sectionMoved = true; - movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false); + movedSectionTop = min(height(), section->y()) + section->overflowTop(false); } - section->setPos(bl, m_height); + section->setLocation(bl, height()); - m_height += section->height(); - m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false)); + setHeight(height() + section->height()); + m_overflowLeft = min(m_overflowLeft, section->x() + section->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, section->x() + section->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, section->y() + section->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, section->y() + section->overflowHeight(false)); section = sectionBelow(section); } - m_height += bpBottom; + setHeight(height() + bpBottom); if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) { - IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height()); + IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - m_caption->setPos(m_caption->marginLeft(), m_height); + m_caption->setLocation(m_caption->marginLeft(), height()); if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) m_caption->repaintDuringLayoutIfMoved(captionRect); - m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom(); - m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false)); + setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); + m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false)); } if (isPositioned()) calcHeight(); - m_overflowHeight = max(m_overflowHeight, m_height); + m_overflowHeight = max(m_overflowHeight, height()); // table can be containing block of positioned elements. // FIXME: Only pass true if width or height changed. @@ -411,9 +400,9 @@ void RenderTable::layout() if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -427,10 +416,8 @@ void RenderTable::layout() statePusher.pop(); - bool didFullRepaint = true; + bool didFullRepaint = repainter.repaintAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. - if (checkForRepaint) - didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); if (!didFullRepaint && sectionMoved) repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop)); @@ -447,8 +434,8 @@ void RenderTable::setCellWidths() void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += xPos(); - ty += yPos(); + tx += x(); + ty += y(); PaintPhase paintPhase = paintInfo.phase; @@ -458,6 +445,15 @@ void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os) return; + bool pushedClip = pushContentsClip(paintInfo, tx, ty); + paintObject(paintInfo, tx, ty); + if (pushedClip) + popContentsClip(paintInfo, paintPhase, tx, ty); +} + +void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) +{ + PaintPhase paintPhase = paintInfo.phase; if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE) paintBoxDecorations(paintInfo, tx, ty); @@ -469,19 +465,20 @@ void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseBlockBackground) return; - + // We don't paint our own background, but we do let the kids paint their backgrounds. if (paintPhase == PaintPhaseChildBlockBackgrounds) paintPhase = PaintPhaseChildBlockBackground; + PaintInfo info(paintInfo); info.phase = paintPhase; info.paintingRoot = paintingRootForChildren(paintInfo); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (!child->hasLayer() && (child->isTableSection() || child == m_caption)) + if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) child->paint(info, tx, ty); } - + if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) { // Collect all the unique border styles that we want to paint in a sorted list. Once we // have all the styles sorted, we then do individual passes, painting each style of border @@ -517,16 +514,9 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) ty += captionHeight; } - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); if (style()->hasBorder() && !collapseBorders()) paintBorder(paintInfo.context, tx, ty, w, h, style()); @@ -548,14 +538,7 @@ void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty) ty += captionHeight; } - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } void RenderTable::calcPrefWidths() @@ -664,7 +647,7 @@ void RenderTable::recalcSections() const switch (child->style()->display()) { case TABLE_CAPTION: if (!m_caption && child->isRenderBlock()) { - m_caption = static_cast<RenderBlock*>(child); + m_caption = toRenderBlock(child); m_caption->setNeedsLayout(true); } break; @@ -724,12 +707,6 @@ void RenderTable::recalcSections() const m_needsSectionRecalc = false; } -RenderObject* RenderTable::removeChildNode(RenderObject* child, bool fullRemove) -{ - setNeedsSectionRecalc(); - return RenderContainer::removeChildNode(child, fullRemove); -} - int RenderTable::calcBorderLeft() const { if (collapseBorders()) { @@ -1119,7 +1096,7 @@ void RenderTable::updateFirstLetter() { } -int RenderTable::getBaselineOfFirstLineBox() const +int RenderTable::firstLineBoxBaseline() const { RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); if (firstNonEmptySection && !firstNonEmptySection->numRows()) @@ -1128,12 +1105,12 @@ int RenderTable::getBaselineOfFirstLineBox() const if (!firstNonEmptySection) return -1; - return firstNonEmptySection->yPos() + firstNonEmptySection->getBaselineOfFirstLineBox(); + return firstNonEmptySection->y() + firstNonEmptySection->firstLineBoxBaseline(); } -IntRect RenderTable::getOverflowClipRect(int tx, int ty) +IntRect RenderTable::overflowClipRect(int tx, int ty) { - IntRect rect = RenderBlock::getOverflowClipRect(tx, ty); + IntRect rect = RenderBlock::overflowClipRect(tx, ty); // If we have a caption, expand the clip to include the caption. // FIXME: Technically this is wrong, but it's virtually impossible to fix this @@ -1149,4 +1126,29 @@ IntRect RenderTable::getOverflowClipRect(int tx, int ty) return rect; } +bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) +{ + tx += x(); + ty += y(); + + // Check kids first. + if (!hasOverflowClip() || overflowClipRect(tx, ty).contains(xPos, yPos)) { + for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) && + child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); + return true; + } + } + } + + // Check our bounds next. + if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); + return true; + } + + return false; +} + } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.h b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h index 59cb00e..07e02b0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTable.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h @@ -39,26 +39,6 @@ class TableLayout; class RenderTable : public RenderBlock { public: - enum Rules { - None = 0x00, - RGroups = 0x01, - CGroups = 0x02, - Groups = 0x03, - Rows = 0x05, - Cols = 0x0a, - All = 0x0f - }; - enum Frame { - Void = 0x00, - Above = 0x01, - Below = 0x02, - Lhs = 0x04, - Rhs = 0x08, - Hsides = 0x03, - Vsides = 0x0c, - Box = 0x0f - }; - RenderTable(Node*); ~RenderTable(); @@ -79,8 +59,6 @@ public: int borderTop() const; int borderBottom() const; - Rules getRules() const { return static_cast<Rules>(m_rules); } - const Color& bgColor() const { return style()->backgroundColor(); } int outerBorderTop() const; @@ -94,13 +72,17 @@ public: // overrides virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject* oldChild); + virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintObject(PaintInfo&, int tx, int ty); virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); virtual void layout(); virtual void calcPrefWidths(); - - virtual int getBaselineOfFirstLineBox() const; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int xPos, int yPos, int tx, int ty, HitTestAction); + + virtual int firstLineBoxBaseline() const; virtual RenderBlock* firstLineBlock() const; virtual void updateFirstLetter(); @@ -169,8 +151,6 @@ public: setNeedsLayout(true); } - virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true); - RenderTableSection* sectionAbove(const RenderTableSection*, bool skipEmptySections = false) const; RenderTableSection* sectionBelow(const RenderTableSection*, bool skipEmptySections = false) const; @@ -183,7 +163,7 @@ public: bool hasSections() const { return m_head || m_foot || m_firstBody; } - virtual IntRect getOverflowClipRect(int tx, int ty); + virtual IntRect overflowClipRect(int tx, int ty); void recalcSectionsIfNeeded() const { @@ -192,7 +172,7 @@ public: } protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: void recalcSections() const; @@ -209,9 +189,6 @@ private: const CollapsedBorderValue* m_currentBorder; - unsigned m_frame : 4; // Frame - unsigned m_rules : 4; // Rules - mutable bool m_hasColElements : 1; mutable bool m_needsSectionRecalc : 1; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp index 02e7729..9b02c9d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) @@ -25,11 +25,13 @@ #include "config.h" #include "RenderTableCell.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "HTMLNames.h" #include "HTMLTableCellElement.h" #include "RenderTableCol.h" #include "RenderView.h" +#include "TransformState.h" using namespace std; @@ -43,9 +45,8 @@ RenderTableCell::RenderTableCell(Node* node) , m_column(-1) , m_rowSpan(1) , m_columnSpan(1) - , m_topExtra(0) - , m_bottomExtra(0) - , m_widthChanged(false) + , m_intrinsicPaddingTop(0) + , m_intrinsicPaddingBottom(0) , m_percentageHeight(0) { updateFromElement(); @@ -63,9 +64,9 @@ void RenderTableCell::destroy() void RenderTableCell::updateFromElement() { - Node* node = element(); - if (node && (node->hasTagName(tdTag) || node->hasTagName(thTag))) { - HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(node); + Node* n = node(); + if (n && (n->hasTagName(tdTag) || n->hasTagName(thTag))) { + HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(n); int oldRSpan = m_rowSpan; int oldCSpan = m_columnSpan; @@ -105,10 +106,10 @@ void RenderTableCell::calcPrefWidths() table()->recalcSectionsIfNeeded(); RenderBlock::calcPrefWidths(); - if (element() && style()->autoWrap()) { + if (node() && style()->autoWrap()) { // See if nowrap was set. Length w = styleOrColWidth(); - String nowrap = static_cast<Element*>(element())->getAttribute(nowrapAttr); + String nowrap = static_cast<Element*>(node())->getAttribute(nowrapAttr); if (!nowrap.isNull() && w.isFixed()) // Nowrap is set, but we didn't actually use it because of the // fixed width set on the cell. Even so, it is a WinIE/Moz trait @@ -123,28 +124,44 @@ void RenderTableCell::calcWidth() { } -void RenderTableCell::setWidth(int width) +void RenderTableCell::updateWidth(int w) { - if (width != m_width) { - m_width = width; - m_widthChanged = true; + if (w != width()) { + setWidth(w); + setCellWidthChanged(true); } } void RenderTableCell::layout() { - layoutBlock(m_widthChanged); - m_widthChanged = false; + layoutBlock(cellWidthChanged()); + setCellWidthChanged(false); } -IntRect RenderTableCell::absoluteClippedOverflowRect() +int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const +{ + return RenderBlock::paddingTop() + (includeIntrinsicPadding ? intrinsicPaddingTop() : 0); +} + +int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const +{ + return RenderBlock::paddingBottom() + (includeIntrinsicPadding ? intrinsicPaddingBottom() : 0); +} + +void RenderTableCell::setOverrideSize(int size) +{ + clearIntrinsicPadding(); + RenderBlock::setOverrideSize(size); +} + +IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { // If the table grid is dirty, we cannot get reliable information about adjoining cells, // so we ignore outside borders. This should not be a problem because it means that // the table is going to recalculate the grid, relayout and repaint its current rect, which // includes any outside borders of this cell. if (!table()->collapseBorders() || table()->needsSectionRecalc()) - return RenderBlock::absoluteClippedOverflowRect(); + return RenderBlock::clippedOverflowRectForRepaint(repaintContainer); bool rtl = table()->style()->direction() == RTL; int outlineSize = style()->outlineSize(); @@ -152,13 +169,13 @@ IntRect RenderTableCell::absoluteClippedOverflowRect() int right = max(borderHalfRight(true), outlineSize); int top = max(borderHalfTop(true), outlineSize); int bottom = max(borderHalfBottom(true), outlineSize); - if (left && !rtl || right && rtl) { + if ((left && !rtl) || (right && rtl)) { if (RenderTableCell* before = table()->cellBefore(this)) { top = max(top, before->borderHalfTop(true)); bottom = max(bottom, before->borderHalfBottom(true)); } } - if (left && rtl || right && !rtl) { + if ((left && rtl) || (right && !rtl)) { if (RenderTableCell* after = table()->cellAfter(this)) { top = max(top, after->borderHalfTop(true)); bottom = max(bottom, after->borderHalfBottom(true)); @@ -177,69 +194,68 @@ IntRect RenderTableCell::absoluteClippedOverflowRect() } } left = max(left, -overflowLeft(false)); - top = max(top, -overflowTop(false) - borderTopExtra()); - IntRect r(-left, -borderTopExtra() - top, left + max(width() + right, overflowWidth(false)), borderTopExtra() + top + max(height() + bottom + borderBottomExtra(), overflowHeight(false))); + top = max(top, -overflowTop(false)); + IntRect r(-left, - top, left + max(width() + right, overflowWidth(false)), top + max(height() + bottom, overflowHeight(false))); - if (RenderView* v = view()) + if (RenderView* v = view()) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); - - computeAbsoluteRepaintRect(r); + } + computeRectForRepaint(repaintContainer, r); return r; } -void RenderTableCell::computeAbsoluteRepaintRect(IntRect& r, bool fixed) +void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& r, bool fixed) { - r.setY(r.y() + m_topExtra); + if (repaintContainer == this) + return; + r.setY(r.y()); RenderView* v = view(); - if ((!v || !v->layoutState()) && parent()) - r.move(-parent()->xPos(), -parent()->yPos()); // Rows are in the same coordinate space, so don't add their offset in. - RenderBlock::computeAbsoluteRepaintRect(r, fixed); + if ((!v || !v->layoutStateEnabled()) && 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); } -FloatPoint RenderTableCell::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const +void RenderTableCell::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const { + if (repaintContainer == this) + return; + RenderView* v = view(); - if ((!v || !v->layoutState()) && parent()) { + if ((!v || !v->layoutStateEnabled()) && parent()) { // Rows are in the same coordinate space, so don't add their offset in. - localPoint.move(-parent()->xPos(), -parent()->yPos()); + // FIXME: this is wrong with transforms + transformState.move(-parentBox()->x(), -parentBox()->y()); } - return RenderBlock::localToAbsolute(localPoint, fixed, useTransforms); + RenderBlock::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); } -FloatPoint RenderTableCell::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +void RenderTableCell::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { - FloatPoint localPoint = RenderBlock::absoluteToLocal(containerPoint, fixed, useTransforms); + RenderBlock::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); if (parent()) { // Rows are in the same coordinate space, so add their offset back in. - localPoint.move(parent()->xPos(), parent()->yPos()); + // FIXME: this is wrong with transforms + transformState.move(parentBox()->x(), parentBox()->y()); } - return localPoint; } -FloatQuad RenderTableCell::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const +int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const { - FloatQuad quad = localQuad; - if (parent()) { - // Rows are in the same coordinate space, so don't add their offset in. - quad.move(-parent()->xPos(), -parent()->yPos()); - } - return RenderBlock::localToAbsoluteQuad(quad, fixed); -} + if (isRootLineBox) + return RenderBox::baselinePosition(firstLine, isRootLineBox); -int RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/) const -{ // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there // is no such line box or table-row, the baseline is the bottom of content edge of the cell box. - - int firstLineBaseline = getBaselineOfFirstLineBox(); + int firstLineBaseline = firstLineBoxBaseline(); if (firstLineBaseline != -1) return firstLineBaseline; - return paddingTop() + borderTop() + contentHeight(); } -void RenderTableCell::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderTableCell::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { if (parent() && section() && style() && style()->height() != newStyle->height()) section()->setNeedsCellRecalc(); @@ -249,17 +265,12 @@ void RenderTableCell::styleWillChange(RenderStyle::Diff diff, const RenderStyle* RenderBlock::styleWillChange(diff, newStyle); } -void RenderTableCell::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); setHasBoxDecorations(true); } -bool RenderTableCell::requiresLayer() -{ - return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); -} - // The following rules apply for resolving conflicts and figuring out which border // to use. // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting @@ -630,24 +641,17 @@ int RenderTableCell::borderHalfBottom(bool outer) const void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; - - // check if we need to do anything at all... - int os = 2 * maximalOutlineSize(paintInfo.phase); - if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) { - if (ty - table()->outerBorderTop() >= paintInfo.rect.bottom() + os || - ty + m_topExtra + m_height + m_bottomExtra + table()->outerBorderBottom() <= paintInfo.rect.y() - os) - return; - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - paintCollapsedBorder(paintInfo.context, tx, ty, w, h); - } else { - if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + m_topExtra + overflowHeight(false) + m_bottomExtra <= paintInfo.rect.y() - os) - return; - RenderBlock::paintObject(paintInfo, tx, ty + m_topExtra); - } + tx += x(); + ty += y(); + int os = 2 * maximalOutlineSize(paintInfo.phase); + if (ty - table()->outerBorderTop() < paintInfo.rect.bottom() + os && + ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os) + paintCollapsedBorder(paintInfo.context, tx, ty, width(), height()); + return; + } + + RenderBlock::paint(paintInfo, tx, ty); } static EBorderStyle collapsedBorderStyle(EBorderStyle style) @@ -661,7 +665,7 @@ static EBorderStyle collapsedBorderStyle(EBorderStyle style) struct CollapsedBorder { CollapsedBorderValue borderValue; - RenderObject::BorderSide side; + BoxSide side; bool shouldPaint; int x1; int y1; @@ -677,7 +681,7 @@ public: { } - void addBorder(const CollapsedBorderValue& borderValue, RenderObject::BorderSide borderSide, bool shouldPaint, + void addBorder(const CollapsedBorderValue& borderValue, BoxSide borderSide, bool shouldPaint, int x1, int y1, int x2, int y2, EBorderStyle borderStyle) { if (borderValue.exists() && shouldPaint) { @@ -789,8 +793,8 @@ void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) { if (border->borderValue == *table()->currentBorderStyle()) - drawBorder(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, - border->borderValue.color(), style()->color(), border->style, 0, 0); + drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, + border->borderValue.color(), style()->color(), border->style, 0, 0); } } @@ -807,17 +811,12 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i return; if (backgroundObject != this) { - tx += m_x; - ty += m_y + m_topExtra; + tx += x(); + ty += y(); } int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); - - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; + int h = height(); Color c = backgroundObject->style()->backgroundColor(); const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers(); @@ -832,7 +831,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i paintInfo.context->save(); paintInfo.context->clip(clipRect); } - paintFillLayers(paintInfo, c, bgLayer, my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h); if (shouldClip) paintInfo.context->restore(); } @@ -845,10 +844,10 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); + int h = height(); if (style()->boxShadow()) - paintBoxShadow(paintInfo.context, tx, ty - borderTopExtra(), w, h, style()); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, tx, ty, this); @@ -856,7 +855,6 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) if (!style()->hasBorder() || tableElt->collapseBorders()) return; - ty -= borderTopExtra(); paintBorder(paintInfo.context, tx, ty, w, h, style()); } @@ -870,13 +868,9 @@ void RenderTableCell::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); + int h = height(); - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h index 20b7da7..a57b24b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h @@ -59,13 +59,11 @@ public: Length styleOrColWidth() const; - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } virtual void calcPrefWidths(); virtual void calcWidth(); - virtual void setWidth(int); - - virtual bool expandsToEncloseOverhangingFloats() const { return true; } + void updateWidth(int); int borderLeft() const; int borderRight() const; @@ -96,35 +94,38 @@ public: void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h); void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject); - // Lie about position to outside observers. - virtual int yPos() const { return m_y + m_topExtra; } - - virtual IntRect absoluteClippedOverflowRect(); - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); - virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; - virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; - virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const; + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const; - void setCellTopExtra(int p) { m_topExtra = p; } - void setCellBottomExtra(int p) { m_bottomExtra = p; } + void setIntrinsicPaddingTop(int p) { m_intrinsicPaddingTop = p; } + void setIntrinsicPaddingBottom(int p) { m_intrinsicPaddingBottom = p; } + void setIntrinsicPadding(int top, int bottom) { setIntrinsicPaddingTop(top); setIntrinsicPaddingBottom(bottom); } + void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); } + + int intrinsicPaddingTop() const { return m_intrinsicPaddingTop; } + int intrinsicPaddingBottom() const { return m_intrinsicPaddingBottom; } - virtual int borderTopExtra() const { return m_topExtra; } - virtual int borderBottomExtra() const { return m_bottomExtra; } + virtual int paddingTop(bool includeIntrinsicPadding = true) const; + virtual int paddingBottom(bool includeIntrinsicPadding = true) const; + + virtual void setOverrideSize(int); protected: - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + 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: int m_row; int m_column; int m_rowSpan; int m_columnSpan; - int m_topExtra : 31; - int m_bottomExtra : 31; - bool m_widthChanged : 1; + int m_intrinsicPaddingTop; + int m_intrinsicPaddingBottom; int m_percentageHeight; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp index 5c2a049..d9a4172 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp @@ -37,7 +37,7 @@ namespace WebCore { using namespace HTMLNames; RenderTableCol::RenderTableCol(Node* node) - : RenderContainer(node), m_span(1) + : RenderBox(node), m_span(1) { // init RenderObject attributes setInline(true); // our object is not Inline @@ -47,9 +47,9 @@ RenderTableCol::RenderTableCol(Node* node) void RenderTableCol::updateFromElement() { int oldSpan = m_span; - Node* node = element(); - if (node && (node->hasTagName(colTag) || node->hasTagName(colgroupTag))) { - HTMLTableColElement* tc = static_cast<HTMLTableColElement*>(node); + Node* n = node(); + if (n && (n->hasTagName(colTag) || n->hasTagName(colgroupTag))) { + HTMLTableColElement* tc = static_cast<HTMLTableColElement*>(n); m_span = tc->span(); } else m_span = !(style() && style()->display() == TABLE_COLUMN_GROUP); @@ -69,16 +69,14 @@ bool RenderTableCol::canHaveChildren() const return style()->display() == TABLE_COLUMN_GROUP; } -IntRect RenderTableCol::absoluteClippedOverflowRect() +IntRect RenderTableCol::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { // For now, just repaint the whole table. // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we // might have propagated a background color or borders into. - RenderObject* table = parent(); - if (table && !table->isTable()) - table = table->parent(); - if (table && table->isTable()) - return table->absoluteClippedOverflowRect(); + // FIXME: check for repaintContainer each time here? + if (RenderObject* parentTable = table()) + return parentTable->clippedOverflowRectForRepaint(repaintContainer); return IntRect(); } @@ -89,4 +87,20 @@ void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } +void RenderTableCol::calcPrefWidths() +{ + setPrefWidthsDirty(false); + + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->setPrefWidthsDirty(false); +} + +RenderTable* RenderTableCol::table() const +{ + RenderObject* table = parent(); + if (table && !table->isTable()) + table = table->parent(); + return table && table->isTable() ? static_cast<RenderTable*>(table) : 0; +} + } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h index 6752bd8..6b17ec4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h @@ -28,15 +28,21 @@ #ifndef RenderTableCol_h #define RenderTableCol_h -#include "RenderContainer.h" +#include "RenderBox.h" +#include "RenderTable.h" namespace WebCore { -class RenderTableCol : public RenderContainer +class RenderTableCol : public RenderBox { public: RenderTableCol(Node*); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + virtual const char* renderName() const { return "RenderTableCol"; } virtual bool isTableCol() const { return true; } virtual int lineHeight(bool) const { return 0; } @@ -44,15 +50,20 @@ public: virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; virtual bool canHaveChildren() const; - virtual bool requiresLayer() { return false; } + virtual bool requiresLayer() const { return false; } - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void calcPrefWidths(); + int span() const { return m_span; } void setSpan(int s) { m_span = s; } - + private: + RenderTable* table() const; + + RenderObjectChildList m_children; int m_span; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp index 21ba91a..33b2c39 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp @@ -33,16 +33,12 @@ #include "RenderTableCell.h" #include "RenderView.h" -#if ENABLE(WML) -#include "WMLNames.h" -#endif - namespace WebCore { using namespace HTMLNames; RenderTableRow::RenderTableRow(Node* node) - : RenderContainer(node) + : RenderBox(node) { // init RenderObject attributes setInline(false); // our object is not Inline @@ -52,20 +48,20 @@ void RenderTableRow::destroy() { RenderTableSection* recalcSection = section(); - RenderContainer::destroy(); + RenderBox::destroy(); if (recalcSection) recalcSection->setNeedsCellRecalc(); } -void RenderTableRow::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderTableRow::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { if (section() && style() && style()->height() != newStyle->height()) section()->setNeedsCellRecalc(); ASSERT(newStyle->display() == TABLE_ROW); - RenderContainer::styleWillChange(diff, newStyle); + RenderBox::styleWillChange(diff, newStyle); } void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) @@ -74,19 +70,7 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) if (!beforeChild && isAfterContent(lastChild())) beforeChild = lastChild(); - bool isTableRow = element() && element()->hasTagName(trTag); - -#if ENABLE(WML) - if (!isTableRow && element() && element()->isWMLElement()) - isTableRow = element()->hasTagName(WMLNames::trTag); -#endif - if (!child->isTableCell()) { - if (isTableRow && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) { - RenderContainer::addChild(child, beforeChild); - return; - } - RenderObject* last = beforeChild; if (!last) last = lastChild(); @@ -121,8 +105,8 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) if (parent()) section()->addCell(cell, this); - ASSERT(!beforeChild || beforeChild->isTableCell() || isTableRow && beforeChild->element() && beforeChild->element()->hasTagName(formTag) && document()->isHTMLDocument()); - RenderContainer::addChild(cell, beforeChild); + ASSERT(!beforeChild || beforeChild->isTableCell()); + RenderBox::addChild(cell, beforeChild); if (beforeChild || nextSibling()) section()->setNeedsCellRecalc(); @@ -148,7 +132,7 @@ void RenderTableRow::layout() // We only ever need to repaint if our cells didn't, which menas that they didn't need // layout, so we know that our bounds didn't change. This code is just making up for // the fact that we did not repaint in setStyle() because we had a layout hint. - // We cannot call repaint() because our absoluteClippedOverflowRect() is taken from the + // We cannot call repaint() because our clippedOverflowRectForRepaint() is taken from the // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells. if (selfNeedsLayout() && checkForRepaintDuringLayout()) { for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -161,13 +145,14 @@ void RenderTableRow::layout() setNeedsLayout(false); } -IntRect RenderTableRow::absoluteClippedOverflowRect() +IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { // For now, just repaint the whole table. // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we // might have propagated a background color into. + // FIXME: do repaintContainer checks here if (RenderTable* parentTable = table()) - return parentTable->absoluteClippedOverflowRect(); + return parentTable->clippedOverflowRectForRepaint(repaintContainer); return IntRect(); } @@ -182,7 +167,7 @@ bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& r // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { + if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -193,10 +178,9 @@ bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& r void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty) { - ASSERT(m_layer); - if (!m_layer) + ASSERT(hasSelfPaintingLayer()); + if (!layer()) return; - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { // Paint the row background behind the cell. @@ -204,7 +188,7 @@ void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty) RenderTableCell* cell = static_cast<RenderTableCell*>(child); cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this); } - if (!child->hasLayer()) + if (!toRenderBox(child)->hasSelfPaintingLayer()) child->paint(paintInfo, tx, ty); } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h index a65d0e9..9622480 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h @@ -31,10 +31,15 @@ namespace WebCore { -class RenderTableRow : public RenderContainer { +class RenderTableRow : public RenderBox { public: RenderTableRow(Node*); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()); } RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()); } @@ -47,19 +52,21 @@ private: virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual int lineHeight(bool, bool) const { return 0; } - virtual void position(InlineBox*) { } virtual void layout(); - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); // The only time rows get a layer is when they have transparency. - virtual bool requiresLayer() { return isTransparent() || hasOverflowClip(); } + virtual bool requiresLayer() const { return isTransparent() || hasOverflowClip() || hasTransform() || hasMask(); } virtual void paint(PaintInfo&, int tx, int ty); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); +private: + RenderObjectChildList m_children; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp index be43ab8..27c230b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp @@ -43,11 +43,10 @@ namespace WebCore { using namespace HTMLNames; RenderTableSection::RenderTableSection(Node* node) - : RenderContainer(node) + : RenderBox(node) , m_gridRows(0) , m_cCol(0) , m_cRow(-1) - , m_needsCellRecalc(false) , m_outerBorderLeft(0) , m_outerBorderRight(0) , m_outerBorderTop(0) @@ -56,6 +55,7 @@ RenderTableSection::RenderTableSection(Node* node) , m_overflowWidth(0) , m_overflowTop(0) , m_overflowHeight(0) + , m_needsCellRecalc(false) , m_hasOverflowingCell(false) { // init RenderObject attributes @@ -71,7 +71,7 @@ void RenderTableSection::destroy() { RenderTable* recalcTable = table(); - RenderContainer::destroy(); + RenderBox::destroy(); // recalc cell info because RenderTable has unguarded pointers // stored that point to this RenderTableSection. @@ -85,14 +85,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (!beforeChild && isAfterContent(lastChild())) beforeChild = lastChild(); - bool isTableSection = element() && (element()->hasTagName(theadTag) || element()->hasTagName(tbodyTag) || element()->hasTagName(tfootTag)); - if (!child->isTableRow()) { - if (isTableSection && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) { - RenderContainer::addChild(child, beforeChild); - return; - } - RenderObject* last = beforeChild; if (!last) last = lastChild(); @@ -111,7 +104,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild return; } - RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */); + RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table row */); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(TABLE_ROW); @@ -131,7 +124,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (!ensureRows(m_cRow + 1)) return; - m_grid[m_cRow].rowRenderer = child; + m_grid[m_cRow].rowRenderer = static_cast<RenderTableRow*>(child); if (!beforeChild) { m_grid[m_cRow].height = child->style()->height(); @@ -143,8 +136,14 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild while (beforeChild && beforeChild->parent() != this) beforeChild = beforeChild->parent(); - ASSERT(!beforeChild || beforeChild->isTableRow() || isTableSection && beforeChild->element() && beforeChild->element()->hasTagName(formTag) && document()->isHTMLDocument()); - RenderContainer::addChild(child, beforeChild); + ASSERT(!beforeChild || beforeChild->isTableRow()); + RenderBox::addChild(child, beforeChild); +} + +void RenderTableSection::removeChild(RenderObject* oldChild) +{ + setNeedsCellRecalc(); + RenderBox::removeChild(oldChild); } bool RenderTableSection::ensureRows(int numRows) @@ -174,7 +173,7 @@ bool RenderTableSection::ensureRows(int numRows) return true; } -void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row) +void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) { int rSpan = cell->rowSpan(); int cSpan = cell->colSpan(); @@ -238,7 +237,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row) for (int r = 0; r < rSpan; r++) { CellStruct& c = cellAt(m_cRow + r, m_cCol); - if (currentCell.cell && !c.cell) + if (!c.cell) c.cell = currentCell.cell; if (currentCell.inColSpan) c.inColSpan = true; @@ -248,10 +247,8 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row) currentCell.cell = 0; currentCell.inColSpan = true; } - if (cell) { - cell->setRow(m_cRow); - cell->setCol(table()->effColToCol(col)); - } + cell->setRow(m_cRow); + cell->setCol(table()->effColToCol(col)); } void RenderTableSection::setCellWidths() @@ -283,11 +280,11 @@ void RenderTableSection::setCellWidths() if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. - statePusher.push(this, IntSize(m_x, m_y)); + statePusher.push(this, IntSize(x(), y())); } cell->repaint(); } - cell->setWidth(w); + cell->updateWidth(w); } } } @@ -297,6 +294,12 @@ void RenderTableSection::setCellWidths() int RenderTableSection::calcRowHeight() { +#ifndef NDEBUG + setNeedsLayoutIsForbidden(true); +#endif + + ASSERT(!needsLayout()); + RenderTableCell* cell; int spacing = table()->vBorderSpacing(); @@ -333,19 +336,23 @@ int RenderTableSection::calcRowHeight() if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. - statePusher.push(this, IntSize(m_x, m_y)); + statePusher.push(this, IntSize(x(), y())); } cell->setOverrideSize(-1); cell->setChildNeedsLayout(true, false); cell->layoutIfNeeded(); } + int adjustedPaddingTop = cell->paddingTop() - cell->intrinsicPaddingTop(); + int adjustedPaddingBottom = cell->paddingBottom() - cell->intrinsicPaddingBottom(); + int adjustedHeight = cell->height() - (cell->intrinsicPaddingTop() + cell->intrinsicPaddingBottom()); + // Explicit heights use the border box in quirks mode. In strict mode do the right // thing and actually add in the border and padding. ch = cell->style()->height().calcValue(0) + - (cell->style()->htmlHacks() ? 0 : (cell->paddingTop() + cell->paddingBottom() + + (cell->style()->htmlHacks() ? 0 : (adjustedPaddingTop + adjustedPaddingBottom + cell->borderTop() + cell->borderBottom())); - ch = max(ch, cell->height()); + ch = max(ch, adjustedHeight); pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0); @@ -356,8 +363,8 @@ int RenderTableSection::calcRowHeight() if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { int b = cell->baselinePosition(); if (b > cell->borderTop() + cell->paddingTop()) { - baseline = max(baseline, b); - bdesc = max(bdesc, m_rowPos[indx] + ch - b); + baseline = max(baseline, b - cell->intrinsicPaddingTop()); + bdesc = max(bdesc, m_rowPos[indx] + ch - (b - cell->intrinsicPaddingTop())); } } } @@ -372,21 +379,48 @@ int RenderTableSection::calcRowHeight() m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]); } +#ifndef NDEBUG + setNeedsLayoutIsForbidden(false); +#endif + + ASSERT(!needsLayout()); + statePusher.pop(); return m_rowPos[m_gridRows]; } +void RenderTableSection::layout() +{ + ASSERT(needsLayout()); + + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); + for (RenderObject* child = children()->firstChild(); child; child = child->nextSibling()) { + if (child->isTableRow()) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); + } + } + statePusher.pop(); + setNeedsLayout(false); +} + int RenderTableSection::layoutRows(int toAdd) { +#ifndef NDEBUG + setNeedsLayoutIsForbidden(true); +#endif + + ASSERT(!needsLayout()); + int rHeight; int rindx; int totalRows = m_gridRows; // Set the width of our section now. The rows will also be this width. - m_width = table()->contentWidth(); + setWidth(table()->contentWidth()); m_overflowLeft = 0; - m_overflowWidth = m_width; + m_overflowWidth = width(); m_overflowTop = 0; m_overflowHeight = 0; m_hasOverflowingCell = false; @@ -454,13 +488,13 @@ int RenderTableSection::layoutRows(int toAdd) int vspacing = table()->vBorderSpacing(); int nEffCols = table()->numEffCols(); - LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y)); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); for (int r = 0; r < totalRows; r++) { // Set the row's x/y position and width/height. - if (RenderObject* rowRenderer = m_grid[r].rowRenderer) { - rowRenderer->setPos(0, m_rowPos[r]); - rowRenderer->setWidth(m_width); + if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { + rowRenderer->setLocation(0, m_rowPos[r]); + rowRenderer->setWidth(width()); rowRenderer->setHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); } @@ -494,19 +528,40 @@ int RenderTableSection::layoutRows(int toAdd) (!table()->style()->height().isAuto() && rHeight != cell->height()); for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) { - if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || o->scrollsOverflow() || flexAllChildren)) { + if (!o->isText() && o->style()->height().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) { // Tables with no sections do not flex. if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) { o->setNeedsLayout(true, false); - cell->setChildNeedsLayout(true, false); cellChildrenFlex = true; } } } + + if (HashSet<RenderBox*>* percentHeightDescendants = cell->percentHeightDescendants()) { + HashSet<RenderBox*>::iterator end = percentHeightDescendants->end(); + for (HashSet<RenderBox*>::iterator it = percentHeightDescendants->begin(); it != end; ++it) { + RenderBox* box = *it; + if (!box->isReplaced() && !box->scrollsOverflow() && !flexAllChildren) + continue; + + while (box != cell) { + if (box->normalChildNeedsLayout()) + break; + box->setChildNeedsLayout(true, false); + box = box->containingBlock(); + ASSERT(box); + if (!box) + break; + } + cellChildrenFlex = true; + } + } + if (cellChildrenFlex) { + cell->setChildNeedsLayout(true, false); // Alignment within a cell is based off the calculated // height, which becomes irrelevant once the cell has - // been resized based off its percentage. -dwh + // been resized based off its percentage. cell->setOverrideSize(max(0, rHeight - cell->borderTop() - cell->paddingTop() - cell->borderBottom() - cell->paddingBottom())); @@ -521,48 +576,57 @@ int RenderTableSection::layoutRows(int toAdd) } } + int oldTe = cell->intrinsicPaddingTop(); + int oldBe = cell->intrinsicPaddingBottom(); + int heightWithoutIntrinsicPadding = cell->height() - oldTe - oldBe; + int te = 0; switch (cell->style()->verticalAlign()) { case SUB: case SUPER: case TEXT_TOP: case TEXT_BOTTOM: - case BASELINE: - te = getBaseline(r) - cell->baselinePosition(); + case BASELINE: { + int b = cell->baselinePosition(); + if (b > cell->borderTop() + cell->paddingTop()) + te = getBaseline(r) - (b - oldTe); break; + } case TOP: te = 0; break; case MIDDLE: - te = (rHeight - cell->height()) / 2; + te = (rHeight - heightWithoutIntrinsicPadding) / 2; break; case BOTTOM: - te = rHeight - cell->height(); + te = rHeight - heightWithoutIntrinsicPadding; break; default: break; } - - int oldTe = cell->borderTopExtra(); - int oldBe = cell->borderBottomExtra(); - - int be = rHeight - cell->height() - te; - cell->setCellTopExtra(te); - cell->setCellBottomExtra(be); + + int be = rHeight - heightWithoutIntrinsicPadding - te; + cell->setIntrinsicPaddingTop(te); + cell->setIntrinsicPaddingBottom(be); + if (te != oldTe || be != oldBe) { + cell->setNeedsLayout(true, false); + cell->layoutIfNeeded(); + } + if ((te != oldTe || be > oldBe) && !table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) cell->repaint(); - IntRect oldCellRect(cell->xPos(), cell->yPos() - cell->borderTopExtra() , cell->width(), cell->height()); + IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height()); if (style()->direction() == RTL) { - cell->setPos(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]); + cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]); } else - cell->setPos(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]); + cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]); - m_overflowLeft = min(m_overflowLeft, cell->xPos() + cell->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, cell->xPos() + cell->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, cell->yPos() + cell->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, cell->yPos() + cell->overflowHeight(false)); + m_overflowLeft = min(m_overflowLeft, cell->x() + cell->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, cell->x() + cell->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, cell->y() + cell->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, cell->y() + cell->overflowHeight(false)); m_hasOverflowingCell |= cell->overflowLeft(false) || cell->overflowWidth(false) > cell->width() || cell->overflowTop(false) || cell->overflowHeight(false) > cell->height(); // If the cell moved, we have to repaint it as well as any floating/positioned @@ -573,23 +637,31 @@ int RenderTableSection::layoutRows(int toAdd) } } +#ifndef NDEBUG + setNeedsLayoutIsForbidden(false); +#endif + + ASSERT(!needsLayout()); + statePusher.pop(); - m_height = m_rowPos[totalRows]; - m_overflowHeight = max(m_overflowHeight, m_height); - return m_height; + setHeight(m_rowPos[totalRows]); + m_overflowHeight = max(m_overflowHeight, height()); + return height(); } int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { - int bottom = RenderContainer::lowestPosition(includeOverflowInterior, includeSelf); + int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf); if (!includeOverflowInterior && hasOverflowClip()) return bottom; for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (cell->isTableCell()) - bottom = max(bottom, cell->yPos() + cell->lowestPosition(false)); + for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isTableCell()) { + RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + bottom = max(bottom, cell->y() + cell->lowestPosition(false)); + } } } @@ -598,14 +670,16 @@ int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int right = RenderContainer::rightmostPosition(includeOverflowInterior, includeSelf); + int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf); if (!includeOverflowInterior && hasOverflowClip()) return right; for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (cell->isTableCell()) - right = max(right, cell->xPos() + cell->rightmostPosition(false)); + for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isTableCell()) { + RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + right = max(right, cell->x() + cell->rightmostPosition(false)); + } } } @@ -614,14 +688,16 @@ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool inc int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int left = RenderContainer::leftmostPosition(includeOverflowInterior, includeSelf); + int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf); if (!includeOverflowInterior && hasOverflowClip()) return left; for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { - for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { - if (cell->isTableCell()) - left = min(left, cell->xPos() + cell->leftmostPosition(false)); + for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isTableCell()) { + RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + left = min(left, cell->x() + cell->leftmostPosition(false)); + } } } @@ -837,7 +913,7 @@ void RenderTableSection::recalcOuterBorder() m_outerBorderRight = calcOuterBorderRight(rtl); } -int RenderTableSection::getBaselineOfFirstLineBox() const +int RenderTableSection::firstLineBoxBaseline() const { if (!m_gridRows) return -1; @@ -851,7 +927,7 @@ int RenderTableSection::getBaselineOfFirstLineBox() const for (size_t i = 0; i < firstRow->size(); ++i) { RenderTableCell* cell = firstRow->at(i).cell; if (cell) - firstLineBaseline = max(firstLineBaseline, cell->yPos() + cell->paddingTop() + cell->borderTop() + cell->contentHeight()); + firstLineBaseline = max(firstLineBaseline, cell->y() + cell->paddingTop() + cell->borderTop() + cell->contentHeight()); } return firstLineBaseline; @@ -871,11 +947,23 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty) if (!totalRows || !totalCols) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); + + PaintPhase phase = paintInfo.phase; + bool pushedClip = pushContentsClip(paintInfo, tx, ty); + paintObject(paintInfo, tx, ty); + if (pushedClip) + popContentsClip(paintInfo, phase, tx, ty); +} +void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) +{ // Check which rows and cols are visible and only paint these. // FIXME: Could use a binary search here. + unsigned totalRows = m_gridRows; + unsigned totalCols = table()->columns().size(); + PaintPhase paintPhase = paintInfo.phase; int x = paintInfo.rect.x(); int y = paintInfo.rect.y(); @@ -962,11 +1050,11 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty) // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for // painting the row background for the cell. - if (!row->hasLayer()) + if (!row->hasSelfPaintingLayer()) cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row); } - if ((!cell->hasLayer() && !row->hasLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders) + if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders) cell->paint(paintInfo, tx, ty); } } @@ -992,11 +1080,13 @@ void RenderTableSection::recalcCells() m_cCol = 0; if (!ensureRows(m_cRow + 1)) break; - m_grid[m_cRow].rowRenderer = row; + + RenderTableRow* tableRow = static_cast<RenderTableRow*>(row); + m_grid[m_cRow].rowRenderer = tableRow; for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - addCell(static_cast<RenderTableCell*>(cell), row); + addCell(static_cast<RenderTableCell*>(cell), tableRow); } } } @@ -1049,27 +1139,24 @@ void RenderTableSection::splitColumn(int pos, int newSize) } } -RenderObject* RenderTableSection::removeChildNode(RenderObject* child, bool fullRemove) -{ - setNeedsCellRecalc(); - return RenderContainer::removeChildNode(child, fullRemove); -} - // Hit Testing -bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action) +bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) { // Table sections cannot ever be hit tested. Effectively they do not exist. // Just forward to our children always. - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); + + if (hasOverflowClip() && !overflowClipRect(tx, ty).contains(xPos, yPos)) + return false; for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { // FIXME: We have to skip over inline flows, since they can show up inside table rows // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h index 8d460cb..30614f0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h @@ -33,23 +33,32 @@ namespace WebCore { class RenderTableCell; +class RenderTableRow; -class RenderTableSection : public RenderContainer { +class RenderTableSection : public RenderBox { public: RenderTableSection(Node*); ~RenderTableSection(); + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; } virtual bool isTableSection() const { return true; } virtual void destroy(); + virtual void layout(); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject* oldChild); - virtual int getBaselineOfFirstLineBox() const; + virtual int firstLineBoxBaseline() const; - void addCell(RenderTableCell*, RenderObject* row); + void addCell(RenderTableCell*, RenderTableRow* row); void setCellWidths(); int calcRowHeight(); @@ -66,7 +75,7 @@ public: struct RowStruct { Row* row; - RenderObject* rowRenderer; + RenderTableRow* rowRenderer; int baseline; Length height; }; @@ -77,9 +86,9 @@ public: void appendColumn(int pos); void splitColumn(int pos, int newSize); - virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? m_width : m_overflowWidth; } + virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? width() : m_overflowWidth; } virtual int overflowLeft(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowLeft; } - virtual int overflowHeight(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? m_height : m_overflowHeight; } + virtual int overflowHeight(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? height() : m_overflowHeight; } virtual int overflowTop(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowTop; } virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const; @@ -98,6 +107,8 @@ public: int outerBorderRight() const { return m_outerBorderRight; } virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintObject(PaintInfo&, int tx, int ty); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); int numRows() const { return m_gridRows; } @@ -118,25 +129,24 @@ public: int getBaseline(int row) { return m_grid[row].baseline; } - virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); private: virtual int lineHeight(bool, bool) const { return 0; } - virtual void position(InlineBox*) { } bool ensureRows(int); void clearGrid(); + RenderObjectChildList m_children; + Vector<RowStruct> m_grid; - int m_gridRows; Vector<int> m_rowPos; + int m_gridRows; + // the current insertion position int m_cCol; int m_cRow; - bool m_needsCellRecalc; int m_outerBorderLeft; int m_outerBorderRight; @@ -146,6 +156,8 @@ private: int m_overflowWidth; int m_overflowTop; int m_overflowHeight; + + bool m_needsCellRecalc; bool m_hasOverflowingCell; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp index d7fdbb9..ada3961 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. @@ -26,6 +26,7 @@ #include "RenderText.h" #include "CharacterNames.h" +#include "FloatQuad.h" #include "FrameView.h" #include "InlineTextBox.h" #include "Range.h" @@ -35,6 +36,7 @@ #include "RenderView.h" #include "Text.h" #include "TextBreakIterator.h" +#include "VisiblePosition.h" #include "break_lines.h" #include <wtf/AlwaysInline.h> @@ -52,23 +54,26 @@ static inline bool charactersAreAllASCII(StringImpl* text) RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) : RenderObject(node) - , m_text(str) + , m_minWidth(-1) + , m_text(document()->displayStringModifiedByEncoding(str)) , m_firstTextBox(0) , m_lastTextBox(0) - , m_minWidth(-1) , m_maxWidth(-1) , m_beginMinWidth(0) , m_endMinWidth(0) - , m_selectionState(SelectionNone) , m_hasTab(false) , m_linesDirty(false) , m_containsReversedText(false) , m_isAllASCII(charactersAreAllASCII(m_text.get())) + , m_knownNotToUseFallbackFonts(false) { ASSERT(m_text); - setRenderText(); - m_text = m_text->replace('\\', backslashAsCurrencySymbol()); + setIsText(); + + // FIXME: It would be better to call this only if !m_text->containsOnlyWhitespace(). + // But that might slow things down, and maybe should only be done if visuallyNonEmpty + // is still false. Not making any change for now, but should consider in the future. view()->frameView()->setIsVisuallyNonEmpty(); } @@ -97,18 +102,21 @@ bool RenderText::isWordBreak() const return false; } -void RenderText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderObject::styleDidChange(diff, oldStyle); + // There is no need to ever schedule repaints from a style change of a text run, since + // we already did this for the parent of the text run. + // We do have to schedule layouts, though, since a style change can force us to + // need to relayout. + if (diff == StyleDifferenceLayout) { + setNeedsLayoutAndPrefWidthsRecalc(); + m_knownNotToUseFallbackFonts = false; + } ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE; ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE; - if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity() -#if ENABLE(SVG) - || isSVGText() /* All SVG text has to be transformed */ -#endif - ) { + if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) { if (RefPtr<StringImpl> textToTransform = originalText()) setText(textToTransform.release(), true); } @@ -198,17 +206,17 @@ void RenderText::deleteTextBoxes() PassRefPtr<StringImpl> RenderText::originalText() const { - Node* e = element(); + Node* e = node(); return e ? static_cast<Text*>(e)->string() : 0; } -void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool) +void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - rects.append(IntRect(tx + box->xPos(), ty + box->yPos(), box->width(), box->height())); + rects.append(IntRect(tx + box->x(), ty + box->y(), box->width(), box->height())); } -void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight) +void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight) { // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this @@ -220,12 +228,12 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne start = min(start, static_cast<unsigned>(INT_MAX)); end = min(end, static_cast<unsigned>(INT_MAX)); - FloatPoint absPos = localToAbsoluteForContent(FloatPoint()); + 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->xPos(), absPos.y() + box->yPos(), box->width(), box->height()); + IntRect r = IntRect(absPos.x() + box->x(), absPos.y() + box->y(), box->width(), box->height()); if (useSelectionHeight) { IntRect selectionRect = box->selectionRect(absPos.x(), absPos.y(), start, end); r.setHeight(selectionRect.height()); @@ -239,7 +247,7 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values r.setHeight(box->height()); - r.setY(absPos.y() + box->yPos()); + r.setY(absPos.y() + box->y()); } rects.append(r); } @@ -247,13 +255,13 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne } } -void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool) +void RenderText::absoluteQuads(Vector<FloatQuad>& quads) { for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - quads.append(localToAbsoluteQuad(FloatRect(box->xPos(), box->yPos(), box->width(), box->height()))); + quads.append(localToAbsoluteQuad(FloatRect(box->x(), box->y(), box->width(), box->height()))); } -void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight) +void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight) { // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this @@ -268,7 +276,7 @@ void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned 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(box->xPos(), box->yPos(), box->width(), box->height()); + IntRect r = IntRect(box->x(), box->y(), box->width(), box->height()); if (useSelectionHeight) { IntRect selectionRect = box->selectionRect(0, 0, start, end); r.setHeight(selectionRect.height()); @@ -282,7 +290,7 @@ void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values r.setHeight(box->height()); - r.setY(box->yPos()); + r.setY(box->y()); } quads.append(localToAbsoluteQuad(FloatRect(r))); } @@ -301,71 +309,71 @@ InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const return 0; InlineTextBox* s = m_firstTextBox; - int off = s->m_len; + int off = s->len(); while (offset > off && s->nextTextBox()) { s = s->nextTextBox(); - off = s->m_start + s->m_len; + off = s->start() + s->len(); } // we are now in the correct text run - pos = (offset > off ? s->m_len : s->m_len - (off - offset) ); + pos = (offset > off ? s->len() : s->len() - (off - offset) ); return s; } -VisiblePosition RenderText::positionForCoordinates(int x, int y) +VisiblePosition RenderText::positionForPoint(const IntPoint& point) { if (!firstTextBox() || textLength() == 0) - return VisiblePosition(element(), 0, DOWNSTREAM); + return createVisiblePosition(0, DOWNSTREAM); // Get the offset for the position, since this will take rtl text into account. int offset; // FIXME: We should be able to roll these special cases into the general cases in the loop below. - if (firstTextBox() && y < firstTextBox()->root()->bottomOverflow() && x < firstTextBox()->m_x) { + if (firstTextBox() && point.y() < firstTextBox()->root()->bottomOverflow() && point.x() < firstTextBox()->m_x) { // at the y coordinate of the first line or above // and the x coordinate is to the left of the first text box left edge - offset = firstTextBox()->offsetForPosition(x); - return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM); + offset = firstTextBox()->offsetForPosition(point.x()); + return createVisiblePosition(offset + firstTextBox()->start(), DOWNSTREAM); } - if (lastTextBox() && y >= lastTextBox()->root()->topOverflow() && x >= lastTextBox()->m_x + lastTextBox()->m_width) { + if (lastTextBox() && point.y() >= lastTextBox()->root()->topOverflow() && point.x() >= lastTextBox()->m_x + lastTextBox()->m_width) { // 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(x); - return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM); + offset = lastTextBox()->offsetForPosition(point.x()); + return createVisiblePosition(offset + lastTextBox()->start(), DOWNSTREAM); } InlineTextBox* lastBoxAbove = 0; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { - if (y >= box->root()->topOverflow()) { + if (point.y() >= box->root()->topOverflow()) { int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow(); - if (y < bottom) { - offset = box->offsetForPosition(x); + if (point.y() < bottom) { + offset = box->offsetForPosition(point.x()); - if (x == box->m_x) + if (point.x() == box->m_x) // the x coordinate is equal to the left edge of this box // the affinity must be downstream so the position doesn't jump back to the previous line - return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM); + return createVisiblePosition(offset + box->start(), DOWNSTREAM); - if (x < box->m_x + box->m_width) + if (point.x() < box->m_x + box->m_width) // and the x coordinate is to the left of the right edge of this box // check to see if position goes in this box - return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); + return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); - if (!box->prevOnLine() && x < box->m_x) + if (!box->prevOnLine() && point.x() < box->m_x) // box is first on line // and the x coordinate is to the left of the first text box left edge - return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM); + return createVisiblePosition(offset + box->start(), DOWNSTREAM); if (!box->nextOnLine()) // box is last on line // and the x coordinate is to the right of the last text box right edge // generate VisiblePosition, use UPSTREAM affinity if possible - return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); + return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); } lastBoxAbove = box; } } - return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM); + return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM); } IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) @@ -384,7 +392,13 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e int left = box->positionForOffset(caretOffset); - int rootLeft = box->root()->xPos(); + // Distribute the caret's width to either side of the offset. + int caretWidthLeftOfOffset = caretWidth / 2; + left -= caretWidthLeftOfOffset; + int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset; + + int rootLeft = box->root()->x(); + int rootRight = rootLeft + box->root()->width(); // FIXME: should we use the width of the root inline box or the // width of the containing block for this? if (extraWidthToEndOfLine) @@ -392,18 +406,28 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e RenderBlock* cb = containingBlock(); if (style()->autoWrap()) { - int availableWidth = cb->lineWidth(top); + int availableWidth = cb->lineWidth(top, false); if (box->direction() == LTR) - left = min(left, rootLeft + availableWidth - 1); + left = min(left, rootLeft + availableWidth - caretWidthRightOfOffset); else + left = max(left, cb->x()); + } else { + // If there is no wrapping, the caret can leave its containing block, but not its root line box. + if (cb->style()->direction() == LTR) { + int rightEdge = max(cb->width(), rootRight); + left = min(left, rightEdge - caretWidthRightOfOffset); left = max(left, rootLeft); + } else { + int leftEdge = min(cb->x(), rootLeft); + left = max(left, leftEdge); + left = min(left, rootRight - caretWidth); + } } - const int caretWidth = 1; return IntRect(left, top, caretWidth, height); } -ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos) const +ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts) const { if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) { int monospaceCharacterWidth = f.spaceWidth(); @@ -433,7 +457,7 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, return w; } - return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos)); + return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos), fallbackFonts); } void RenderText::trimmedPrefWidths(int leadWidth, @@ -502,7 +526,7 @@ void RenderText::trimmedPrefWidths(int leadWidth, linelen++; if (linelen) { - endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW); + endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0); if (firstLine) { firstLine = false; leadWidth = 0; @@ -546,7 +570,15 @@ int RenderText::maxPrefWidth() const void RenderText::calcPrefWidths(int leadWidth) { - ASSERT(m_hasTab || prefWidthsDirty()); + HashSet<const SimpleFontData*> fallbackFonts; + calcPrefWidths(leadWidth, fallbackFonts); + if (fallbackFonts.isEmpty()) + m_knownNotToUseFallbackFonts = true; +} + +void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts) +{ + ASSERT(m_hasTab || prefWidthsDirty() || !m_knownNotToUseFallbackFonts); m_minWidth = 0; m_beginMinWidth = 0; @@ -618,7 +650,7 @@ void RenderText::calcPrefWidths(int leadWidth) lastWordBoundary++; continue; } else if (c == softHyphen) { - currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth); + currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts); lastWordBoundary = i + 1; continue; } @@ -641,13 +673,13 @@ void RenderText::calcPrefWidths(int leadWidth) int wordLen = j - i; if (wordLen) { - int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth); + int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts); currMinWidth += w; if (betweenWords) { if (lastWordBoundary == i) currMaxWidth += w; else - currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth); + currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts); lastWordBoundary = j; } @@ -707,7 +739,7 @@ void RenderText::calcPrefWidths(int leadWidth) } } - if (needsWordSpacing && len > 1 || ignoringSpaces && !firstWord) + if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord)) currMaxWidth += wordSpacing; m_minWidth = max(currMinWidth, m_minWidth); @@ -734,33 +766,26 @@ bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const return currPos >= (from + len); } -int RenderText::minXPos() const +IntPoint RenderText::firstRunOrigin() const { - if (!m_firstTextBox) - return 0; - - // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX. - int minXPos = 6666666; - for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - minXPos = min(minXPos, static_cast<int>(box->m_x)); - return minXPos; + return IntPoint(firstRunX(), firstRunY()); } -int RenderText::xPos() const +int RenderText::firstRunX() const { return m_firstTextBox ? m_firstTextBox->m_x : 0; } -int RenderText::yPos() const +int RenderText::firstRunY() const { return m_firstTextBox ? m_firstTextBox->m_y : 0; } - + void RenderText::setSelectionState(SelectionState state) { InlineTextBox* box; - m_selectionState = state; + RenderObject::setSelectionState(state); if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) { int startPos, endPos; selectionStartEnd(startPos, endPos); @@ -846,6 +871,11 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, RootInlineBox* prev = firstRootBox->prevRootBox(); if (prev) firstRootBox = prev; + } else if (lastTextBox()) { + ASSERT(!lastRootBox); + firstRootBox = lastTextBox()->root(); + firstRootBox->markDirty(); + dirtiedLines = true; } for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) { if (curr->lineBreakObj() == this && curr->lineBreakPos() > end) @@ -864,11 +894,11 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, static inline bool isInlineFlowOrEmptyText(RenderObject* o) { - if (o->isInlineFlow()) + if (o->isRenderInline()) return true; if (!o->isText()) return false; - StringImpl* text = static_cast<RenderText*>(o)->text(); + StringImpl* text = toRenderText(o)->text(); if (!text) return true; return !text->length(); @@ -883,18 +913,17 @@ UChar RenderText::previousCharacter() break; UChar prev = ' '; if (previousText && previousText->isText()) - if (StringImpl* previousString = static_cast<RenderText*>(previousText)->text()) + if (StringImpl* previousString = toRenderText(previousText)->text()) prev = (*previousString)[previousString->length() - 1]; return prev; } void RenderText::setTextInternal(PassRefPtr<StringImpl> text) { - m_text = text; + ASSERT(text); + m_text = document()->displayStringModifiedByEncoding(text); ASSERT(m_text); - m_text = m_text->replace('\\', backslashAsCurrencySymbol()); - #if ENABLE(SVG) if (isSVGText()) { if (style() && style()->whiteSpace() == PRE) { @@ -971,14 +1000,7 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force) setTextInternal(text); setNeedsLayoutAndPrefWidthsRecalc(); -} - -int RenderText::height() const -{ - int retval = 0; - if (firstTextBox()) - retval = lastTextBox()->m_y + lastTextBox()->height() - firstTextBox()->m_y; - return retval; + m_knownNotToUseFallbackFonts = false; } int RenderText::lineHeight(bool firstLine, bool) const @@ -987,7 +1009,7 @@ int RenderText::lineHeight(bool firstLine, bool) const return parent()->lineHeight(firstLine, true); } -void RenderText::dirtyLineBoxes(bool fullLayout, bool) +void RenderText::dirtyLineBoxes(bool fullLayout) { if (fullLayout) deleteTextBoxes(); @@ -998,15 +1020,14 @@ void RenderText::dirtyLineBoxes(bool fullLayout, bool) m_linesDirty = false; } -InlineTextBox* RenderText::createInlineTextBox() +InlineTextBox* RenderText::createTextBox() { return new (renderArena()) InlineTextBox(this); } -InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool) +InlineTextBox* RenderText::createInlineTextBox() { - ASSERT(!isRootLineBox); - InlineTextBox* textBox = createInlineTextBox(); + InlineTextBox* textBox = createTextBox(); if (!m_firstTextBox) m_firstTextBox = m_lastTextBox = textBox; else { @@ -1014,15 +1035,16 @@ InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool) textBox->setPreviousLineBox(m_lastTextBox); m_lastTextBox = textBox; } + textBox->setIsText(true); return textBox; } -void RenderText::position(InlineBox* box) +void RenderText::positionLineBox(InlineBox* box) { InlineTextBox* s = static_cast<InlineTextBox*>(box); // FIXME: should not be needed!!! - if (!s->m_len) { + if (!s->len()) { // We want the box to be destroyed. s->remove(); s->destroy(renderArena()); @@ -1033,7 +1055,7 @@ void RenderText::position(InlineBox* box) m_containsReversedText |= s->direction() == RTL; } -unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bool firstLine) const +unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts) const { if (from >= textLength()) return 0; @@ -1041,61 +1063,74 @@ unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bo if (from + len > textLength()) len = textLength() - from; - return width(from, len, style(firstLine)->font(), xPos); + return width(from, len, style(firstLine)->font(), xPos, fallbackFonts); } -unsigned int RenderText::width(unsigned int from, unsigned int len, const Font& f, int xPos) const +unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, HashSet<const SimpleFontData*>* fallbackFonts) const { - if (!characters() || from > textLength()) + ASSERT(from + len <= textLength()); + if (!characters()) return 0; - if (from + len > textLength()) - len = textLength() - from; - int w; if (&f == &style()->font()) { - if (!style()->preserveNewline() && !from && len == textLength()) - w = maxPrefWidth(); - else - w = widthFromCache(f, from, len, xPos); + if (!style()->preserveNewline() && !from && len == textLength()) { + if (fallbackFonts) { + if (prefWidthsDirty() || !m_knownNotToUseFallbackFonts) { + const_cast<RenderText*>(this)->calcPrefWidths(0, *fallbackFonts); + if (fallbackFonts->isEmpty()) + m_knownNotToUseFallbackFonts = true; + } + w = m_maxWidth; + } else + w = maxPrefWidth(); + } else + w = widthFromCache(f, from, len, xPos, fallbackFonts); } else - w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos)); + w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos), fallbackFonts); return w; } -int RenderText::width() const +IntRect RenderText::linesBoundingBox() const { - // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX. - int minx = 100000000; - int maxx = 0; - // slooow - for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) { - if (s->m_x < minx) - minx = s->m_x; - if (s->m_x + s->m_width > maxx) - maxx = s->m_x + s->m_width; + IntRect result; + + ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist. + if (firstTextBox() && lastTextBox()) { + // Return the width of the minimal left side and the maximal right side. + int leftSide = 0; + int rightSide = 0; + for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { + if (curr == firstTextBox() || curr->x() < leftSide) + leftSide = curr->x(); + if (curr == firstTextBox() || curr->x() + curr->width() > rightSide) + rightSide = curr->x() + curr->width(); + } + result.setWidth(rightSide - leftSide); + result.setX(leftSide); + result.setHeight(lastTextBox()->y() + lastTextBox()->height() - firstTextBox()->y()); + result.setY(firstTextBox()->y()); } - return max(0, maxx - minx); + return result; } -IntRect RenderText::absoluteClippedOverflowRect() +IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { RenderObject* cb = containingBlock(); - return cb->absoluteClippedOverflowRect(); + return cb->clippedOverflowRectForRepaint(repaintContainer); } -IntRect RenderText::selectionRect(bool clipToVisibleContent) +IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent) { ASSERT(!needsLayout()); - IntRect rect; if (selectionState() == SelectionNone) - return rect; + return IntRect(); RenderBlock* cb = containingBlock(); if (!cb) - return rect; + return IntRect(); // Now calculate startPos and endPos for painting selection. // We include a selection while endPos > 0 @@ -1113,39 +1148,32 @@ IntRect RenderText::selectionRect(bool clipToVisibleContent) } if (startPos == endPos) - return rect; + return IntRect(); + IntRect rect; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) rect.unite(box->selectionRect(0, 0, startPos, endPos)); if (clipToVisibleContent) - computeAbsoluteRepaintRect(rect); + computeRectForRepaint(repaintContainer, rect); else { if (cb->hasColumns()) cb->adjustRectForColumns(rect); - // FIXME: This doesn't work correctly with transforms. - FloatPoint absPos = localToAbsolute(); - rect.move(absPos.x(), absPos.y()); + + rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); } return rect; } -int RenderText::verticalPositionHint(bool firstLine) const -{ - if (parent()->isReplaced()) - return 0; // Treat inline blocks just like blocks. There can't be any vertical position hint. - return parent()->verticalPositionHint(firstLine); -} - int RenderText::caretMinOffset() const { InlineTextBox* box = firstTextBox(); if (!box) return 0; - int minOffset = box->m_start; + int minOffset = box->start(); for (box = box->nextTextBox(); box; box = box->nextTextBox()) - minOffset = min(minOffset, box->m_start); + minOffset = min<int>(minOffset, box->start()); return minOffset; } @@ -1154,9 +1182,9 @@ int RenderText::caretMaxOffset() const InlineTextBox* box = lastTextBox(); if (!box) return textLength(); - int maxOffset = box->m_start + box->m_len; + int maxOffset = box->start() + box->len(); for (box = box->prevTextBox(); box; box = box->prevTextBox()) - maxOffset = max(maxOffset, box->m_start + box->m_len); + maxOffset = max<int>(maxOffset, box->start() + box->len()); return maxOffset; } @@ -1164,14 +1192,14 @@ unsigned RenderText::caretMaxRenderedOffset() const { int l = 0; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - l += box->m_len; + l += box->len(); return l; } int RenderText::previousOffset(int current) const { StringImpl* si = m_text.get(); - TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length()); + TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current - 1; @@ -1179,13 +1207,122 @@ int RenderText::previousOffset(int current) const if (result == TextBreakDone) result = current - 1; +#ifdef BUILDING_ON_TIGER + // ICU 3.2 allows character breaks before a half-width Katakana voiced mark. + if (static_cast<unsigned>(result) < si->length()) { + UChar character = (*si)[result]; + if (character == 0xFF9E || character == 0xFF9F) + --result; + } +#endif + return result; } +#define HANGUL_CHOSEONG_START (0x1100) +#define HANGUL_CHOSEONG_END (0x115F) +#define HANGUL_JUNGSEONG_START (0x1160) +#define HANGUL_JUNGSEONG_END (0x11A2) +#define HANGUL_JONGSEONG_START (0x11A8) +#define HANGUL_JONGSEONG_END (0x11F9) +#define HANGUL_SYLLABLE_START (0xAC00) +#define HANGUL_SYLLABLE_END (0xD7AF) +#define HANGUL_JONGSEONG_COUNT (28) + +enum HangulState { + HangulStateL, + HangulStateV, + HangulStateT, + HangulStateLV, + HangulStateLVT, + HangulStateBreak +}; + +inline bool isHangulLVT(UChar32 character) +{ + return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT; +} + +int RenderText::previousOffsetForBackwardDeletion(int current) const +{ +#if PLATFORM(MAC) + UChar32 character; + while (current > 0) { + if (U16_IS_TRAIL((*m_text)[--current])) + --current; + if (current < 0) + break; + + UChar32 character = m_text->characterStartingAt(current); + + // We don't combine characters in Armenian ... Limbu range for backward deletion. + if ((character >= 0x0530) && (character < 0x1950)) + break; + + if (u_isbase(character) && (character != 0xFF9E) && (character != 0xFF9F)) + break; + } + + if (current <= 0) + return current; + + // Hangul + character = m_text->characterStartingAt(current); + if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) { + HangulState state; + HangulState initialState; + + if (character < HANGUL_JUNGSEONG_START) + state = HangulStateL; + else if (character < HANGUL_JONGSEONG_START) + state = HangulStateV; + else if (character < HANGUL_SYLLABLE_START) + state = HangulStateT; + else + state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV; + + 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))) { + switch (state) { + case HangulStateV: + if (character <= HANGUL_CHOSEONG_END) + state = HangulStateL; + else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character)) + state = HangulStateLV; + else if (character > HANGUL_JUNGSEONG_END) + state = HangulStateBreak; + break; + case HangulStateT: + if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END)) + state = HangulStateV; + else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END)) + state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV); + else if (character < HANGUL_JUNGSEONG_START) + state = HangulStateBreak; + break; + default: + state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak; + break; + } + if (state == HangulStateBreak) + break; + + --current; + } + } + + return current; +#else + // Platforms other than Mac delete by one code point. + return current - 1; +#endif +} + int RenderText::nextOffset(int current) const { StringImpl* si = m_text.get(); - TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length()); + TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current + 1; @@ -1193,6 +1330,15 @@ int RenderText::nextOffset(int current) const if (result == TextBreakDone) result = current + 1; +#ifdef BUILDING_ON_TIGER + // ICU 3.2 allows character breaks before a half-width Katakana voiced mark. + if (static_cast<unsigned>(result) < si->length()) { + UChar character = (*si)[result]; + if (character == 0xFF9E || character == 0xFF9F) + ++result; + } +#endif + return result; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.h b/src/3rdparty/webkit/WebCore/rendering/RenderText.h index 4c62638..2e04a9e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderText.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.h @@ -1,7 +1,7 @@ /* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -52,26 +52,23 @@ public: StringImpl* text() const { return m_text.get(); } - virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); - virtual InlineTextBox* createInlineTextBox(); - virtual void dirtyLineBoxes(bool fullLayout, bool isRootInlineBox = false); + InlineTextBox* createInlineTextBox(); + void dirtyLineBoxes(bool fullLayout); - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + void absoluteRectsForRange(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + virtual void absoluteQuads(Vector<FloatQuad>&); + void absoluteQuadsForRange(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); - virtual VisiblePosition positionForCoordinates(int x, int y); + 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() - virtual void position(InlineBox*); + void positionLineBox(InlineBox*); - virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos) const; - virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false) const; - virtual int width() const; - virtual int height() const; + virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; + virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; @@ -85,28 +82,24 @@ public: int& beginMaxW, int& endMaxW, int& minW, int& maxW, bool& stripFrontSpaces); - // returns the minimum x position of all runs relative to the parent. - // defaults to 0. - int minXPos() const; + IntRect linesBoundingBox() const; - virtual int xPos() const; - virtual int yPos() const; - - virtual int verticalPositionHint(bool firstLine) const; + IntPoint firstRunOrigin() const; + int firstRunX() const; + int firstRunY() const; void setText(PassRefPtr<StringImpl>, bool force = false); void setTextWithOffset(PassRefPtr<StringImpl>, unsigned offset, unsigned len, bool force = false); virtual bool canBeSelectionLeaf() const { return true; } - virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); } virtual void setSelectionState(SelectionState s); - virtual IntRect selectionRect(bool clipToVisibleContent = true); + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual int marginLeft() const { return style()->marginLeft().calcMinValue(0); } virtual int marginRight() const { return style()->marginRight().calcMinValue(0); } - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); InlineTextBox* firstTextBox() const { return m_firstTextBox; } InlineTextBox* lastTextBox() const { return m_lastTextBox; } @@ -116,6 +109,7 @@ public: virtual unsigned caretMaxRenderedOffset() const; virtual int previousOffset(int current) const; + virtual int previousOffsetForBackwardDeletion(int current) const; virtual int nextOffset(int current) const; bool containsReversedText() const { return m_containsReversedText; } @@ -126,14 +120,20 @@ public: void checkConsistency() const; + virtual void calcPrefWidths(int leadWidth); + protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleWillChange(StyleDifference, const RenderStyle*) { } + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void setTextInternal(PassRefPtr<StringImpl>); - virtual void calcPrefWidths(int leadWidth); virtual UChar previousCharacter(); + + virtual InlineTextBox* createTextBox(); // Subclassed by SVG. private: + void calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts); + // Make length() private so that callers that have a RenderText* // will use the more efficient textLength() instead, while // callers with a RenderObject* can continue to use length(). @@ -145,20 +145,20 @@ private: void deleteTextBoxes(); bool containsOnlyWhitespace(unsigned from, unsigned len) const; - int widthFromCache(const Font&, int start, int len, int xPos) const; + int widthFromCache(const Font&, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts) const; bool isAllASCII() const { return m_isAllASCII; } + int m_minWidth; // here to minimize padding in 64-bit. + RefPtr<StringImpl> m_text; InlineTextBox* m_firstTextBox; InlineTextBox* m_lastTextBox; - int m_minWidth; int m_maxWidth; int m_beginMinWidth; int m_endMinWidth; - unsigned m_selectionState : 3; // enums on Windows are signed, so this needs to be unsigned to prevent it turning negative. bool m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines. bool m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n'). bool m_hasTab : 1; // Whether or not we have a variable width tab character (e.g., <pre> with '\t'). @@ -170,8 +170,24 @@ private: // or removed). bool m_containsReversedText : 1; bool m_isAllASCII : 1; + mutable bool m_knownNotToUseFallbackFonts : 1; }; +inline RenderText* toRenderText(RenderObject* o) +{ + ASSERT(!o || o->isText()); + return static_cast<RenderText*>(o); +} + +inline const RenderText* toRenderText(const RenderObject* o) +{ + ASSERT(!o || o->isText()); + return static_cast<const RenderText*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderText(const RenderText*); + #ifdef NDEBUG inline void RenderText::checkConsistency() const { diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp index 8f853f8..29c8c8a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp @@ -22,19 +22,21 @@ #include "config.h" #include "RenderTextControl.h" +#include "AXObjectCache.h" #include "CharacterNames.h" #include "Editor.h" #include "Event.h" #include "EventNames.h" #include "Frame.h" #include "HTMLBRElement.h" -#include "HTMLFormControlElement.h" #include "HTMLNames.h" #include "HitTestResult.h" +#include "RenderLayer.h" +#include "RenderText.h" #include "ScrollbarTheme.h" #include "SelectionController.h" -#include "TextControlInnerElements.h" #include "Text.h" +#include "TextControlInnerElements.h" #include "TextIterator.h" using namespace std; @@ -79,12 +81,12 @@ RenderTextControl::~RenderTextControl() m_innerText->detach(); } -void RenderTextControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); if (m_innerText) { - RenderBlock* textBlockRenderer = static_cast<RenderBlock*>(m_innerText->renderer()); + RenderBlock* textBlockRenderer = toRenderBlock(m_innerText->renderer()); RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style()); // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. @@ -97,18 +99,32 @@ void RenderTextControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle } } - setHasOverflowClip(false); setReplaced(isInline()); } +static inline bool updateUserModifyProperty(Node* node, RenderStyle* style) +{ + bool isEnabled = true; + bool isReadOnlyControl = false; + + if (node->isElementNode()) { + Element* element = static_cast<Element*>(node); + isEnabled = element->isEnabledFormControl(); + isReadOnlyControl = element->isReadOnlyFormControl(); + } + + style->setUserModify((isReadOnlyControl || !isEnabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); + return !isEnabled; +} + void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const { // The inner block, if present, always has its direction set to LTR, // so we need to inherit the direction from the element. textBlockStyle->setDirection(style()->direction()); - textBlockStyle->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); - if (!node()->isEnabled()) + bool disabled = updateUserModifyProperty(node(), textBlockStyle); + if (disabled) textBlockStyle->setColor(disabledTextColor(textBlockStyle->color(), startStyle->backgroundColor())); } @@ -126,18 +142,18 @@ void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBloc int RenderTextControl::textBlockHeight() const { - return m_height - paddingTop() - paddingBottom() - borderTop() - borderBottom(); + return height() - paddingTop() - paddingBottom() - borderTop() - borderBottom(); } int RenderTextControl::textBlockWidth() const { - return m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight() - - m_innerText->renderer()->paddingLeft() - m_innerText->renderer()->paddingRight(); + return width() - paddingLeft() - paddingRight() - borderLeft() - borderRight() + - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight(); } void RenderTextControl::updateFromElement() { - m_innerText->renderer()->style()->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); + updateUserModifyProperty(node(), m_innerText->renderer()->style()); } void RenderTextControl::setInnerTextValue(const String& innerTextValue) @@ -148,13 +164,17 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue) value = ""; else { value = innerTextValue; - value = value.replace('\\', backslashAsCurrencySymbol()); + value = document()->displayStringModifiedByEncoding(value); } if (value != text() || !m_innerText->hasChildNodes()) { if (value != text()) { - if (Frame* frame = document()->frame()) + if (Frame* frame = document()->frame()) { frame->editor()->clearUndoRedoOperations(); + + if (AXObjectCache::accessibilityEnabled()) + document()->axObjectCache()->postNotification(this, "AXValueChanged", false); + } } ExceptionCode ec = 0; @@ -170,7 +190,7 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue) m_userEdited = false; } - formControlElement()->setValueMatchesRenderer(); + static_cast<Element*>(node())->setFormControlValueMatchesRenderer(true); } void RenderTextControl::setUserEdited(bool isUserEdited) @@ -217,7 +237,7 @@ void RenderTextControl::setSelectionRange(int start, int end) document()->updateLayout(); - if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderer()->height()) { + if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderBox()->height()) { cacheSelection(start, end); return; } @@ -228,10 +248,12 @@ void RenderTextControl::setSelectionRange(int start, int end) else endPosition = visiblePositionForIndex(end); - ASSERT(startPosition.isNotNull() && endPosition.isNotNull()); - ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node()); - - Selection newSelection = Selection(startPosition, endPosition); + // startPosition and endPosition can be null position for example when + // "-webkit-user-select: none" style attribute is specified. + if (startPosition.isNotNull() && endPosition.isNotNull()) { + ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node()); + } + VisibleSelection newSelection = VisibleSelection(startPosition, endPosition); if (Frame* frame = document()->frame()) frame->selection()->setSelection(newSelection); @@ -242,10 +264,10 @@ void RenderTextControl::setSelectionRange(int start, int end) frame->setSelectionGranularity(CharacterGranularity); } -Selection RenderTextControl::selection(int start, int end) const +VisibleSelection RenderTextControl::selection(int start, int end) const { - return Selection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY), - VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY)); + return VisibleSelection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY), + VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY)); } VisiblePosition RenderTextControl::visiblePositionForIndex(int index) @@ -274,7 +296,7 @@ int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos) RefPtr<Range> range = Range::create(document()); range->setStart(m_innerText.get(), 0, ec); ASSERT(!ec); - range->setEnd(indexPosition.node(), indexPosition.offset(), ec); + range->setEnd(indexPosition.node(), indexPosition.deprecatedEditingOffset(), ec); ASSERT(!ec); return TextIterator::rangeLength(range.get()); } @@ -293,14 +315,8 @@ String RenderTextControl::finishText(Vector<UChar>& result) const result.shrink(--size); // Convert backslash to currency symbol. - UChar symbol = backslashAsCurrencySymbol(); - if (symbol != '\\') { - for (size_t i = 0; i < size; ++i) { - if (result[i] == '\\') - result[i] = symbol; - } - } - + document()->displayBufferModifiedByEncoding(result.data(), result.size()); + return String::adopt(result); } @@ -349,6 +365,7 @@ static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& b } } breakNode = 0; + breakOffset = 0; } String RenderTextControl::textWithHardLineBreaks() @@ -365,7 +382,7 @@ String RenderTextControl::textWithHardLineBreaks() if (!renderer) return ""; - InlineBox* box = renderer->isText() ? static_cast<RenderText*>(renderer)->firstTextBox() : renderer->inlineBoxWrapper(); + InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : toRenderBox(renderer)->inlineBoxWrapper(); if (!box) return ""; @@ -424,25 +441,26 @@ int RenderTextControl::scrollbarThickness() const void RenderTextControl::calcHeight() { - m_height = m_innerText->renderer()->borderTop() + m_innerText->renderer()->borderBottom() + - m_innerText->renderer()->paddingTop() + m_innerText->renderer()->paddingBottom() + - m_innerText->renderer()->marginTop() + m_innerText->renderer()->marginBottom(); + setHeight(m_innerText->renderBox()->borderTop() + m_innerText->renderBox()->borderBottom() + + m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() + + m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom()); adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true)); - m_height += paddingTop() + paddingBottom() + borderTop() + borderBottom(); + setHeight(height() + paddingTop() + paddingBottom() + borderTop() + borderBottom()); // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. - if (m_innerText->renderer()->style()->overflowX() == OSCROLL || (m_innerText->renderer()->style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap)) - m_height += scrollbarThickness(); + if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap)) + setHeight(height() + scrollbarThickness()); RenderBlock::calcHeight(); } -void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int x, int y, int tx, int ty) +void RenderTextControl::hitInnerTextElement(HitTestResult& result, int xPos, int yPos, int tx, int ty) { result.setInnerNode(m_innerText.get()); - result.setLocalPoint(IntPoint(x - tx - m_x - m_innerText->renderer()->xPos(), - y - ty - m_y - m_innerText->renderer()->yPos())); + result.setInnerNonSharedNode(m_innerText.get()); + result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(), + yPos - ty - y() - m_innerText->renderBox()->y())); } void RenderTextControl::forwardEvent(Event* event) @@ -454,7 +472,7 @@ void RenderTextControl::forwardEvent(Event* event) IntRect RenderTextControl::controlClipRect(int tx, int ty) const { - IntRect clipRect = contentBox(); + IntRect clipRect = contentBoxRect(); clipRect.move(tx, ty); return clipRect; } @@ -469,11 +487,9 @@ void RenderTextControl::calcPrefWidths() if (style()->width().isFixed() && style()->width().value() > 0) m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value()); else { - // Figure out how big a text control needs to be for a given number of characters - // (using "0" as the nominal character). - const UChar ch = '0'; - float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false)); - m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderer()->paddingLeft() + m_innerText->renderer()->paddingRight(); + // Use average character width. Matches IE. + float charWidth = style()->font().primaryFont()->avgCharWidth(); + m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight(); } if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { @@ -503,7 +519,7 @@ void RenderTextControl::selectionChanged(bool userTriggered) if (Frame* frame = document()->frame()) { if (frame->selection()->isRange() && userTriggered) - static_cast<EventTargetNode*>(node())->dispatchEventForType(eventNames().selectEvent, true, false); + node()->dispatchEvent(eventNames().selectEvent, true, false); } } @@ -512,80 +528,9 @@ void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); } -void RenderTextControl::autoscroll() -{ - RenderLayer* layer = m_innerText->renderer()->layer(); - if (layer) - layer->autoscroll(); -} - -int RenderTextControl::scrollWidth() const -{ - if (m_innerText) - return m_innerText->scrollWidth(); - return RenderBlock::scrollWidth(); -} - -int RenderTextControl::scrollHeight() const -{ - if (m_innerText) - return m_innerText->scrollHeight(); - return RenderBlock::scrollHeight(); -} - -int RenderTextControl::scrollLeft() const -{ - if (m_innerText) - return m_innerText->scrollLeft(); - return RenderBlock::scrollLeft(); -} - -int RenderTextControl::scrollTop() const -{ - if (m_innerText) - return m_innerText->scrollTop(); - return RenderBlock::scrollTop(); -} - -void RenderTextControl::setScrollLeft(int newLeft) -{ - if (m_innerText) - m_innerText->setScrollLeft(newLeft); -} - -void RenderTextControl::setScrollTop(int newTop) -{ - if (m_innerText) - m_innerText->setScrollTop(newTop); -} - -bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) -{ - RenderLayer* layer = m_innerText->renderer()->layer(); - if (layer && layer->scroll(direction, granularity, multiplier)) - return true; - return RenderObject::scroll(direction, granularity, multiplier); -} - -bool RenderTextControl::isScrollable() const -{ - if (m_innerText && m_innerText->renderer()->isScrollable()) - return true; - return RenderObject::isScrollable(); -} - HTMLElement* RenderTextControl::innerTextElement() const { return m_innerText.get(); } -FormControlElement* RenderTextControl::formControlElement() const -{ - if (node()->isHTMLElement()) - return static_cast<HTMLFormControlElement*>(node()); - - ASSERT_NOT_REACHED(); - return 0; -} - } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h index 40f5116..bce9619 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h @@ -26,8 +26,7 @@ namespace WebCore { -class FormControlElement; -class Selection; +class VisibleSelection; class TextControlInnerElement; class TextControlInnerTextElement; @@ -36,6 +35,7 @@ public: virtual ~RenderTextControl(); virtual const char* renderName() const { return "RenderTextControl"; } + virtual bool isTextControl() const { return true; } virtual bool hasControlClip() const { return false; } virtual IntRect controlClipRect(int tx, int ty) const; virtual void calcHeight(); @@ -45,8 +45,8 @@ public: virtual bool canHaveChildren() const { return false; } virtual bool avoidsFloats() const { return true; } - virtual bool isEdited() const { return m_edited; } - virtual void setEdited(bool isEdited) { m_edited = isEdited; } + bool isEdited() const { return m_edited; } + void setEdited(bool isEdited) { m_edited = isEdited; } bool isUserEdited() const { return m_userEdited; } void setUserEdited(bool isUserEdited); @@ -57,7 +57,7 @@ public: void setSelectionEnd(int); void select(); void setSelectionRange(int start, int end); - Selection selection(int start, int end) const; + VisibleSelection selection(int start, int end) const; virtual void subtreeHasChanged(); String text(); @@ -67,17 +67,6 @@ public: virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); virtual bool canBeProgramaticallyScrolled(bool) const { return true; } - virtual void autoscroll(); - - // Subclassed to forward to our inner div. - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); - virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool isScrollable() const; VisiblePosition visiblePositionForIndex(int index); int indexForVisiblePosition(const VisiblePosition&); @@ -89,10 +78,10 @@ protected: void adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const; void setInnerTextValue(const String&); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); void createSubtreeIfNeeded(TextControlInnerElement* innerBlock); - void hitInnerTextBlock(HitTestResult&, int x, int y, int tx, int ty); + void hitInnerTextElement(HitTestResult&, int x, int y, int tx, int ty); void forwardEvent(Event*); int textBlockWidth() const; @@ -106,8 +95,6 @@ protected: friend class TextIterator; HTMLElement* innerTextElement() const; - FormControlElement* formControlElement() const; - private: String finishText(Vector<UChar>&) const; @@ -116,6 +103,21 @@ private: RefPtr<TextControlInnerTextElement> m_innerText; }; +inline RenderTextControl* toRenderTextControl(RenderObject* o) +{ + ASSERT(!o || o->isTextControl()); + return static_cast<RenderTextControl*>(o); +} + +inline const RenderTextControl* toRenderTextControl(const RenderObject* o) +{ + ASSERT(!o || o->isTextControl()); + return static_cast<const RenderTextControl*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTextControl(const RenderTextControl*); + } // namespace WebCore #endif // RenderTextControl_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp index f860524..df31c2b 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -43,52 +43,27 @@ RenderTextControlMultiLine::~RenderTextControlMultiLine() void RenderTextControlMultiLine::subtreeHasChanged() { RenderTextControl::subtreeHasChanged(); - formControlElement()->setValueMatchesRenderer(false); + static_cast<Element*>(node())->setFormControlValueMatchesRenderer(false); if (!node()->focused()) return; + // Fire the "input" DOM event + node()->dispatchEvent(eventNames().inputEvent, true, false); + if (Frame* frame = document()->frame()) frame->textDidChangeInTextArea(static_cast<Element*>(node())); } -void RenderTextControlMultiLine::layout() -{ - int oldHeight = m_height; - calcHeight(); - - int oldWidth = m_width; - calcWidth(); - - bool relayoutChildren = oldHeight != m_height || oldWidth != m_width; - RenderObject* innerTextRenderer = innerTextElement()->renderer(); - - // Set the text block height - int desiredHeight = textBlockHeight(); - if (desiredHeight != innerTextRenderer->height()) - relayoutChildren = true; - innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); - - // Set the text block width - int desiredWidth = textBlockWidth(); - if (desiredWidth != innerTextRenderer->width()) - relayoutChildren = true; - innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); - - RenderBlock::layoutBlock(relayoutChildren); -} - bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) { if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction)) return false; - if (result.innerNode() == element()) { - hitInnerTextBlock(result, x, y, tx, ty); - return true; - } + if (result.innerNode() == node() || result.innerNode() == innerTextElement()) + hitInnerTextElement(result, x, y, tx, ty); - return false; + return true; } void RenderTextControlMultiLine::forwardEvent(Event* event) @@ -104,7 +79,7 @@ int RenderTextControlMultiLine::preferredContentWidth(float charWidth) const void RenderTextControlMultiLine::adjustControlHeightBasedOnLineHeight(int lineHeight) { - m_height += lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows(); + setHeight(height() + lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows()); } int RenderTextControlMultiLine::baselinePosition(bool, bool) const @@ -132,10 +107,9 @@ PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const R adjustInnerTextStyle(startStyle, textBlockStyle.get()); - // Forward overflow properties. - textBlockStyle->setOverflowX(startStyle->overflowX() == OVISIBLE ? OAUTO : startStyle->overflowX()); - textBlockStyle->setOverflowY(startStyle->overflowY() == OVISIBLE ? OAUTO : startStyle->overflowY()); - + // FIXME: This code should just map wrap into CSS in the DOM code. + // Then here we should set the textBlockStyle appropriately based off this + // object's style()->whiteSpace() and style->wordWrap(). // Set word wrap property based on wrap attribute. if (static_cast<HTMLTextAreaElement*>(node())->shouldWrapText()) { textBlockStyle->setWhiteSpace(PRE_WRAP); @@ -147,10 +121,6 @@ PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const R textBlockStyle->setDisplay(BLOCK); - // We're adding three extra pixels of padding to line textareas up with text fields. - textBlockStyle->setPaddingLeft(Length(3, Fixed)); - textBlockStyle->setPaddingRight(Length(3, Fixed)); - return textBlockStyle.release(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h index 591a65d..579047d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h @@ -33,7 +33,6 @@ public: virtual bool isTextArea() const { return true; } virtual void subtreeHasChanged(); - virtual void layout(); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); void forwardEvent(Event*); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp index 4f52527..a5db44e 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -30,6 +30,7 @@ #include "HitTestResult.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include "InputElement.h" #include "LocalizedStrings.h" #include "MouseEvent.h" #include "PlatformKeyboardEvent.h" @@ -38,6 +39,7 @@ #include "SearchPopupMenu.h" #include "SelectionController.h" #include "Settings.h" +#include "SimpleFontData.h" #include "TextControlInnerElements.h" using namespace std; @@ -69,7 +71,7 @@ RenderTextControlSingleLine::~RenderTextControlSingleLine() bool RenderTextControlSingleLine::placeholderShouldBeVisible() const { - return static_cast<HTMLInputElement*>(node())->placeholderShouldBeVisible(); + return inputElement()->placeholderShouldBeVisible(); } void RenderTextControlSingleLine::updatePlaceholderVisibility() @@ -90,6 +92,7 @@ void RenderTextControlSingleLine::updatePlaceholderVisibility() void RenderTextControlSingleLine::addSearchResult() { + ASSERT(node()->isHTMLElement()); HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); if (input->maxResults() <= 0) return; @@ -121,11 +124,13 @@ void RenderTextControlSingleLine::addSearchResult() void RenderTextControlSingleLine::stopSearchEventTimer() { + ASSERT(node()->isHTMLElement()); m_searchEventTimer.stop(); } void RenderTextControlSingleLine::showPopup() { + ASSERT(node()->isHTMLElement()); if (m_searchPopupIsVisible) return; @@ -155,6 +160,7 @@ void RenderTextControlSingleLine::showPopup() void RenderTextControlSingleLine::hidePopup() { + ASSERT(node()->isHTMLElement()); if (m_searchPopup) m_searchPopup->hide(); @@ -166,24 +172,24 @@ void RenderTextControlSingleLine::subtreeHasChanged() bool wasEdited = isEdited(); RenderTextControl::subtreeHasChanged(); - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + InputElement* input = inputElement(); input->setValueFromRenderer(input->constrainValue(text())); - if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) - updateCancelButtonVisibility(cancelButtonRenderer->style()); + if (m_cancelButton) + updateCancelButtonVisibility(); // If the incremental attribute is set, then dispatch the search event - if (!input->getAttribute(incrementalAttr).isNull()) + if (input->searchEventsShouldBeDispatched()) startSearchEventTimer(); - if (!wasEdited && input->focused()) { + if (!wasEdited && node()->focused()) { if (Frame* frame = document()->frame()) - frame->textFieldDidBeginEditing(input); + frame->textFieldDidBeginEditing(static_cast<Element*>(node())); } - if (input->focused()) { + if (node()->focused()) { if (Frame* frame = document()->frame()) - frame->textDidChangeInTextField(input); + frame->textDidChangeInTextField(static_cast<Element*>(node())); } } @@ -192,42 +198,37 @@ void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty) RenderTextControl::paint(paintInfo, tx, ty); if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) { - IntRect contentsRect = contentBox(); + IntRect contentsRect = contentBoxRect(); // Convert the rect into the coords used for painting the content - contentsRect.move(tx + xPos(), ty + yPos()); + contentsRect.move(tx + x(), ty + y()); theme()->paintCapsLockIndicator(this, paintInfo, contentsRect); } } void RenderTextControlSingleLine::layout() { - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); - bool relayoutChildren = oldHeight != m_height || oldWidth != m_width; + bool relayoutChildren = oldHeight != height() || oldWidth != width(); - RenderObject* innerTextRenderer = innerTextElement()->renderer(); - RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0; + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + RenderBox* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderBox() : 0; // Set the text block height int desiredHeight = textBlockHeight(); int currentHeight = innerTextRenderer->height(); - if (m_innerBlock || currentHeight > m_height) { + if (currentHeight > height()) { if (desiredHeight != currentHeight) relayoutChildren = true; innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); - } - - if (m_innerBlock) { - ASSERT(innerBlockRenderer); - if (desiredHeight != innerBlockRenderer->height()) - relayoutChildren = true; - innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed)); + if (m_innerBlock) + innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed)); } // Set the text block width @@ -237,7 +238,7 @@ void RenderTextControlSingleLine::layout() innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); if (m_innerBlock) { - int innerBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight(); + int innerBlockWidth = width() - paddingLeft() - paddingRight() - borderLeft() - borderRight(); if (innerBlockWidth != innerBlockRenderer->width()) relayoutChildren = true; innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed)); @@ -245,16 +246,14 @@ void RenderTextControlSingleLine::layout() RenderBlock::layoutBlock(relayoutChildren); - // For text fields, center the inner text vertically - // Don't do this for search fields, since we don't honor height for them - if (!m_innerBlock) { - currentHeight = innerTextRenderer->height(); - if (currentHeight < m_height) - innerTextRenderer->setPos(innerTextRenderer->xPos(), (m_height - currentHeight) / 2); - } + // Center the child block vertically + RenderBox* childBlock = innerBlockRenderer ? innerBlockRenderer : innerTextRenderer; + currentHeight = childBlock->height(); + if (currentHeight < height()) + childBlock->setLocation(childBlock->x(), (height() - currentHeight) / 2); } -bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) { // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point // was on the control but not on the inner element (see Radar 4617841). @@ -262,37 +261,39 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, // and act as if we've hit the close block if we're to the right of the inner text block. - if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction)) + if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction)) return false; - if (result.innerNode() != element() && result.innerNode() != m_innerBlock.get()) - return false; - - hitInnerTextBlock(result, x, y, tx, ty); + // If we hit a node inside the inner text element, say that we hit that element, + // and if we hit our node (e.g. we're over the border or padding), also say that we hit the + // inner text element so that it gains focus. + if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node()) + hitInnerTextElement(result, xPos, yPos, tx, ty); - if (!m_innerBlock) + // If we're not a search field, or we already found the results or cancel buttons, we're done. + if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton) return true; Node* innerNode = 0; - RenderObject* innerBlockRenderer = m_innerBlock->renderer(); - RenderObject* innerTextRenderer = innerTextElement()->renderer(); + RenderBox* innerBlockRenderer = m_innerBlock->renderBox(); + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); IntPoint localPoint = result.localPoint(); - localPoint.move(-innerBlockRenderer->xPos(), -innerBlockRenderer->yPos()); + localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y()); - int textLeft = tx + m_x + innerBlockRenderer->xPos() + innerTextRenderer->xPos(); - if (m_resultsButton && m_resultsButton->renderer() && x < textLeft) + int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x(); + if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft) innerNode = m_resultsButton.get(); if (!innerNode) { int textRight = textLeft + innerTextRenderer->width(); - if (m_cancelButton && m_cancelButton->renderer() && x > textRight) + if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight) innerNode = m_cancelButton.get(); } if (innerNode) { result.setInnerNode(innerNode); - localPoint.move(-innerNode->renderer()->xPos(), -innerNode->renderer()->yPos()); + localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y()); } result.setLocalPoint(localPoint); @@ -301,7 +302,7 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit void RenderTextControlSingleLine::forwardEvent(Event* event) { - RenderObject* innerTextRenderer = innerTextElement()->renderer(); + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); if (event->type() == eventNames().blurEvent) { if (innerTextRenderer) { @@ -318,16 +319,16 @@ void RenderTextControlSingleLine::forwardEvent(Event* event) return; } - FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true); - if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBox().x()) + FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true); + if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x()) m_resultsButton->defaultEventHandler(event); - else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBox().right()) + else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBoxRect().right()) m_cancelButton->defaultEventHandler(event); else RenderTextControl::forwardEvent(event); } -void RenderTextControlSingleLine::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderTextControl::styleDidChange(diff, oldStyle); @@ -344,6 +345,8 @@ void RenderTextControlSingleLine::styleDidChange(RenderStyle::Diff diff, const R if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) cancelRenderer->setStyle(createCancelButtonStyle(style())); + + setHasOverflowClip(false); } void RenderTextControlSingleLine::capsLockStateMayHaveChanged() @@ -359,7 +362,7 @@ void RenderTextControlSingleLine::capsLockStateMayHaveChanged() bool shouldDrawCapsLockIndicator = false; if (Frame* frame = document()->frame()) - shouldDrawCapsLockIndicator = static_cast<HTMLInputElement*>(node())->inputType() == HTMLInputElement::PASSWORD + shouldDrawCapsLockIndicator = inputElement()->isPasswordField() && frame->selection()->isFocusedAndActive() && document()->focusedNode() == node() && PlatformKeyboardEvent::currentCapsLockState(); @@ -374,14 +377,14 @@ int RenderTextControlSingleLine::textBlockWidth() const { int width = RenderTextControl::textBlockWidth(); - if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) { + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { resultsRenderer->calcWidth(); - width -= resultsRenderer->width(); + width -= resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->marginRight(); } - if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) { + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) { cancelRenderer->calcWidth(); - width -= cancelRenderer->width(); + width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight(); } return width; @@ -389,17 +392,20 @@ int RenderTextControlSingleLine::textBlockWidth() const int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const { - int factor = static_cast<HTMLInputElement*>(node())->size(); + int factor = inputElement()->size(); if (factor <= 0) factor = 20; int result = static_cast<int>(ceilf(charWidth * factor)); - if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) + // For text inputs, IE adds some extra width. + result += style()->font().primaryFont()->maxCharWidth() - charWidth; + + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() + resultsRenderer->paddingLeft() + resultsRenderer->paddingRight(); - if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() + cancelRenderer->paddingLeft() + cancelRenderer->paddingRight(); @@ -408,30 +414,30 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight) { - if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) { - static_cast<RenderBlock*>(resultsRenderer)->calcHeight(); - m_height = max(m_height, - resultsRenderer->borderTop() + resultsRenderer->borderBottom() + - resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() + - resultsRenderer->marginTop() + resultsRenderer->marginBottom()); + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { + toRenderBlock(resultsRenderer)->calcHeight(); + setHeight(max(height(), + resultsRenderer->borderTop() + resultsRenderer->borderBottom() + + resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() + + resultsRenderer->marginTop() + resultsRenderer->marginBottom())); lineHeight = max(lineHeight, resultsRenderer->height()); } - if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) { - static_cast<RenderBlock*>(cancelRenderer)->calcHeight(); - m_height = max(m_height, - cancelRenderer->borderTop() + cancelRenderer->borderBottom() + - cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() + - cancelRenderer->marginTop() + cancelRenderer->marginBottom()); + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) { + toRenderBlock(cancelRenderer)->calcHeight(); + setHeight(max(height(), + cancelRenderer->borderTop() + cancelRenderer->borderBottom() + + cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() + + cancelRenderer->marginTop() + cancelRenderer->marginBottom())); lineHeight = max(lineHeight, cancelRenderer->height()); } - m_height += lineHeight; + setHeight(height() + lineHeight); } void RenderTextControlSingleLine::createSubtreeIfNeeded() { - if (!static_cast<HTMLInputElement*>(node())->isSearchField()) { + if (!inputElement()->isSearchField()) { RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); return; } @@ -466,17 +472,15 @@ void RenderTextControlSingleLine::updateFromElement() bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible(); m_placeholderVisible = placeholderShouldBeVisible(); - if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) - updateCancelButtonVisibility(cancelButtonRenderer->style()); - - HTMLInputElement* element = static_cast<HTMLInputElement*>(node()); + if (m_cancelButton) + updateCancelButtonVisibility(); if (m_placeholderVisible) { ExceptionCode ec = 0; - innerTextElement()->setInnerText(element->getAttribute(placeholderAttr), ec); - ASSERT(ec == 0); - } else if (!formControlElement()->valueMatchesRenderer() || placeholderVisibilityShouldChange) - setInnerTextValue(element->value()); + innerTextElement()->setInnerText(inputElement()->placeholder(), ec); + ASSERT(!ec); + } else if (!static_cast<Element*>(node())->formControlValueMatchesRenderer() || placeholderVisibilityShouldChange) + setInnerTextValue(inputElement()->value()); if (m_searchPopupIsVisible) m_searchPopup->updateFromElement(); @@ -484,16 +488,17 @@ void RenderTextControlSingleLine::updateFromElement() void RenderTextControlSingleLine::cacheSelection(int start, int end) { - static_cast<HTMLInputElement*>(node())->cacheSelection(start, end); + inputElement()->cacheSelection(start, end); } PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const { RefPtr<RenderStyle> textBlockStyle; if (placeholderShouldBeVisible()) { - RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::INPUT_PLACEHOLDER); - textBlockStyle = RenderStyle::clone(pseudoStyle); - } else { + if (RenderStyle* pseudoStyle = getCachedPseudoStyle(INPUT_PLACEHOLDER)) + textBlockStyle = RenderStyle::clone(pseudoStyle); + } + if (!textBlockStyle) { textBlockStyle = RenderStyle::create(); textBlockStyle->inheritFrom(startStyle); } @@ -527,6 +532,8 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const { + ASSERT(node()->isHTMLElement()); + RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create(); innerBlockStyle->inheritFrom(startStyle); @@ -541,15 +548,16 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const { + ASSERT(node()->isHTMLElement()); HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); RefPtr<RenderStyle> resultsBlockStyle; if (input->maxResults() < 0) - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_DECORATION); + resultsBlockStyle = getCachedPseudoStyle(SEARCH_DECORATION); else if (!input->maxResults()) - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_DECORATION); + resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_DECORATION); else - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_BUTTON); + resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_BUTTON); if (!resultsBlockStyle) resultsBlockStyle = RenderStyle::create(); @@ -562,9 +570,10 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(co PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const { + ASSERT(node()->isHTMLElement()); RefPtr<RenderStyle> cancelBlockStyle; - if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(RenderStyle::SEARCH_CANCEL_BUTTON)) + if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(SEARCH_CANCEL_BUTTON)) // We may be sharing style with another search field, but we must not share the cancel button style. cancelBlockStyle = RenderStyle::clone(pseudoStyle.get()); else @@ -573,14 +582,30 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(con if (startStyle) cancelBlockStyle->inheritFrom(startStyle); - updateCancelButtonVisibility(cancelBlockStyle.get()); + cancelBlockStyle->setVisibility(visibilityForCancelButton()); return cancelBlockStyle.release(); } -void RenderTextControlSingleLine::updateCancelButtonVisibility(RenderStyle* style) const +void RenderTextControlSingleLine::updateCancelButtonVisibility() const { + if (!m_cancelButton->renderer()) + return; + + const RenderStyle* curStyle = m_cancelButton->renderer()->style(); + EVisibility buttonVisibility = visibilityForCancelButton(); + if (curStyle->visibility() == buttonVisibility) + return; + + RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle); + cancelButtonStyle->setVisibility(buttonVisibility); + m_cancelButton->renderer()->setStyle(cancelButtonStyle); +} + +EVisibility RenderTextControlSingleLine::visibilityForCancelButton() const +{ + ASSERT(node()->isHTMLElement()); HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - style->setVisibility(input->value().isEmpty() ? HIDDEN : VISIBLE); + return input->value().isEmpty() ? HIDDEN : VISIBLE; } const AtomicString& RenderTextControlSingleLine::autosaveName() const @@ -590,6 +615,7 @@ const AtomicString& RenderTextControlSingleLine::autosaveName() const void RenderTextControlSingleLine::startSearchEventTimer() { + ASSERT(node()->isHTMLElement()); unsigned length = text().length(); // If there's no text, fire the event right away. @@ -606,12 +632,14 @@ void RenderTextControlSingleLine::startSearchEventTimer() void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*) { + ASSERT(node()->isHTMLElement()); static_cast<HTMLInputElement*>(node())->onSearch(); } // PopupMenuClient methods void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents) { + ASSERT(node()->isHTMLElement()); ASSERT(static_cast<int>(listIndex) < listSize()); HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); if (static_cast<int>(listIndex) == (listSize() - 1)) { @@ -662,7 +690,7 @@ PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const PopupMenuStyle RenderTextControlSingleLine::menuStyle() const { - return PopupMenuStyle(style()->color(), style()->backgroundColor(), style()->font(), style()->visibility() == VISIBLE); + return PopupMenuStyle(style()->color(), style()->backgroundColor(), style()->font(), style()->visibility() == VISIBLE, style()->textIndent(), style()->direction()); } int RenderTextControlSingleLine::clientInsetLeft() const @@ -682,9 +710,9 @@ int RenderTextControlSingleLine::clientInsetRight() const int RenderTextControlSingleLine::clientPaddingLeft() const { - int padding = clientPaddingLeft(); + int padding = paddingLeft(); - if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) padding += resultsRenderer->width(); return padding; @@ -692,9 +720,9 @@ int RenderTextControlSingleLine::clientPaddingLeft() const int RenderTextControlSingleLine::clientPaddingRight() const { - int padding = clientPaddingRight(); + int padding = paddingRight(); - if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) padding += cancelRenderer->width(); return padding; @@ -732,6 +760,7 @@ bool RenderTextControlSingleLine::itemIsSelected(unsigned) const void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex) { + ASSERT(node()->isHTMLElement()); static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex)); } @@ -745,10 +774,65 @@ HostWindow* RenderTextControlSingleLine::hostWindow() const return document()->view()->hostWindow(); } +void RenderTextControlSingleLine::autoscroll() +{ + RenderLayer* layer = innerTextElement()->renderBox()->layer(); + if (layer) + layer->autoscroll(); +} + +int RenderTextControlSingleLine::scrollWidth() const +{ + if (innerTextElement()) + return innerTextElement()->scrollWidth(); + return RenderBlock::scrollWidth(); +} + +int RenderTextControlSingleLine::scrollHeight() const +{ + if (innerTextElement()) + return innerTextElement()->scrollHeight(); + return RenderBlock::scrollHeight(); +} + +int RenderTextControlSingleLine::scrollLeft() const +{ + if (innerTextElement()) + return innerTextElement()->scrollLeft(); + return RenderBlock::scrollLeft(); +} + +int RenderTextControlSingleLine::scrollTop() const +{ + if (innerTextElement()) + return innerTextElement()->scrollTop(); + return RenderBlock::scrollTop(); +} + +void RenderTextControlSingleLine::setScrollLeft(int newLeft) +{ + if (innerTextElement()) + innerTextElement()->setScrollLeft(newLeft); +} + +void RenderTextControlSingleLine::setScrollTop(int newTop) +{ + if (innerTextElement()) + innerTextElement()->setScrollTop(newTop); +} + +bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) +{ + RenderLayer* layer = innerTextElement()->renderBox()->layer(); + if (layer && layer->scroll(direction, granularity, multiplier)) + return true; + return RenderBlock::scroll(direction, granularity, multiplier); +} + PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) { RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(client, orientation, this); else @@ -756,4 +840,9 @@ PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClie return widget.release(); } +InputElement* RenderTextControlSingleLine::inputElement() const +{ + return toInputElement(static_cast<Element*>(node())); +} + } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h index a0d8d68..23352b4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h @@ -27,6 +27,7 @@ namespace WebCore { +class InputElement; class SearchFieldCancelButtonElement; class SearchFieldResultsButtonElement; class SearchPopupMenu; @@ -58,9 +59,20 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); void forwardEvent(Event*); -private: - virtual void capsLockStateMayHaveChanged(); + void capsLockStateMayHaveChanged(); + + virtual void autoscroll(); + + // Subclassed to forward to our inner div. + virtual int scrollLeft() const; + virtual int scrollTop() const; + virtual int scrollWidth() const; + virtual int scrollHeight() const; + virtual void setScrollLeft(int); + virtual void setScrollTop(int); + virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); +private: int textBlockWidth() const; virtual int preferredContentWidth(float charWidth) const; virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); @@ -68,14 +80,15 @@ private: void createSubtreeIfNeeded(); virtual void updateFromElement(); virtual void cacheSelection(int start, int end); - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle) const; PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle) const; PassRefPtr<RenderStyle> createCancelButtonStyle(const RenderStyle* startStyle) const; - void updateCancelButtonVisibility(RenderStyle*) const; + void updateCancelButtonVisibility() const; + EVisibility visibilityForCancelButton() const; const AtomicString& autosaveName() const; void startSearchEventTimer(); @@ -104,6 +117,8 @@ private: virtual HostWindow* hostWindow() const; virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); + InputElement* inputElement() const; + private: bool m_placeholderVisible; bool m_searchPopupIsVisible; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp index c8beba0..7da9e5a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp @@ -46,7 +46,7 @@ RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str) PassRefPtr<StringImpl> RenderTextFragment::originalText() const { - Node* e = element(); + Node* e = node(); RefPtr<StringImpl> result = (e ? static_cast<Text*>(e)->string() : contentString()); if (result && (start() > 0 || start() < result->length())) result = result->substring(start(), end()); @@ -75,7 +75,7 @@ void RenderTextFragment::setTextInternal(PassRefPtr<StringImpl> text) UChar RenderTextFragment::previousCharacter() { if (start()) { - Node* e = element(); + Node* e = node(); StringImpl* original = (e ? static_cast<Text*>(e)->string() : contentString()); if (original) return (*original)[start() - 1]; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp index aa18407..517d911 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp @@ -62,7 +62,7 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE) style->setDisplay(BLOCK); - if (UAHasAppearance && theme()->isControlStyled(style, border, background, backgroundColor)) { + if (UAHasAppearance && isControlStyled(style, border, background, backgroundColor)) { if (part == MenulistPart) { style->setAppearance(MenulistButtonPart); part = MenulistButtonPart; @@ -268,6 +268,12 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf if (o->parent()->isSlider()) return paintMediaSliderThumb(o, paintInfo, r); break; + case MediaTimeRemainingPart: + return paintMediaTimeRemaining(o, paintInfo, r); + case MediaCurrentTimePart: + return paintMediaCurrentTime(o, paintInfo, r); + case MediaTimelineContainerPart: + return paintMediaTimelineContainer(o, paintInfo, r); case MenulistButtonPart: case TextFieldPart: case TextAreaPart: @@ -365,24 +371,68 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf #if ENABLE(VIDEO) bool RenderTheme::hitTestMediaControlPart(RenderObject* o, const IntPoint& absPoint) { - FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms + if (!o->isBox()) + return false; - return o->borderBox().contains(roundedIntPoint(localPoint)); + FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms + return toRenderBox(o)->borderBoxRect().contains(roundedIntPoint(localPoint)); } #endif Color RenderTheme::activeSelectionBackgroundColor() const { - if (!m_activeSelectionColor.isValid()) - m_activeSelectionColor = platformActiveSelectionBackgroundColor().blendWithWhite(); - return m_activeSelectionColor; + if (!m_activeSelectionBackgroundColor.isValid()) + m_activeSelectionBackgroundColor = platformActiveSelectionBackgroundColor().blendWithWhite(); + return m_activeSelectionBackgroundColor; } Color RenderTheme::inactiveSelectionBackgroundColor() const { - if (!m_inactiveSelectionColor.isValid()) - m_inactiveSelectionColor = platformInactiveSelectionBackgroundColor().blendWithWhite(); - return m_inactiveSelectionColor; + if (!m_inactiveSelectionBackgroundColor.isValid()) + m_inactiveSelectionBackgroundColor = platformInactiveSelectionBackgroundColor().blendWithWhite(); + return m_inactiveSelectionBackgroundColor; +} + +Color RenderTheme::activeSelectionForegroundColor() const +{ + if (!m_activeSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) + m_activeSelectionForegroundColor = platformActiveSelectionForegroundColor(); + return m_activeSelectionForegroundColor; +} + +Color RenderTheme::inactiveSelectionForegroundColor() const +{ + if (!m_inactiveSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) + m_inactiveSelectionForegroundColor = platformInactiveSelectionForegroundColor(); + return m_inactiveSelectionForegroundColor; +} + +Color RenderTheme::activeListBoxSelectionBackgroundColor() const +{ + if (!m_activeListBoxSelectionBackgroundColor.isValid()) + m_activeListBoxSelectionBackgroundColor = platformActiveListBoxSelectionBackgroundColor(); + return m_activeListBoxSelectionBackgroundColor; +} + +Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const +{ + if (!m_inactiveListBoxSelectionBackgroundColor.isValid()) + m_inactiveListBoxSelectionBackgroundColor = platformInactiveListBoxSelectionBackgroundColor(); + return m_inactiveListBoxSelectionBackgroundColor; +} + +Color RenderTheme::activeListBoxSelectionForegroundColor() const +{ + if (!m_activeListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) + m_activeListBoxSelectionForegroundColor = platformActiveListBoxSelectionForegroundColor(); + return m_activeListBoxSelectionForegroundColor; +} + +Color RenderTheme::inactiveListBoxSelectionForegroundColor() const +{ + if (!m_inactiveListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) + m_inactiveListBoxSelectionForegroundColor = platformInactiveListBoxSelectionForegroundColor(); + return m_inactiveListBoxSelectionForegroundColor; } Color RenderTheme::platformActiveSelectionBackgroundColor() const @@ -391,50 +441,56 @@ Color RenderTheme::platformActiveSelectionBackgroundColor() const return Color(0, 0, 255); } -Color RenderTheme::platformInactiveSelectionBackgroundColor() const +Color RenderTheme::platformActiveSelectionForegroundColor() const { - // Use a grey color by default if the platform theme doesn't define anything. - return Color(128, 128, 128); + // Use a white color by default if the platform theme doesn't define anything. + return Color::white; } -Color RenderTheme::platformActiveSelectionForegroundColor() const +Color RenderTheme::platformInactiveSelectionBackgroundColor() const { - return Color(); + // Use a grey color by default if the platform theme doesn't define anything. + // This color matches Firefox's inactive color. + return Color(176, 176, 176); } Color RenderTheme::platformInactiveSelectionForegroundColor() const { - return Color(); + // Use a black color by default. + return Color::black; } -Color RenderTheme::activeListBoxSelectionBackgroundColor() const +Color RenderTheme::platformActiveListBoxSelectionBackgroundColor() const { - return activeSelectionBackgroundColor(); + return platformActiveSelectionBackgroundColor(); } -Color RenderTheme::activeListBoxSelectionForegroundColor() const +Color RenderTheme::platformActiveListBoxSelectionForegroundColor() const { - // Use a white color by default if the platform theme doesn't define anything. - return Color(255, 255, 255); + return platformActiveSelectionForegroundColor(); } -Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const +Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor() const { - return inactiveSelectionBackgroundColor(); + return platformInactiveSelectionBackgroundColor(); } -Color RenderTheme::inactiveListBoxSelectionForegroundColor() const +Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const { - // Use a black color by default if the platform theme doesn't define anything. - return Color(0, 0, 0); + return platformInactiveSelectionForegroundColor(); } int RenderTheme::baselinePosition(const RenderObject* o) const { + if (!o->isBox()) + return 0; + + const RenderBox* box = toRenderBox(o); + #if USE(NEW_THEME) - return o->height() + o->marginTop() + m_theme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom(); + return box->height() + box->marginTop() + m_theme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom(); #else - return o->height() + o->marginTop(); + return box->height() + box->marginTop(); #endif } @@ -521,7 +577,7 @@ ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const bool RenderTheme::isActive(const RenderObject* o) const { - Node* node = o->element(); + Node* node = o->node(); if (!node) return false; @@ -538,28 +594,39 @@ bool RenderTheme::isActive(const RenderObject* o) const bool RenderTheme::isChecked(const RenderObject* o) const { - if (!o->element()) + if (!o->node() || !o->node()->isElementNode()) + return false; + + InputElement* inputElement = toInputElement(static_cast<Element*>(o->node())); + if (!inputElement) return false; - return o->element()->isChecked(); + + return inputElement->isChecked(); } bool RenderTheme::isIndeterminate(const RenderObject* o) const { - if (!o->element()) + if (!o->node() || !o->node()->isElementNode()) + return false; + + InputElement* inputElement = toInputElement(static_cast<Element*>(o->node())); + if (!inputElement) return false; - return o->element()->isIndeterminate(); + + return inputElement->isIndeterminate(); } bool RenderTheme::isEnabled(const RenderObject* o) const { - if (!o->element()) + Node* node = o->node(); + if (!node || !node->isElementNode()) return true; - return o->element()->isEnabled(); + return static_cast<Element*>(node)->isEnabledFormControl(); } bool RenderTheme::isFocused(const RenderObject* o) const { - Node* node = o->element(); + Node* node = o->node(); if (!node) return false; Document* document = node->document(); @@ -569,23 +636,24 @@ bool RenderTheme::isFocused(const RenderObject* o) const bool RenderTheme::isPressed(const RenderObject* o) const { - if (!o->element()) + if (!o->node()) return false; - return o->element()->active(); + return o->node()->active(); } bool RenderTheme::isReadOnlyControl(const RenderObject* o) const { - if (!o->element()) + Node* node = o->node(); + if (!node || !node->isElementNode()) return false; - return o->element()->isReadOnlyControl(); + return static_cast<Element*>(node)->isReadOnlyFormControl(); } bool RenderTheme::isHovered(const RenderObject* o) const { - if (!o->element()) + if (!o->node()) return false; - return o->element()->hovered(); + return o->node()->hovered(); } bool RenderTheme::isDefault(const RenderObject* o) const @@ -661,10 +729,6 @@ void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Ele { } -void RenderTheme::adjustButtonInnerStyle(RenderStyle*) const -{ -} - void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } @@ -699,8 +763,15 @@ void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderS void RenderTheme::platformColorsDidChange() { - m_activeSelectionColor = Color(); - m_inactiveSelectionColor = Color(); + m_activeSelectionForegroundColor = Color(); + m_inactiveSelectionForegroundColor = Color(); + m_activeSelectionBackgroundColor = Color(); + m_inactiveSelectionBackgroundColor = Color(); + + m_activeListBoxSelectionForegroundColor = Color(); + m_inactiveListBoxSelectionForegroundColor = Color(); + m_activeListBoxSelectionBackgroundColor = Color(); + m_inactiveListBoxSelectionForegroundColor = Color(); } Color RenderTheme::systemColor(int cssValueId) const @@ -768,9 +839,19 @@ Color RenderTheme::systemColor(int cssValueId) const return Color(); } -Color RenderTheme::platformTextSearchHighlightColor() const +Color RenderTheme::platformActiveTextSearchHighlightColor() const +{ + return Color(255, 150, 50); // Orange. +} + +Color RenderTheme::platformInactiveTextSearchHighlightColor() const +{ + return Color(255, 255, 0); // Yellow. +} + +Color RenderTheme::focusRingColor() const { - return Color(255, 255, 0); + return Color(0, 0, 0); // Black. } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h index f948936..a1519ce 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h @@ -23,12 +23,16 @@ #ifndef RenderTheme_h #define RenderTheme_h -#include "RenderObject.h" #if USE(NEW_THEME) #include "Theme.h" #else #include "ThemeTypes.h" #endif +#include "RenderObject.h" +#include "RenderTheme.h" +#include "ScrollTypes.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { @@ -37,11 +41,24 @@ class PopupMenu; class RenderMenuList; class CSSStyleSheet; -class RenderTheme { -public: +class RenderTheme : public RefCounted<RenderTheme> { +protected: RenderTheme(); + +public: virtual ~RenderTheme() { } + // This function is to be implemented in your platform-specific theme implementation to hand back the + // appropriate platform theme. When the theme is needed in non-page dependent code, a default theme is + // used as fallback, which is returned for a nulled page, so the platform code needs to account for this. + static PassRefPtr<RenderTheme> themeForPage(Page* page); + + // When the theme is needed in non-page dependent code, the defaultTheme() is used as fallback. + static inline PassRefPtr<RenderTheme> defaultTheme() + { + return themeForPage(0); + }; + // This method is called whenever style has been computed for an element and the appearance // property has been set to a value other than "none". The theme should map in all of the appropriate // metrics and defaults given the contents of the style. This includes sophisticated operations like @@ -104,23 +121,23 @@ public: // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle*) const { return false; } - // The selection color. + // Text selection colors. Color activeSelectionBackgroundColor() const; Color inactiveSelectionBackgroundColor() const; + Color activeSelectionForegroundColor() const; + Color inactiveSelectionForegroundColor() const; - virtual Color platformTextSearchHighlightColor() const; + // List box selection colors + Color activeListBoxSelectionBackgroundColor() const; + Color activeListBoxSelectionForegroundColor() const; + Color inactiveListBoxSelectionBackgroundColor() const; + Color inactiveListBoxSelectionForegroundColor() const; - // The platform selection color. - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveSelectionForegroundColor() const; - virtual Color platformInactiveSelectionForegroundColor() const; + // Highlighting colors for TextMatches. + virtual Color platformActiveTextSearchHighlightColor() const; + virtual Color platformInactiveTextSearchHighlightColor() const; - // List Box selection color - virtual Color activeListBoxSelectionBackgroundColor() const; - virtual Color activeListBoxSelectionForegroundColor() const; - virtual Color inactiveListBoxSelectionBackgroundColor() const; - virtual Color inactiveListBoxSelectionForegroundColor() const; + virtual Color focusRingColor() const; virtual void platformColorsDidChange(); @@ -132,22 +149,44 @@ public: virtual int minimumMenuListSize(RenderStyle*) const { return 0; } - virtual void adjustButtonInnerStyle(RenderStyle*) const; virtual void adjustSliderThumbSize(RenderObject*) const; virtual int popupInternalPaddingLeft(RenderStyle*) const { return 0; } virtual int popupInternalPaddingRight(RenderStyle*) const { return 0; } virtual int popupInternalPaddingTop(RenderStyle*) const { return 0; } virtual int popupInternalPaddingBottom(RenderStyle*) const { return 0; } - + virtual bool popupOptionSupportsTextIndent() const { return false; } + + virtual int buttonInternalPaddingLeft() const { return 0; } + virtual int buttonInternalPaddingRight() const { return 0; } + virtual int buttonInternalPaddingTop() const { return 0; } + virtual int buttonInternalPaddingBottom() const { return 0; } + + virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return RegularScrollbar; } + // Method for painting the caps lock indicator virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return 0; }; #if ENABLE(VIDEO) + // Media controls virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); #endif protected: + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + virtual Color platformInactiveListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionForegroundColor() const; + virtual Color platformInactiveListBoxSelectionForegroundColor() const; + + virtual bool supportsSelectionForegroundColors() const { return true; } + virtual bool supportsListBoxSelectionForegroundColors() const { return true; } + #if !USE(NEW_THEME) // Methods for each appearance value. virtual void adjustCheckboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -203,6 +242,9 @@ protected: virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaTimelineContainer(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; } public: // Methods for state querying @@ -218,17 +260,21 @@ public: bool isDefault(const RenderObject*) const; private: - mutable Color m_activeSelectionColor; - mutable Color m_inactiveSelectionColor; + mutable Color m_activeSelectionBackgroundColor; + mutable Color m_inactiveSelectionBackgroundColor; + mutable Color m_activeSelectionForegroundColor; + mutable Color m_inactiveSelectionForegroundColor; + + mutable Color m_activeListBoxSelectionBackgroundColor; + mutable Color m_inactiveListBoxSelectionBackgroundColor; + mutable Color m_activeListBoxSelectionForegroundColor; + mutable Color m_inactiveListBoxSelectionForegroundColor; + #if USE(NEW_THEME) Theme* m_theme; // The platform-specific theme. #endif }; -// Function to obtain the theme. This is implemented in your platform-specific theme implementation to hand -// back the appropriate platform theme. -RenderTheme* theme(); - } // namespace WebCore #endif // RenderTheme_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp new file mode 100644 index 0000000..c4020d3 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008, 2009 Google Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 "RenderThemeChromiumLinux.h" + +#include "Color.h" +#include "CSSValueKeywords.h" +#include "RenderObject.h" +#include "UserAgentStyleSheets.h" + +namespace WebCore { + +PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create() +{ + return adoptRef(new RenderThemeChromiumLinux()); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* rt = RenderThemeChromiumLinux::create().releaseRef(); + return rt; +} + +RenderThemeChromiumLinux::RenderThemeChromiumLinux() +{ +} + +RenderThemeChromiumLinux::~RenderThemeChromiumLinux() +{ +} + +Color RenderThemeChromiumLinux::systemColor(int cssValueId) const +{ + static const Color linuxButtonGrayColor(0xffdddddd); + + if (cssValueId == CSSValueButtonface) + return linuxButtonGrayColor; + return RenderTheme::systemColor(cssValueId); +} + +String RenderThemeChromiumLinux::extraDefaultStyleSheet() +{ + return RenderThemeChromiumSkia::extraDefaultStyleSheet() + + String(themeChromiumLinuxUserAgentStyleSheet, sizeof(themeChromiumLinuxUserAgentStyleSheet)); +} + +bool RenderThemeChromiumLinux::controlSupportsTints(const RenderObject* o) const +{ + return isEnabled(o); +} + +Color RenderThemeChromiumLinux::activeListBoxSelectionBackgroundColor() const +{ + return Color(0x28, 0x28, 0x28); +} + +Color RenderThemeChromiumLinux::activeListBoxSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeChromiumLinux::inactiveListBoxSelectionBackgroundColor() const +{ + return Color(0xc8, 0xc8, 0xc8); +} + +Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const +{ + return Color(0x32, 0x32, 0x32); +} + +bool RenderThemeChromiumLinux::supportsControlTints() const +{ + return true; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h new file mode 100644 index 0000000..e75ddd5 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumLinux.h @@ -0,0 +1,62 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008, 2009 Google, Inc. + * All rights reserved. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 RenderThemeChromiumLinux_h +#define RenderThemeChromiumLinux_h + +#include "RenderThemeChromiumSkia.h" + +namespace WebCore { + + class RenderThemeChromiumLinux : public RenderThemeChromiumSkia { + public: + static PassRefPtr<RenderTheme> create(); + virtual String extraDefaultStyleSheet(); + + virtual Color systemColor(int cssValidId) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // List Box selection color + virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionForegroundColor() const; + virtual Color inactiveListBoxSelectionBackgroundColor() const; + virtual Color inactiveListBoxSelectionForegroundColor() const; + + private: + RenderThemeChromiumLinux(); + virtual ~RenderThemeChromiumLinux(); + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const; + }; + +} // namespace WebCore + +#endif // RenderThemeChromiumLinux_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h new file mode 100644 index 0000000..5497d52 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.h @@ -0,0 +1,220 @@ +/* + * This file is part of the theme implementation for form controls in WebCore. + * + * Copyright (C) 2005 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 RenderThemeChromiumMac_h +#define RenderThemeChromiumMac_h + +#import "RenderTheme.h" +#import <AppKit/AppKit.h> +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +#ifdef __OBJC__ +@class WebCoreRenderThemeNotificationObserver; +#else +class WebCoreRenderThemeNotificationObserver; +#endif + +namespace WebCore { + + class RenderStyle; + + class RenderThemeChromiumMac : public RenderTheme { + public: + static PassRefPtr<RenderTheme> create(); + + // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline + // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of + // controls that need to do this. + virtual int baselinePosition(const RenderObject*) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const { return true; } + + virtual void adjustRepaintRect(const RenderObject*, IntRect&); + + virtual bool isControlStyled(const RenderStyle*, const BorderData&, + const FillLayer&, const Color& backgroundColor) const; + + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionBackgroundColor() const; + + virtual Color focusRingColor() const; + + virtual void platformColorsDidChange(); + + // System fonts. + virtual void systemFont(int cssValueId, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual void adjustSliderThumbSize(RenderObject*) const; + + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; + + virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } + + virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual Color systemColor(int cssValueId) const; + + protected: + virtual bool supportsSelectionForegroundColors() const { return false; } + + // Methods for each appearance value. + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const; + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setButtonSize(RenderStyle*) const; + + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + 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&); + virtual bool paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + 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&); + + private: + RenderThemeChromiumMac(); + virtual ~RenderThemeChromiumMac(); + + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; + + // Get the control size based off the font. Used by some of the controls (like buttons). + NSControlSize controlSizeForFont(RenderStyle*) const; + NSControlSize controlSizeForSystemFont(RenderStyle*) const; + void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); + void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; + void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const; + + void updateCheckedState(NSCell*, const RenderObject*); + void updateEnabledState(NSCell*, const RenderObject*); + void updateFocusedState(NSCell*, const RenderObject*); + void updatePressedState(NSCell*, const RenderObject*); + + // Helpers for adjusting appearance and for painting + const IntSize* checkboxSizes() const; + const int* checkboxMargins() const; + void setCheckboxCellState(const RenderObject*, const IntRect&); + + const IntSize* radioSizes() const; + const int* radioMargins() const; + void setRadioCellState(const RenderObject*, const IntRect&); + + void setButtonPaddingFromControlSize(RenderStyle*, NSControlSize) const; + const IntSize* buttonSizes() const; + const int* buttonMargins() const; + void setButtonCellState(const RenderObject*, const IntRect&); + + void setPopupButtonCellState(const RenderObject*, const IntRect&); + const IntSize* popupButtonSizes() const; + const int* popupButtonMargins() const; + const int* popupButtonPadding(NSControlSize) const; + void paintMenuListButtonGradients(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + const IntSize* menuListSizes() const; + + const IntSize* searchFieldSizes() const; + const IntSize* cancelButtonSizes() const; + const IntSize* resultsButtonSizes() const; + void setSearchCellState(RenderObject*, const IntRect&); + void setSearchFieldSize(RenderStyle*) const; + + NSButtonCell* checkbox() const; + NSButtonCell* radio() const; + NSButtonCell* button() const; + NSPopUpButtonCell* popupButton() const; + NSSearchFieldCell* search() const; + NSMenu* searchMenuTemplate() const; + NSSliderCell* sliderThumbHorizontal() const; + NSSliderCell* sliderThumbVertical() const; + + private: + mutable RetainPtr<NSButtonCell> m_checkbox; + mutable RetainPtr<NSButtonCell> m_radio; + mutable RetainPtr<NSButtonCell> m_button; + mutable RetainPtr<NSPopUpButtonCell> m_popupButton; + mutable RetainPtr<NSSearchFieldCell> m_search; + mutable RetainPtr<NSMenu> m_searchMenuTemplate; + mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal; + mutable RetainPtr<NSSliderCell> m_sliderThumbVertical; + + bool m_isSliderThumbHorizontalPressed; + bool m_isSliderThumbVerticalPressed; + + mutable HashMap<int, RGBA32> m_systemColorCache; + + RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; + }; + +} // namespace WebCore + +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm new file mode 100644 index 0000000..bd90831 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumMac.mm @@ -0,0 +1,2016 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +// FIXME: we still need to figure out if passing a null view to the cell +// drawing routines will work. I expect not, and if that's the case we'll have +// to figure out something else. For now, at least leave the lines commented +// in, but the procurement of the view if 0'd. + +#import "config.h" +#import "RenderThemeChromiumMac.h" + +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#import <math.h> + +#import "BitmapImage.h" +#import "ChromiumBridge.h" +#import "ColorMac.h" +#import "CSSStyleSelector.h" +#import "CSSValueKeywords.h" +#import "Element.h" +#import "FoundationExtras.h" +#import "FrameView.h" +#import "GraphicsContext.h" +#import "HTMLInputElement.h" +#import "HTMLMediaElement.h" +#import "HTMLNames.h" +#import "Image.h" +#import "LocalCurrentGraphicsContext.h" +#import "MediaControlElements.h" +#import "RenderSlider.h" +#import "RenderView.h" +#import "SharedBuffer.h" +#import "WebCoreSystemInterface.h" +#import <wtf/RetainPtr.h> + +#ifdef BUILDING_ON_TIGER +typedef int NSInteger; +typedef unsigned NSUInteger; +#endif + +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. + +@interface WebCoreRenderThemeNotificationObserver : NSObject +{ + WebCore::RenderTheme *_theme; +} + +- (id)initWithTheme:(WebCore::RenderTheme *)theme; +- (void)systemColorsDidChange:(NSNotification *)notification; + +@end + +@implementation WebCoreRenderThemeNotificationObserver + +- (id)initWithTheme:(WebCore::RenderTheme *)theme +{ + [super init]; + _theme = theme; + + return self; +} + +- (void)systemColorsDidChange:(NSNotification *)notification +{ + ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]); + _theme->platformColorsDidChange(); +} + +@end + +namespace WebCore { + +using namespace HTMLNames; + +enum { + TopMargin, + RightMargin, + BottomMargin, + LeftMargin +}; + +enum { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +// In our Mac port, we don't define PLATFORM(MAC) and thus don't pick up the +// |operator NSRect()| on WebCore::IntRect and FloatRect. This substitues for +// that missing conversion operator. +NSRect IntRectToNSRect(const IntRect & rect) +{ + return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +NSRect FloatRectToNSRect(const FloatRect & rect) +{ + return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +IntRect NSRectToIntRect(const NSRect & rect) +{ + return IntRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); +} + +PassRefPtr<RenderTheme> RenderThemeChromiumMac::create() +{ + return adoptRef(new RenderThemeChromiumMac); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* rt = RenderThemeChromiumMac::create().releaseRef(); + return rt; +} + +RenderThemeChromiumMac::RenderThemeChromiumMac() + : m_isSliderThumbHorizontalPressed(false) + , m_isSliderThumbVerticalPressed(false) + , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) +{ + [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() + selector:@selector(systemColorsDidChange:) + name:NSSystemColorsDidChangeNotification + object:nil]; +} + +RenderThemeChromiumMac::~RenderThemeChromiumMac() +{ + [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; +} + +Color RenderThemeChromiumMac::platformActiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeChromiumMac::activeListBoxSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeChromiumMac::focusRingColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return oldAquaFocusRingColor(); + + return systemColor(CSSValueWebkitFocusRingColor); +} + +static FontWeight toFontWeight(NSInteger appKitFontWeight) +{ + ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); + if (appKitFontWeight > 14) + appKitFontWeight = 14; + else if (appKitFontWeight < 1) + appKitFontWeight = 1; + + static FontWeight fontWeights[] = { + FontWeight100, + FontWeight100, + FontWeight200, + FontWeight300, + FontWeight400, + FontWeight500, + FontWeight600, + FontWeight600, + FontWeight700, + FontWeight800, + FontWeight800, + FontWeight900, + FontWeight900, + FontWeight900 + }; + return fontWeights[appKitFontWeight - 1]; +} + +void RenderThemeChromiumMac::systemFont(int cssValueId, FontDescription& fontDescription) const +{ + static FontDescription systemFont; + static FontDescription smallSystemFont; + static FontDescription menuFont; + static FontDescription labelFont; + static FontDescription miniControlFont; + static FontDescription smallControlFont; + static FontDescription controlFont; + + FontDescription* cachedDesc; + NSFont* font = nil; + switch (cssValueId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) + font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) + font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; + break; + case CSSValueWebkitMiniControl: + cachedDesc = &miniControlFont; + if (!miniControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; + break; + case CSSValueWebkitSmallControl: + cachedDesc = &smallControlFont; + if (!smallControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; + break; + case CSSValueWebkitControl: + cachedDesc = &controlFont; + if (!controlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + break; + default: + cachedDesc = &systemFont; + if (!systemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; + } + + if (font) { + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->firstFamily().setFamily([font familyName]); + cachedDesc->setSpecifiedSize([font pointSize]); + cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); + cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); + } + fontDescription = *cachedDesc; +} + +static RGBA32 convertNSColorToColor(NSColor *color) +{ + NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + if (colorInColorSpace) { + static const double scaleFactor = nextafter(256.0, 0.0); + return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); + } + + // 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 + // the colors in the pattern instead. + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; + NSEraseRect(NSMakeRect(0, 0, 1, 1)); + [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; + [NSGraphicsContext restoreGraphicsState]; + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +static RGBA32 menuBackgroundColor() +{ + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); + CGRect rect = CGRectMake(0, 0, 1, 1); + HIThemeMenuDrawInfo drawInfo; + drawInfo.version = 0; + drawInfo.menuType = kThemeMenuTypePopUp; + HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +void RenderThemeChromiumMac::platformColorsDidChange() +{ + m_systemColorCache.clear(); + RenderTheme::platformColorsDidChange(); +} + +Color RenderThemeChromiumMac::systemColor(int cssValueId) const +{ + if (m_systemColorCache.contains(cssValueId)) + return m_systemColorCache.get(cssValueId); + + Color color; + switch (cssValueId) { + case CSSValueActiveborder: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; + case CSSValueActivecaption: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + case CSSValueAppworkspace: + color = convertNSColorToColor([NSColor headerColor]); + break; + case CSSValueBackground: + // Use theme independent default + break; + case CSSValueButtonface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueButtonhighlight: + color = convertNSColorToColor([NSColor controlHighlightColor]); + break; + case CSSValueButtonshadow: + color = convertNSColorToColor([NSColor controlShadowColor]); + break; + case CSSValueButtontext: + color = convertNSColorToColor([NSColor controlTextColor]); + break; + case CSSValueCaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueGraytext: + color = convertNSColorToColor([NSColor disabledControlTextColor]); + break; + case CSSValueHighlight: + color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); + break; + case CSSValueHighlighttext: + color = convertNSColorToColor([NSColor selectedTextColor]); + break; + case CSSValueInactiveborder: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaption: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueInfobackground: + // There is no corresponding NSColor for this so we use a hard coded value. + color = 0xFFFBFCC5; + break; + case CSSValueInfotext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueMenu: + color = menuBackgroundColor(); + break; + case CSSValueMenutext: + color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); + break; + case CSSValueScrollbar: + color = convertNSColorToColor([NSColor scrollBarColor]); + break; + case CSSValueText: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueThreeddarkshadow: + color = convertNSColorToColor([NSColor controlDarkShadowColor]); + break; + case CSSValueThreedshadow: + color = convertNSColorToColor([NSColor shadowColor]); + break; + case CSSValueThreedface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueThreedhighlight: + color = convertNSColorToColor([NSColor highlightColor]); + break; + case CSSValueThreedlightshadow: + color = convertNSColorToColor([NSColor controlLightHighlightColor]); + break; + case CSSValueWebkitFocusRingColor: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; + case CSSValueWindow: + color = convertNSColorToColor([NSColor windowBackgroundColor]); + break; + case CSSValueWindowframe: + color = convertNSColorToColor([NSColor windowFrameColor]); + break; + case CSSValueWindowtext: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + } + + if (!color.isValid()) + color = RenderTheme::systemColor(cssValueId); + + if (color.isValid()) + m_systemColorCache.set(cssValueId, color.rgb()); + + return color; +} + +bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const BorderData& border, + const FillLayer& background, const Color& backgroundColor) const +{ + 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 + // is in effect we treat it like the control is styled. + if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) + return true; + + return RenderTheme::isControlStyled(style, border, background, backgroundColor); +} + +// FIXME: Use the code from the old upstream version, before it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r) +{ + float zoomLevel = o->style()->effectiveZoom(); + + switch (o->style()->appearance()) { + case CheckboxPart: { + // Since we query the prototype cell, we need to update its state to match. + setCheckboxCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + IntSize size = checkboxSizes()[[checkbox() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(size.width() * zoomLevel); + r = inflateRect(r, size, checkboxMargins(), zoomLevel); + break; + } + case RadioPart: { + // Since we query the prototype cell, we need to update its state to match. + setRadioCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + IntSize size = radioSizes()[[radio() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(size.width() * zoomLevel); + r = inflateRect(r, size, radioMargins(), zoomLevel); + break; + } + case PushButtonPart: + case DefaultButtonPart: + case ButtonPart: { + // Since we query the prototype cell, we need to update its state to match. + setButtonCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + if ([button() bezelStyle] == NSRoundedBezelStyle) { + IntSize size = buttonSizes()[[button() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + r = inflateRect(r, size, buttonMargins(), zoomLevel); + } + break; + } + case MenulistPart: { + setPopupButtonCellState(o, r); + IntSize size = popupButtonSizes()[[popupButton() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + r = inflateRect(r, size, popupButtonMargins(), zoomLevel); + break; + } + default: + break; + } +} + +IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const +{ + // Only do the inflation if the available width/height are too small. Otherwise try to + // fit the glow/check space into the available box's width/height. + int widthDelta = r.width() - (size.width() + margins[LeftMargin] * zoomLevel + margins[RightMargin] * zoomLevel); + int heightDelta = r.height() - (size.height() + margins[TopMargin] * zoomLevel + margins[BottomMargin] * zoomLevel); + IntRect result(r); + if (widthDelta < 0) { + result.setX(result.x() - margins[LeftMargin] * zoomLevel); + result.setWidth(result.width() - widthDelta); + } + if (heightDelta < 0) { + result.setY(result.y() - margins[TopMargin] * zoomLevel); + result.setHeight(result.height() - heightDelta); + } + return result; +} + +void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o) +{ + bool oldIndeterminate = [cell state] == NSMixedState; + bool indeterminate = isIndeterminate(o); + bool checked = isChecked(o); + + if (oldIndeterminate != indeterminate) { + [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; + return; + } + + bool oldChecked = [cell state] == NSOnState; + if (checked != oldChecked) + [cell setState:checked ? NSOnState : NSOffState]; +} + +void RenderThemeChromiumMac::updateEnabledState(NSCell* cell, const RenderObject* o) +{ + bool oldEnabled = [cell isEnabled]; + bool enabled = isEnabled(o); + if (enabled != oldEnabled) + [cell setEnabled:enabled]; +} + +void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject* o) +{ + bool oldFocused = [cell showsFirstResponder]; + bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); + if (focused != oldFocused) + [cell setShowsFirstResponder:focused]; +} + +void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o) +{ + bool oldPressed = [cell isHighlighted]; + bool pressed = (o->node() && o->node()->active()); + if (pressed != oldPressed) + [cell setHighlighted:pressed]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +int RenderThemeChromiumMac::baselinePosition(const RenderObject* o) const +{ + if (!o->isBox()) + return 0; + + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) { + const RenderBox* box = toRenderBox(o); + return box->marginTop() + box->height() - 2 * o->style()->effectiveZoom(); // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + } + return RenderTheme::baselinePosition(o); +} + +bool RenderThemeChromiumMac::controlSupportsTints(const RenderObject* o) const +{ + // An alternate way to implement this would be to get the appropriate cell object + // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of + // that would be that we would match AppKit behavior more closely, but a disadvantage + // would be that we would rely on an AppKit SPI method. + + if (!isEnabled(o)) + return false; + + // Checkboxes only have tint when checked. + if (o->style()->appearance() == CheckboxPart) + return isChecked(o); + + // For now assume other controls have tint if enabled. + return true; +} + +NSControlSize RenderThemeChromiumMac::controlSizeForFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= 16) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} + +void RenderThemeChromiumMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) +{ + NSControlSize size; + if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) + size = NSRegularControlSize; + else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) + size = NSSmallControlSize; + else + size = NSMiniControlSize; + if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. + [cell setControlSize:size]; +} + +IntSize RenderThemeChromiumMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForFont(style)]; +} + +IntSize RenderThemeChromiumMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForSystemFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForSystemFont(style)]; +} + +void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const +{ + // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. + IntSize size = sizeForFont(style, sizes); + if (style->width().isIntrinsicOrAuto() && size.width() > 0) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto() && size.height() > 0) + style->setHeight(Length(size.height(), Fixed)); +} + +void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const +{ + FontDescription fontDescription; + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::SerifFamily); + + NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; + fontDescription.firstFamily().setFamily([font familyName]); + fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); + fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); + + // Reset line height + style->setLineHeight(RenderStyle::initialLineHeight()); + + if (style->setFontDescription(fontDescription)) + style->font().update(0); +} + +NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) + return NSRegularControlSize; + if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) + return NSSmallControlSize; + return NSMiniControlSize; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Determine the width and height needed for the control and prepare the cell for painting. + setCheckboxCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + NSButtonCell* checkbox = this->checkbox(); + IntSize size = checkboxSizes()[[checkbox controlSize]]; + size.setWidth(size.width() * zoomLevel); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = inflateRect(r, size, checkboxMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [checkbox drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; + [checkbox setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::checkboxSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::checkboxMargins() const +{ + static const int margins[3][4] = + { + { 3, 4, 4, 2 }, + { 4, 3, 3, 3 }, + { 4, 3, 3, 3 }, + }; + return margins[[checkbox() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setCheckboxCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* checkbox = this->checkbox(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(checkbox, checkboxSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(checkbox, o); + updateEnabledState(checkbox, o); + updatePressedState(checkbox, o); + updateFocusedState(checkbox, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setCheckboxSize(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, checkboxSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Determine the width and height needed for the control and prepare the cell for painting. + setRadioCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + NSButtonCell* radio = this->radio(); + IntSize size = radioSizes()[[radio controlSize]]; + size.setWidth(size.width() * zoomLevel); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = inflateRect(r, size, radioMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [radio drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; + [radio setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::radioSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::radioMargins() const +{ + static const int margins[3][4] = + { + { 2, 2, 4, 2 }, + { 3, 2, 3, 2 }, + { 1, 0, 2, 0 }, + }; + return margins[[radio() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setRadioCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* radio = this->radio(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(radio, radioSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(radio, o); + updateEnabledState(radio, o); + updatePressedState(radio, o); + updateFocusedState(radio, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setRadioSize(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, radioSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const +{ + // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large + // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is + // by definition constrained, since we select mini only for small cramped environments. + // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent + // padding. + const int padding = 8 * style->effectiveZoom(); + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(0, Fixed)); + style->setPaddingBottom(Length(0, Fixed)); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // There are three appearance constants for buttons. + // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow + // custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't + // scale vertically. + // (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically. + // (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will + // also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination + // solely on the rectangle of the control. + + // Determine our control size based off our font. + NSControlSize controlSize = controlSizeForFont(style); + + if (style->appearance() == PushButtonPart) { + // Ditch the border. + style->resetBorder(); + + // Height is locked to auto. + style->setHeight(Length(Auto)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + // Set the button's vertical size. + setButtonSize(style); + + // Add in the padding that we'd like to use. + setButtonPaddingFromControlSize(style, controlSize); + + // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out + // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate + // system font for the control size instead. + setFontFromControlSize(selector, style, controlSize); + } else { + // Set a min-height so that we can't get smaller than the mini button. + style->setMinHeight(Length(static_cast<int>(15 * style->effectiveZoom()), Fixed)); + + // Reset the top and bottom borders. + style->resetBorderTop(); + style->resetBorderBottom(); + } + + style->setBoxShadow(0); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::buttonSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::buttonMargins() const +{ + static const int margins[3][4] = + { + { 4, 6, 7, 6 }, + { 4, 5, 6, 5 }, + { 0, 1, 1, 1 }, + }; + return margins[[button() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonSize(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, buttonSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* button = this->button(); + + // Set the control size based off the rectangle we're painting into. + if (o->style()->appearance() == SquareButtonPart || + r.height() > buttonSizes()[NSRegularControlSize].height() * o->style()->effectiveZoom()) { + // Use the square button + if ([button bezelStyle] != NSShadowlessSquareBezelStyle) + [button setBezelStyle:NSShadowlessSquareBezelStyle]; + } else if ([button bezelStyle] != NSRoundedBezelStyle) + [button setBezelStyle:NSRoundedBezelStyle]; + + setControlSize(button, buttonSizes(), r.size(), o->style()->effectiveZoom()); + + NSWindow *window = [nil window]; + BOOL isDefaultButton = (isDefault(o) && [window isKeyWindow]); + [button setKeyEquivalent:(isDefaultButton ? @"\r" : @"")]; + + // Update the various states we respond to. + updateCheckedState(button, o); + updateEnabledState(button, o); + updatePressedState(button, o); + updateFocusedState(button, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + NSButtonCell* button = this->button(); + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Determine the width and height needed for the control and prepare the cell for painting. + setButtonCellState(o, r); + + paintInfo.context->save(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the button + // shadow. We don't consider this part of the bounds of the control in WebKit. + float zoomLevel = o->style()->effectiveZoom(); + IntSize size = buttonSizes()[[button controlSize]]; + size.setWidth(r.width()); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = r; + if ([button bezelStyle] == NSRoundedBezelStyle) { + // Center the button within the available space. + if (inflatedRect.height() > size.height()) { + inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2); + inflatedRect.setHeight(size.height()); + } + + // Now inflate it to account for the shadow. + inflatedRect = inflateRect(inflatedRect, size, buttonMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + } + + NSView *view = nil; + NSWindow *window = [view window]; + NSButtonCell *previousDefaultButtonCell = [window defaultButtonCell]; + + if (isDefault(o) && [window isKeyWindow]) { + [window setDefaultButtonCell:button]; + wkAdvanceDefaultButtonPulseAnimation(button); + } else if ([previousDefaultButtonCell isEqual:button]) + [window setDefaultButtonCell:nil]; + + [button drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:view]; + [button setControlView:nil]; + + if (![previousDefaultButtonCell isEqual:button]) + [window setDefaultButtonCell:previousDefaultButtonCell]; + + paintInfo.context->restore(); + + return false; +} + +bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawBezeledTextFieldCell(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); + return false; +} + +void RenderThemeChromiumMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + if (paintInfo.context->paintingDisabled()) + return true; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r); + + return false; +} + +bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawBezeledTextArea(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); + return false; +} + +void RenderThemeChromiumMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +const int* RenderThemeChromiumMac::popupButtonMargins() const +{ + static const int margins[3][4] = + { + { 0, 3, 1, 3 }, + { 0, 3, 2, 3 }, + { 0, 1, 0, 1 } + }; + return margins[[popupButton() controlSize]]; +} + +const IntSize* RenderThemeChromiumMac::popupButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const +{ + static const int padding[3][4] = + { + { 2, 26, 3, 8 }, + { 2, 23, 3, 8 }, + { 2, 22, 3, 10 } + }; + return padding[size]; +} + +bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + setPopupButtonCellState(o, r); + + NSPopUpButtonCell* popupButton = this->popupButton(); + + float zoomLevel = o->style()->effectiveZoom(); + IntSize size = popupButtonSizes()[[popupButton controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + + // Now inflate it to account for the shadow. + IntRect inflatedRect = r; + if (r.width() >= minimumMenuListSize(o->style())) + 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); +#endif + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [popupButton drawWithFrame:IntRectToNSRect(inflatedRect) inView:nil]; + [popupButton setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +static const float baseFontSize = 11.0f; +static const float baseArrowHeight = 4.0f; +static const float baseArrowWidth = 5.0f; +static const float baseSpaceBetweenArrows = 2.0f; +static const int arrowPaddingLeft = 6; +static const int arrowPaddingRight = 6; +static const int paddingBeforeSeparator = 4; +static const int baseBorderRadius = 5; +static const int styledPopupPaddingLeft = 8; +static const int styledPopupPaddingTop = 1; +static const int styledPopupPaddingBottom = 2; + +static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + CGContextRef context = paintInfo.context->platformContext(); + + paintInfo.context->save(); + + int radius = o->style()->borderTopLeftRadius().width(); + + RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + + FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); + struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); + RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); + + FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); + struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); + RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); + + struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); + paintInfo.context->save(); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(r, + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, mainShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, topGradient); + paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + IntSize(), IntSize()); + CGContextDrawShading(context, topShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, bottomGradient); + paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), + IntSize(), IntSize(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, bottomShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(r, + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, leftShading.get()); + CGContextDrawShading(context, rightShading.get()); + paintInfo.context->restore(); + + paintInfo.context->restore(); +} + +bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + paintInfo.context->save(); + + IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), + r.y() + o->style()->borderTopWidth(), + r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), + r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); + // Draw the gradients to give the styled popup menu a button appearance + paintMenuListButtonGradients(o, paintInfo, bounds); + + // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds + float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); + float centerY = bounds.y() + bounds.height() / 2.0f; + float arrowHeight = baseArrowHeight * fontScale; + float arrowWidth = baseArrowWidth * fontScale; + float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; + float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; + + if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) + return false; + + paintInfo.context->setFillColor(o->style()->color()); + paintInfo.context->setStrokeStyle(NoStroke); + + FloatPoint arrow1[3]; + arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); + arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); + arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); + + // Draw the top arrow + paintInfo.context->drawConvexPolygon(3, arrow1, true); + + FloatPoint arrow2[3]; + arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); + arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); + arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); + + // Draw the bottom arrow + paintInfo.context->drawConvexPolygon(3, arrow2, true); + + Color leftSeparatorColor(0, 0, 0, 40); + Color rightSeparatorColor(255, 255, 255, 40); + + // FIXME: Should the separator thickness and space be scaled up by fontScale? + int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. + int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? + + // 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->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), + IntPoint(leftEdgeOfSeparator, bounds.bottom())); + + paintInfo.context->setStrokeColor(rightSeparatorColor); + paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), + IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); + + paintInfo.context->restore(); + return false; +} + +static const IntSize* menuListButtonSizes() +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + NSControlSize controlSize = controlSizeForFont(style); + + style->resetBorder(); + style->resetPadding(); + + // Height is locked to auto. + style->setHeight(Length(Auto)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + // Set the foreground color to black or gray when we have the aqua look. + // Cast to RGB32 is to work around a compiler bug. + style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); + + // Set the button's vertical size. + setSizeFromFont(style, menuListButtonSizes()); + + // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out + // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate + // system font for the control size instead. + setFontFromControlSize(selector, style, controlSize); + + style->setBoxShadow(0); +} + +int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[LeftPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingLeft * style->effectiveZoom(); + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[RightPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) { + float fontScale = style->fontSize() / baseFontSize; + float arrowWidth = baseArrowWidth * fontScale; + return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); + } + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[TopPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingTop * style->effectiveZoom(); + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[BottomPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingBottom * style->effectiveZoom(); + return 0; +} + +void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + float fontScale = style->fontSize() / baseFontSize; + + style->resetPadding(); + style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? + + const int minHeight = 15; + style->setMinHeight(Length(minHeight, Fixed)); + + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) +{ + NSPopUpButtonCell* popupButton = this->popupButton(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(popupButton, o); + updateEnabledState(popupButton, o); + updatePressedState(popupButton, o); + updateFocusedState(popupButton, o); +} + +const IntSize* RenderThemeChromiumMac::menuListSizes() const +{ + static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; + return sizes; +} + +int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const +{ + return sizeForSystemFont(style, menuListSizes()).width(); +} + +static const int trackWidth = 5; +static const int trackRadius = 2; + +void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + IntRect bounds = r; + float zoomLevel = o->style()->effectiveZoom(); + float zoomedTrackWidth = trackWidth * zoomLevel; + + if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { + bounds.setHeight(zoomedTrackWidth); + bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); + } else if (o->style()->appearance() == SliderVerticalPart) { + bounds.setWidth(zoomedTrackWidth); + bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); + } + + LocalCurrentGraphicsContext localContext(paintInfo.context); + CGContextRef context = paintInfo.context->platformContext(); + RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + + paintInfo.context->save(); + CGContextClipToRect(context, bounds); + + struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading; + if (o->style()->appearance() == SliderVerticalPart) + mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false)); + else + mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false)); + + IntSize radius(trackRadius, trackRadius); + paintInfo.context->addRoundedRectClip(bounds, + radius, radius, + radius, radius); + CGContextDrawShading(context, mainShading.get()); + paintInfo.context->restore(); + + return false; +} + +void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->setBoxShadow(0); +} + +static const float verticalSliderHeightPadding = 0.1f; + +bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + ASSERT(o->parent()->isSlider()); + + NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart + ? sliderThumbVertical() + : sliderThumbHorizontal(); + + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Update the various states we respond to. + updateEnabledState(sliderThumbCell, o->parent()); + updateFocusedState(sliderThumbCell, o->parent()); + + // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. + bool oldPressed; + if (o->style()->appearance() == SliderThumbVerticalPart) + oldPressed = m_isSliderThumbVerticalPressed; + else + oldPressed = m_isSliderThumbHorizontalPressed; + + bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode(); + + if (o->style()->appearance() == SliderThumbVerticalPart) + m_isSliderThumbVerticalPressed = pressed; + else + m_isSliderThumbHorizontalPressed = pressed; + + if (pressed != oldPressed) { + if (pressed) + [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; + else + [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; + } + + FloatRect bounds = r; + // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. + if (o->style()->appearance() == SliderThumbVerticalPart) + bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); + + paintInfo.context->save(); + float zoomLevel = o->style()->effectiveZoom(); + + FloatRect unzoomedRect = bounds; + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [sliderThumbCell drawWithFrame:FloatRectToNSRect(unzoomedRect) inView:nil]; + [sliderThumbCell setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +const int sliderThumbWidth = 15; +const int sliderThumbHeight = 15; +const int mediaSliderThumbWidth = 13; +const int mediaSliderThumbHeight = 14; + +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)); + } else if (o->style()->appearance() == MediaSliderThumbPart) { + o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed)); + o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed)); + } +} + +bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + NSSearchFieldCell* search = this->search(); + LocalCurrentGraphicsContext localContext(paintInfo.context); + + setSearchCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + IntRect unzoomedRect = r; + + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + // Set the search button to nil before drawing. Then reset it so we can draw it later. + [search setSearchButtonCell:nil]; + + [search drawWithFrame:NSRect(IntRectToNSRect(unzoomedRect)) inView:nil]; +#ifdef BUILDING_ON_TIGER + if ([search showsFirstResponder]) + wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect)); +#endif + + [search setControlView:nil]; + [search resetSearchButtonCell]; + + paintInfo.context->restore(); + + return false; +} + +void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect& r) +{ + NSSearchFieldCell* search = this->search(); + + [search setControlSize:controlSizeForFont(o->style())]; + + // Update the various states we respond to. + updateEnabledState(search, o); + updateFocusedState(search, o); +} + +const IntSize* RenderThemeChromiumMac::searchFieldSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; + return sizes; +} + +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()); +} + +void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // Override border. + style->resetBorder(); + const short borderWidth = 2 * style->effectiveZoom(); + style->setBorderLeftWidth(borderWidth); + style->setBorderLeftStyle(INSET); + style->setBorderRightWidth(borderWidth); + style->setBorderRightStyle(INSET); + style->setBorderBottomWidth(borderWidth); + style->setBorderBottomStyle(INSET); + style->setBorderTopWidth(borderWidth); + 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); + + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + updatePressedState([search cancelButtonCell], o); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + NSRect bounds = [search cancelButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + + IntRect unzoomedRect(NSRectToIntRect(bounds)); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search cancelButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; + [[search cancelButtonCell] setControlView:nil]; + + paintInfo.context->restore(); + return false; +} + +const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; + return sizes; +} + +void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, cancelButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; + return sizes; +} + +static const int emptyResultsOffset = 9; +void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return false; +} + +void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if ([search searchMenuTemplate] != nil) + [search setSearchMenuTemplate:nil]; + + NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + [[search searchButtonCell] drawWithFrame:bounds inView:nil]; + [[search searchButtonCell] setControlView:nil]; + return false; +} + +static const int resultsArrowWidth = 5; +void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if (![search searchMenuTemplate]) + [search setSearchMenuTemplate:searchMenuTemplate()]; + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + + IntRect unzoomedRect(NSRectToIntRect(bounds)); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search searchButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; + [[search searchButtonCell] setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +#if ENABLE(VIDEO) +// FIXME: This enum is lifted from RenderThemeMac.mm We need to decide which theme to use for the default controls, or decide to avoid wkDrawMediaUIPart and render our own. +typedef enum { + MediaControllerThemeClassic = 1, + MediaControllerThemeQT = 2 +} MediaControllerThemeStyle; +#endif + +bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaFullscreenButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSeekBackButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSeekForwardButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + float timeLoaded = 0; + float currentTime = 0; + float duration = 0; + if (MediaPlayer* player = mediaElement->player()) { + duration = player->duration(); + timeLoaded = player->maxTimeBuffered(); + currentTime = player->currentTime(); + } + + wkDrawMediaSliderTrack(MediaControllerThemeClassic, paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSliderThumb, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::checkbox() const +{ + if (!m_checkbox) { + m_checkbox.adoptNS([[NSButtonCell alloc] init]); + [m_checkbox.get() setButtonType:NSSwitchButton]; + [m_checkbox.get() setTitle:nil]; + [m_checkbox.get() setAllowsMixedState:YES]; + [m_checkbox.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_checkbox.get(); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::radio() const +{ + if (!m_radio) { + m_radio.adoptNS([[NSButtonCell alloc] init]); + [m_radio.get() setButtonType:NSRadioButton]; + [m_radio.get() setTitle:nil]; + [m_radio.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_radio.get(); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::button() const +{ + if (!m_button) { + m_button.adoptNS([[NSButtonCell alloc] init]); + [m_button.get() setTitle:nil]; + [m_button.get() setButtonType:NSMomentaryPushInButton]; + } + + return m_button.get(); +} + +NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const +{ + if (!m_popupButton) { + m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popupButton.get() setUsesItemFromMenu:NO]; + [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_popupButton.get(); +} + +NSSearchFieldCell* RenderThemeChromiumMac::search() const +{ + if (!m_search) { + m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); + [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; + [m_search.get() setBezeled:YES]; + [m_search.get() setEditable:YES]; + [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_search.get(); +} + +NSMenu* RenderThemeChromiumMac::searchMenuTemplate() const +{ + if (!m_searchMenuTemplate) + m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); + + return m_searchMenuTemplate.get(); +} + +NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const +{ + if (!m_sliderThumbHorizontal) { + m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbHorizontal.get() setTitle:nil]; + [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; + [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbHorizontal.get(); +} + +NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const +{ + if (!m_sliderThumbVertical) { + m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbVertical.get() setTitle:nil]; + [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; + [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbVertical.get(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp new file mode 100644 index 0000000..1fb0cb2 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008, 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 + * along with this library; 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 "RenderThemeChromiumSkia.h" + +#include "ChromiumBridge.h" +#include "CSSValueKeywords.h" +#include "GraphicsContext.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "Image.h" +#include "MediaControlElements.h" +#include "PlatformContextSkia.h" +#include "RenderBox.h" +#include "RenderObject.h" +#include "ScrollbarTheme.h" +#include "TransformationMatrix.h" +#include "UserAgentStyleSheets.h" + +#include "SkShader.h" +#include "SkGradientShader.h" + +namespace WebCore { + +enum PaddingType { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 }; + +// The background for the media player controls should be a 60% opaque black rectangle. This +// matches the UI mockups for the default UI theme. +static const float defaultMediaControlOpacity = 0.6f; + +// These values all match Safari/Win. +static const float defaultControlFontPixelSize = 13; +static const float defaultCancelButtonSize = 9; +static const float minCancelButtonSize = 5; +static const float maxCancelButtonSize = 21; +static const float defaultSearchFieldResultsDecorationSize = 13; +static const float minSearchFieldResultsDecorationSize = 9; +static const float maxSearchFieldResultsDecorationSize = 30; +static const float defaultSearchFieldResultsButtonWidth = 18; + +static void setSizeIfAuto(RenderStyle* style, const IntSize& size) +{ + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto()) + style->setHeight(Length(size.height(), Fixed)); +} + +#if ENABLE(VIDEO) +// Attempt to retrieve a HTMLMediaElement from a Node. Returns NULL if one cannot be found. +static HTMLMediaElement* mediaElementParent(Node* node) +{ + if (!node) + return 0; + Node* mediaNode = node->shadowAncestorNode(); + if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) + return 0; + + return static_cast<HTMLMediaElement*>(mediaNode); +} +#endif + +// We aim to match IE here. +// -IE uses a font based on the encoding as the default font for form controls. +// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT), +// which returns MS Shell Dlg) +// -Safari uses Lucida Grande. +// +// FIXME: The only case where we know we don't match IE is for ANSI encodings. +// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel +// sizes (e.g. 15px). So, for now we just use Arial. +const String& RenderThemeChromiumSkia::defaultGUIFont() +{ + DEFINE_STATIC_LOCAL(String, fontFace, ("Arial")); + return fontFace; +} + +float RenderThemeChromiumSkia::defaultFontSize = 16.0; + +RenderThemeChromiumSkia::RenderThemeChromiumSkia() +{ +} + +RenderThemeChromiumSkia::~RenderThemeChromiumSkia() +{ +} + +// Use the Windows style sheets to match their metrics. +String RenderThemeChromiumSkia::extraDefaultStyleSheet() +{ + return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); +} + +String RenderThemeChromiumSkia::extraQuirksStyleSheet() +{ + return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); +} + +#if ENABLE(VIDEO) +String RenderThemeChromiumSkia::extraMediaControlsStyleSheet() +{ + return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); +} +#endif + +bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const +{ + return true; +} + +bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const +{ + // This causes WebKit to draw the focus rings for us. + return false; +} + +Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const +{ + return Color(0x1e, 0x90, 0xff); +} + +Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const +{ + return Color(0xc8, 0xc8, 0xc8); +} + +Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const +{ + return Color(0x32, 0x32, 0x32); +} + +Color RenderThemeChromiumSkia::focusRingColor() const +{ + static Color focusRingColor(229, 151, 0, 255); + return focusRingColor; +} + +double RenderThemeChromiumSkia::caretBlinkInterval() const +{ + // Disable the blinking caret in layout test mode, as it introduces + // a race condition for the pixel tests. http://b/1198440 + if (ChromiumBridge::layoutTestMode()) + return 0; + + return caretBlinkIntervalInternal(); +} + +void RenderThemeChromiumSkia::systemFont(int propId, FontDescription& fontDescription) const +{ + float fontSize = defaultFontSize; + + switch (propId) { + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + // Why 2 points smaller? Because that's what Gecko does. Note that we + // are assuming a 96dpi screen, which is the default that we use on + // Windows. + static const float pointsPerInch = 72.0f; + static const float pixelsPerInch = 96.0f; + fontSize -= (2.0f / pointsPerInch) * pixelsPerInch; + break; + } + + fontDescription.firstFamily().setFamily(defaultGUIFont()); + fontDescription.setSpecifiedSize(fontSize); + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::NoFamily); + fontDescription.setWeight(FontWeightNormal); + fontDescription.setItalic(false); +} + +int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const +{ + return 0; +} + +bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef(); + static Image* const uncheckedImage = Image::loadPlatformResource("linuxCheckboxOff").releaseRef(); + + Image* image = this->isChecked(o) ? checkedImage : uncheckedImage; + i.context->drawImage(image, rect); + return false; +} + +void RenderThemeChromiumSkia::setCheckboxSize(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; + + // FIXME: A hard-coded size of 13 is used. This is wrong but necessary + // for now. It matches Firefox. At different DPI settings on Windows, + // 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); + setSizeIfAuto(style, size); +} + +bool RenderThemeChromiumSkia::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + static Image* const checkedImage = Image::loadPlatformResource("linuxRadioOn").releaseRef(); + static Image* const uncheckedImage = Image::loadPlatformResource("linuxRadioOff").releaseRef(); + + Image* image = this->isChecked(o) ? checkedImage : uncheckedImage; + i.context->drawImage(image, rect); + return false; +} + +void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const +{ + // Use same sizing for radio box as checkbox. + setCheckboxSize(style); +} + +static SkColor brightenColor(double h, double s, double l, float brightenAmount) +{ + l += brightenAmount; + if (l > 1.0) + l = 1.0; + if (l < 0.0) + l = 0.0; + + return makeRGBAFromHSLA(h, s, l, 1.0); +} + +static void paintButtonLike(RenderTheme* theme, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + SkCanvas* const canvas = i.context->platformContext()->canvas(); + SkPaint paint; + SkRect skrect; + const int right = rect.x() + rect.width(); + const int bottom = rect.y() + rect.height(); + SkColor baseColor = SkColorSetARGB(0xff, 0xdd, 0xdd, 0xdd); + if (o->style()->hasBackground()) + baseColor = o->style()->backgroundColor().rgb(); + double h, s, l; + Color(baseColor).getHSL(h, s, l); + // Our standard gradient is from 0xdd to 0xf8. This is the amount of + // increased luminance between those values. + SkColor lightColor(brightenColor(h, s, l, 0.105)); + + // If the button is too small, fallback to drawing a single, solid color + if (rect.width() < 5 || rect.height() < 5) { + paint.setColor(baseColor); + skrect.set(rect.x(), rect.y(), right, bottom); + canvas->drawRect(skrect, paint); + return; + } + + const int borderAlpha = theme->isHovered(o) ? 0x80 : 0x55; + paint.setARGB(borderAlpha, 0, 0, 0); + canvas->drawLine(rect.x() + 1, rect.y(), right - 1, rect.y(), paint); + canvas->drawLine(right - 1, rect.y() + 1, right - 1, bottom - 1, paint); + canvas->drawLine(rect.x() + 1, bottom - 1, right - 1, bottom - 1, paint); + canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), bottom - 1, paint); + + paint.setARGB(0xff, 0, 0, 0); + SkPoint p[2]; + const int lightEnd = theme->isPressed(o) ? 1 : 0; + const int darkEnd = !lightEnd; + p[lightEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(rect.y())); + p[darkEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(bottom - 1)); + SkColor colors[2]; + colors[0] = lightColor; + colors[1] = baseColor; + + SkShader* shader = SkGradientShader::CreateLinear( + p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL); + paint.setStyle(SkPaint::kFill_Style); + paint.setShader(shader); + shader->unref(); + + skrect.set(rect.x() + 1, rect.y() + 1, right - 1, bottom - 1); + canvas->drawRect(skrect, paint); + + paint.setShader(NULL); + paint.setColor(brightenColor(h, s, l, -0.0588)); + canvas->drawPoint(rect.x() + 1, rect.y() + 1, paint); + canvas->drawPoint(right - 2, rect.y() + 1, paint); + canvas->drawPoint(rect.x() + 1, bottom - 2, paint); + canvas->drawPoint(right - 2, bottom - 2, paint); +} + +bool RenderThemeChromiumSkia::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + paintButtonLike(this, o, i, rect); + return false; +} + +bool RenderThemeChromiumSkia::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return true; +} + +bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); + style->setWidth(Length(cancelButtonSize, Fixed)); + style->setHeight(Length(cancelButtonSize, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // 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()); + + // 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); + + static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef(); + static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef(); + i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); + return false; +} + +void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + IntSize emptySize(1, 11); + style->setWidth(Length(emptySize.width(), Fixed)); + style->setHeight(Length(emptySize.height(), Fixed)); +} + +void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the decoration size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + style->setWidth(Length(magnifierSize, Fixed)); + style->setHeight(Length(magnifierSize, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + 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()); + + // 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); + + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); + i.context->drawImage(magnifierImage, bounds); + return false; +} + +void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); + style->setWidth(Length(magnifierWidth, Fixed)); + style->setHeight(Length(magnifierHeight, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent()) + return false; + if (!o->parent() || !o->parent()->isBox()) + return false; + + 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); + + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef(); + i.context->drawImage(magnifierImage, bounds); + return false; +} + +bool RenderThemeChromiumSkia::paintMediaButtonInternal(GraphicsContext* context, const IntRect& rect, Image* image) +{ + context->beginTransparencyLayer(defaultMediaControlOpacity); + + // Draw background. + Color oldFill = context->fillColor(); + Color oldStroke = context->strokeColor(); + + context->setFillColor(Color::black); + context->setStrokeColor(Color::black); + context->drawRect(rect); + + context->setFillColor(oldFill); + context->setStrokeColor(oldStroke); + + // Create a destination rectangle for the image that is centered in the drawing rectangle, rounded left, and down. + IntRect imageRect = image->rect(); + imageRect.setY(rect.y() + (rect.height() - image->height() + 1) / 2); + imageRect.setX(rect.x() + (rect.width() - image->width() + 1) / 2); + + context->drawImage(image, imageRect, CompositeSourceAtop); + context->endTransparencyLayer(); + + return false; +} + +bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); + if (!mediaElement) + return false; + + static Image* mediaPlay = Image::loadPlatformResource("mediaPlay").releaseRef(); + static Image* mediaPause = Image::loadPlatformResource("mediaPause").releaseRef(); + + return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); +#else + return false; +#endif +} + +bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(o->node()); + if (!mediaElement) + return false; + + static Image* soundFull = Image::loadPlatformResource("mediaSoundFull").releaseRef(); + static Image* soundNone = Image::loadPlatformResource("mediaSoundNone").releaseRef(); + + return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); +#else + return false; +#endif +} + +void RenderThemeChromiumSkia::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +{ + // Height is locked to auto on all browsers. + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +bool RenderThemeChromiumSkia::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + SkCanvas* const canvas = i.context->platformContext()->canvas(); + const int right = rect.x() + rect.width(); + const int middle = rect.y() + rect.height() / 2; + + paintButtonLike(this, o, i, rect); + + SkPaint paint; + paint.setARGB(0xff, 0, 0, 0); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kFill_Style); + + SkPath path; + path.moveTo(right - 13, middle - 3); + path.rLineTo(6, 0); + path.rLineTo(-3, 6); + path.close(); + canvas->drawPath(path, paint); + + return false; +} + +void RenderThemeChromiumSkia::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustMenuListStyle(selector, style, e); +} + +// Used to paint styled menulists (i.e. with a non-default border) +bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMenuList(o, i, rect); +} + +int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const +{ + return menuListInternalPadding(style, LeftPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const +{ + return menuListInternalPadding(style, RightPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const +{ + return menuListInternalPadding(style, TopPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const +{ + 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; +} + +// static +void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize) +{ + defaultFontSize = static_cast<float>(fontSize); +} + +double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const +{ + return RenderTheme::caretBlinkInterval(); +} + +int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const +{ + // This internal padding is in addition to the user-supplied padding. + // Matches the FF behavior. + int padding = styledMenuListInternalPadding[paddingType]; + + // Reserve the space for right arrow here. The rest of the padding is + // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from + // RenderMenuList to lay out the individual items in the popup. + // If the MenuList actually has appearance "NoAppearance", then that means + // we don't draw a button, so don't reserve space for it. + const int barType = style->direction() == LTR ? RightPadding : LeftPadding; + if (paddingType == barType && style->appearance() != NoControlPart) + padding += ScrollbarTheme::nativeTheme()->scrollbarThickness(); + + return padding; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h new file mode 100644 index 0000000..b81d4fa --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumSkia.h @@ -0,0 +1,144 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008, 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; 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 RenderThemeChromiumSkia_h +#define RenderThemeChromiumSkia_h + +#include "RenderTheme.h" + +namespace WebCore { + + class RenderThemeChromiumSkia : public RenderTheme { + public: + RenderThemeChromiumSkia(); + virtual ~RenderThemeChromiumSkia(); + + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); +#if ENABLE(VIDEO) + virtual String extraMediaControlsStyleSheet(); +#endif + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle*) const; + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color focusRingColor() const; + + // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts. + virtual double caretBlinkInterval() const; + + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // MenuList refers to an unstyled menulist (meaning a menulist without + // background-color or border set) and MenuListButton refers to a styled + // menulist (a menulist with background-color or border set). They have + // this distinction to support showing aqua style themes whenever they + // possibly can, which is something we don't want to replicate. + // + // In short, we either go down the MenuList code path or the MenuListButton + // codepath. We never go down both. And in both cases, they render the + // entire menulist. + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // These methods define the padding for the MenuList's inner block. + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + 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; + + // Provide a way to pass the default font size from the Settings object + // to the render theme. FIXME: http://b/1129186 A cleaner way would be + // to remove the default font size from this object and have callers + // that need the value to get it directly from the appropriate Settings + // object. + static void setDefaultFontSize(int); + + protected: + static const String& defaultGUIFont(); + + // The default variable-width font size. We use this as the default font + // size for the "system font", and as a base size (which we then shrink) for + // form control fonts. + static float defaultFontSize; + + virtual double caretBlinkIntervalInternal() const; + + private: + int menuListInternalPadding(RenderStyle*, int paddingType) const; + bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); + }; + +} // namespace WebCore + +#endif // RenderThemeChromiumSkia_h diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp new file mode 100644 index 0000000..4ed8d88 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -0,0 +1,581 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "RenderThemeChromiumWin.h" + +#include <windows.h> +#include <uxtheme.h> +#include <vssym32.h> + +#include "ChromiumBridge.h" +#include "CSSValueKeywords.h" +#include "FontSelector.h" +#include "FontUtilsChromiumWin.h" +#include "GraphicsContext.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "MediaControlElements.h" +#include "RenderBox.h" +#include "RenderSlider.h" +#include "ScrollbarTheme.h" +#include "TransparencyWin.h" +#include "WindowsVersion.h" + +// FIXME: This dependency should eventually be removed. +#include <skia/ext/skia_utils_win.h> + +#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ + offsetof(structName, member) + \ + (sizeof static_cast<structName*>(0)->member) +#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ + SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) + +namespace WebCore { + +namespace { +class ThemePainter : public TransparencyWin { +public: + ThemePainter(GraphicsContext* context, const IntRect& r) + { + TransformMode transformMode = getTransformMode(context->getCTM()); + init(context, getLayerMode(context, transformMode), transformMode, r); + } + + ~ThemePainter() + { + composite(); + } + +private: + static bool canvasHasMultipleLayers(const SkCanvas* canvas) + { + SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); + iter.next(); // There is always at least one layer. + return !iter.done(); // There is > 1 layer if the the iterator can stil advance. + } + + static LayerMode getLayerMode(GraphicsContext* context, TransformMode transformMode) + { + if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. + return WhiteLayer; + else if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. + return OpaqueCompositeLayer; + else // Nothing interesting. + return transformMode == KeepTransform ? NoLayer : OpaqueCompositeLayer; + } + + static TransformMode getTransformMode(const TransformationMatrix& matrix) + { + if (matrix.b() != 0 || matrix.c() != 0) // Skew. + return Untransform; + else if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. + return ScaleTransform; + else // Nothing interesting. + return KeepTransform; + } +}; + +} // namespace + +static void getNonClientMetrics(NONCLIENTMETRICS* metrics) +{ + static UINT size = WebCore::isVistaOrNewer() ? + sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; + metrics->cbSize = size; + bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); + ASSERT(success); +} + +static FontDescription smallSystemFont; +static FontDescription menuFont; +static FontDescription labelFont; + +// Internal static helper functions. We don't put them in an anonymous +// namespace so they have easier access to the WebCore namespace. + +static bool supportsFocus(ControlPart appearance) +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case DefaultButtonPart: + case SearchFieldPart: + case TextFieldPart: + case TextAreaPart: + return true; + } + return false; +} + +// Return the height of system font |font| in pixels. We use this size by +// default for some non-form-control elements. +static float systemFontSize(const LOGFONT& font) +{ + float size = -font.lfHeight; + if (size < 0) { + HFONT hFont = CreateFontIndirect(&font); + if (hFont) { + HDC hdc = GetDC(0); // What about printing? Is this the right DC? + if (hdc) { + HGDIOBJ hObject = SelectObject(hdc, hFont); + TEXTMETRIC tm; + GetTextMetrics(hdc, &tm); + SelectObject(hdc, hObject); + ReleaseDC(0, hdc); + size = tm.tmAscent; + } + DeleteObject(hFont); + } + } + + // The "codepage 936" bit here is from Gecko; apparently this helps make + // fonts more legible in Simplified Chinese where the default font size is + // too small. + // + // FIXME: http://b/1119883 Since this is only used for "small caption", + // "menu", and "status bar" objects, I'm not sure how much this even + // matters. Plus the Gecko patch went in back in 2002, and maybe this + // isn't even relevant anymore. We should investigate whether this should + // be removed, or perhaps broadened to be "any CJK locale". + // + return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; +} + +// Converts |points| to pixels. One point is 1/72 of an inch. +static float pointsToPixels(float points) +{ + static float pixelsPerInch = 0.0f; + if (!pixelsPerInch) { + HDC hdc = GetDC(0); // What about printing? Is this the right DC? + if (hdc) { // Can this ever actually be NULL? + pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + } else { + pixelsPerInch = 96.0f; + } + } + + static const float pointsPerInch = 72.0f; + return points / pointsPerInch * pixelsPerInch; +} + +static double querySystemBlinkInterval(double defaultInterval) +{ + UINT blinkTime = GetCaretBlinkTime(); + if (blinkTime == 0) + return defaultInterval; + if (blinkTime == INFINITE) + return 0; + return blinkTime / 1000.0; +} + +PassRefPtr<RenderTheme> RenderThemeChromiumWin::create() +{ + return adoptRef(new RenderThemeChromiumWin); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef(); + return rt; +} + +bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const +{ + // Let webkit draw one of its halo rings around any focused element, + // except push buttons. For buttons we use the windows PBS_DEFAULTED + // styling to give it a blue border. + return style->appearance() == ButtonPart + || style->appearance() == PushButtonPart; +} + +Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color(0x00, 0x00, 0xff); // Royal blue. + COLORREF color = GetSysColor(COLOR_HIGHLIGHT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); +} + +Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color(0x99, 0x99, 0x99); // Medium gray. + COLORREF color = GetSysColor(COLOR_GRAYTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); +} + +Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color(0xff, 0xff, 0xcc); // Pale yellow. + COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); +} + +Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const +{ + return Color::white; +} + +Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const +{ + return Color(0xff, 0x96, 0x32); // Orange. +} + +Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const +{ + return Color(0xff, 0xff, 0x96); // Yellow. +} + +void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const +{ + // This logic owes much to RenderThemeSafari.cpp. + FontDescription* cachedDesc = 0; + AtomicString faceName; + float fontSize = 0; + switch (propId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); + fontSize = systemFontSize(metrics.lfSmCaptionFont); + } + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); + fontSize = systemFontSize(metrics.lfMenuFont); + } + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = metrics.lfStatusFont.lfFaceName; + fontSize = systemFontSize(metrics.lfStatusFont); + } + break; + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + faceName = defaultGUIFont(); + // Why 2 points smaller? Because that's what Gecko does. + fontSize = defaultFontSize - pointsToPixels(2); + break; + default: + faceName = defaultGUIFont(); + fontSize = defaultFontSize; + break; + } + + if (!cachedDesc) + cachedDesc = &fontDescription; + + if (fontSize) { + cachedDesc->firstFamily().setFamily(faceName); + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->setSpecifiedSize(fontSize); + cachedDesc->setWeight(FontWeightNormal); + cachedDesc->setItalic(false); + } + fontDescription = *cachedDesc; +} + +void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const +{ + // These sizes match what WinXP draws for various menus. + const int sliderThumbAlongAxis = 11; + const int sliderThumbAcrossAxis = 21; + if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == MediaSliderThumbPart) { + o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed)); + o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed)); + } else if (o->style()->appearance() == SliderThumbVerticalPart) { + o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed)); + o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed)); + } +} + +bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintButton(o, i, r); +} +bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintButton(o, i, r); +} + +bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + const ThemeData& themeData = getThemeData(o); + + WebCore::ThemePainter painter(i.context, r); + ChromiumBridge::paintButton(painter.context(), + themeData.m_part, + themeData.m_state, + themeData.m_classicState, + painter.drawRect()); + return false; +} + +bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextFieldInternal(o, i, r, true); +} + +bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + const ThemeData& themeData = getThemeData(o); + + WebCore::ThemePainter painter(i.context, r); + ChromiumBridge::paintTrackbar(painter.context(), + themeData.m_part, + themeData.m_state, + themeData.m_classicState, + painter.drawRect()); + return false; +} + +bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintSliderTrack(o, i, r); +} + +// Used to paint unstyled menulists (i.e. with the default border) +bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + if (!o->isBox()) + return false; + + const RenderBox* box = toRenderBox(o); + int borderRight = box->borderRight(); + int borderLeft = box->borderLeft(); + int borderTop = box->borderTop(); + int borderBottom = box->borderBottom(); + + // If all the borders are 0, then tell skia not to paint the border on the + // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not + // draw individual borders and then pass that to skia so we can avoid + // drawing any borders that are set to 0. For non-zero borders, we draw the + // border, but webkit just draws over it. + bool drawEdges = !(borderRight == 0 && borderLeft == 0 && borderTop == 0 && borderBottom == 0); + + paintTextFieldInternal(o, i, r, drawEdges); + + // Take padding and border into account. If the MenuList is smaller than + // the size of a button, make sure to shrink it appropriately and not put + // its x position to the left of the menulist. + const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL); + int spacingLeft = borderLeft + box->paddingLeft(); + int spacingRight = borderRight + box->paddingRight(); + int spacingTop = borderTop + box->paddingTop(); + int spacingBottom = borderBottom + box->paddingBottom(); + + int buttonX; + if (r.right() - r.x() < buttonWidth) + buttonX = r.x(); + else + buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft; + + // Compute the rectangle of the button in the destination image. + IntRect rect(buttonX, + r.y() + spacingTop, + std::min(buttonWidth, r.right() - r.x()), + r.height() - (spacingTop + spacingBottom)); + + // Get the correct theme data for a textfield and paint the menu. + WebCore::ThemePainter painter(i.context, rect); + ChromiumBridge::paintMenuList(painter.context(), + CP_DROPDOWNBUTTON, + determineState(o), + determineClassicState(o), + painter.drawRect()); + return false; +} + +// static +void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) +{ + RenderThemeChromiumSkia::setDefaultFontSize(fontSize); + + // Reset cached fonts. + smallSystemFont = menuFont = labelFont = FontDescription(); +} + +double RenderThemeChromiumWin::caretBlinkIntervalInternal() const +{ + // This involves a system call, so we cache the result. + static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); + return blinkInterval; +} + +unsigned RenderThemeChromiumWin::determineState(RenderObject* o) +{ + unsigned result = TS_NORMAL; + ControlPart appearance = o->style()->appearance(); + if (!isEnabled(o)) + result = TS_DISABLED; + else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance)) + result = ETS_READONLY; // Readonly is supported on textfields. + else if (isPressed(o)) // Active overrides hover and focused. + result = TS_PRESSED; + else if (supportsFocus(appearance) && isFocused(o)) + result = ETS_FOCUSED; + else if (isHovered(o)) + result = TS_HOT; + if (isChecked(o)) + result += 4; // 4 unchecked states, 4 checked states. + return result; +} + +unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) +{ + unsigned result = TUS_NORMAL; + if (!isEnabled(o->parent())) + result = TUS_DISABLED; + else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) + result = TUS_FOCUSED; + else if (static_cast<RenderSlider*>(o->parent())->inDragMode()) + result = TUS_PRESSED; + else if (isHovered(o)) + result = TUS_HOT; + return result; +} + +unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) +{ + unsigned result = 0; + if (!isEnabled(o)) + result = DFCS_INACTIVE; + else if (isPressed(o)) // Active supersedes hover + result = DFCS_PUSHED; + else if (isHovered(o)) + result = DFCS_HOT; + if (isChecked(o)) + result |= DFCS_CHECKED; + return result; +} + +ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o) +{ + ThemeData result; + switch (o->style()->appearance()) { + case CheckboxPart: + result.m_part = BP_CHECKBOX; + result.m_state = determineState(o); + result.m_classicState = DFCS_BUTTONCHECK; + break; + case RadioPart: + result.m_part = BP_RADIOBUTTON; + result.m_state = determineState(o); + result.m_classicState = DFCS_BUTTONRADIO; + break; + case PushButtonPart: + case ButtonPart: + result.m_part = BP_PUSHBUTTON; + result.m_state = determineState(o); + result.m_classicState = DFCS_BUTTONPUSH; + break; + case SliderHorizontalPart: + result.m_part = TKP_TRACK; + result.m_state = TRS_NORMAL; + break; + case SliderVerticalPart: + result.m_part = TKP_TRACKVERT; + result.m_state = TRVS_NORMAL; + break; + case SliderThumbHorizontalPart: + result.m_part = TKP_THUMBBOTTOM; + result.m_state = determineSliderThumbState(o); + break; + case SliderThumbVerticalPart: + result.m_part = TKP_THUMBVERT; + result.m_state = determineSliderThumbState(o); + break; + case ListboxPart: + case MenulistPart: + case SearchFieldPart: + case TextFieldPart: + case TextAreaPart: + result.m_part = EP_EDITTEXT; + result.m_state = determineState(o); + break; + } + + result.m_classicState |= determineClassicState(o); + + return result; +} + +bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, + const RenderObject::PaintInfo& i, + const IntRect& r, + bool drawEdges) +{ + // Nasty hack to make us not paint the border on text fields with a + // border-radius. Webkit paints elements with border-radius for us. + // FIXME: Get rid of this if-check once we can properly clip rounded + // borders: http://b/1112604 and http://b/1108635 + // FIXME: make sure we do the right thing if css background-clip is set. + if (o->style()->hasBorderRadius()) + return false; + + const ThemeData& themeData = getThemeData(o); + + // Fallback to white if the specified color object is invalid. + Color backgroundColor(Color::white); + if (o->style()->backgroundColor().isValid()) { + backgroundColor = o->style()->backgroundColor(); + } + + // If we have background-image, don't fill the content area to expose the + // parent's background. Also, we shouldn't fill the content area if the + // alpha of the color is 0. The API of Windows GDI ignores the alpha. + // + // Note that we should paint the content area white if we have neither the + // background color nor background image explicitly specified to keep the + // appearance of select element consistent with other browsers. + bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha() != 0; + + WebCore::ThemePainter painter(i.context, r); + ChromiumBridge::paintTextField(painter.context(), + themeData.m_part, + themeData.m_state, + themeData.m_classicState, + painter.drawRect(), + backgroundColor, + fillContentArea, + drawEdges); + return false; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.h new file mode 100644 index 0000000..5e98c9b --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeChromiumWin.h @@ -0,0 +1,106 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 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 + * along with this library; 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 RenderThemeChromiumWin_h +#define RenderThemeChromiumWin_h + +#include "RenderThemeChromiumSkia.h" + +#if WIN32 +typedef void* HANDLE; +typedef struct HINSTANCE__* HINSTANCE; +typedef HINSTANCE HMODULE; +#endif + +namespace WebCore { + + struct ThemeData { + ThemeData() : m_part(0), m_state(0), m_classicState(0) {} + + unsigned m_part; + unsigned m_state; + unsigned m_classicState; + }; + + class RenderThemeChromiumWin : public RenderThemeChromiumSkia { + public: + static PassRefPtr<RenderTheme> create(); + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformActiveTextSearchHighlightColor() const; + virtual Color platformInactiveTextSearchHighlightColor() const; + + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; + + virtual void adjustSliderThumbSize(RenderObject*) const; + + // Various paint functions. + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // MenuList refers to an unstyled menulist (meaning a menulist without + // background-color or border set) and MenuListButton refers to a styled + // menulist (a menulist with background-color or border set). They have + // this distinction to support showing aqua style themes whenever they + // possibly can, which is something we don't want to replicate. + // + // In short, we either go down the MenuList code path or the MenuListButton + // codepath. We never go down both. And in both cases, they render the + // entire menulist. + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // Override RenderThemeChromiumSkia's setDefaultFontSize method to also reset the local font property caches. + // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. + static void setDefaultFontSize(int); + + protected: + virtual double caretBlinkIntervalInternal() const; + + private: + RenderThemeChromiumWin() { } + virtual ~RenderThemeChromiumWin() { } + + unsigned determineState(RenderObject*); + unsigned determineSliderThumbState(RenderObject*); + unsigned determineClassicState(RenderObject*); + + ThemeData getThemeData(RenderObject*); + + bool paintTextFieldInternal(RenderObject*, const RenderObject::PaintInfo&, const IntRect&, bool); + }; + +} // namespace WebCore + +#endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h index a1da7ff..ba32105 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h @@ -39,8 +39,7 @@ class RenderStyle; class RenderThemeMac : public RenderTheme { public: - RenderThemeMac(); - virtual ~RenderThemeMac(); + static PassRefPtr<RenderTheme> create(); // A method asking if the control changes its tint when the window has focus or not. virtual bool controlSupportsTints(const RenderObject*) const; @@ -55,7 +54,13 @@ public: virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionForegroundColor() const; + virtual Color platformInactiveListBoxSelectionBackgroundColor() const; + virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual Color focusRingColor() const; + + virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } virtual void platformColorsDidChange(); @@ -76,6 +81,8 @@ public: virtual Color systemColor(int cssValueId) const; protected: + virtual bool supportsSelectionForegroundColors() const { return false; } + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -109,6 +116,7 @@ protected: virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); +#if ENABLE(VIDEO) 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&); @@ -116,8 +124,19 @@ protected: 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 paintMediaTimelineContainer(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // Media controls + virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); + virtual String extraMediaControlsStyleSheet(); +#endif private: + RenderThemeMac(); + virtual ~RenderThemeMac(); + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp index 31315bc..914f7ee 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,6 +35,7 @@ #include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "RenderMediaControls.h" #include "RenderSlider.h" #include "RenderView.h" #include "RetainPtr.h" @@ -64,13 +66,22 @@ enum { leftPadding }; -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderThemeSafari::create() { - static RenderThemeSafari safariTheme; - static RenderThemeWin windowsTheme; + return adoptRef(new RenderThemeSafari); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* safariTheme = RenderThemeSafari::create().releaseRef(); + static RenderTheme* windowsTheme = RenderThemeWin::create().releaseRef(); + + // FIXME: This is called before Settings has been initialized by WebKit, so will return a + // potentially wrong answer the very first time it's called (see + // <https://bugs.webkit.org/show_bug.cgi?id=26493>). if (Settings::shouldPaintNativeControls()) - return &windowsTheme; - return &safariTheme; + return windowsTheme; // keep the reference of one. + return safariTheme; // keep the reference of one. } #if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME) @@ -83,6 +94,17 @@ SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGConte #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value)) #endif +SOFT_LINK_OPTIONAL(SafariTheme, STCopyThemeColor, CGColorRef, APIENTRY, (unsigned color, SafariTheme::ThemeControlState)); + +static const unsigned stFocusRingColorID = 4; + +static const unsigned aquaFocusRingColor = 0xFF7DADD9; + +static RGBA32 makeRGBAFromCGColor(CGColorRef color) +{ + const CGFloat* components = CGColorGetComponents(color); + return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]); +} ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const { @@ -138,6 +160,22 @@ Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const return Color(56, 117, 215); } +Color RenderThemeSafari::focusRingColor() const +{ + static Color focusRingColor; + + if (!focusRingColor.isValid()) { + if (STCopyThemeColorPtr()) { + RetainPtr<CGColorRef> color(AdoptCF, STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState)); + focusRingColor = makeRGBAFromCGColor(color.get()); + } + if (!focusRingColor.isValid()) + focusRingColor = aquaFocusRingColor; + } + + return focusRingColor; +} + static float systemFontSizeForControlSize(NSControlSize controlSize) { static float sizes[] = { 13.0f, 11.0f, 9.0f }; @@ -272,8 +310,14 @@ IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, co int RenderThemeSafari::baselinePosition(const RenderObject* o) const { - if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) - return o->marginTop() + o->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + if (!o->isBox()) + return 0; + + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) { + const RenderBox* box = toRenderBox(o); + return box->marginTop() + box->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + } + return RenderTheme::baselinePosition(o); } @@ -828,7 +872,7 @@ void RenderThemeSafari::adjustMenuListStyle(CSSStyleSelector* selector, RenderSt // Set the foreground color to black or gray when we have the aqua look. // Cast to RGB32 is to work around a compiler bug. - style->setColor(e->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray); + style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); // Set the button's vertical size. setButtonSize(style); @@ -909,8 +953,7 @@ bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const RenderObject::Pa { IntRect bounds = r; - if (o->style()->appearance() == SliderHorizontalPart || - o->style()->appearance() == MediaSliderPart) { + if (o->style()->appearance() == SliderHorizontalPart) { bounds.setHeight(trackWidth); bounds.setY(r.y() + r.height() / 2 - trackWidth / 2); } else if (o->style()->appearance() == SliderVerticalPart) { @@ -967,19 +1010,17 @@ bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const RenderObject::Pa const int sliderThumbWidth = 15; const int sliderThumbHeight = 15; -const int mediaSliderThumbWidth = 13; -const int mediaSliderThumbHeight = 14; void RenderThemeSafari::adjustSliderThumbSize(RenderObject* o) const { if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { o->style()->setWidth(Length(sliderThumbWidth, Fixed)); o->style()->setHeight(Length(sliderThumbHeight, Fixed)); - } else if (o->style()->appearance() == MediaSliderThumbPart) { - o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed)); - o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed)); - } - + } +#if ENABLE(VIDEO) + else if (o->style()->appearance() == MediaSliderThumbPart) + RenderMediaControls::adjustMediaSliderThumbSize(o); +#endif } bool RenderThemeSafari::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) @@ -1129,104 +1170,37 @@ bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const Ren #if ENABLE(VIDEO) bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - Node* node = o->element(); - Node* mediaNode = node ? node->shadowAncestorNode() : 0; - if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) - return false; - - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); - if (!mediaElement) - return false; - -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - paintThemePart(mediaElement->muted() ? SafariTheme::MediaUnMuteButtonPart : SafariTheme::MediaMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - Node* node = o->element(); - Node* mediaNode = node ? node->shadowAncestorNode() : 0; - if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) - return false; - - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); - if (!mediaElement) - return false; - -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - paintThemePart(mediaElement->canPlay() ? SafariTheme::MediaPlayButtonPart : SafariTheme::MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - paintThemePart(SafariTheme::MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - Node* node = o->element(); - Node* mediaNode = node ? node->shadowAncestorNode() : 0; - if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) - return false; - - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); - if (!mediaElement) - return false; - - float percentLoaded = 0; - if (MediaPlayer* player = mediaElement->player()) - if (player->duration()) - percentLoaded = player->maxTimeBuffered() / player->duration(); - -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - ASSERT(SafariThemeLibrary()); - STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, percentLoaded); -#endif - return false; + return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r); } bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - ASSERT(SafariThemeLibrary()); - -#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 - paintThemePart(SafariTheme::MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); -#endif - - return false; + return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r); } #endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h index 8ac5acf..4685238 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -46,8 +47,7 @@ class RenderStyle; class RenderThemeSafari : public RenderTheme { public: - RenderThemeSafari(); - virtual ~RenderThemeSafari(); + static PassRefPtr<RenderTheme> create(); // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of @@ -69,6 +69,8 @@ public: virtual Color platformInactiveSelectionBackgroundColor() const; virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color focusRingColor() const; + // System fonts. virtual void systemFont(int propId, FontDescription&) const; @@ -137,6 +139,9 @@ protected: #endif private: + RenderThemeSafari(); + virtual ~RenderThemeSafari(); + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins) const; // Get the control size based off the font. Used by some of the controls (like buttons). diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp index fd07b54..9491aae 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,17 +22,20 @@ #include "config.h" #include "RenderThemeWin.h" -#include "CSSStyleSheet.h" #include "CSSValueKeywords.h" -#include "Document.h" +#include "Element.h" +#include "Frame.h" #include "GraphicsContext.h" -#include "HTMLElement.h" -#include "HTMLSelectElement.h" -#include "Icon.h" #include "RenderSlider.h" +#include "Settings.h" #include "SoftLinking.h" +#include "SystemInfo.h" #include "UserAgentStyleSheets.h" +#if ENABLE(VIDEO) +#include "RenderMediaControls.h" +#endif + #include <tchar.h> /* @@ -54,10 +58,14 @@ // Textfield constants #define TFP_TEXTFIELD 1 +#define EP_EDITBORDER_NOSCROLL 6 #define TFS_READONLY 6 -// ComboBox constants (from tmschema.h) +// ComboBox constants (from vsstyle.h) #define CP_DROPDOWNBUTTON 1 +#define CP_BORDER 4 +#define CP_READONLY 5 +#define CP_DROPDOWNBUTTONRIGHT 6 // TrackBar (slider) parts #define TKP_TRACK 1 @@ -83,14 +91,6 @@ #define PBS_DISABLED 4 #define PBS_DEFAULTED 5 -// This is the fixed width IE and Firefox use for buttons on dropdown menus -static const int dropDownButtonWidth = 17; - -static const int shell32MagnifierIconIndex = 22; - -// Default font size to match Firefox. -static const float defaultControlFontPixelSize = 13; - SOFT_LINK_LIBRARY(uxtheme) SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList)) SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme)) @@ -100,20 +100,51 @@ SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE static bool haveTheme; +static const unsigned vistaMenuListButtonOutset = 1; + +using namespace std; + namespace WebCore { +// This is the fixed width IE and Firefox use for buttons on dropdown menus +static const int dropDownButtonWidth = 17; + +static const int shell32MagnifierIconIndex = 22; + +// Default font size to match Firefox. +static const float defaultControlFontPixelSize = 13; + +static const float defaultCancelButtonSize = 9; +static const float minCancelButtonSize = 5; +static const float maxCancelButtonSize = 21; +static const float defaultSearchFieldResultsDecorationSize = 13; +static const float minSearchFieldResultsDecorationSize = 9; +static const float maxSearchFieldResultsDecorationSize = 30; +static const float defaultSearchFieldResultsButtonWidth = 18; + static bool gWebKitIsBeingUnloaded; +static bool documentIsInApplicationChromeMode(const Document* document) +{ + Settings* settings = document->settings(); + return settings && settings->inApplicationChromeMode(); +} + void RenderThemeWin::setWebKitIsBeingUnloaded() { gWebKitIsBeingUnloaded = true; } +PassRefPtr<RenderTheme> RenderThemeWin::create() +{ + return adoptRef(new RenderThemeWin); +} + #if !USE(SAFARI_THEME) -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) { - static RenderThemeWin winTheme; - return &winTheme; + static RenderTheme* winTheme = RenderThemeWin::create().releaseRef(); + return winTheme; } #endif @@ -202,24 +233,24 @@ bool RenderThemeWin::supportsHover(const RenderStyle*) const Color RenderThemeWin::platformActiveSelectionBackgroundColor() const { COLORREF color = GetSysColor(COLOR_HIGHLIGHT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const { - COLORREF color = GetSysColor(COLOR_GRAYTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + // This color matches Firefox. + return Color(176, 176, 176); } Color RenderThemeWin::platformActiveSelectionForegroundColor() const { COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } Color RenderThemeWin::platformInactiveSelectionForegroundColor() const { - return Color::white; + return platformActiveSelectionForegroundColor(); } static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize) @@ -319,22 +350,23 @@ void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) co } } -bool RenderThemeWin::supportsFocus(ControlPart appearance) +bool RenderThemeWin::supportsFocus(ControlPart appearance) const { switch (appearance) { case PushButtonPart: case ButtonPart: case DefaultButtonPart: - case TextFieldPart: - case TextAreaPart: return true; - case MenulistPart: - return false; default: return false; } } +bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const +{ + return supportsFocus(style->appearance()); +} + unsigned RenderThemeWin::determineClassicState(RenderObject* o) { unsigned state = 0; @@ -376,7 +408,7 @@ unsigned RenderThemeWin::determineState(RenderObject* o) ControlPart appearance = o->style()->appearance(); if (!isEnabled(o)) result = TS_DISABLED; - else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance)) + else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance)) result = TFS_READONLY; // Readonly is supported on textfields. else if (isPressed(o)) // Active overrides hover and focused. result = TS_ACTIVE; @@ -435,6 +467,7 @@ ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o) result.m_part = DFC_SCROLL; result.m_state = determineClassicState(o); break; + case SearchFieldPart: case TextFieldPart: case TextAreaPart: result.m_part = TFP_TEXTFIELD; @@ -481,16 +514,22 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o) break; case MenulistPart: case MenulistButtonPart: - result.m_part = CP_DROPDOWNBUTTON; - result.m_state = determineState(o); + result.m_part = isRunningOnVistaOrLater() ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON; + if (isRunningOnVistaOrLater() && documentIsInApplicationChromeMode(o->document())) { + // The "readonly" look we use in application chrome mode + // only uses a "normal" look for the drop down button. + result.m_state = TS_NORMAL; + } else + result.m_state = determineState(o); break; case RadioPart: result.m_part = BP_RADIO; result.m_state = determineState(o); break; + case SearchFieldPart: case TextFieldPart: case TextAreaPart: - result.m_part = TFP_TEXTFIELD; + result.m_part = isRunningOnVistaOrLater() ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD; result.m_state = determineState(o); break; case SliderHorizontalPart: @@ -602,8 +641,20 @@ bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintIn bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - // The outer box of a menu list is just a text field. Paint it first. - drawControl(i.context, o, textFieldTheme(), ThemeData(TFP_TEXTFIELD, determineState(o)), r); + HANDLE theme; + int part; + if (haveTheme && isRunningOnVistaOrLater()) { + theme = menuListTheme(); + if (documentIsInApplicationChromeMode(o->document())) + part = CP_READONLY; + else + part = CP_BORDER; + } else { + theme = textFieldTheme(); + part = TFP_TEXTFIELD; + } + + drawControl(i.context, o, theme, ThemeData(part, determineState(o)), r); return paintMenuListButton(o, i, r); } @@ -656,6 +707,13 @@ bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::Pa buttonRect.setX(buttonRect.right() - dropDownButtonWidth); buttonRect.setWidth(dropDownButtonWidth); + if (isRunningOnVistaOrLater()) { + // Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border. + buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset); + buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset); + buttonRect.setWidth(buttonRect.width() + vistaMenuListButtonOutset); + } + drawControl(i.context, o, menuListTheme(), getThemeData(o), buttonRect); return false; @@ -697,15 +755,30 @@ void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const o->style()->setWidth(Length(sliderThumbWidth, Fixed)); o->style()->setHeight(Length(sliderThumbHeight, Fixed)); } +#if ENABLE(VIDEO) + else if (o->style()->appearance() == MediaSliderThumbPart) + RenderMediaControls::adjustMediaSliderThumbSize(o); +#endif } -void RenderThemeWin::adjustButtonInnerStyle(RenderStyle* style) const +int RenderThemeWin::buttonInternalPaddingLeft() const { - // This inner padding matches Firefox. - style->setPaddingTop(Length(1, Fixed)); - style->setPaddingRight(Length(3, Fixed)); - style->setPaddingBottom(Length(1, Fixed)); - style->setPaddingLeft(Length(3, Fixed)); + return 3; +} + +int RenderThemeWin::buttonInternalPaddingRight() const +{ + return 3; +} + +int RenderThemeWin::buttonInternalPaddingTop() const +{ + return 1; +} + +int RenderThemeWin::buttonInternalPaddingBottom() const +{ + return 1; } bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) @@ -714,44 +787,49 @@ bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::Paint } void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const -{ - // Override padding size to match AppKit text positioning. +{ + // Override paddingSize to match AppKit text positioning. const int padding = 1; style->setPaddingLeft(Length(padding, Fixed)); style->setPaddingRight(Length(padding, Fixed)); style->setPaddingTop(Length(padding, Fixed)); style->setPaddingBottom(Length(padding, Fixed)); + if (e && e->focused() && e->document()->frame()->selection()->isFocusedAndActive()) + style->setOutlineOffset(-2); } bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - Color buttonColor = (o->element() && o->element()->active()) ? Color(138, 138, 138) : Color(186, 186, 186); - - IntSize cancelSize(10, 10); - IntSize cancelRadius(cancelSize.width() / 2, cancelSize.height() / 2); - int x = r.x() + (r.width() - cancelSize.width()) / 2; - int y = r.y() + (r.height() - cancelSize.height()) / 2 + 1; - IntRect cancelBounds(IntPoint(x, y), cancelSize); - paintInfo.context->save(); - paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius); - paintInfo.context->fillRect(cancelBounds, buttonColor); - - // Draw the 'x' - IntSize xSize(3, 3); - IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize); - paintInfo.context->setStrokeColor(Color::white); - paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size()); - paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom())); - - paintInfo.context->restore(); + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // Make sure the scaled button stays square and will fit in its parent's box + bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height()))); + bounds.setWidth(bounds.height()); + + // 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); + + static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef(); + static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef(); + paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); return false; } void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize cancelSize(13, 11); - style->setWidth(Length(cancelSize.width(), Fixed)); - style->setHeight(Length(cancelSize.height(), Fixed)); + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int cancelButtonSize = lroundf(min(max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); + style->setWidth(Length(cancelButtonSize, Fixed)); + style->setHeight(Length(cancelButtonSize, Fixed)); } void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const @@ -760,46 +838,73 @@ void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector style->setWidth(Length(emptySize.width(), Fixed)); style->setHeight(Length(emptySize.height(), Fixed)); } - + void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize magnifierSize(15, 11); - style->setWidth(Length(magnifierSize.width(), Fixed)); - style->setHeight(Length(magnifierSize.height(), Fixed)); + // Scale the decoration size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierSize = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + style->setWidth(Length(magnifierSize, Fixed)); + style->setHeight(Length(magnifierSize, Fixed)); } bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + 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(min(parentBox.width(), min(parentBox.height(), bounds.height()))); bounds.setWidth(bounds.height()); - TCHAR buffer[MAX_PATH]; - UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer)); - if (!length) - return 0; + // 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); - if (_tcscat_s(buffer, TEXT("\\shell32.dll"))) - return 0; - - HICON hIcon; - if (!::ExtractIconEx(buffer, shell32MagnifierIconIndex, 0, &hIcon, 1)) - return 0; - - RefPtr<Icon> icon = Icon::create(hIcon); - icon->paint(paintInfo.context, bounds); + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); + paintInfo.context->drawImage(magnifierImage, bounds); return false; } void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize magnifierSize(15, 11); - style->setWidth(Length(magnifierSize.width(), Fixed)); - style->setHeight(Length(magnifierSize.height(), Fixed)); + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierHeight = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); + style->setWidth(Length(magnifierWidth, Fixed)); + style->setHeight(Length(magnifierHeight, Fixed)); } bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - paintSearchFieldResultsDecoration(o, paintInfo, r); + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent()) + return false; + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // Make sure the scaled decoration will fit in its parent's box + bounds.setHeight(min(parentBox.height(), bounds.height())); + bounds.setWidth(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); + + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef(); + paintInfo.context->drawImage(magnifierImage, bounds); return false; } @@ -849,4 +954,41 @@ Color RenderThemeWin::systemColor(int cssValueId) const return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } +#if ENABLE(VIDEO) +bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaSeekForwardButton, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaSlider, o, paintInfo, r); +} + +bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r); +} +#endif + } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h index 8562b22..99c2004 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h @@ -2,6 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2006, 2008 Apple Computer, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -48,8 +49,7 @@ struct ThemeData { class RenderThemeWin : public RenderTheme { public: - RenderThemeWin(); - ~RenderThemeWin(); + static PassRefPtr<RenderTheme> create(); virtual String extraDefaultStyleSheet(); virtual String extraQuirksStyleSheet(); @@ -92,7 +92,12 @@ public: virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); virtual void adjustSliderThumbSize(RenderObject*) const; - virtual void adjustButtonInnerStyle(RenderStyle*) const; + virtual bool popupOptionSupportsTextIndent() const { return true; } + + virtual int buttonInternalPaddingLeft() const; + virtual int buttonInternalPaddingRight() const; + virtual int buttonInternalPaddingTop() const; + virtual int buttonInternalPaddingBottom() const; virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); @@ -117,7 +122,22 @@ public: static void setWebKitIsBeingUnloaded(); + virtual bool supportsFocusRing(const RenderStyle*) const; + +#if ENABLE(VIDEO) + 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&); + virtual bool paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + 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&); +#endif + private: + RenderThemeWin(); + ~RenderThemeWin(); + void addIntrinsicMargins(RenderStyle*) const; void close(); @@ -126,7 +146,7 @@ private: unsigned determineSliderThumbState(RenderObject*); unsigned determineButtonState(RenderObject*); - bool supportsFocus(ControlPart); + bool supportsFocus(ControlPart) const; ThemeData getThemeData(RenderObject*); ThemeData getClassicThemeData(RenderObject* o); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp index f46ff20..79d1724 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "RenderTreeAsText.h" +#include "CSSMutableStyleDeclaration.h" #include "CharacterNames.h" #include "Document.h" #include "Frame.h" @@ -34,6 +35,7 @@ #include "HTMLNames.h" #include "InlineTextBox.h" #include "RenderBR.h" +#include "RenderInline.h" #include "RenderListMarker.h" #include "RenderTableCell.h" #include "RenderView.h" @@ -43,9 +45,11 @@ #include <wtf/Vector.h> #if ENABLE(SVG) -#include "RenderSVGRoot.h" +#include "RenderPath.h" #include "RenderSVGContainer.h" +#include "RenderSVGImage.h" #include "RenderSVGInlineText.h" +#include "RenderSVGRoot.h" #include "RenderSVGText.h" #include "SVGRenderTreeAsText.h" #endif @@ -69,7 +73,7 @@ static void writeIndent(TextStream& ts, int indent) ts << " "; } -static void printBorderStyle(TextStream& ts, const RenderObject& o, const EBorderStyle borderStyle) +static void printBorderStyle(TextStream& ts, const EBorderStyle borderStyle) { switch (borderStyle) { case BNONE: @@ -169,18 +173,46 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) if (o.style() && o.style()->zIndex()) ts << " zI: " << o.style()->zIndex(); - if (o.element()) { - String tagName = getTagName(o.element()); + if (o.node()) { + String tagName = getTagName(o.node()); if (!tagName.isEmpty()) { ts << " {" << tagName << "}"; // flag empty or unstyled AppleStyleSpan because we never // want to leave them in the DOM - if (isEmptyOrUnstyledAppleStyleSpan(o.element())) + if (isEmptyOrUnstyledAppleStyleSpan(o.node())) ts << " *empty or unstyled AppleStyleSpan*"; } } - IntRect r(o.xPos(), o.yPos(), o.width(), o.height()); + bool adjustForTableCells = o.containingBlock()->isTableCell(); + + IntRect r; + if (o.isText()) { + // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating + // many test results. + const RenderText& text = *toRenderText(&o); + IntRect linesBox = text.linesBoundingBox(); + r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height()); + if (adjustForTableCells && !text.firstTextBox()) + adjustForTableCells = false; + } else if (o.isRenderInline()) { + // FIXME: Would be better not to just dump 0, 0 as the x and y here. + const RenderInline& inlineFlow = *toRenderInline(&o); + r = IntRect(0, 0, inlineFlow.linesBoundingBox().width(), inlineFlow.linesBoundingBox().height()); + adjustForTableCells = false; + } else if (o.isTableCell()) { + // FIXME: Deliberately dump the "inner" box of table cells, since that is what current results reflect. We'd like + // to clean up the results to dump both the outer box and the intrinsic padding so that both bits of information are + // captured by the results. + const RenderTableCell& cell = static_cast<const RenderTableCell&>(o); + r = IntRect(cell.x(), cell.y() + cell.intrinsicPaddingTop(), cell.width(), cell.height() - cell.intrinsicPaddingTop() - cell.intrinsicPaddingBottom()); + } else if (o.isBox()) + r = toRenderBox(&o)->frameRect(); + + // FIXME: Temporary in order to ensure compatibility with existing layout test results. + if (adjustForTableCells) + r.move(0, -static_cast<RenderTableCell*>(o.containingBlock())->intrinsicPaddingTop()); + ts << " " << r; if (!(o.isText() && !o.isBR())) { @@ -206,17 +238,21 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) o.style()->textStrokeWidth() > 0) ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]"; - if (o.borderTop() || o.borderRight() || o.borderBottom() || o.borderLeft()) { + if (!o.isBoxModelObject()) + return ts; + + const RenderBoxModelObject& box = *toRenderBoxModelObject(&o); + if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; BorderValue prevBorder; if (o.style()->borderTop() != prevBorder) { prevBorder = o.style()->borderTop(); - if (!o.borderTop()) + if (!box.borderTop()) ts << " none"; else { - ts << " (" << o.borderTop() << "px "; - printBorderStyle(ts, o, o.style()->borderTopStyle()); + ts << " (" << box.borderTop() << "px "; + printBorderStyle(ts, o.style()->borderTopStyle()); Color col = o.style()->borderTopColor(); if (!col.isValid()) col = o.style()->color(); @@ -226,11 +262,11 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) if (o.style()->borderRight() != prevBorder) { prevBorder = o.style()->borderRight(); - if (!o.borderRight()) + if (!box.borderRight()) ts << " none"; else { - ts << " (" << o.borderRight() << "px "; - printBorderStyle(ts, o, o.style()->borderRightStyle()); + ts << " (" << box.borderRight() << "px "; + printBorderStyle(ts, o.style()->borderRightStyle()); Color col = o.style()->borderRightColor(); if (!col.isValid()) col = o.style()->color(); @@ -239,12 +275,12 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) } if (o.style()->borderBottom() != prevBorder) { - prevBorder = o.style()->borderBottom(); - if (!o.borderBottom()) + prevBorder = box.style()->borderBottom(); + if (!box.borderBottom()) ts << " none"; else { - ts << " (" << o.borderBottom() << "px "; - printBorderStyle(ts, o, o.style()->borderBottomStyle()); + ts << " (" << box.borderBottom() << "px "; + printBorderStyle(ts, o.style()->borderBottomStyle()); Color col = o.style()->borderBottomColor(); if (!col.isValid()) col = o.style()->color(); @@ -254,11 +290,11 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) if (o.style()->borderLeft() != prevBorder) { prevBorder = o.style()->borderLeft(); - if (!o.borderLeft()) + if (!box.borderLeft()) ts << " none"; else { - ts << " (" << o.borderLeft() << "px "; - printBorderStyle(ts, o, o.style()->borderLeftStyle()); + ts << " (" << box.borderLeft() << "px "; + printBorderStyle(ts, o.style()->borderLeftStyle()); Color col = o.style()->borderLeftColor(); if (!col.isValid()) col = o.style()->color(); @@ -304,14 +340,18 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run) { - ts << "text run at (" << run.m_x << "," << run.m_y << ") width " << run.m_width; + // FIXME: Table cell adjustment is temporary until results can be updated. + int y = run.m_y; + if (o.containingBlock()->isTableCell()) + y -= static_cast<RenderTableCell*>(o.containingBlock())->intrinsicPaddingTop(); + ts << "text run at (" << run.m_x << "," << y << ") width " << run.m_width; if (run.direction() == RTL || run.m_dirOverride) { ts << (run.direction() == RTL ? " RTL" : " LTR"); if (run.m_dirOverride) ts << " override"; } ts << ": " - << quoteAndEscapeNonPrintables(String(o.text()).substring(run.m_start, run.m_len)) + << quoteAndEscapeNonPrintables(String(o.text()).substring(run.start(), run.len())) << "\n"; } @@ -337,6 +377,10 @@ void write(TextStream& ts, const RenderObject& o, int indent) write(ts, static_cast<const RenderSVGInlineText&>(o), indent); return; } + if (o.isSVGImage()) { + write(ts, static_cast<const RenderSVGImage&>(o), indent); + return; + } #endif writeIndent(ts, indent); @@ -344,7 +388,7 @@ void write(TextStream& ts, const RenderObject& o, int indent) ts << o << "\n"; if (o.isText() && !o.isBR()) { - const RenderText& text = static_cast<const RenderText&>(o); + const RenderText& text = *toRenderText(&o); for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) { writeIndent(ts, indent + 1); writeTextRun(ts, text, *box); @@ -361,12 +405,12 @@ void write(TextStream& ts, const RenderObject& o, int indent) Widget* widget = static_cast<const RenderWidget&>(o).widget(); if (widget && widget->isFrameView()) { FrameView* view = static_cast<FrameView*>(widget); - RenderObject* root = view->frame()->contentRenderer(); + RenderView* root = view->frame()->contentRenderer(); if (root) { view->layout(); RenderLayer* l = root->layer(); if (l) - writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height()), indent + 1); + writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), indent + 1); } } } @@ -394,9 +438,9 @@ static void write(TextStream& ts, RenderLayer& l, ts << " scrollX " << l.scrollXOffset(); if (l.scrollYOffset()) ts << " scrollY " << l.scrollYOffset(); - if (l.renderer()->clientWidth() != l.scrollWidth()) + if (l.renderBox() && l.renderBox()->clientWidth() != l.scrollWidth()) ts << " scrollWidth " << l.scrollWidth(); - if (l.renderer()->clientHeight() != l.scrollHeight()) + if (l.renderBox() && l.renderBox()->clientHeight() != l.scrollHeight()) ts << " scrollHeight " << l.scrollHeight(); } @@ -420,7 +464,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye // Ensure our lists are up-to-date. l->updateZOrderLists(); - l->updateOverflowList(); + l->updateNormalFlowList(); bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect, rootLayer); Vector<RenderLayer*>* negList = l->negZOrderList(); @@ -435,10 +479,10 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye if (shouldPaint) write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, negList && negList->size() > 0, indent); - Vector<RenderLayer*>* overflowList = l->overflowList(); - if (overflowList) { - for (unsigned i = 0; i != overflowList->size(); ++i) - writeLayers(ts, rootLayer, overflowList->at(i), paintDirtyRect, indent); + Vector<RenderLayer*>* normalFlowList = l->normalFlowList(); + if (normalFlowList) { + for (unsigned i = 0; i != normalFlowList->size(); ++i) + writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, indent); } Vector<RenderLayer*>* posList = l->posZOrderList(); @@ -470,7 +514,7 @@ static String nodePosition(Node* node) static void writeSelection(TextStream& ts, const RenderObject* o) { - Node* n = o->element(); + Node* n = o->node(); if (!n || !n->isDocumentNode()) return; @@ -479,15 +523,15 @@ static void writeSelection(TextStream& ts, const RenderObject* o) if (!frame) return; - Selection selection = frame->selection()->selection(); + VisibleSelection selection = frame->selection()->selection(); if (selection.isCaret()) { - ts << "caret: position " << selection.start().offset() << " of " << nodePosition(selection.start().node()); + ts << "caret: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().node()); if (selection.affinity() == UPSTREAM) ts << " (upstream affinity)"; ts << "\n"; } else if (selection.isRange()) - ts << "selection start: position " << selection.start().offset() << " of " << nodePosition(selection.start().node()) << "\n" - << "selection end: position " << selection.end().offset() << " of " << nodePosition(selection.end().node()) << "\n"; + ts << "selection start: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().node()) << "\n" + << "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().node()) << "\n"; } String externalRepresentation(RenderObject* o) @@ -501,9 +545,9 @@ String externalRepresentation(RenderObject* o) #endif if (o->view()->frameView()) o->view()->frameView()->layout(); - RenderLayer* l = o->layer(); - if (l) { - writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height())); + if (o->hasLayer()) { + RenderLayer* l = toRenderBox(o)->layer(); + writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height())); writeSelection(ts, o); } return ts.release(); diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp index 3d9cb3d..246d0c0 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp @@ -35,15 +35,35 @@ #include "HTMLVideoElement.h" #include "MediaPlayer.h" +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#endif + using namespace std; namespace WebCore { using namespace HTMLNames; +static const int cDefaultWidth = 300; +static const int cDefaultHeight = 150; + RenderVideo::RenderVideo(HTMLMediaElement* video) - : RenderMedia(video, video->player() ? video->player()->naturalSize() : IntSize(300, 150)) + : 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()) + setIntrinsicSize(IntSize(cDefaultWidth, 1)); + else + setIntrinsicSize(IntSize(cDefaultWidth, cDefaultHeight)); + } } RenderVideo::~RenderVideo() @@ -68,7 +88,7 @@ void RenderVideo::videoSizeChanged() IntRect RenderVideo::videoBox() const { - IntRect contentRect = contentBox(); + IntRect contentRect = contentBoxRect(); if (intrinsicSize().isEmpty() || contentRect.isEmpty()) return IntRect(); @@ -124,13 +144,14 @@ void RenderVideo::updatePlayer() mediaPlayer->setVisible(false); return; } + +#if USE(ACCELERATED_COMPOSITING) + layer()->rendererContentChanged(); +#endif - // FIXME: This doesn't work correctly with transforms. - FloatPoint absPos = localToAbsolute(); IntRect videoBounds = videoBox(); - videoBounds.move(absPos.x(), absPos.y()); mediaPlayer->setFrameView(document()->view()); - mediaPlayer->setRect(videoBounds); + mediaPlayer->setSize(IntSize(videoBounds.width(), videoBounds.height())); mediaPlayer->setVisible(true); } @@ -234,6 +255,32 @@ void RenderVideo::calcPrefWidths() setPrefWidthsDirty(false); } +#if USE(ACCELERATED_COMPOSITING) +bool RenderVideo::supportsAcceleratedRendering() const +{ + MediaPlayer* p = player(); + if (p) + return p->supportsAcceleratedRendering(); + + return false; +} + +void RenderVideo::acceleratedRenderingStateChanged() +{ + MediaPlayer* p = player(); + if (p) + p->acceleratedRenderingStateChanged(); +} + +GraphicsLayer* RenderVideo::videoGraphicsLayer() const +{ + if (hasLayer() && layer()->isComposited()) + return layer()->backing()->graphicsLayer(); + + return 0; +} +#endif // USE(ACCELERATED_COMPOSITING) + } // namespace WebCore #endif diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h index 43c1e7b..1c7b259 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h @@ -33,6 +33,9 @@ namespace WebCore { class HTMLMediaElement; +#if USE(ACCELERATED_COMPOSITING) +class GraphicsLayer; +#endif class RenderVideo : public RenderMedia { public: @@ -41,6 +44,9 @@ public: virtual const char* renderName() const { return "RenderVideo"; } + virtual bool requiresLayer() const { return true; } + virtual bool isVideo() const { return true; } + virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty); virtual void layout(); @@ -51,9 +57,16 @@ public: virtual void calcPrefWidths(); void videoSizeChanged(); + IntRect videoBox() const; void updateFromElement(); +#if USE(ACCELERATED_COMPOSITING) + bool supportsAcceleratedRendering() const; + virtual void acceleratedRenderingStateChanged(); + GraphicsLayer* videoGraphicsLayer() const; +#endif + protected: virtual void intrinsicSizeChanged() { videoSizeChanged(); } @@ -64,8 +77,6 @@ private: bool isWidthSpecified() const; bool isHeightSpecified() const; - IntRect videoBox() const; - void updatePlayer(); }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp index 1715509..05d40bc 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp @@ -1,8 +1,6 @@ -/** - * This file is part of the HTML widget for KDE. - * +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,10 +23,19 @@ #include "Document.h" #include "Element.h" +#include "FloatQuad.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "HitTestResult.h" #include "RenderLayer.h" +#include "RenderSelectionInfo.h" +#include "RenderWidget.h" +#include "TransformState.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif namespace WebCore { @@ -50,10 +57,7 @@ RenderView::RenderView(Node* node, FrameView* view) // init RenderObject attributes setInline(false); - - // try to contrain the width to the views width - m_width = 0; - m_height = 0; + m_minPrefWidth = 0; m_maxPrefWidth = 0; @@ -73,13 +77,13 @@ RenderView::~RenderView() void RenderView::calcHeight() { if (!printing() && m_frameView) - m_height = viewHeight(); + setHeight(viewHeight()); } void RenderView::calcWidth() { if (!printing() && m_frameView) - m_width = viewWidth(); + setWidth(viewWidth()); m_marginLeft = 0; m_marginRight = 0; } @@ -96,10 +100,10 @@ void RenderView::calcPrefWidths() void RenderView::layout() { if (printing()) - m_minPrefWidth = m_maxPrefWidth = m_width; + m_minPrefWidth = m_maxPrefWidth = width(); // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. - bool relayoutChildren = !printing() && (!m_frameView || m_width != viewWidth() || m_height != viewHeight()); + bool relayoutChildren = !printing() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); if (relayoutChildren) { setChildNeedsLayout(true, false); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -117,10 +121,10 @@ void RenderView::layout() if (needsLayout()) RenderBlock::layout(); - // Ensure that docWidth() >= width() and docHeight() >= height(). - setOverflowWidth(m_width); - setOverflowHeight(m_height); - + // Reset overflowWidth and overflowHeight, since they act as a lower bound for docWidth() and docHeight(). + setOverflowWidth(width()); + setOverflowHeight(height()); + setOverflowWidth(docWidth()); setOverflowHeight(docHeight()); @@ -131,29 +135,20 @@ void RenderView::layout() setNeedsLayout(false); } -FloatPoint RenderView::localToAbsolute(FloatPoint localPoint, bool fixed, bool) const +void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool /*useTransforms*/, TransformState& transformState) const { - if (fixed && m_frameView) - localPoint += m_frameView->scrollOffset(); + // If a container was specified, and was not 0 or the RenderView, + // then we should have found it by now. + ASSERT_UNUSED(repaintContainer, !repaintContainer || repaintContainer == this); - return localPoint; -} - -FloatPoint RenderView::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool) const -{ if (fixed && m_frameView) - containerPoint -= m_frameView->scrollOffset(); - - return containerPoint; + transformState.move(m_frameView->scrollOffset()); } -FloatQuad RenderView::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const +void RenderView::mapAbsoluteToLocalPoint(bool fixed, bool /*useTransforms*/, TransformState& transformState) const { - FloatQuad quad = localQuad; if (fixed && m_frameView) - quad += m_frameView->scrollOffset(); - - return quad; + transformState.move(-m_frameView->scrollOffset()); } void RenderView::paint(PaintInfo& paintInfo, int tx, int ty) @@ -212,12 +207,20 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int) } } -void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) +bool RenderView::shouldRepaint(const IntRect& r) const { - if (printing() || ur.width() == 0 || ur.height() == 0) - return; + if (printing() || r.width() == 0 || r.height() == 0) + return false; if (!m_frameView) + return false; + + return true; +} + +void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) +{ + if (!shouldRepaint(ur)) return; // We always just invalidate the root view, since we could be an iframe that is clipped out @@ -225,7 +228,7 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) Element* elt = document()->ownerElement(); if (!elt) m_frameView->repaintContentRectangle(ur, immediate); - else if (RenderObject* obj = elt->renderer()) { + else if (RenderBox* obj = elt->renderBox()) { IntRect vr = viewRect(); IntRect r = intersection(ur, vr); @@ -240,8 +243,30 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) } } -void RenderView::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderView::repaintRectangleInViewAndCompositedLayers(const IntRect& ur, bool immediate) { + if (!shouldRepaint(ur)) + return; + + repaintViewRectangle(ur, immediate); + +#if USE(ACCELERATED_COMPOSITING) + // If we're a frame, repaintViewRectangle will have repainted via a RenderObject in the + // parent document. + if (document()->ownerElement()) + return; + + if (compositor()->inCompositingMode()) + compositor()->repaintCompositedLayersAbsoluteRect(ur); +#endif +} + +void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) +{ + // If a container was specified, and was not 0 or the RenderView, + // then we should have found it by now. + ASSERT_UNUSED(repaintContainer, !repaintContainer || repaintContainer == this); + if (printing()) return; @@ -253,17 +278,17 @@ void RenderView::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) rect = m_layer->transform()->mapRect(rect); } -void RenderView::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool) +void RenderView::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { rects.append(IntRect(tx, ty, m_layer->width(), m_layer->height())); } -void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool) +void RenderView::absoluteQuads(Vector<FloatQuad>& quads) { quads.append(FloatRect(0, 0, m_layer->width(), m_layer->height())); } -RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) +static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) { if (!object) return 0; @@ -272,21 +297,11 @@ RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) return child ? child : object->nextInPreOrderAfterChildren(); } -IntRect RenderView::selectionRect(bool clipToVisibleContent) -{ - // The virtual selectionRect() should never be called on the RenderView. - // We assert because there used to be ambiguity between - // RenderView::selectionRect(bool) and - // virtual RenderObject::selectionRect(bool) const - ASSERT_NOT_REACHED(); - return RenderBlock::selectionRect(clipToVisibleContent); -} - IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { - document()->updateRendering(); + document()->updateStyleIfNeeded(); - typedef HashMap<RenderObject*, SelectionInfo*> SelectionMap; + typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectionMap; SelectionMap selectedObjects; RenderObject* os = m_selectionStart; @@ -294,13 +309,13 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - selectedObjects.set(os, new SelectionInfo(os, clipToVisibleContent)); + selectedObjects.set(os, new RenderSelectionInfo(os, clipToVisibleContent)); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - SelectionInfo* blockInfo = selectedObjects.get(cb); + RenderSelectionInfo* blockInfo = selectedObjects.get(cb); if (blockInfo) break; - selectedObjects.set(cb, new SelectionInfo(cb, clipToVisibleContent)); + selectedObjects.set(cb, new RenderSelectionInfo(cb, clipToVisibleContent)); cb = cb->containingBlock(); } } @@ -312,14 +327,29 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const IntRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { - SelectionInfo* info = i->second; + RenderSelectionInfo* info = i->second; selRect.unite(info->rect()); delete info; } return selRect; } -void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos) +#if USE(ACCELERATED_COMPOSITING) +// Compositing layer dimensions take outline size into account, so we have to recompute layer +// bounds when it changes. +// FIXME: This is ugly; it would be nice to have a better way to do this. +void RenderView::setMaximalOutlineSize(int o) +{ + if (o != m_maximalOutlineSize) { + m_maximalOutlineSize = o; + + if (m_frameView) + m_frameView->updateCompositingLayers(FrameView::ForcedCompositingUpdate); + } +} +#endif + +void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) { // Make sure both our start and end objects are defined. // Check www.msnbc.com and try clicking around to find the case where this happened. @@ -337,14 +367,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e int oldEndPos = m_selectionEndPos; // Objects each have a single selection rect to examine. - typedef HashMap<RenderObject*, SelectionInfo*> SelectedObjectMap; + typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectedObjectMap; SelectedObjectMap oldSelectedObjects; SelectedObjectMap newSelectedObjects; // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise // the union of those rects might remain the same even when changes have occurred. - typedef HashMap<RenderBlock*, BlockSelectionInfo*> SelectedBlockMap; + typedef HashMap<RenderBlock*, RenderBlockSelectionInfo*> SelectedBlockMap; SelectedBlockMap oldSelectedBlocks; SelectedBlockMap newSelectedBlocks; @@ -353,13 +383,13 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - oldSelectedObjects.set(os, new SelectionInfo(os, true)); + oldSelectedObjects.set(os, new RenderSelectionInfo(os, true)); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - BlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb); + RenderBlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb); if (blockInfo) break; - oldSelectedBlocks.set(cb, new BlockSelectionInfo(cb)); + oldSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); cb = cb->containingBlock(); } } @@ -397,18 +427,22 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e o = o->nextInPreOrder(); } + m_cachedSelectionBounds = IntRect(); + // Now that the selection state has been updated for the new objects, walk them again and // put them in the new objects list. o = start; while (o && o != stop) { if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { - newSelectedObjects.set(o, new SelectionInfo(o, true)); + newSelectedObjects.set(o, new RenderSelectionInfo(o, true)); RenderBlock* cb = o->containingBlock(); while (cb && !cb->isRenderView()) { - BlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb); + RenderBlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb); if (blockInfo) break; - newSelectedBlocks.set(cb, new BlockSelectionInfo(cb)); + blockInfo = new RenderBlockSelectionInfo(cb); + newSelectedBlocks.set(cb, blockInfo); + m_cachedSelectionBounds.unite(blockInfo->rects()); cb = cb->containingBlock(); } } @@ -429,14 +463,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e // Have any of the old selected objects changed compared to the new selection? for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { RenderObject* obj = i->first; - SelectionInfo* newInfo = newSelectedObjects.get(obj); - SelectionInfo* oldInfo = i->second; + RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); + RenderSelectionInfo* oldInfo = i->second; if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() || (m_selectionStart == obj && oldStartPos != m_selectionStartPos) || (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) { - repaintViewRectangle(oldInfo->rect()); + oldInfo->repaint(); if (newInfo) { - repaintViewRectangle(newInfo->rect()); + newInfo->repaint(); newSelectedObjects.remove(obj); delete newInfo; } @@ -447,8 +481,8 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e // Any new objects that remain were not found in the old objects dict, and so they need to be updated. SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) { - SelectionInfo* newInfo = i->second; - repaintViewRectangle(newInfo->rect()); + RenderSelectionInfo* newInfo = i->second; + newInfo->repaint(); delete newInfo; } @@ -456,12 +490,13 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { RenderBlock* block = i->first; - BlockSelectionInfo* newInfo = newSelectedBlocks.get(block); - BlockSelectionInfo* oldInfo = i->second; + RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); + RenderBlockSelectionInfo* oldInfo = i->second; if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { - repaintViewRectangle(oldInfo->rects()); + if (blockRepaintMode == RepaintNewXOROld) + oldInfo->repaint(); if (newInfo) { - repaintViewRectangle(newInfo->rects()); + newInfo->repaint(); newSelectedBlocks.remove(block); delete newInfo; } @@ -472,15 +507,16 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) { - BlockSelectionInfo* newInfo = i->second; - repaintViewRectangle(newInfo->rects()); + RenderBlockSelectionInfo* newInfo = i->second; + newInfo->repaint(); delete newInfo; } } void RenderView::clearSelection() { - setSelection(0, -1, 0, -1); + repaintViewRectangle(m_cachedSelectionBounds); + setSelection(0, -1, 0, -1, RepaintNewMinusOld); } void RenderView::selectionStartEnd(int& startPos, int& endPos) const @@ -496,17 +532,17 @@ bool RenderView::printing() const void RenderView::updateWidgetPositions() { - RenderObjectSet::iterator end = m_widgets.end(); - for (RenderObjectSet::iterator it = m_widgets.begin(); it != end; ++it) + RenderWidgetSet::iterator end = m_widgets.end(); + for (RenderWidgetSet::iterator it = m_widgets.begin(); it != end; ++it) (*it)->updateWidgetPosition(); } -void RenderView::addWidget(RenderObject* o) +void RenderView::addWidget(RenderWidget* o) { m_widgets.add(o); } -void RenderView::removeWidget(RenderObject* o) +void RenderView::removeWidget(RenderWidget* o) { m_widgets.remove(o); } @@ -514,7 +550,7 @@ void RenderView::removeWidget(RenderObject* o) IntRect RenderView::viewRect() const { if (printing()) - return IntRect(0, 0, m_width, m_height); + return IntRect(0, 0, width(), height()); if (m_frameView) return m_frameView->visibleContentRect(); return IntRect(); @@ -522,16 +558,13 @@ IntRect RenderView::viewRect() const int RenderView::docHeight() const { - int h = m_height; - int lowestPos = lowestPosition(); - if (lowestPos > h) - h = lowestPos; + int h = lowestPosition(); // FIXME: This doesn't do any margin collapsing. // Instead of this dh computation we should keep the result // when we call RenderBlock::layout. int dh = 0; - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) + for (RenderBox* c = firstChildBox(); c; c = c->nextSiblingBox()) dh += c->height() + c->marginTop() + c->marginBottom(); if (dh > h) @@ -542,12 +575,9 @@ int RenderView::docHeight() const int RenderView::docWidth() const { - int w = m_width; - int rightmostPos = rightmostPosition(); - if (rightmostPos > w) - w = rightmostPos; + int w = rightmostPosition(); - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { + for (RenderBox* c = firstChildBox(); c; c = c->nextSiblingBox()) { int dw = c->width() + c->marginLeft() + c->marginRight(); if (dw > w) w = dw; @@ -576,9 +606,17 @@ int RenderView::viewWidth() const return width; } +float RenderView::zoomFactor() const +{ + if (m_frameView->frame() && m_frameView->frame()->shouldApplyPageZoom()) + return m_frameView->frame()->zoomFactor(); + + return 1.0f; +} + // The idea here is to take into account what object is moving the pagination point, and // thus choose the best place to chop it. -void RenderView::setBestTruncatedAt(int y, RenderObject* forRenderer, bool forcedBreak) +void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak) { // Nobody else can set a page break once we have a forced break. if (m_forcedPageBreak) @@ -591,21 +629,66 @@ void RenderView::setBestTruncatedAt(int y, RenderObject* forRenderer, bool force return; } - // prefer the widest object who tries to move the pagination point - int width = forRenderer->width(); - if (width > m_truncatorWidth) { - m_truncatorWidth = width; + // Prefer the widest object that tries to move the pagination point + IntRect boundingBox = forRenderer->borderBoundingBox(); + if (boundingBox.width() > m_truncatorWidth) { + m_truncatorWidth = boundingBox.width(); m_bestTruncatedAt = y; } } void RenderView::pushLayoutState(RenderObject* root) { - ASSERT(!m_frameView->needsFullRepaint()); + ASSERT(!doingFullRepaint()); ASSERT(m_layoutStateDisableCount == 0); ASSERT(m_layoutState == 0); m_layoutState = new (renderArena()) LayoutState(root); } +void RenderView::updateHitTestResult(HitTestResult& result, const IntPoint& point) +{ + if (result.innerNode()) + return; + + Node* node = document()->documentElement(); + if (node) { + result.setInnerNode(node); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(node); + result.setLocalPoint(point); + } +} + +#if USE(ACCELERATED_COMPOSITING) +bool RenderView::usesCompositing() const +{ + return m_compositor && m_compositor->inCompositingMode(); +} + +RenderLayerCompositor* RenderView::compositor() +{ + if (!m_compositor) + m_compositor.set(new RenderLayerCompositor(this)); + + return m_compositor.get(); +} +#endif + +void RenderView::didMoveOnscreen() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_compositor) + m_compositor->didMoveOnscreen(); +#endif +} + +void RenderView::willMoveOffscreen() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_compositor) + m_compositor->willMoveOffscreen(); +#endif +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.h b/src/3rdparty/webkit/WebCore/rendering/RenderView.h index 96597de..b0de7dd 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderView.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.h @@ -25,12 +25,18 @@ #define RenderView_h #include "FrameView.h" -#include "Frame.h" #include "LayoutState.h" #include "RenderBlock.h" +#include <wtf/OwnPtr.h> namespace WebCore { +class RenderWidget; + +#if USE(ACCELERATED_COMPOSITING) +class RenderLayerCompositor; +#endif + class RenderView : public RenderBlock { public: RenderView(Node*, FrameView*); @@ -44,30 +50,26 @@ public: virtual void calcWidth(); virtual void calcHeight(); virtual void calcPrefWidths(); - virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; - virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; - virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const; - - int docHeight() const; - int docWidth() const; // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. int viewHeight() const; int viewWidth() const; - - float zoomFactor() const { return m_frameView->frame() && m_frameView->frame()->shouldApplyPageZoom() ? m_frameView->frame()->zoomFactor() : 1.0f; } - FrameView* frameView() const { return m_frameView; } + float zoomFactor() const; - virtual bool hasOverhangingFloats() { return false; } + FrameView* frameView() const { return m_frameView; } - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); virtual void repaintViewRectangle(const IntRect&, bool immediate = false); + // Repaint the view, and all composited layers that intersect the given absolute rectangle. + // FIXME: ideally we'd never have to do this, if all repaints are container-relative. + virtual void repaintRectangleInViewAndCompositedLayers(const IntRect&, bool immediate = false); virtual void paint(PaintInfo&, int tx, int ty); virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); - void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos); + enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld }; + void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld); void clearSelection(); virtual RenderObject* selectionStart() const { return m_selectionStart; } virtual RenderObject* selectionEnd() const { return m_selectionEnd; } @@ -76,39 +78,54 @@ public: 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 setBestTruncatedAt(int y, RenderObject *forRenderer, bool forcedBreak = false); + void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false); int bestTruncatedAt() const { return m_bestTruncatedAt; } int truncatedAt() const { return m_truncatedAt; } - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); IntRect selectionBounds(bool clipToVisibleContent = true) const; +#if USE(ACCELERATED_COMPOSITING) + void setMaximalOutlineSize(int o); +#else void setMaximalOutlineSize(int o) { m_maximalOutlineSize = o; } +#endif int maximalOutlineSize() const { return m_maximalOutlineSize; } virtual IntRect viewRect() const; - virtual void selectionStartEnd(int& startPos, int& endPos) const; + void selectionStartEnd(int& startPos, int& endPos) const; IntRect printRect() const { return m_printRect; } void setPrintRect(const IntRect& r) { m_printRect = r; } void updateWidgetPositions(); - void addWidget(RenderObject*); - void removeWidget(RenderObject*); + void addWidget(RenderWidget*); + void removeWidget(RenderWidget*); // layoutDelta is used transiently during layout to store how far an object has moved from its - // last layout location, in order to repaint correctly - const IntSize& layoutDelta() const { return m_layoutDelta; } - void addLayoutDelta(const IntSize& delta) { m_layoutDelta += delta; } + // last layout location, in order to repaint correctly. + // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter. + IntSize layoutDelta() const + { + return m_layoutState ? m_layoutState->m_layoutDelta : IntSize(); + } + void addLayoutDelta(const IntSize& delta) + { + if (m_layoutState) + m_layoutState->m_layoutDelta += delta; + } + + bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); } void pushLayoutState(RenderBox* renderer, const IntSize& offset) { - if (m_layoutStateDisableCount || m_frameView->needsFullRepaint()) + if (doingFullRepaint()) return; + // We push LayoutState even if layoutState is disabled because it stores layoutDelta too. m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset); } @@ -116,24 +133,45 @@ public: void popLayoutState() { - if (m_layoutStateDisableCount || m_frameView->needsFullRepaint()) + if (doingFullRepaint()) return; LayoutState* state = m_layoutState; m_layoutState = state->m_next; state->destroy(renderArena()); } - LayoutState* layoutState() const { return m_layoutStateDisableCount ? 0 : m_layoutState; } + // 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; } // Suspends the LayoutState optimization. Used under transforms that cannot be represented by // LayoutState (common in SVG) and when manipulating the render tree during layout in ways // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around). + // Note that even when disabled, LayoutState is still used to store layoutDelta. void disableLayoutState() { m_layoutStateDisableCount++; } void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; } + virtual void updateHitTestResult(HitTestResult&, const IntPoint&); + + // Notifications that this view became visible in a window, or will be + // removed from the window. + void didMoveOnscreen(); + void willMoveOffscreen(); + +#if USE(ACCELERATED_COMPOSITING) + RenderLayerCompositor* compositor(); + bool usesCompositing() const; +#endif + +protected: + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; + private: - // selectionRect should never be called on a RenderView - virtual IntRect selectionRect(bool); + bool shouldRepaint(const IntRect& r) const; + + int docHeight() const; + int docWidth() const; protected: FrameView* m_frameView; @@ -150,26 +188,46 @@ protected: int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables. IntRect m_printRect; // Used when printing. - typedef HashSet<RenderObject*> RenderObjectSet; + typedef HashSet<RenderWidget*> RenderWidgetSet; - RenderObjectSet m_widgets; + RenderWidgetSet m_widgets; private: + IntRect m_cachedSelectionBounds; + int m_bestTruncatedAt; int m_truncatorWidth; bool m_forcedPageBreak; - IntSize m_layoutDelta; LayoutState* m_layoutState; unsigned m_layoutStateDisableCount; +#if USE(ACCELERATED_COMPOSITING) + OwnPtr<RenderLayerCompositor> m_compositor; +#endif }; +inline RenderView* toRenderView(RenderObject* o) +{ + ASSERT(!o || o->isRenderView()); + return static_cast<RenderView*>(o); +} + +inline const RenderView* toRenderView(const RenderObject* o) +{ + ASSERT(!o || o->isRenderView()); + return static_cast<const RenderView*>(o); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderView(const RenderView*); + + // Stack-based class to assist with LayoutState push/pop class LayoutStateMaintainer : Noncopyable { public: // ctor to push now - LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool shouldPush = true) + LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false) : m_view(view) - , m_shouldPushPop(shouldPush) + , m_disabled(disableState) , m_didStart(false) , m_didEnd(false) { @@ -179,7 +237,7 @@ public: // ctor to maybe push later LayoutStateMaintainer(RenderView* view) : m_view(view) - , m_shouldPushPop(true) + , m_disabled(false) , m_didStart(false) , m_didEnd(false) { @@ -190,33 +248,32 @@ public: ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). } + void push(RenderBox* root, IntSize offset) + { + ASSERT(!m_didStart); + // We push state even if disabled, because we still need to store layoutDelta + m_view->pushLayoutState(root, offset); + if (m_disabled) + m_view->disableLayoutState(); + m_didStart = true; + } + void pop() { if (m_didStart) { ASSERT(!m_didEnd); - if (m_shouldPushPop) - m_view->popLayoutState(); - else + m_view->popLayoutState(); + if (m_disabled) m_view->enableLayoutState(); m_didEnd = true; } } - void push(RenderBox* root, IntSize offset) - { - ASSERT(!m_didStart); - if (m_shouldPushPop) - m_view->pushLayoutState(root, offset); - else - m_view->disableLayoutState(); - m_didStart = true; - } - bool didPush() const { return m_didStart; } private: RenderView* m_view; - bool m_shouldPushPop : 1; // true if we should push/pop, rather than disable/enable + bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled bool m_didStart : 1; // true if we did a push or disable bool m_didEnd : 1; // true if we popped or re-enabled }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp index 1a9744a..ec2ee6a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp @@ -1,9 +1,7 @@ -/** - * This file is part of the HTML widget for KDE. - * +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,13 +25,8 @@ #include "AnimationController.h" #include "AXObjectCache.h" -#include "Document.h" -#include "Element.h" -#include "Event.h" -#include "FrameView.h" #include "GraphicsContext.h" #include "HitTestResult.h" -#include "RenderLayer.h" #include "RenderView.h" using namespace std; @@ -47,14 +40,11 @@ static HashMap<const Widget*, RenderWidget*>& widgetRendererMap() } RenderWidget::RenderWidget(Node* node) - : RenderReplaced(node) - , m_widget(0) - , m_refCount(0) + : RenderReplaced(node) + , m_widget(0) + , m_frameView(node->document()->view()) + , m_refCount(0) { - // a replaced element doesn't support being anonymous - ASSERT(node); - m_view = node->document()->view(); - view()->addWidget(this); // Reference counting is used to prevent the widget from being @@ -75,14 +65,15 @@ void RenderWidget::destroy() if (RenderView* v = view()) v->removeWidget(this); - if (AXObjectCache::accessibilityEnabled()) + if (AXObjectCache::accessibilityEnabled()) { + document()->axObjectCache()->childrenChanged(this->parent()); document()->axObjectCache()->remove(this); - + } remove(); if (m_widget) { - if (m_view) - m_view->removeChild(m_widget); + if (m_frameView) + m_frameView->removeChild(m_widget); widgetRendererMap().remove(m_widget); } @@ -90,33 +81,33 @@ void RenderWidget::destroy() if (hasOverrideSize()) setOverrideSize(-1); - RenderLayer* layer = m_layer; - RenderArena* arena = renderArena(); - - if (layer) - layer->clearClipRects(); - if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); + if (hasLayer()) { + layer()->clearClipRects(); + setHasLayer(false); + destroyLayer(); + } + + // 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(); setNode(0); deref(arena); - - if (layer) - layer->destroy(arena); } RenderWidget::~RenderWidget() { ASSERT(m_refCount <= 0); - deleteWidget(); + clearWidget(); } void RenderWidget::setWidgetGeometry(const IntRect& frame) { - if (element() && m_widget->frameRect() != frame) { + if (node() && m_widget->frameRect() != frame) { RenderArena* arena = ref(); - RefPtr<Node> protectedElement(element()); + RefPtr<Node> protectedElement(node()); m_widget->setFrameRect(frame); deref(arena); } @@ -128,7 +119,7 @@ void RenderWidget::setWidget(Widget* widget) if (m_widget) { m_widget->removeFromParent(); widgetRendererMap().remove(m_widget); - deleteWidget(); + clearWidget(); } m_widget = widget; if (m_widget) { @@ -144,7 +135,7 @@ void RenderWidget::setWidget(Widget* widget) else m_widget->show(); } - m_view->addChild(m_widget); + m_frameView->addChild(m_widget); } } } @@ -156,7 +147,7 @@ void RenderWidget::layout() setNeedsLayout(false); } -void RenderWidget::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderReplaced::styleDidChange(diff, oldStyle); if (m_widget) { @@ -172,8 +163,8 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) if (!shouldPaint(paintInfo, tx, ty)) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); @@ -183,14 +174,26 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) return; } - if (!m_view || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) + if (!m_frameView || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) return; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) - paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true); + paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif + bool clipToBorderRadius = style()->overflowX() != OVISIBLE && style()->hasBorderRadius(); + if (clipToBorderRadius) { + // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. + paintInfo.context->save(); + + IntSize topLeft, topRight, bottomLeft, bottomRight; + IntRect borderRect = IntRect(tx, ty, width(), height()); + style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight); + + paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight); + } + 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 @@ -200,11 +203,28 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) // 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. m_widget->paint(paintInfo.context, paintInfo.rect); + + if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget)->useSlowRepaints()) { + ASSERT(!paintInfo.overlapTestRequests->contains(this)); + paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); + } } + if (clipToBorderRadius) + paintInfo.context->restore(); + // Paint a partially transparent wash over selected widgets. - if (isSelected() && !document()->printing()) + if (isSelected() && !document()->printing()) { + // FIXME: selectionRect() is in absolute, not painting coordinates. paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor()); + } +} + +void RenderWidget::setOverlapTestResult(bool isOverlapped) +{ + ASSERT(m_widget); + ASSERT(m_widget->isFrameView()); + static_cast<FrameView*>(m_widget)->setIsOverlapped(isOverlapped); } void RenderWidget::deref(RenderArena *arena) @@ -222,27 +242,27 @@ void RenderWidget::updateWidgetPosition() FloatPoint absPos = localToAbsolute(); absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); - int width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - int height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); - IntRect newBounds(absPos.x(), absPos.y(), width, height); + IntRect newBounds(absPos.x(), absPos.y(), w, h); IntRect oldBounds(m_widget->frameRect()); - if (newBounds != oldBounds) { - // The widget changed positions. Update the frame geometry. - if (checkForRepaintDuringLayout()) { - RenderView* v = view(); - if (!v->printing()) { - v->repaintViewRectangle(oldBounds); - v->repaintViewRectangle(newBounds); - } - } - + bool boundsChanged = newBounds != oldBounds; + if (boundsChanged) { RenderArena* arena = ref(); - element()->ref(); + node()->ref(); m_widget->setFrameRect(newBounds); - element()->deref(); + node()->deref(); deref(arena); } + + // 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()) { + FrameView* frameView = static_cast<FrameView*>(m_widget); + if (boundsChanged || frameView->needsLayout()) + frameView->layout(); + } } void RenderWidget::setSelectionState(SelectionState state) @@ -254,9 +274,17 @@ void RenderWidget::setSelectionState(SelectionState state) } } -void RenderWidget::deleteWidget() +void RenderWidget::clearWidget() +{ + Widget* widget = m_widget; + m_widget = 0; + if (widget) + deleteWidget(widget); +} + +void RenderWidget::deleteWidget(Widget* widget) { - delete m_widget; + delete widget; } RenderWidget* RenderWidget::find(const Widget* widget) @@ -270,8 +298,8 @@ bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& res bool inside = RenderReplaced::nodeAtPoint(request, result, x, y, tx, ty, action); // Check to see if we are really over the widget itself (and not just in the border/padding area). - if (inside && !hadResult && result.innerNode() == element()) - result.setIsOverWidget(contentBox().contains(result.localPoint())); + if (inside && !hadResult && result.innerNode() == node()) + result.setIsOverWidget(contentBoxRect().contains(result.localPoint())); return inside; } diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h index a64bb54..d23dbb3 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h +++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h @@ -1,8 +1,6 @@ /* - * This file is part of the HTML widget for KDE. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,51 +22,51 @@ #ifndef RenderWidget_h #define RenderWidget_h +#include "OverlapTestRequestClient.h" #include "RenderReplaced.h" namespace WebCore { class Widget; -class RenderWidget : public RenderReplaced { +class RenderWidget : public RenderReplaced, private OverlapTestRequestClient { public: - RenderWidget(Node*); virtual ~RenderWidget(); - virtual bool isWidget() const { return true; } + Widget* widget() const { return m_widget; } + virtual void setWidget(Widget*); - virtual void paint(PaintInfo&, int tx, int ty); + static RenderWidget* find(const Widget*); - virtual void destroy(); - virtual void layout(); + void updateWidgetPosition(); - Widget* widget() const { return m_widget; } - static RenderWidget* find(const Widget*); +protected: + RenderWidget(Node*); - RenderArena* ref() { ++m_refCount; return renderArena(); } - void deref(RenderArena*); + FrameView* frameView() const { return m_frameView; } - virtual void setSelectionState(SelectionState); + void clearWidget(); - virtual void updateWidgetPosition(); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void layout(); - virtual void setWidget(Widget*); +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 deleteWidget(Widget*); + virtual void setOverlapTestResult(bool); -protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - -private: void setWidgetGeometry(const IntRect&); - virtual void deleteWidget(); + RenderArena* ref() { ++m_refCount; return renderArena(); } + void deref(RenderArena*); -protected: Widget* m_widget; - FrameView* m_view; - -private: + FrameView* m_frameView; int m_refCount; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp index bb88f24..ed125ee 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp @@ -74,10 +74,15 @@ void RootInlineBox::detachEllipsisBox(RenderArena* arena) } } +RenderLineBoxList* RootInlineBox::rendererLineBoxes() const +{ + return block()->lineBoxes(); +} + void RootInlineBox::clearTruncation() { if (m_hasEllipsisBox) { - detachEllipsisBox(m_object->renderArena()); + detachEllipsisBox(renderer()->renderArena()); InlineFlowBox::clearTruncation(); } } @@ -94,13 +99,13 @@ bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxE return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth); } -void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, +void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, InlineBox* markupBox) { // Create an ellipsis box. - EllipsisBox* ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this, - ellipsisWidth - (markupBox ? markupBox->width() : 0), - yPos(), height(), baseline(), !prevRootBox(), + EllipsisBox* ellipsisBox = new (renderer()->renderArena()) EllipsisBox(renderer(), ellipsisStr, this, + ellipsisWidth - (markupBox ? markupBox->width() : 0), height(), + y(), !prevRootBox(), markupBox); if (!gEllipsisBoxMap) @@ -108,8 +113,9 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, in gEllipsisBoxMap->add(this, ellipsisBox); m_hasEllipsisBox = true; - if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) { - ellipsisBox->m_x = xPos() + width(); + // FIXME: Do we need an RTL version of this? + if (ltr && (x() + width() + ellipsisWidth) <= blockRightEdge) { + ellipsisBox->m_x = x() + width(); return; } @@ -117,20 +123,20 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, in // of that glyph. Mark all of the objects that intersect the ellipsis box as not painting (as being // truncated). bool foundBox = false; - ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); + ellipsisBox->m_x = placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, foundBox); } -int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) +int RootInlineBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox) { - int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); + int result = InlineFlowBox::placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, foundBox); if (result == -1) - result = ltr ? blockEdge - ellipsisWidth : blockEdge; + result = ltr ? blockRightEdge - ellipsisWidth : blockLeftEdge; return result; } void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& paintInfo, int tx, int ty) const { - if (m_hasEllipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE && + if (m_hasEllipsisBox && renderer()->shouldPaintWithinRoot(paintInfo) && renderer()->style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) ellipsisBox()->paint(paintInfo, tx, ty); } @@ -139,7 +145,7 @@ void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& paintInfo, int tx, void RootInlineBox::addHighlightOverflow() { - Frame* frame = object()->document()->frame(); + Frame* frame = renderer()->document()->frame(); if (!frame) return; Page* page = frame->page(); @@ -148,17 +154,17 @@ void RootInlineBox::addHighlightOverflow() // Highlight acts as a selection inflation. FloatRect rootRect(0, selectionTop(), width(), selectionHeight()); - IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(object()->node(), object()->style()->highlight(), rootRect)); + IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect)); setHorizontalOverflowPositions(min(leftOverflow(), inflatedRect.x()), max(rightOverflow(), inflatedRect.right())); setVerticalOverflowPositions(min(topOverflow(), inflatedRect.y()), max(bottomOverflow(), inflatedRect.bottom())); } void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType) { - if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) + if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; - Frame* frame = object()->document()->frame(); + Frame* frame = renderer()->document()->frame(); if (!frame) return; Page* page = frame->page(); @@ -166,10 +172,10 @@ void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int return; // Get the inflated rect so that we can properly hit test. - FloatRect rootRect(tx + xPos(), ty + selectionTop(), width(), selectionHeight()); - FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(object()->node(), highlightType, rootRect); + FloatRect rootRect(tx + x(), ty + selectionTop(), width(), selectionHeight()); + FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(renderer()->node(), highlightType, rootRect); if (inflatedRect.intersects(paintInfo.rect)) - page->chrome()->client()->paintCustomHighlight(object()->node(), highlightType, rootRect, rootRect, false, true); + page->chrome()->client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true); } #endif @@ -179,7 +185,7 @@ void RootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) InlineFlowBox::paint(paintInfo, tx, ty); paintEllipsisBox(paintInfo, tx, ty); #if PLATFORM(MAC) - RenderStyle* styleToUse = object()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(m_firstLine); if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(paintInfo, tx, ty, styleToUse->highlight()); #endif @@ -189,7 +195,7 @@ bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re { if (m_hasEllipsisBox && visibleToHitTesting()) { if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } } @@ -210,10 +216,10 @@ void RootInlineBox::adjustPosition(int dx, int dy) void RootInlineBox::childRemoved(InlineBox* box) { - if (box->object() == m_lineBreakObj) + if (box->renderer() == m_lineBreakObj) setLineBreakInfo(0, 0, BidiStatus()); - for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->object(); prev = prev->prevRootBox()) { + for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->renderer(); prev = prev->prevRootBox()) { prev->setLineBreakInfo(0, 0, BidiStatus()); prev->markDirty(); } @@ -232,26 +238,36 @@ GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBl InlineBox* firstBox = firstSelectedBox(); InlineBox* lastBox = lastSelectedBox(); if (leftGap) - result.uniteLeft(block()->fillLeftSelectionGap(firstBox->parent()->object(), - firstBox->xPos(), selTop, selHeight, + result.uniteLeft(block()->fillLeftSelectionGap(firstBox->parent()->renderer(), + firstBox->x(), selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); if (rightGap) - result.uniteRight(block()->fillRightSelectionGap(lastBox->parent()->object(), - lastBox->xPos() + lastBox->width(), selTop, selHeight, + result.uniteRight(block()->fillRightSelectionGap(lastBox->parent()->renderer(), + lastBox->x() + lastBox->width(), selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); + // When dealing with bidi text, a non-contiguous selection region is possible. + // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out + // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the + // selection will look like (underline denotes selection): + // |aaa|bbb|AAA| + // ___ _ + // We can see that the |bbb| run is not part of the selection while the runs around it are. if (firstBox && firstBox != lastBox) { // Now fill in any gaps on the line that occurred between two selected elements. - int lastX = firstBox->xPos() + firstBox->width(); + int lastX = firstBox->x() + firstBox->width(); + bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::SelectionNone; for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) { if (box->selectionState() != RenderObject::SelectionNone) { - result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(), - lastX + tx, selTop + ty, - box->xPos() - lastX, selHeight, paintInfo)); - lastX = box->xPos() + box->width(); + if (isPreviousBoxSelected) // VisibleSelection may be non-contiguous, see comment above. + result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->renderer(), + lastX + tx, selTop + ty, + box->x() - lastX, selHeight, paintInfo)); + lastX = box->x() + box->width(); } if (box == lastBox) break; + isPreviousBoxSelected = box->selectionState() != RenderObject::SelectionNone; } } @@ -316,10 +332,10 @@ int RootInlineBox::selectionTop() // This line has actually been moved further down, probably from a large line-height, but possibly because the // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous // line's bottom overflow if the offsets are greater on both sides. - int prevLeft = block()->leftOffset(prevBottom); - int prevRight = block()->rightOffset(prevBottom); - int newLeft = block()->leftOffset(selectionTop); - int newRight = block()->rightOffset(selectionTop); + int prevLeft = block()->leftOffset(prevBottom, !prevRootBox()); + int prevRight = block()->rightOffset(prevBottom, !prevRootBox()); + int newLeft = block()->leftOffset(selectionTop, !prevRootBox()); + int newRight = block()->rightOffset(selectionTop, !prevRootBox()); if (prevLeft > newLeft || prevRight < newRight) return selectionTop; } @@ -329,12 +345,12 @@ int RootInlineBox::selectionTop() RenderBlock* RootInlineBox::block() const { - return static_cast<RenderBlock*>(m_object); + return toRenderBlock(renderer()); } -bool isEditableLeaf(InlineBox* leaf) +static bool isEditableLeaf(InlineBox* leaf) { - return leaf && leaf->object() && leaf->object()->element() && leaf->object()->element()->isContentEditable(); + return leaf && leaf->renderer() && leaf->renderer()->node() && leaf->renderer()->node()->isContentEditable(); } InlineBox* RootInlineBox::closestLeafChildForXPos(int x, bool onlyEditableLeaves) @@ -345,19 +361,19 @@ InlineBox* RootInlineBox::closestLeafChildForXPos(int x, bool onlyEditableLeaves return firstLeaf; // Avoid returning a list marker when possible. - if (x <= firstLeaf->m_x && !firstLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf))) + if (x <= firstLeaf->m_x && !firstLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf))) // The x coordinate is less or equal to left edge of the firstLeaf. // Return it. return firstLeaf; - if (x >= lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf))) + if (x >= lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf))) // The x coordinate is greater or equal to right edge of the lastLeaf. // Return it. return lastLeaf; InlineBox* closestLeaf = 0; for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) { - if (!leaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) { + if (!leaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) { closestLeaf = leaf; if (x < leaf->m_x + leaf->m_width) // The x coordinate is less than the right edge of the box. @@ -394,12 +410,28 @@ EllipsisBox* RootInlineBox::ellipsisBox() const void RootInlineBox::setVerticalOverflowPositions(int top, int bottom) { if (!m_overflow) { - if (top == m_y && bottom == m_y + m_height) + const Font& font = renderer()->style(m_firstLine)->font(); + if (top == m_y && bottom == m_y + font.height()) return; - m_overflow = new (m_object->renderArena()) Overflow(this); + m_overflow = new (renderer()->renderArena()) Overflow(this); } m_overflow->m_topOverflow = top; m_overflow->m_bottomOverflow = bottom; } +void RootInlineBox::removeLineBoxFromRenderObject() +{ + block()->lineBoxes()->removeLineBox(this); +} + +void RootInlineBox::extractLineBoxFromRenderObject() +{ + block()->lineBoxes()->extractLineBox(this); +} + +void RootInlineBox::attachLineBoxToRenderObject() +{ + block()->lineBoxes()->attachLineBox(this); +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h index 4724110..171be9d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h @@ -28,9 +28,10 @@ namespace WebCore { -class BidiStatus; class EllipsisBox; class HitTestResult; + +struct BidiStatus; struct GapRects; class RootInlineBox : public InlineFlowBox { @@ -43,7 +44,7 @@ public: { } - virtual bool isRootInlineBox() { return true; } + virtual bool isRootInlineBox() const { return true; } virtual void destroy(RenderArena*); void detachEllipsisBox(RenderArena*); @@ -53,16 +54,18 @@ public: virtual void adjustPosition(int dx, int dy); - virtual int topOverflow() { return m_overflow ? m_overflow->m_topOverflow : m_y; } - virtual int bottomOverflow() { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_height; } - virtual int leftOverflow() { return m_overflow ? m_overflow->m_leftOverflow : m_x; } - virtual int rightOverflow() { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; } + virtual int topOverflow() const { return m_overflow ? m_overflow->m_topOverflow : m_y; } + virtual int bottomOverflow() const { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_renderer->style(m_firstLine)->font().height(); } + virtual int leftOverflow() const { return m_overflow ? m_overflow->m_leftOverflow : m_x; } + virtual int rightOverflow() const { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; } virtual void setVerticalOverflowPositions(int top, int bottom); void setHorizontalOverflowPositions(int left, int right); virtual void setVerticalSelectionPositions(int top, int bottom); + virtual RenderLineBoxList* rendererLineBoxes() const; + #if ENABLE(SVG) virtual void computePerCharacterLayoutInformation() { } #endif @@ -83,8 +86,8 @@ public: void childRemoved(InlineBox* box); bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth); - void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox* markupBox = 0); - virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox); + void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, InlineBox* markupBox = 0); + virtual int placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox); EllipsisBox* ellipsisBox() const; @@ -114,20 +117,24 @@ public: RenderBlock* block() const; int selectionTop(); - int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + m_height; } + int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + height(); } int selectionHeight() { return max(0, selectionBottom() - selectionTop()); } InlineBox* closestLeafChildForXPos(int x, bool onlyEditableLeaves = false); - Vector<RenderObject*>& floats() + Vector<RenderBox*>& floats() { ASSERT(!isDirty()); if (!m_overflow) - m_overflow = new (m_object->renderArena()) Overflow(this); + m_overflow = new (m_renderer->renderArena()) Overflow(this); return m_overflow->floats; } - Vector<RenderObject*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; } + Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; } + + virtual void extractLineBoxFromRenderObject(); + virtual void attachLineBoxToRenderObject(); + virtual void removeLineBoxFromRenderObject(); protected: // Normally we are only as tall as the style on our block dictates, but we might have content @@ -138,11 +145,11 @@ protected: struct Overflow { Overflow(RootInlineBox* box) : m_topOverflow(box->m_y) - , m_bottomOverflow(box->m_y + box->m_height) + , m_bottomOverflow(box->m_y + box->height()) , m_leftOverflow(box->m_x) , m_rightOverflow(box->m_x + box->m_width) , m_selectionTop(box->m_y) - , m_selectionBottom(box->m_y + box->m_height) + , m_selectionBottom(box->m_y + box->height()) { } @@ -158,7 +165,7 @@ protected: int m_selectionBottom; // Floats hanging off the line are pushed into this vector during layout. It is only // good for as long as the line has not been marked dirty. - Vector<RenderObject*> floats; + Vector<RenderBox*> floats; private: void* operator new(size_t) throw(); }; @@ -184,7 +191,7 @@ inline void RootInlineBox::setHorizontalOverflowPositions(int left, int right) if (!m_overflow) { if (left == m_x && right == m_x + m_width) return; - m_overflow = new (m_object->renderArena()) Overflow(this); + m_overflow = new (m_renderer->renderArena()) Overflow(this); } m_overflow->m_leftOverflow = left; m_overflow->m_rightOverflow = right; @@ -193,9 +200,10 @@ inline void RootInlineBox::setHorizontalOverflowPositions(int left, int right) inline void RootInlineBox::setVerticalSelectionPositions(int top, int bottom) { if (!m_overflow) { - if (top == m_y && bottom == m_y + m_height) + const Font& font = m_renderer->style(m_firstLine)->font(); + if (top == m_y && bottom == m_y + font.height()) return; - m_overflow = new (m_object->renderArena()) Overflow(this); + m_overflow = new (m_renderer->renderArena()) Overflow(this); } m_overflow->m_selectionTop = top; m_overflow->m_selectionBottom = bottom; diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp index 89bab2d..8871a75 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp @@ -274,7 +274,7 @@ void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float angleStack.isEmpty() && baselineShiftStack.isEmpty() && curx == 0.0f && cury == 0.0f; - RenderSVGTextPath* textPath = static_cast<RenderSVGTextPath*>(flowBox->object()); + RenderSVGTextPath* textPath = static_cast<RenderSVGTextPath*>(flowBox->renderer()); Path path = textPath->layoutPath(); float baselineShift = calculateBaselineShift(textPath); @@ -521,7 +521,7 @@ TransformationMatrix SVGChar::characterTransform() const ctm.rotate(angle); if (pathData) { - ctm.scale(pathData->xScale, pathData->yScale); + ctm.scaleNonUniform(pathData->xScale, pathData->yScale); ctm.translate(pathData->xShift, pathData->yShift); ctm.rotate(pathData->orientationAngle); } diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp index 3ea1193..2649664 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp @@ -43,9 +43,10 @@ int SVGInlineFlowBox::placeBoxesHorizontally(int, int&, int&, bool&) return 0; } -void SVGInlineFlowBox::verticallyAlignBoxes(int&) +int SVGInlineFlowBox::verticallyAlignBoxes(int) { // no-op + return 0; } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h index 96c5d4a..1aa2637 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h @@ -33,12 +33,19 @@ class SVGInlineFlowBox : public InlineFlowBox { public: SVGInlineFlowBox(RenderObject* obj) : InlineFlowBox(obj) + , m_height(0) { } + virtual int svgBoxHeight() const { return m_height; } + void setHeight(int h) { m_height = h; } + virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); + +private: + int m_height; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp index 5f59700..d0fa9ae 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp @@ -38,12 +38,11 @@ #include <float.h> -using std::max; - namespace WebCore { SVGInlineTextBox::SVGInlineTextBox(RenderObject* obj) : InlineTextBox(obj) + , m_height(0) { } @@ -77,7 +76,7 @@ SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { ASSERT(style); - return style->font().floatWidth(svgTextRunForInlineTextBox(textObject()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); + return style->font().floatWidth(svgTextRunForInlineTextBox(textRenderer()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); } float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int, int) const @@ -125,14 +124,14 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker { , m_distance(FLT_MAX) , m_x(x) , m_y(y) - , m_offset(0) + , m_offsetOfHitCharacter(0) { } void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { - RenderStyle* style = textBox->textObject()->style(); + RenderStyle* style = textBox->textRenderer()->style(); Vector<SVGChar>::iterator closestCharacter = 0; unsigned int closestOffset = UINT_MAX; @@ -164,7 +163,7 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker { if (closestOffset != UINT_MAX) { // Record current chunk, if it contains the current closest character next to the mouse. m_character = closestCharacter; - m_offset = closestOffset; + m_offsetOfHitCharacter = closestOffset; } } @@ -173,12 +172,12 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker { return m_character; } - int offset() const + int offsetOfHitCharacter() const { if (!m_character) return 0; - return m_offset; + return m_offsetOfHitCharacter; } private: @@ -187,7 +186,7 @@ private: int m_x; int m_y; - int m_offset; + int m_offsetOfHitCharacter; }; // Helper class for selectionRect() @@ -199,7 +198,7 @@ struct SVGInlineTextBoxSelectionRectWalker { void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { - RenderStyle* style = textBox->textObject()->style(); + RenderStyle* style = textBox->textRenderer()->style(); for (Vector<SVGChar>::iterator it = start; it != end; ++it) { if (it->isHidden()) @@ -221,7 +220,7 @@ private: FloatRect m_selectionRect; }; -SVGChar* SVGInlineTextBox::closestCharacterToPosition(int x, int y, int& offset) const +SVGChar* SVGInlineTextBox::closestCharacterToPosition(int x, int y, int& offsetOfHitCharacter) const { SVGRootInlineBox* rootBox = svgRootInlineBox(); if (!rootBox) @@ -232,25 +231,30 @@ SVGChar* SVGInlineTextBox::closestCharacterToPosition(int x, int y, int& offset) rootBox->walkTextChunks(&walker, this); - offset = walkerCallback.offset(); + offsetOfHitCharacter = walkerCallback.offsetOfHitCharacter(); return walkerCallback.character(); } -bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const +bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& closestOffsetInBox) const { - SVGChar* charAtPosPtr = closestCharacterToPosition(x, y, offset); + int offsetOfHitCharacter = 0; + SVGChar* charAtPosPtr = closestCharacterToPosition(x, y, offsetOfHitCharacter); if (!charAtPosPtr) return false; SVGChar& charAtPos = *charAtPosPtr; - RenderStyle* style = textObject()->style(m_firstLine); - FloatRect glyphRect = calculateGlyphBoundaries(style, offset, charAtPos); + RenderStyle* style = textRenderer()->style(m_firstLine); + FloatRect glyphRect = calculateGlyphBoundaries(style, offsetOfHitCharacter, charAtPos); + // FIXME: Why? if (direction() == RTL) - offset++; + offsetOfHitCharacter++; + + // The caller actually the closest offset before/after the hit char + // closestCharacterToPosition returns us offsetOfHitCharacter. + closestOffsetInBox = offsetOfHitCharacter; - // FIXME: todo list - // (#13910) This code does not handle bottom-to-top/top-to-bottom vertical text. + // FIXME: (bug 13910) This code does not handle bottom-to-top/top-to-bottom vertical text. // Check whether y position hits the current character if (y < charAtPos.y - glyphRect.height() || y > charAtPos.y) @@ -258,21 +262,21 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const // Check whether x position hits the current character if (x < charAtPos.x) { - if (offset > 0 && direction() == LTR) + if (closestOffsetInBox > 0 && direction() == LTR) return true; - else if (offset < (int) end() && direction() == RTL) + else if (closestOffsetInBox < (int) end() && direction() == RTL) return true; return false; } - // If we are past the last glyph of this box, don't mark it as 'hit' anymore. - if (x >= charAtPos.x + glyphRect.width() && offset == (int) end()) - return false; - - // Snap to character at half of it's advance + // Adjust the closest offset to after the char if x was after the char midpoint if (x >= charAtPos.x + glyphRect.width() / 2.0) - offset += direction() == RTL ? -1 : 1; + closestOffsetInBox += direction() == RTL ? -1 : 1; + + // If we are past the last glyph of this box, don't mark it as 'hit' + if (x >= charAtPos.x + glyphRect.width() && closestOffsetInBox == (int) end()) + return false; return true; } @@ -296,8 +300,8 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, ASSERT(!isLineBreak()); IntRect rect = selectionRect(0, 0, 0, len()); - if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { - object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (renderer()->style()->visibility() == VISIBLE && rect.contains(x, y)) { + renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -324,12 +328,12 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos) void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGPaintServer* activePaintServer) { - if (object()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline) + if (renderer()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline) return; ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); - RenderText* text = textObject(); + RenderText* text = textRenderer(); ASSERT(text); bool isPrinting = text->document()->printing(); @@ -346,9 +350,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t // Set our font RenderStyle* styleToUse = text->style(isFirstLineStyle()); - const Font* font = &styleToUse->font(); - if (*font != paintInfo.context->font()) - paintInfo.context->setFont(*font); + const Font& font = styleToUse->font(); TransformationMatrix ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) @@ -365,8 +367,8 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t if (containsComposition && !useCustomUnderlines) paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font, - text->document()->frame()->editor()->compositionStart(), - text->document()->frame()->editor()->compositionEnd()); + text->document()->frame()->editor()->compositionStart(), + text->document()->frame()->editor()->compositionEnd()); paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true); @@ -395,7 +397,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t run.setActivePaintServer(activePaintServer); #endif - paintInfo.context->drawText(run, origin); + paintInfo.context->drawText(font, run, origin); if (paintInfo.phase != PaintPhaseSelection) { paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false); @@ -434,7 +436,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t paintInfo.context->concatCTM(ctm.inverse()); } -void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar, const UChar*, int length, GraphicsContext* p, RenderStyle* style, const Font* f) +void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar, const UChar*, int length, GraphicsContext* p, RenderStyle* style, const Font& font) { if (selectionState() == RenderObject::SelectionNone) return; @@ -446,7 +448,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar return; Color textColor = style->color(); - Color color = object()->selectionBackgroundColor(); + Color color = renderer()->selectionBackgroundColor(); if (!color.isValid() || color.alpha() == 0) return; @@ -473,9 +475,9 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar p->save(); int adjust = startPos >= boxStartOffset ? boxStartOffset : 0; - p->drawHighlightForText(svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), - IntPoint((int) svgChar.x, (int) svgChar.y - f->ascent()), - f->ascent() + f->descent(), color, startPos - adjust, endPos - adjust); + 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); p->restore(); } @@ -498,7 +500,7 @@ static inline Path pathForDecoration(ETextDecoration decoration, RenderObject* o void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsContext* context, int tx, int ty, int width, const SVGChar& svgChar, const SVGTextDecorationInfo& info) { - if (object()->style()->visibility() != VISIBLE) + if (renderer()->style()->visibility() != VISIBLE) return; // This function does NOT accept combinated text decorations. It's meant to be invoked for just one. @@ -510,10 +512,11 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte if (!isFilled && !isStroked) return; + int baseline = renderer()->style(m_firstLine)->font().ascent(); if (decoration == UNDERLINE) - ty += m_baseline; + ty += baseline; else if (decoration == LINE_THROUGH) - ty += 2 * m_baseline / 3; + ty += 2 * baseline / 3; context->save(); context->beginPath(); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h index 1ddc23a..410218d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h @@ -29,14 +29,18 @@ namespace WebCore { - class SVGChar; class SVGRootInlineBox; - class SVGTextDecorationInfo; + + struct SVGChar; + struct SVGTextDecorationInfo; class SVGInlineTextBox : public InlineTextBox { public: SVGInlineTextBox(RenderObject* obj); + virtual int svgBoxHeight() const { return m_height; } + void setHeight(int h) { m_height = h; } + virtual int selectionTop(); virtual int selectionHeight(); @@ -50,7 +54,7 @@ namespace WebCore { void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGPaintServer*); // SVGs custom paint selection method - void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font*); + void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&); // SVGs custom paint decoration method void paintDecoration(ETextDecoration, GraphicsContext*, int tx, int ty, int width, const SVGChar&, const SVGTextDecorationInfo&); @@ -67,6 +71,8 @@ namespace WebCore { private: friend class RenderSVGInlineText; bool svgCharacterHitsPosition(int x, int y, int& offset) const; + + int m_height; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp index c88e8e8..f3f2b8c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp @@ -2,6 +2,7 @@ * 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. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,7 +26,6 @@ #if ENABLE(SVG) #include "SVGRenderSupport.h" -#include "TransformationMatrix.h" #include "ImageBuffer.h" #include "RenderObject.h" #include "RenderSVGContainer.h" @@ -35,14 +35,50 @@ #include "SVGResourceMasker.h" #include "SVGStyledElement.h" #include "SVGURIReference.h" +#include "TransformState.h" +#include "TransformationMatrix.h" +#include <wtf/UnusedParam.h> namespace WebCore { -void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter) -{ - SVGElement* svgElement = static_cast<SVGElement*>(object->element()); - ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); +IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer) +{ + // Return early for any cases where we don't actually paint + if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent()) + return IntRect(); + + // Pass our local paint rect to computeRectForRepaint() which will + // map to parent coords and recurse up the parent chain. + IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates()); + object->computeRectForRepaint(repaintContainer, repaintRect); + return repaintRect; +} + +void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + // 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); +} + +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. + 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) +{ +#if !ENABLE(FILTERS) + UNUSED_PARAM(filter); + UNUSED_PARAM(rootFilter); +#endif + ASSERT(object); + SVGElement* svgElement = static_cast<SVGElement*>(object->node()); + ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); const RenderStyle* style = object->style(); @@ -58,7 +94,7 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa paintInfo.context->beginTransparencyLayer(opacity); } -#if ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) AtomicString filterId(svgStyle->filter()); #endif @@ -67,7 +103,7 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa Document* document = object->document(); -#if ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) SVGResourceFilter* newFilter = getFilterById(document, filterId); if (newFilter == rootFilter) { // Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>. @@ -81,10 +117,10 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa SVGResourceClipper* clipper = getClipperById(document, clipperId); SVGResourceMasker* masker = getMaskerById(document, maskerId); -#if ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) if (filter) { filter->addClient(styledElement); - filter->prepareFilter(paintInfo.context, boundingBox); + filter->prepareFilter(paintInfo.context, object); } else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif @@ -102,16 +138,21 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); } -void finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, GraphicsContext* savedContext) +void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext) { +#if !ENABLE(FILTERS) + UNUSED_PARAM(filter); + UNUSED_PARAM(savedContext); +#endif + ASSERT(object); const RenderStyle* style = object->style(); ASSERT(style); -#if ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) if (filter) { - filter->applyFilter(paintInfo.context, boundingBox); + filter->applyFilter(paintInfo.context, object); paintInfo.context = savedContext; } #endif @@ -143,17 +184,13 @@ void renderSubtreeToImage(ImageBuffer* image, RenderObject* item) svgContainer->setDrawsContents(false); } -void clampImageBufferSizeToViewport(RenderObject* object, IntSize& size) +void clampImageBufferSizeToViewport(FrameView* frameView, IntSize& size) { - if (!object || !object->isRenderView()) + if (!frameView) return; - RenderView* view = static_cast<RenderView*>(object); - if (!view->frameView()) - return; - - int viewWidth = view->frameView()->visibleWidth(); - int viewHeight = view->frameView()->visibleHeight(); + int viewWidth = frameView->visibleWidth(); + int viewHeight = frameView->visibleHeight(); if (size.width() > viewWidth) size.setWidth(viewWidth); @@ -162,6 +199,41 @@ void clampImageBufferSizeToViewport(RenderObject* object, IntSize& size) size.setHeight(viewHeight); } +FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent) +{ + FloatRect boundingBox; + + RenderObject* current = container->firstChild(); + for (; current != 0; current = current->nextSibling()) { + FloatRect childBBox = includeAllPaintedContent ? current->repaintRectInLocalCoordinates() : current->objectBoundingBox(); + FloatRect childBBoxInLocalCoords = current->localToParentTransform().mapRect(childBBox); + boundingBox.unite(childBBoxInLocalCoords); + } + + return boundingBox; +} + +FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) +{ +#if ENABLE(FILTERS) + SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter()); + if (filter) + return filter->filterBBoxForItemBBox(object->objectBoundingBox()); +#else + UNUSED_PARAM(object); +#endif + return FloatRect(); +} + +void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform) +{ + if (localToAncestorTransform.isIdentity()) + return; + + paintInfo.context->concatCTM(localToAncestorTransform); + paintInfo.rect = localToAncestorTransform.inverse().mapRect(paintInfo.rect); +} + } // namespace WebCore #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h index 7fdfcf8..da2bf59 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h @@ -1,9 +1,8 @@ /** - * This file is part of the DOM implementation for WebKit. - * * Copyright (C) 2007 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. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,21 +21,53 @@ * */ +#ifndef SVGRenderBase_h +#define SVGRenderBase_h + #if ENABLE(SVG) #include "RenderObject.h" namespace WebCore { -class SVGResourceFilter; -void prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0); -void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, GraphicsContext* savedContext); + 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); + + 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); + + // returns the filter bounding box (or the empty rect if no filter) in local coordinates + static FloatRect filterBoundingBoxForRenderer(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); -// This offers a way to render parts of a WebKit rendering tree into a ImageBuffer. -class ImageBuffer; -void renderSubtreeToImage(ImageBuffer*, RenderObject*); + // This offers a way to render parts of a WebKit rendering tree into a ImageBuffer. + void renderSubtreeToImage(ImageBuffer*, RenderObject*); -void clampImageBufferSizeToViewport(RenderObject*, IntSize&); + void clampImageBufferSizeToViewport(FrameView*, IntSize& imageBufferSize); +} // namespace WebCore -} +#endif // ENABLE(SVG) -#endif +#endif // SVGRenderBase_h diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp index eff2fff..33baeba 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -33,7 +33,9 @@ #include "GraphicsTypes.h" #include "InlineTextBox.h" #include "HTMLNames.h" +#include "RenderPath.h" #include "RenderSVGContainer.h" +#include "RenderSVGImage.h" #include "RenderSVGInlineText.h" #include "RenderSVGText.h" #include "RenderSVGRoot.h" @@ -78,6 +80,31 @@ TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep) return ts; } +template<typename ValueType> +static void writeNameValuePair(TextStream& ts, const char* name, ValueType value) +{ + ts << " [" << name << "=" << value << "]"; +} + +template<typename ValueType> +static void writeNameAndQuotedValue(TextStream& ts, const char* name, ValueType value) +{ + ts << " [" << name << "=\"" << value << "\"]"; +} + +static void writeIfNotEmpty(TextStream& ts, const char* name, const String& value) +{ + if (!value.isEmpty()) + writeNameValuePair(ts, name, value); +} + +template<typename ValueType> +static void writeIfNotDefault(TextStream& ts, const char* name, ValueType value, ValueType defaultValue) +{ + if (value != defaultValue) + writeNameValuePair(ts, name, value); +} + TextStream& operator<<(TextStream& ts, const IntPoint& p) { return ts << "(" << p.x() << "," << p.y() << ")"; @@ -88,7 +115,7 @@ TextStream& operator<<(TextStream& ts, const IntRect& r) return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height(); } -bool hasFractions(double val) +static bool hasFractions(double val) { double epsilon = 0.0001; int ival = static_cast<int>(val); @@ -232,11 +259,9 @@ static void writeStyle(TextStream& ts, const RenderObject& object) const SVGRenderStyle* svgStyle = style->svgStyle(); if (!object.localTransform().isIdentity()) - ts << " [transform=" << object.localTransform() << "]"; - if (svgStyle->imageRendering() != SVGRenderStyle::initialImageRendering()) - ts << " [image rendering=" << svgStyle->imageRendering() << "]"; - if (style->opacity() != RenderStyle::initialOpacity()) - ts << " [opacity=" << style->opacity() << "]"; + writeNameValuePair(ts, "transform", object.localTransform()); + writeIfNotDefault(ts, "image rendering", svgStyle->imageRendering(), SVGRenderStyle::initialImageRendering()); + writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity()); if (object.isRenderPath()) { const RenderPath& path = static_cast<const RenderPath&>(object); SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, &path); @@ -250,20 +275,15 @@ static void writeStyle(TextStream& ts, const RenderObject& object) const DashArray& dashArray = dashArrayFromRenderingStyle(style); double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeWidth(), 1.0f); - if (svgStyle->strokeOpacity() != 1.0f) - ts << s << "[opacity=" << svgStyle->strokeOpacity() << "]"; - if (strokeWidth != 1.0f) - ts << s << "[stroke width=" << strokeWidth << "]"; - if (svgStyle->strokeMiterLimit() != 4) - ts << s << "[miter limit=" << svgStyle->strokeMiterLimit() << "]"; - if (svgStyle->capStyle() != 0) - ts << s << "[line cap=" << svgStyle->capStyle() << "]"; - if (svgStyle->joinStyle() != 0) - ts << s << "[line join=" << svgStyle->joinStyle() << "]"; - if (dashOffset != 0.0f) - ts << s << "[dash offset=" << dashOffset << "]"; + writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); + writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); + writeIfNotDefault(ts, "miter limit", svgStyle->strokeMiterLimit(), 4.0f); + writeIfNotDefault(ts, "line cap", svgStyle->capStyle(), ButtCap); + writeIfNotDefault(ts, "line join", svgStyle->joinStyle(), MiterJoin); + writeIfNotDefault(ts, "dash offset", dashOffset, 0.0); if (!dashArray.isEmpty()) - ts << s << "[dash array=" << dashArray << "]"; + writeNameValuePair(ts, "dash array", dashArray); + ts << "}]"; } SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, &path); @@ -273,52 +293,47 @@ static void writeStyle(TextStream& ts, const RenderObject& object) if (fillPaintServer) ts << s << *fillPaintServer; - if (style->svgStyle()->fillOpacity() != 1.0f) - ts << s << "[opacity=" << style->svgStyle()->fillOpacity() << "]"; - if (style->svgStyle()->fillRule() != RULE_NONZERO) - ts << s << "[fill rule=" << style->svgStyle()->fillRule() << "]"; + writeIfNotDefault(ts, "opacity", svgStyle->fillOpacity(), 1.0f); + writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO); ts << "}]"; } } + if (!svgStyle->clipPath().isEmpty()) - ts << " [clip path=\"" << svgStyle->clipPath() << "\"]"; - if (!svgStyle->startMarker().isEmpty()) - ts << " [start marker=" << svgStyle->startMarker() << "]"; - if (!svgStyle->midMarker().isEmpty()) - ts << " [middle marker=" << svgStyle->midMarker() << "]"; - if (!svgStyle->endMarker().isEmpty()) - ts << " [end marker=" << svgStyle->endMarker() << "]"; - if (!svgStyle->filter().isEmpty()) - ts << " [filter=" << svgStyle->filter() << "]"; + writeNameAndQuotedValue(ts, "clip path", svgStyle->clipPath()); + writeIfNotEmpty(ts, "start marker", svgStyle->startMarker()); + writeIfNotEmpty(ts, "middle marker", svgStyle->midMarker()); + writeIfNotEmpty(ts, "end marker", svgStyle->endMarker()); + writeIfNotEmpty(ts, "filter", svgStyle->filter()); } -static TextStream& operator<<(TextStream& ts, const RenderPath& path) +static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object) { - ts << " " << path.absoluteTransform().mapRect(path.relativeBBox()); - - writeStyle(ts, path); - - ts << " [data=\"" << path.path().debugString() << "\"]"; + ts << " " << object.absoluteTransform().mapRect(object.repaintRectInLocalCoordinates()); + writeStyle(ts, object); + return ts; +} +static TextStream& operator<<(TextStream& ts, const RenderPath& path) +{ + writePositionAndStyle(ts, path); + writeNameAndQuotedValue(ts, "data", path.path().debugString()); return ts; } static TextStream& operator<<(TextStream& ts, const RenderSVGContainer& container) { - ts << " " << container.absoluteTransform().mapRect(container.relativeBBox()); - - writeStyle(ts, container); - - return ts; + return writePositionAndStyle(ts, container); } static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root) { - ts << " " << root.absoluteTransform().mapRect(root.relativeBBox()); - - writeStyle(ts, root); + return writePositionAndStyle(ts, root); +} - return ts; +static TextStream& operator<<(TextStream& ts, const RenderSVGImage& root) +{ + return writePositionAndStyle(ts, root); } static TextStream& operator<<(TextStream& ts, const RenderSVGText& text) @@ -329,10 +344,10 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGText& text) return ts; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks()); - ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; + ts << " at (" << text.x() << "," << text.y() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; if (text.parent() && (text.parent()->style()->color() != text.style()->color())) - ts << " [color=" << text.style()->color().name() << "]"; + writeNameValuePair(ts, "color", text.style()->color().name()); return ts; } @@ -430,7 +445,7 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB ts << " override"; } - ts << ": " << quoteAndEscapeNonPrintables(String(textBox->textObject()->text()).substring(textBox->start() + range.startOffset, offset)) << "\n"; + ts << ": " << quoteAndEscapeNonPrintables(String(textBox->textRenderer()->text()).substring(textBox->start() + range.startOffset, offset)) << "\n"; j++; } @@ -445,93 +460,63 @@ static inline void writeSVGInlineText(TextStream& ts, const RenderSVGInlineText& writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent); } -static String getTagName(SVGStyledElement* elem) +static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent) { - if (elem) - return elem->nodeName(); - return ""; + writeIndent(ts, indent); + ts << object.renderName(); + + if (object.node()) + ts << " {" << object.node()->nodeName() << "}"; } -void write(TextStream& ts, const RenderSVGContainer& container, int indent) +static void writeChildren(TextStream& ts, const RenderObject& object, int indent) { - writeIndent(ts, indent); - ts << container.renderName(); - - if (container.element()) { - String tagName = getTagName(static_cast<SVGStyledElement*>(container.element())); - if (!tagName.isEmpty()) - ts << " {" << tagName << "}"; - } + for (RenderObject* child = object.firstChild(); child; child = child->nextSibling()) + write(ts, *child, indent + 1); +} +void write(TextStream& ts, const RenderSVGContainer& container, int indent) +{ + writeStandardPrefix(ts, container, indent); ts << container << "\n"; - - for (RenderObject* child = container.firstChild(); child; child = child->nextSibling()) - write(ts, *child, indent + 1); + writeChildren(ts, container, indent); } void write(TextStream& ts, const RenderSVGRoot& root, int indent) { - writeIndent(ts, indent); - ts << root.renderName(); - - if (root.element()) { - String tagName = getTagName(static_cast<SVGStyledElement*>(root.element())); - if (!tagName.isEmpty()) - ts << " {" << tagName << "}"; - } - + writeStandardPrefix(ts, root, indent); ts << root << "\n"; - - for (RenderObject* child = root.firstChild(); child; child = child->nextSibling()) - write(ts, *child, indent + 1); + writeChildren(ts, root, indent); } void write(TextStream& ts, const RenderSVGText& text, int indent) { - writeIndent(ts, indent); - ts << text.renderName(); - - if (text.element()) { - String tagName = getTagName(static_cast<SVGStyledElement*>(text.element())); - if (!tagName.isEmpty()) - ts << " {" << tagName << "}"; - } - + writeStandardPrefix(ts, text, indent); ts << text << "\n"; - - for (RenderObject* child = text.firstChild(); child; child = child->nextSibling()) - write(ts, *child, indent + 1); + writeChildren(ts, text, indent); } void write(TextStream& ts, const RenderSVGInlineText& text, int indent) { - writeIndent(ts, indent); - ts << text.renderName(); - - if (text.element()) { - String tagName = getTagName(static_cast<SVGStyledElement*>(text.element())); - if (!tagName.isEmpty()) - ts << " {" << tagName << "}"; - } + writeStandardPrefix(ts, text, indent); - ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << text.width() << "x" << text.height() << "\n"; + // Why not just linesBoundingBox()? + ts << " " << FloatRect(text.firstRunOrigin(), text.linesBoundingBox().size()) << "\n"; writeSVGInlineText(ts, text, indent); } void write(TextStream& ts, const RenderPath& path, int indent) { - writeIndent(ts, indent); - ts << path.renderName(); - - if (path.element()) { - String tagName = getTagName(static_cast<SVGStyledElement*>(path.element())); - if (!tagName.isEmpty()) - ts << " {" << tagName << "}"; - } - + writeStandardPrefix(ts, path, indent); ts << path << "\n"; } +void write(TextStream& ts, const RenderSVGImage& image, int indent) +{ + writeStandardPrefix(ts, image, indent); + ts << image << "\n"; +} + void writeRenderResources(TextStream& ts, Node* parent) { ASSERT(parent); @@ -549,6 +534,7 @@ void writeRenderResources(TextStream& ts, Node* parent) continue; String elementId = svgElement->getAttribute(HTMLNames::idAttr); + // FIXME: These names are lies! if (resource->isPaintServer()) { RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource); ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *paintServer << "}" << "\n"; diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h index c4d832d..35c3d5c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h @@ -45,13 +45,15 @@ namespace WebCore { class RenderSVGInlineText; class RenderSVGRoot; class RenderSVGText; + class RenderSVGImage; // functions used by the main RenderTreeAsText code void write(TextStream&, const RenderPath&, int indent = 0); void write(TextStream&, const RenderSVGContainer&, int indent = 0); -void write(TextStream&, const RenderSVGInlineText&, int ident = 0); +void write(TextStream&, const RenderSVGInlineText&, int indent = 0); void write(TextStream&, const RenderSVGRoot&, int indent = 0); -void write(TextStream&, const RenderSVGText&, int ident = 0); +void write(TextStream&, const RenderSVGText&, int indent = 0); +void write(TextStream&, const RenderSVGImage&, int indent = 0); void writeRenderResources(TextStream&, Node* parent); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp index f7623ba..d92f54c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp @@ -30,6 +30,7 @@ #include "Editor.h" #include "Frame.h" #include "GraphicsContext.h" +#include "RenderBlock.h" #include "RenderSVGRoot.h" #include "SVGInlineFlowBox.h" #include "SVGInlineTextBox.h" @@ -343,7 +344,7 @@ struct SVGRootInlineBoxPaintWalker { , m_chunkStarted(false) , m_paintInfo(paintInfo) , m_savedInfo(paintInfo) - , m_boundingBox(tx + rootBox->xPos(), ty + rootBox->yPos(), rootBox->width(), rootBox->height()) + , m_boundingBox(tx + rootBox->x(), ty + rootBox->y(), rootBox->width(), rootBox->height()) , m_filter(0) , m_rootFilter(rootFilter) , m_fillPaintServer(0) @@ -395,21 +396,15 @@ struct SVGRootInlineBoxPaintWalker { InlineFlowBox* flowBox = box->parent(); // Initialize text rendering - RenderObject* object = flowBox->object(); + RenderObject* object = flowBox->renderer(); ASSERT(object); m_savedInfo = m_paintInfo; m_paintInfo.context->save(); + // FIXME: Why is this done here instead of in RenderSVGText? if (!flowBox->isRootInlineBox()) - m_paintInfo.context->concatCTM(m_rootBox->object()->localTransform()); - - m_paintInfo.context->concatCTM(object->localTransform()); - - if (!flowBox->isRootInlineBox()) { - prepareToRenderSVGContent(object, m_paintInfo, m_boundingBox, m_filter, m_rootFilter); - m_paintInfo.rect = object->localTransform().inverse().mapRect(m_paintInfo.rect); - } + SVGRenderBase::prepareToRenderSVGContent(object, m_paintInfo, m_boundingBox, m_filter, m_rootFilter); } void chunkEndCallback(InlineBox* box) @@ -419,7 +414,7 @@ struct SVGRootInlineBoxPaintWalker { InlineFlowBox* flowBox = box->parent(); - RenderObject* object = flowBox->object(); + RenderObject* object = flowBox->renderer(); ASSERT(object); // Clean up last used paint server @@ -428,7 +423,7 @@ struct SVGRootInlineBoxPaintWalker { // Finalize text rendering if (!flowBox->isRootInlineBox()) { - finishRenderSVGContent(object, m_paintInfo, m_boundingBox, m_filter, m_savedInfo.context); + SVGRenderBase::finishRenderSVGContent(object, m_paintInfo, m_filter, m_savedInfo.context); m_filter = 0; } @@ -442,7 +437,7 @@ struct SVGRootInlineBoxPaintWalker { InlineFlowBox* flowBox = box->parent(); // Setup fill paint server - RenderObject* object = flowBox->object(); + RenderObject* object = flowBox->renderer(); ASSERT(object); ASSERT(!m_strokePaintServer); @@ -463,7 +458,7 @@ struct SVGRootInlineBoxPaintWalker { InlineFlowBox* flowBox = box->parent(); // Setup stroke paint server - RenderObject* object = flowBox->object(); + RenderObject* object = flowBox->renderer(); ASSERT(object); // If we're both stroked & filled, teardown fill paint server before stroking. @@ -484,7 +479,7 @@ struct SVGRootInlineBoxPaintWalker { void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { - RenderText* text = textBox->textObject(); + RenderText* text = textBox->textRenderer(); ASSERT(text); RenderStyle* styleToUse = text->style(textBox->isFirstLineStyle()); @@ -580,12 +575,10 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) paintInfo.context->save(); SVGResourceFilter* filter = 0; - FloatRect boundingBox(tx + xPos(), ty + yPos(), width(), height()); + FloatRect boundingBox(tx + x(), ty + y(), width(), height()); // Initialize text rendering - paintInfo.context->concatCTM(object()->localTransform()); - prepareToRenderSVGContent(object(), paintInfo, boundingBox, filter); - paintInfo.context->concatCTM(object()->localTransform().inverse()); + SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter); // Render text, chunk-by-chunk SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty); @@ -599,7 +592,7 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) walkTextChunks(&walker); // Finalize text rendering - finishRenderSVGContent(object(), paintInfo, boundingBox, filter, savedInfo.context); + SVGRenderBase::finishRenderSVGContent(renderer(), paintInfo, filter, savedInfo.context); paintInfo.context->restore(); } @@ -611,10 +604,10 @@ int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightP return 0; } -void SVGRootInlineBox::verticallyAlignBoxes(int& heightOfBlock) +int SVGRootInlineBox::verticallyAlignBoxes(int) { // height is set by layoutInlineBoxes. - heightOfBlock = height(); + return height(); } float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) @@ -624,7 +617,7 @@ float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range ASSERT(range.box->isInlineTextBox()); InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); - RenderText* text = textBox->textObject(); + RenderText* text = textBox->textRenderer(); RenderStyle* style = text->style(); return style->font().floatWidth(svgTextRunForInlineTextBox(text->characters() + textBox->start() + range.startOffset, range.endOffset - range.startOffset, style, textBox, 0)); @@ -637,7 +630,7 @@ float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& rang ASSERT(range.box->isInlineTextBox()); InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); - RenderText* text = textBox->textObject(); + RenderText* text = textBox->textRenderer(); const Font& font = text->style()->font(); return (range.endOffset - range.startOffset) * (font.ascent() + font.descent()); @@ -651,7 +644,7 @@ TextRun svgTextRunForInlineTextBox(const UChar* c, int len, RenderStyle* style, TextRun run(c, len, false, static_cast<int>(xPos), textBox->toAdd(), textBox->direction() == RTL, textBox->m_dirOverride || style->visuallyOrdered()); #if ENABLE(SVG_FONTS) - run.setReferencingRenderObject(textBox->textObject()->parent()); + run.setReferencingRenderObject(textBox->textRenderer()->parent()); #endif // We handle letter & word spacing ourselves @@ -671,7 +664,7 @@ static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWi SVGInlineBoxCharacterRange& range = *it; SVGInlineTextBox* box = static_cast<SVGInlineTextBox*>(range.box); - RenderStyle* style = box->object()->style(); + RenderStyle* style = box->renderer()->style(); for (int i = range.startOffset; i < range.endOffset; ++i) { ASSERT(charIt <= chunk.end); @@ -790,13 +783,12 @@ static void applyTextAnchorToTextChunk(SVGTextChunk& chunk) InlineBox* curBox = range.box; ASSERT(curBox->isInlineTextBox()); - ASSERT(curBox->parent() && (curBox->parent()->isRootInlineBox() || curBox->parent()->isInlineFlowBox())); // Move target box if (chunk.isVerticalText) - curBox->setYPos(curBox->yPos() + static_cast<int>(shift)); + curBox->setY(curBox->y() + static_cast<int>(shift)); else - curBox->setXPos(curBox->xPos() + static_cast<int>(shift)); + curBox->setX(curBox->x() + static_cast<int>(shift)); } } @@ -819,9 +811,9 @@ static float calculateTextLengthCorrectionForTextChunk(SVGTextChunk& chunk, ELen if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) { if (chunk.isVerticalText) - chunk.ctm.scale(1.0f, chunk.textLength / computedLength); + chunk.ctm.scaleNonUniform(1.0f, chunk.textLength / computedLength); else - chunk.ctm.scale(chunk.textLength / computedLength, 1.0f); + chunk.ctm.scaleNonUniform(chunk.textLength / computedLength, 1.0f); return 0.0f; } @@ -887,7 +879,7 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation() // Finally the top left position of our box is known. // Propogate this knownledge to our RenderSVGText parent. FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars); - object()->setPos((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); + block()->setLocation((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); // Layout all InlineText/Flow boxes // BEWARE: This requires the root top/left position to be set correctly before! @@ -897,9 +889,9 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation() void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo& info) { if (start->isRootInlineBox()) { - ASSERT(start->object()->element()->hasTagName(SVGNames::textTag)); + ASSERT(start->renderer()->node()->hasTagName(SVGNames::textTag)); - SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(start->object()->element()); + SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(start->renderer()->node()); ASSERT(positioningElement); ASSERT(positioningElement->parentNode()); @@ -909,20 +901,20 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter LastGlyphInfo lastGlyph; for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isText()) + if (curr->renderer()->isText()) buildLayoutInformationForTextBox(info, static_cast<InlineTextBox*>(curr), lastGlyph); else { ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); - if (!flowBox->object()->element()) + if (!flowBox->renderer()->node()) continue; // Skip generated content. - bool isAnchor = flowBox->object()->element()->hasTagName(SVGNames::aTag); - bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag); + bool isAnchor = flowBox->renderer()->node()->hasTagName(SVGNames::aTag); + bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag); if (!isTextPath && !isAnchor) { - SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(flowBox->object()->element()); + SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(flowBox->renderer()->node()); ASSERT(positioningElement); ASSERT(positioningElement->parentNode()); @@ -932,13 +924,13 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter // Handle text-anchor/textLength on path, which is special. SVGTextContentElement* textContent = 0; - Node* node = flowBox->object()->element(); + Node* node = flowBox->renderer()->node(); if (node && node->isSVGElement()) textContent = static_cast<SVGTextContentElement*>(node); ASSERT(textContent); ELengthAdjust lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); - ETextAnchor anchor = flowBox->object()->style()->svgStyle()->textAnchor(); + ETextAnchor anchor = flowBox->renderer()->style()->svgStyle()->textAnchor(); float textAnchorStartOffset = 0.0f; // Initialize sub-layout. We need to create text chunks from the textPath @@ -1007,10 +999,8 @@ void SVGRootInlineBox::layoutInlineBoxes() void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::iterator& it, int& lowX, int& highX, int& lowY, int& highY) { for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { - RenderStyle* style = curr->object()->style(); - const Font& font = style->font(); - - if (curr->object()->isText()) { + RenderStyle* style = curr->renderer()->style(); + if (curr->renderer()->isText()) { SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(curr); unsigned length = textBox->len(); @@ -1038,12 +1028,11 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: int minY = enclosedStringRect.y(); int maxY = minY + enclosedStringRect.height(); - curr->setXPos(minX - object()->xPos()); + curr->setX(minX - block()->x()); curr->setWidth(enclosedStringRect.width()); - curr->setYPos(minY - object()->yPos()); - curr->setBaseline(font.ascent()); - curr->setHeight(enclosedStringRect.height()); + curr->setY(minY - block()->y()); + textBox->setHeight(enclosedStringRect.height()); if (minX < lowX) lowX = minX; @@ -1066,17 +1055,16 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); - if (!flowBox->object()->element()) + if (!flowBox->renderer()->node()) continue; // Skip generated content. layoutInlineBoxes(flowBox, it, minX, maxX, minY, maxY); - curr->setXPos(minX - object()->xPos()); + curr->setX(minX - block()->x()); curr->setWidth(maxX - minX); - curr->setYPos(minY - object()->yPos()); - curr->setBaseline(font.ascent()); - curr->setHeight(maxY - minY); + curr->setY(minY - block()->y()); + static_cast<SVGInlineFlowBox*>(curr)->setHeight(maxY - minY); if (minX < lowX) lowX = minX; @@ -1092,15 +1080,15 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: } } - if (start->isRootInlineBox()) { - int top = lowY - object()->yPos(); - int bottom = highY - object()->yPos(); + if (start->isSVGRootInlineBox()) { + int top = lowY - block()->y(); + int bottom = highY - block()->y(); - start->setXPos(lowX - object()->xPos()); - start->setYPos(top); + start->setX(lowX - block()->x()); + start->setY(top); start->setWidth(highX - lowX); - start->setHeight(highY - lowY); + static_cast<SVGRootInlineBox*>(start)->setHeight(highY - lowY); start->setVerticalOverflowPositions(top, bottom); start->setVerticalSelectionPositions(top, bottom); @@ -1109,7 +1097,7 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& info, InlineTextBox* textBox, LastGlyphInfo& lastGlyph) { - RenderText* text = textBox->textObject(); + RenderText* text = textBox->textRenderer(); ASSERT(text); RenderStyle* style = text->style(textBox->isFirstLineStyle()); @@ -1140,11 +1128,11 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& if (textBox->direction() == RTL) { glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed, glyphName); glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable); - unicodeStr = String(textBox->textObject()->text()->characters() + textBox->end() - i, charsConsumed); + unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->end() - i, charsConsumed); } else { glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i, extraCharsAvailable, charsConsumed, glyphName); glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i, extraCharsAvailable); - unicodeStr = String(textBox->textObject()->text()->characters() + textBox->start() + i, charsConsumed); + unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->start() + i, charsConsumed); } bool assignedX = false; @@ -1194,7 +1182,7 @@ void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& } // Take letter & word spacing and kerning into account - float spacing = font.letterSpacing() + calculateKerning(textBox->object()->element()->renderer()); + float spacing = font.letterSpacing() + calculateKerning(textBox->renderer()->node()->renderer()); const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i); const UChar* lastCharacter = 0; @@ -1369,7 +1357,7 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* #endif for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isText()) { + if (curr->renderer()->isText()) { InlineTextBox* textBox = static_cast<InlineTextBox*>(curr); unsigned length = textBox->len(); @@ -1381,12 +1369,12 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* textBox, length, textBox->start(), textBox->end(), (int) info.handlingTextPath); #endif - RenderText* text = textBox->textObject(); + RenderText* text = textBox->textRenderer(); ASSERT(text); - ASSERT(text->element()); + ASSERT(text->node()); SVGTextContentElement* textContent = 0; - Node* node = text->element()->parent(); + Node* node = text->node()->parent(); while (node && node->isSVGElement() && !textContent) { if (static_cast<SVGElement*>(node)->isTextContent()) textContent = static_cast<SVGTextContentElement*>(node); @@ -1524,10 +1512,10 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); - if (!flowBox->object()->element()) + if (!flowBox->renderer()->node()) continue; // Skip generated content. - bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag); + bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag); #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath); diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h index 800664b..735f755 100644 --- a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h +++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h @@ -47,15 +47,19 @@ class SVGRootInlineBox : public RootInlineBox { public: SVGRootInlineBox(RenderObject* obj) : RootInlineBox(obj) + , m_height(0) { } virtual bool isSVGRootInlineBox() { return true; } + virtual int svgBoxHeight() const { return m_height; } + void setHeight(int h) { m_height = h; } + virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); virtual void computePerCharacterLayoutInformation(); @@ -80,6 +84,7 @@ private: SVGTextDecorationInfo retrievePaintServersForTextDecoration(RenderObject* start); private: + int m_height; Vector<SVGChar> m_svgChars; Vector<SVGTextChunk> m_svgTextChunks; }; diff --git a/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.cpp b/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.cpp new file mode 100644 index 0000000..232ea19 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Portions are Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Robert O'Callahan <roc+@cs.cmu.edu> + * David Baron <dbaron@fas.harvard.edu> + * Christian Biesinger <cbiesinger@web.de> + * Randall Jesup <rjesup@wgate.com> + * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> + * Josh Soref <timeless@mac.com> + * Boris Zbarsky <bzbarsky@mit.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "ScrollBehavior.h" + +namespace WebCore { + +const ScrollAlignment ScrollAlignment::alignCenterIfNeeded = { noScroll, alignCenter, alignToClosestEdge }; +const ScrollAlignment ScrollAlignment::alignToEdgeIfNeeded = { noScroll, alignToClosestEdge, alignToClosestEdge }; +const ScrollAlignment ScrollAlignment::alignCenterAlways = { alignCenter, alignCenter, alignCenter }; +const ScrollAlignment ScrollAlignment::alignTopAlways = { alignTop, alignTop, alignTop }; +const ScrollAlignment ScrollAlignment::alignBottomAlways = { alignBottom, alignBottom, alignBottom }; + +}; // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.h b/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.h new file mode 100644 index 0000000..390c68a --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/ScrollBehavior.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2003, 2009 Apple Inc. All rights reserved. + * + * Portions are Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Robert O'Callahan <roc+@cs.cmu.edu> + * David Baron <dbaron@fas.harvard.edu> + * Christian Biesinger <cbiesinger@web.de> + * Randall Jesup <rjesup@wgate.com> + * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> + * Josh Soref <timeless@mac.com> + * Boris Zbarsky <bzbarsky@mit.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#ifndef ScrollBehavior_h +#define ScrollBehavior_h + +namespace WebCore { + +enum ScrollBehavior { + noScroll, + alignCenter, + alignTop, + alignBottom, + alignLeft, + alignRight, + alignToClosestEdge +}; + +struct ScrollAlignment { + static ScrollBehavior getVisibleBehavior(const ScrollAlignment& s) { return s.m_rectVisible; } + static ScrollBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; } + static ScrollBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; } + + static const ScrollAlignment alignCenterIfNeeded; + static const ScrollAlignment alignToEdgeIfNeeded; + static const ScrollAlignment alignCenterAlways; + static const ScrollAlignment alignTopAlways; + static const ScrollAlignment alignBottomAlways; + + ScrollBehavior m_rectVisible; + ScrollBehavior m_rectHidden; + ScrollBehavior m_rectPartial; +}; + + +}; // namespace WebCore + +#endif // ScrollBehavior_h diff --git a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp index 452333c..cd067de 100644 --- a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp @@ -35,15 +35,19 @@ #include "HTMLNames.h" #include "HTMLTextAreaElement.h" #include "MouseEvent.h" +#include "RenderLayer.h" #include "RenderTextControlSingleLine.h" namespace WebCore { class RenderTextControlInnerBlock : public RenderBlock { public: - RenderTextControlInnerBlock(Node* node) : RenderBlock(node) { } + RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + virtual VisiblePosition positionForPoint(const IntPoint&); + private: + bool m_multiLine; }; bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) @@ -57,6 +61,22 @@ bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, Hit return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction); } +VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) +{ + int contentsX = point.x(); + int contentsY = point.y(); + + // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that + // into account here. + if (m_multiLine) { + RenderTextControl* renderer = static_cast<RenderTextControl*>(node()->shadowAncestorNode()->renderer()); + if (renderer->hasOverflowClip()) + renderer->layer()->addScrolledContentOffset(contentsX, contentsY); + } + + return RenderBlock::positionForPoint(IntPoint(contentsX, contentsY)); +} + TextControlInnerElement::TextControlInnerElement(Document* doc, Node* shadowParent) : HTMLDivElement(HTMLNames::divTag, doc) , m_shadowParent(shadowParent) @@ -98,14 +118,15 @@ void TextControlInnerTextElement::defaultEventHandler(Event* evt) // FIXME: In the future, we should add a way to have default event listeners. Then we would add one to the text field's inner div, and we wouldn't need this subclass. Node* shadowAncestor = shadowAncestorNode(); if (shadowAncestor && shadowAncestor->renderer()) { - ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea()); - if (evt->isBeforeTextInsertedEvent()) + ASSERT(shadowAncestor->renderer()->isTextControl()); + if (evt->isBeforeTextInsertedEvent()) { if (shadowAncestor->renderer()->isTextField()) static_cast<HTMLInputElement*>(shadowAncestor)->defaultEventHandler(evt); else static_cast<HTMLTextAreaElement*>(shadowAncestor)->defaultEventHandler(evt); + } if (evt->type() == eventNames().webkitEditableContentChangedEvent) - static_cast<RenderTextControl*>(shadowAncestor->renderer())->subtreeHasChanged(); + toRenderTextControl(shadowAncestor->renderer())->subtreeHasChanged(); } if (!evt->defaultHandled()) HTMLDivElement::defaultEventHandler(evt); @@ -113,7 +134,13 @@ void TextControlInnerTextElement::defaultEventHandler(Event* evt) RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*) { - return new (arena) RenderTextControlInnerBlock(this); + bool multiLine = false; + Node* shadowAncestor = shadowAncestorNode(); + if (shadowAncestor && shadowAncestor->renderer()) { + ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea()); + multiLine = shadowAncestor->renderer()->isTextArea(); + } + return new (arena) RenderTextControlInnerBlock(this, multiLine); } SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* doc) diff --git a/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp b/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp new file mode 100644 index 0000000..a9e68f4 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/TransformState.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TransformState.h" + +namespace WebCore { + +void TransformState::move(int x, int y, TransformAccumulation accumulate) +{ + if (m_accumulatingTransform && m_accumulatedTransform) { + // If we're accumulating into an existing transform, apply the translation. + if (m_direction == ApplyTransformDirection) + m_accumulatedTransform->translateRight(x, y); + else + m_accumulatedTransform->translate(-x, -y); // We're unapplying, so negate + + // Then flatten if necessary. + if (accumulate == FlattenTransform) + flatten(); + } else { + // Just move the point and, optionally, the quad. + m_lastPlanarPoint.move(x, y); + if (m_mapQuad) + m_lastPlanarQuad.move(x, y); + } + m_accumulatingTransform = accumulate == AccumulateTransform; +} + +void TransformState::applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate) +{ + // If we have an accumulated transform from last time, multiply in this transform + if (m_accumulatedTransform) { + if (m_direction == ApplyTransformDirection) + m_accumulatedTransform->multiply(transformFromContainer); + else + m_accumulatedTransform->multLeft(transformFromContainer); + } else if (accumulate == AccumulateTransform) { + // Make one if we started to accumulate + m_accumulatedTransform.set(new TransformationMatrix(transformFromContainer)); + } + + if (accumulate == FlattenTransform) { + const TransformationMatrix* finalTransform = m_accumulatedTransform ? m_accumulatedTransform.get() : &transformFromContainer; + flattenWithTransform(*finalTransform); + } + m_accumulatingTransform = accumulate == AccumulateTransform; +} + +void TransformState::flatten() +{ + if (!m_accumulatedTransform) { + m_accumulatingTransform = false; + return; + } + + flattenWithTransform(*m_accumulatedTransform); +} + +FloatPoint TransformState::mappedPoint() const +{ + if (!m_accumulatedTransform) + return m_lastPlanarPoint; + + if (m_direction == ApplyTransformDirection) + return m_accumulatedTransform->mapPoint(m_lastPlanarPoint); + + return m_accumulatedTransform->inverse().projectPoint(m_lastPlanarPoint); +} + +FloatQuad TransformState::mappedQuad() const +{ + if (!m_accumulatedTransform) + return m_lastPlanarQuad; + + if (m_direction == ApplyTransformDirection) + return m_accumulatedTransform->mapQuad(m_lastPlanarQuad); + + return m_accumulatedTransform->inverse().projectQuad(m_lastPlanarQuad); +} + +void TransformState::flattenWithTransform(const TransformationMatrix& t) +{ + if (m_direction == ApplyTransformDirection) { + m_lastPlanarPoint = t.mapPoint(m_lastPlanarPoint); + if (m_mapQuad) + m_lastPlanarQuad = t.mapQuad(m_lastPlanarQuad); + } else { + TransformationMatrix inverseTransform = t.inverse(); + m_lastPlanarPoint = inverseTransform.projectPoint(m_lastPlanarPoint); + if (m_mapQuad) + m_lastPlanarQuad = inverseTransform.projectQuad(m_lastPlanarQuad); + } + + // We could throw away m_accumulatedTransform if we wanted to here, but that + // would cause thrash when traversing hierarachies with alternating + // preserve-3d and flat elements. + if (m_accumulatedTransform) + m_accumulatedTransform->makeIdentity(); + m_accumulatingTransform = false; +} + +// HitTestingTransformState methods +void HitTestingTransformState::translate(int x, int y, TransformAccumulation accumulate) +{ + m_accumulatedTransform.translate(x, y); + if (accumulate == FlattenTransform) + flattenWithTransform(m_accumulatedTransform); + + m_accumulatingTransform = accumulate == AccumulateTransform; +} + +void HitTestingTransformState::applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate) +{ + m_accumulatedTransform.multLeft(transformFromContainer); + if (accumulate == FlattenTransform) + flattenWithTransform(m_accumulatedTransform); + + m_accumulatingTransform = accumulate == AccumulateTransform; +} + +void HitTestingTransformState::flatten() +{ + flattenWithTransform(m_accumulatedTransform); +} + +void HitTestingTransformState::flattenWithTransform(const TransformationMatrix& t) +{ + TransformationMatrix inverseTransform = t.inverse(); + m_lastPlanarPoint = inverseTransform.projectPoint(m_lastPlanarPoint); + m_lastPlanarQuad = inverseTransform.projectQuad(m_lastPlanarQuad); + + m_accumulatedTransform.makeIdentity(); + m_accumulatingTransform = false; +} + +FloatPoint HitTestingTransformState::mappedPoint() const +{ + return m_accumulatedTransform.inverse().projectPoint(m_lastPlanarPoint); +} + +FloatQuad HitTestingTransformState::mappedQuad() const +{ + return m_accumulatedTransform.inverse().projectQuad(m_lastPlanarQuad); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/TransformState.h b/src/3rdparty/webkit/WebCore/rendering/TransformState.h new file mode 100644 index 0000000..92275f9 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/rendering/TransformState.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TransformState_h +#define TransformState_h + +#include "FloatPoint.h" +#include "FloatQuad.h" +#include "IntSize.h" +#include "TransformationMatrix.h" +#include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class TransformState : Noncopyable { +public: + enum TransformDirection { ApplyTransformDirection, UnapplyInverseTransformDirection }; + enum TransformAccumulation { FlattenTransform, AccumulateTransform }; + + // If quad is non-null, it will be mapped + TransformState(TransformDirection mappingDirection, const FloatPoint& p, const FloatQuad* quad = 0) + : m_lastPlanarPoint(p) + , m_accumulatingTransform(false) + , m_mapQuad(quad != 0) + , m_direction(mappingDirection) + { + if (quad) + m_lastPlanarQuad = *quad; + } + + void move(const IntSize& s, TransformAccumulation accumulate = FlattenTransform) + { + move(s.width(), s.height(), accumulate); + } + + void move(int x, int y, TransformAccumulation = FlattenTransform); + void applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation = FlattenTransform); + void flatten(); + + // Return the coords of the point or quad in the last flattened layer + FloatPoint lastPlanarPoint() const { return m_lastPlanarPoint; } + FloatQuad lastPlanarQuad() const { return m_lastPlanarQuad; } + + // Return the point or quad mapped through the current transform + FloatPoint mappedPoint() const; + FloatQuad mappedQuad() const; + +private: + void flattenWithTransform(const TransformationMatrix&); + + FloatPoint m_lastPlanarPoint; + FloatQuad m_lastPlanarQuad; + + // We only allocate the transform if we need to + OwnPtr<TransformationMatrix> m_accumulatedTransform; + bool m_accumulatingTransform; + bool m_mapQuad; + TransformDirection m_direction; +}; + +class HitTestingTransformState : public RefCounted<HitTestingTransformState> { +public: + static PassRefPtr<HitTestingTransformState> create(const FloatPoint& p, const FloatQuad& quad) + { + return adoptRef(new HitTestingTransformState(p, quad)); + } + + static PassRefPtr<HitTestingTransformState> create(const HitTestingTransformState& other) + { + return adoptRef(new HitTestingTransformState(other)); + } + + enum TransformAccumulation { FlattenTransform, AccumulateTransform }; + void translate(int x, int y, TransformAccumulation); + void applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation); + + FloatPoint mappedPoint() const; + FloatQuad mappedQuad() const; + void flatten(); + + FloatPoint m_lastPlanarPoint; + FloatQuad m_lastPlanarQuad; + TransformationMatrix m_accumulatedTransform; + bool m_accumulatingTransform; + +private: + HitTestingTransformState(const FloatPoint& p, const FloatQuad& quad) + : m_lastPlanarPoint(p) + , m_lastPlanarQuad(quad) + , m_accumulatingTransform(false) + { + } + + HitTestingTransformState(const HitTestingTransformState& other) + : RefCounted<HitTestingTransformState>() + , m_lastPlanarPoint(other.m_lastPlanarPoint) + , m_lastPlanarQuad(other.m_lastPlanarQuad) + , m_accumulatedTransform(other.m_accumulatedTransform) + , m_accumulatingTransform(other.m_accumulatingTransform) + { + } + + void flattenWithTransform(const TransformationMatrix&); +}; + +} // namespace WebCore + +#endif // TransformState_h diff --git a/src/3rdparty/webkit/WebCore/rendering/bidi.cpp b/src/3rdparty/webkit/WebCore/rendering/bidi.cpp index 6ff2d59..635ad9a 100644 --- a/src/3rdparty/webkit/WebCore/rendering/bidi.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/bidi.cpp @@ -29,6 +29,7 @@ #include "InlineTextBox.h" #include "Logging.h" #include "RenderArena.h" +#include "RenderInline.h" #include "RenderLayer.h" #include "RenderListMarker.h" #include "RenderView.h" @@ -77,18 +78,7 @@ public: int nextBreakablePosition; }; -// Midpoint globals. The goal is not to do any allocation when dealing with -// these midpoints, so we just keep an array around and never clear it. We track -// the number of items and position using the two other variables. -static Vector<InlineIterator>* smidpoints; -static unsigned sNumMidpoints; -static unsigned sCurrMidpoint; -static bool betweenMidpoints; - -static bool isLineEmpty = true; -static bool previousLineBrokeCleanly = true; - -static int getBorderPaddingMargin(RenderObject* child, bool endOfInline) +static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) { bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline; if (leftSide) @@ -102,10 +92,10 @@ static int inlineWidth(RenderObject* child, bool start = true, bool end = true) int extraWidth = 0; RenderObject* parent = child->parent(); while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) { - if (start && parent->firstChild() == child) - extraWidth += getBorderPaddingMargin(parent, false); - if (end && parent->lastChild() == child) - extraWidth += getBorderPaddingMargin(parent, true); + if (start && !child->previousSibling()) + extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), false); + if (end && !child->nextSibling()) + extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), true); child = parent; parent = child->parent(); } @@ -172,9 +162,9 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, while (current) { next = 0; - if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) { + if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) { next = current->firstChild(); - if (next && resolver && next->isInlineFlow()) { + if (next && resolver && next->isRenderInline()) { EUnicodeBidi ub = next->style()->unicodeBidi(); if (ub != UBNormal) { TextDirection dir = next->style()->direction(); @@ -187,19 +177,19 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, } if (!next) { - if (!skipInlines && !oldEndOfInline && current->isInlineFlow()) { + if (!skipInlines && !oldEndOfInline && current->isRenderInline()) { next = current; endOfInline = true; break; } while (current && current != block) { - if (resolver && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal) + if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal) resolver->embed(PopDirectionalFormat); next = current->nextSibling(); if (next) { - if (resolver && next->isInlineFlow()) { + if (resolver && next->isRenderInline()) { EUnicodeBidi ub = next->style()->unicodeBidi(); if (ub != UBNormal) { TextDirection dir = next->style()->direction(); @@ -213,7 +203,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, } current = current->parent(); - if (!skipInlines && current && current != block && current->isInlineFlow()) { + if (!skipInlines && current && current != block && current->isRenderInline()) { next = current; endOfInline = true; break; @@ -226,7 +216,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned() || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. - && next->isInlineFlow())) + && next->isRenderInline())) break; current = next; } @@ -243,7 +233,7 @@ static RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, return 0; RenderObject* o = block->firstChild(); - if (o->isInlineFlow()) { + if (o->isRenderInline()) { if (resolver) { EUnicodeBidi ub = o->style()->unicodeBidi(); if (ub != UBNormal) { @@ -278,7 +268,7 @@ inline void InlineIterator::increment(InlineBidiResolver* resolver) return; if (obj->isText()) { pos++; - if (pos >= static_cast<RenderText*>(obj)->textLength()) { + if (pos >= toRenderText(obj)->textLength()) { obj = bidiNext(block, obj, resolver); pos = 0; nextBreakablePosition = -1; @@ -306,7 +296,7 @@ inline UChar InlineIterator::current() const if (!obj || !obj->isText()) return 0; - RenderText* text = static_cast<RenderText*>(obj); + RenderText* text = toRenderText(obj); if (pos >= text->textLength()) return 0; @@ -326,44 +316,44 @@ ALWAYS_INLINE Direction InlineIterator::direction() const // ------------------------------------------------------------------------------------------------- -static void chopMidpointsAt(RenderObject* obj, unsigned pos) +static void chopMidpointsAt(LineMidpointState& lineMidpointState, RenderObject* obj, unsigned pos) { - if (!sNumMidpoints) + if (!lineMidpointState.numMidpoints) return; - InlineIterator* midpoints = smidpoints->data(); - for (int i = sNumMidpoints - 1; i >= 0; i--) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + for (int i = lineMidpointState.numMidpoints - 1; i >= 0; i--) { const InlineIterator& point = midpoints[i]; if (point.obj == obj && point.pos == pos) { - sNumMidpoints = i; + lineMidpointState.numMidpoints = i; break; } } } -static void checkMidpoints(InlineIterator& lBreak) +static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak) { // Check to see if our last midpoint is a start point beyond the line break. If so, // shave it off the list, and shave off a trailing space if the previous end point doesn't // preserve whitespace. - if (lBreak.obj && sNumMidpoints && sNumMidpoints % 2 == 0) { - InlineIterator* midpoints = smidpoints->data(); - InlineIterator& endpoint = midpoints[sNumMidpoints-2]; - const InlineIterator& startpoint = midpoints[sNumMidpoints-1]; + if (lBreak.obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2]; + const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1]; InlineIterator currpoint = endpoint; while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) currpoint.increment(); if (currpoint == lBreak) { // We hit the line break before the start point. Shave off the start point. - sNumMidpoints--; + lineMidpointState.numMidpoints--; if (endpoint.obj->style()->collapseWhiteSpace()) { if (endpoint.obj->isText()) { // Don't shave a character off the endpoint if it was from a soft hyphen. - RenderText* textObj = static_cast<RenderText*>(endpoint.obj); + RenderText* textObj = toRenderText(endpoint.obj); if (endpoint.pos + 1 < textObj->textLength()) { if (textObj->characters()[endpoint.pos+1] == softHyphen) return; } else if (startpoint.obj->isText()) { - RenderText *startText = static_cast<RenderText*>(startpoint.obj); + RenderText *startText = toRenderText(startpoint.obj); if (startText->textLength() && startText->characters()[0] == softHyphen) return; } @@ -374,33 +364,34 @@ static void checkMidpoints(InlineIterator& lBreak) } } -static void addMidpoint(const InlineIterator& midpoint) +static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) { - if (smidpoints->size() <= sNumMidpoints) - smidpoints->grow(sNumMidpoints + 10); + if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints) + lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10); - InlineIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints++] = midpoint; + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + midpoints[lineMidpointState.numMidpoints++] = midpoint; } static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) { if (start > end || obj->isFloating() || - (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow())) + (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline())) return; - bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints); + LineMidpointState& lineMidpointState = resolver.midpointState(); + bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints); InlineIterator nextMidpoint; if (haveNextMidpoint) - nextMidpoint = smidpoints->at(sCurrMidpoint); - if (betweenMidpoints) { + nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint]; + if (lineMidpointState.betweenMidpoints) { if (!(haveNextMidpoint && nextMidpoint.obj == obj)) return; // This is a new start point. Stop ignoring objects and // adjust our start. - betweenMidpoints = false; + lineMidpointState.betweenMidpoints = false; start = nextMidpoint.pos; - sCurrMidpoint++; + lineMidpointState.currentMidpoint++; if (start < end) return appendRunsForObject(start, end, obj, resolver); } else { @@ -412,8 +403,8 @@ static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBid // An end midpoint has been encountered within our object. We // need to go ahead and append a run with our endpoint. if (static_cast<int>(nextMidpoint.pos + 1) <= end) { - betweenMidpoints = true; - sCurrMidpoint++; + lineMidpointState.betweenMidpoints = true; + lineMidpointState.currentMidpoint++; if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. if (static_cast<int>(nextMidpoint.pos + 1) > start) resolver.addRun(new (obj->renderArena()) @@ -455,7 +446,37 @@ void InlineBidiResolver::appendRun() m_status.eor = OtherNeutral; } -InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) +static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) +{ + if (isRootLineBox) + return toRenderBlock(obj)->createRootInlineBox(); + + if (obj->isText()) { + InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); + // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode + // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.) + if (obj->isBR()) + textBox->setIsText(isOnlyRun || obj->document()->inStrictMode()); + return textBox; + } + + if (obj->isBox()) + return toRenderBox(obj)->createInlineBox(); + + return toRenderInline(obj)->createInlineFlowBox(); +} + +static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) +{ + if (o->isText()) { + if (o->prefWidthsDirty() && o->isCounter()) + toRenderText(o)->calcPrefWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed. + toRenderText(o)->dirtyLineBoxes(fullLayout); + } else + toRenderInline(o)->dirtyLineBoxes(fullLayout); +} + +InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine) { // See if we have an unconstructed line box for this object that is also // the last item on the line. @@ -464,11 +485,10 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) InlineFlowBox* parentBox = 0; InlineFlowBox* result = 0; do { - ASSERT(obj->isInlineFlow() || obj == this); - RenderFlow* flow = static_cast<RenderFlow*>(obj); - + ASSERT(obj->isRenderInline() || obj == this); + // Get the last box we made for this render object. - parentBox = flow->lastLineBox(); + parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox(); // If this box is constructed then it is from a previous line, and we need // to make a new box for our line. If this box is unconstructed but it has @@ -479,10 +499,10 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) if (!parentBox || parentBox->isConstructed() || parentBox->nextOnLine()) { // We need to make a new box for this render object. Once // made, we need to place it at the end of the current line. - InlineBox* newBox = obj->createInlineBox(false, obj == this); + InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this); ASSERT(newBox->isInlineFlowBox()); parentBox = static_cast<InlineFlowBox*>(newBox); - parentBox->setFirstLineStyleBit(m_firstLine); + parentBox->setFirstLineStyleBit(firstLine); constructedNewBox = true; } @@ -509,7 +529,7 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) return result; } -RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool lastLine, RenderObject* endObject) +RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject) { ASSERT(firstRun); @@ -520,29 +540,31 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, if (runCount == 2 && !r->m_object->isListMarker()) isOnlyRun = ((style()->direction() == RTL) ? lastRun : firstRun)->m_object->isListMarker(); - InlineBox* box = r->m_object->createInlineBox(r->m_object->isPositioned(), false, isOnlyRun); + InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun); r->m_box = box; - if (box) { - // If we have no parent box yet, or if the run is not simply a sibling, - // then we need to construct inline boxes as necessary to properly enclose the - // run's inline box. - if (!parentBox || parentBox->object() != r->m_object->parent()) - // Create new inline boxes all the way back to the appropriate insertion point. - parentBox = createLineBoxes(r->m_object->parent()); - - // Append the inline box to this line. - parentBox->addToLine(box); - - bool visuallyOrdered = r->m_object->style()->visuallyOrdered(); - box->setBidiLevel(visuallyOrdered ? 0 : r->level()); - - if (box->isInlineTextBox()) { - InlineTextBox* text = static_cast<InlineTextBox*>(box); - text->setStart(r->m_start); - text->setLen(r->m_stop - r->m_start); - text->m_dirOverride = r->dirOverride(visuallyOrdered); - } + ASSERT(box); + if (!box) + continue; + + // If we have no parent box yet, or if the run is not simply a sibling, + // then we need to construct inline boxes as necessary to properly enclose the + // run's inline box. + if (!parentBox || parentBox->renderer() != r->m_object->parent()) + // Create new inline boxes all the way back to the appropriate insertion point. + parentBox = createLineBoxes(r->m_object->parent(), firstLine); + + // Append the inline box to this line. + parentBox->addToLine(box); + + bool visuallyOrdered = r->m_object->style()->visuallyOrdered(); + box->setBidiLevel(visuallyOrdered ? 0 : r->level()); + + if (box->isInlineTextBox()) { + InlineTextBox* text = static_cast<InlineTextBox*>(box); + text->setStart(r->m_start); + text->setLen(r->m_stop - r->m_start); + text->m_dirOverride = r->dirOverride(visuallyOrdered); } } @@ -563,10 +585,10 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, return lastRootBox(); } -void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd) +void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd) { // First determine our total width. - int availableWidth = lineWidth(m_height); + int availableWidth = lineWidth(height(), firstLine); int totWidth = lineBox->getFlowSpacingWidth(); bool needsWordSpacing = false; unsigned numSpaces = 0; @@ -578,7 +600,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi // correct static x position. They have no effect on the width. // Similarly, line break boxes have no effect on the width. if (r->m_object->isText()) { - RenderText* rt = static_cast<RenderText*>(r->m_object); + RenderText* rt = toRenderText(r->m_object); if (textAlign == JUSTIFY && r != trailingSpaceRun) { const UChar* characters = rt->characters(); @@ -590,28 +612,35 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi } if (int length = rt->textLength()) { - if (!r->m_compact && !r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) - totWidth += rt->style(m_firstLine)->font().wordSpacing(); + if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) + totWidth += rt->style(firstLine)->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length; } - r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, m_firstLine)); - } else if (!r->m_object->isInlineFlow()) { - r->m_object->calcWidth(); - r->m_box->setWidth(r->m_object->width()); - if (!r->m_compact) - totWidth += r->m_object->marginLeft() + r->m_object->marginRight(); + HashSet<const SimpleFontData*> fallbackFonts; + r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, firstLine, &fallbackFonts)); + if (!fallbackFonts.isEmpty() +#if ENABLE(SVG) + && !isSVGText() +#endif + ) { + ASSERT(r->m_box->isText()); + static_cast<InlineTextBox*>(r->m_box)->setFallbackFonts(fallbackFonts); + } + } else if (!r->m_object->isRenderInline()) { + RenderBox* renderBox = toRenderBox(r->m_object); + renderBox->calcWidth(); + r->m_box->setWidth(renderBox->width()); + totWidth += renderBox->marginLeft() + renderBox->marginRight(); } - // Compacts don't contribute to the width of the line, since they are placed in the margin. - if (!r->m_compact) - totWidth += r->m_box->width(); + totWidth += r->m_box->width(); } // Armed with the total width of the line (without justification), // we now examine our text-align property in order to determine where to position the // objects horizontally. The total width of the line can be increased if we end up // justifying text. - int x = leftOffset(m_height); + int x = leftOffset(height(), firstLine); switch(textAlign) { case LEFT: case WEBKIT_LEFT: @@ -619,7 +648,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi // particular with RTL blocks, wide lines should still spill out to the left. if (style()->direction() == LTR) { if (totWidth > availableWidth && trailingSpaceRun) - trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); + trailingSpaceRun->m_box->setWidth(max(0, trailingSpaceRun->m_box->width() - totWidth + availableWidth)); } else { if (trailingSpaceRun) trailingSpaceRun->m_box->setWidth(0); @@ -641,7 +670,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi // for right to left fall through to right aligned if (style()->direction() == LTR) { if (totWidth > availableWidth && trailingSpaceRun) - trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); + trailingSpaceRun->m_box->setWidth(max(0, trailingSpaceRun->m_box->width() - totWidth + availableWidth)); break; } case RIGHT: @@ -658,7 +687,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi x += availableWidth - totWidth; } else { if (totWidth > availableWidth && trailingSpaceRun) { - trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth); + trailingSpaceRun->m_box->setWidth(max(0, trailingSpaceRun->m_box->width() - totWidth + availableWidth)); totWidth -= trailingSpaceRun->m_box->width(); } else x += availableWidth - totWidth; @@ -670,7 +699,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi if (trailingSpaceRun) { totWidth -= trailingSpaceRun->m_box->width(); trailingSpaceWidth = min(trailingSpaceRun->m_box->width(), (availableWidth - totWidth + 1) / 2); - trailingSpaceRun->m_box->setWidth(trailingSpaceWidth); + trailingSpaceRun->m_box->setWidth(max(0, trailingSpaceWidth)); } if (style()->direction() == LTR) x += max((availableWidth - totWidth) / 2, 0); @@ -685,9 +714,9 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi continue; int spaceAdd = 0; - if (r->m_object->isText() && !r->m_compact) { + if (r->m_object->isText()) { unsigned spaces = 0; - const UChar* characters = static_cast<RenderText*>(r->m_object)->characters(); + const UChar* characters = toRenderText(r->m_object)->characters(); for (int i = r->m_start; i < r->m_stop; i++) { UChar c = characters[i]; if (c == ' ' || c == '\n' || c == '\t') @@ -720,27 +749,31 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun) { - lineBox->verticallyAlignBoxes(m_height); - lineBox->setBlockHeight(m_height); + setHeight(lineBox->verticallyAlignBoxes(height())); + lineBox->setBlockHeight(height()); // See if the line spilled out. If so set overflow height accordingly. int bottomOfLine = lineBox->bottomOverflow(); - if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight) + if (bottomOfLine > height() && bottomOfLine > m_overflowHeight) m_overflowHeight = bottomOfLine; // Now make sure we place replaced render objects correctly. for (BidiRun* r = firstRun; r; r = r->next()) { + ASSERT(r->m_box); if (!r->m_box) continue; // Skip runs with no line boxes. // Align positioned boxes with the top of the line box. This is // a reasonable approximation of an appropriate y position. if (r->m_object->isPositioned()) - r->m_box->setYPos(m_height); + r->m_box->setY(height()); // Position is used to properly position both replaced elements and // to update the static normal flow x/y of positioned elements. - r->m_object->position(r->m_box); + if (r->m_object->isText()) + toRenderText(r->m_object)->positionLineBox(r->m_box); + else if (r->m_object->isBox()) + toRenderBox(r->m_object)->positionLineBox(r->m_box); } // Positioned objects and zero-length text nodes destroy their boxes in // position(), which unnecessarily dirties the line. @@ -748,39 +781,11 @@ void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRu } // collects one line of the paragraph and transforms it to visual order -void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end) +void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end, bool previousLineBrokeCleanly) { resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly); } -static void buildCompactRuns(RenderObject* compactObj, InlineBidiResolver& resolver) -{ - ASSERT(compactObj->isRenderBlock()); - ASSERT(!resolver.firstRun()); - - // Format the compact like it is its own single line. We build up all the runs for - // the little compact and then reorder them for bidi. - RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj); - - InlineIterator start(compactBlock, bidiFirst(compactBlock, &resolver), 0); - resolver.setPosition(start); - - betweenMidpoints = false; - isLineEmpty = true; - previousLineBrokeCleanly = true; - - InlineIterator end = compactBlock->findNextLineBreak(resolver); - if (!isLineEmpty) - compactBlock->bidiReorderLine(resolver, end); - - for (BidiRun* run = resolver.firstRun(); run; run = run->next()) - run->m_compact = true; - - sNumMidpoints = 0; - sCurrMidpoint = 0; - betweenMidpoints = false; -} - static inline bool isCollapsibleSpace(UChar character, RenderText* renderer) { if (character == ' ' || character == '\t' || character == softHyphen) @@ -795,12 +800,10 @@ static inline bool isCollapsibleSpace(UChar character, RenderText* renderer) void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom) { bool useRepaintBounds = false; - - invalidateVerticalPosition(); m_overflowHeight = 0; - m_height = borderTop() + paddingTop(); + setHeight(borderTop() + paddingTop()); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); // Figure out if we should clear out our line boxes. @@ -808,7 +811,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // FIXME: Do something better when floats are present. bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren; if (fullLayout) - deleteLineBoxes(); + lineBoxes()->deleteLineBoxes(renderArena()); // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't // clip. @@ -826,10 +829,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool endOfInline = false; RenderObject* o = bidiFirst(this, 0, false); Vector<FloatWithRect> floats; - int containerWidth = max(0, containingBlockWidth()); while (o) { - o->invalidateVerticalPosition(); if (o->isReplaced() || o->isFloating() || o->isPositioned()) { + RenderBox* box = toRenderBox(o); + if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) o->setChildNeedsLayout(true, false); @@ -838,23 +841,21 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i o->setPrefWidthsDirty(true, false); if (o->isPositioned()) - o->containingBlock()->insertPositionedObject(o); + o->containingBlock()->insertPositionedObject(box); else { if (o->isFloating()) - floats.append(FloatWithRect(o)); + floats.append(FloatWithRect(box)); else if (fullLayout || o->needsLayout()) // Replaced elements - o->dirtyLineBoxes(fullLayout); + toRenderBox(o)->dirtyLineBoxes(fullLayout); o->layoutIfNeeded(); } - } else if (o->isText() || (o->isInlineFlow() && !endOfInline)) { + } else if (o->isText() || (o->isRenderInline() && !endOfInline)) { if (fullLayout || o->selfNeedsLayout()) - o->dirtyLineBoxes(fullLayout); - - // Calculate margins of inline flows so that they can be used later by line layout. - if (o->isInlineFlow()) - static_cast<RenderFlow*>(o)->calcMargins(containerWidth); + dirtyLineBoxesForRenderer(o, fullLayout); o->setNeedsLayout(false); + if (!o->isText()) + toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything. } o = bidiNext(this, o, 0, false, &endOfInline); } @@ -862,29 +863,26 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // We want to skip ahead to the first dirty line InlineBidiResolver resolver; unsigned floatIndex; - RootInlineBox* startLine = determineStartPosition(fullLayout, resolver, floats, floatIndex); + bool firstLine = true; + bool previousLineBrokeCleanly = true; + RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex); if (fullLayout && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like // we're supposed to. - if (!document()->view()->needsFullRepaint() && m_layer) { + RenderView* v = view(); + if (v && !v->doingFullRepaint() && hasLayer()) { // Because we waited until we were already inside layout to discover // that the block really needed a full layout, we missed our chance to repaint the layer // before layout started. Luckily the layer has cached the repaint rect for its original // position and size, and so we can use that to make a repaint happen now. - RenderView* c = view(); - if (c && !c->printing()) - c->repaintViewRectangle(m_layer->repaintRect()); + repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); } } FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0; - if (!smidpoints) - smidpoints = new Vector<InlineIterator>(); - - sNumMidpoints = 0; - sCurrMidpoint = 0; + LineMidpointState& lineMidpointState = resolver.midpointState(); // We also find the first clean line and extract these lines. We will add them back // if we determine that we're able to synchronize after handling all our dirty lines. @@ -896,8 +894,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (startLine) { useRepaintBounds = true; - repaintTop = m_height; - repaintBottom = m_height; + repaintTop = height(); + repaintBottom = height(); RenderArena* arena = renderArena(); RootInlineBox* box = startLine; while (box) { @@ -916,9 +914,9 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // adjust the height accordingly. // A line break can be either the first or the last object on a line, depending on its direction. if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { - RenderObject* lastObject = lastLeafChild->object(); + RenderObject* lastObject = lastLeafChild->renderer(); if (!lastObject->isBR()) - lastObject = lastRootBox()->firstLeafChild()->object(); + lastObject = lastRootBox()->firstLeafChild()->renderer(); if (lastObject->isBR()) { EClear clear = lastObject->style()->clear(); if (clear != CNONE) @@ -930,21 +928,21 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool endLineMatched = false; bool checkForEndLineMatch = endLine; bool checkForFloatsFromLastLine = false; - int lastHeight = m_height; + int lastHeight = height(); + + bool isLineEmpty = true; while (!end.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop))) break; - betweenMidpoints = false; + lineMidpointState.reset(); + isLineEmpty = true; - if (m_firstLine && firstChild()->isCompact() && firstChild()->isRenderBlock()) { - buildCompactRuns(firstChild(), resolver); - resolver.setPosition(InlineIterator(this, firstChild()->nextSibling(), 0)); - } + EClear clear = CNONE; - end = findNextLineBreak(resolver, &clear); + end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, &clear); if (resolver.position().atEnd()) { resolver.deleteRuns(); checkForFloatsFromLastLine = true; @@ -953,15 +951,16 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i ASSERT(end != resolver.position()); if (!isLineEmpty) { - bidiReorderLine(resolver, end); + bidiReorderLine(resolver, end, previousLineBrokeCleanly); ASSERT(resolver.position() == end); BidiRun* trailingSpaceRun = 0; - if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()) { + if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() + && resolver.logicallyLastRun()->m_object->style()->autoWrap()) { trailingSpaceRun = resolver.logicallyLastRun(); RenderObject* lastObject = trailingSpaceRun->m_object; if (lastObject->isText()) { - RenderText* lastText = static_cast<RenderText*>(lastObject); + RenderText* lastText = toRenderText(lastObject); const UChar* characters = lastText->characters(); int firstSpace = trailingSpaceRun->stop(); while (firstSpace > trailingSpaceRun->start()) { @@ -976,26 +975,18 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i TextDirection direction = style()->direction(); bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun()); if (firstSpace != trailingSpaceRun->start()) { - ETextAlign textAlign = style()->textAlign(); - // If the trailing white space is at the right hand side of a left-aligned line, then computeHorizontalPositionsForLine() - // does not care if trailingSpaceRun includes non-spaces at the beginning. In all other cases, trailingSpaceRun has to - // contain only the spaces, either because we re-order them or because computeHorizontalPositionsForLine() needs to know - // their width. - bool shouldSeparateSpaces = textAlign != LEFT && textAlign != WEBKIT_LEFT && textAlign != TAAUTO || trailingSpaceRun->m_level % 2 || direction == RTL || shouldReorder; - if (shouldSeparateSpaces) { - BidiContext* baseContext = resolver.context(); - while (BidiContext* parent = baseContext->parent()) - baseContext = parent; - - BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral); - trailingSpaceRun->m_stop = firstSpace; - if (direction == LTR) - resolver.addRun(newTrailingRun); - else - resolver.prependRun(newTrailingRun); - trailingSpaceRun = newTrailingRun; - shouldReorder = false; - } + BidiContext* baseContext = resolver.context(); + while (BidiContext* parent = baseContext->parent()) + baseContext = parent; + + BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral); + trailingSpaceRun->m_stop = firstSpace; + if (direction == LTR) + resolver.addRun(newTrailingRun); + else + resolver.prependRun(newTrailingRun); + trailingSpaceRun = newTrailingRun; + shouldReorder = false; } if (shouldReorder) { if (direction == LTR) { @@ -1017,12 +1008,12 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i RootInlineBox* lineBox = 0; if (resolver.runCount()) { - lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), !end.obj, end.obj && !end.pos ? end.obj : 0); + lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, !end.obj, end.obj && !end.pos ? end.obj : 0); if (lineBox) { lineBox->setEndsWithBreak(previousLineBrokeCleanly); // Now we position all of our text runs horizontally. - computeHorizontalPositionsForLine(lineBox, resolver.firstRun(), trailingSpaceRun, end.atEnd()); + computeHorizontalPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd()); // Now position our text runs vertically. computeVerticalPositionsForLine(lineBox, resolver.firstRun()); @@ -1050,7 +1041,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i } } - m_firstLine = false; + firstLine = false; newLine(clear); } @@ -1073,16 +1064,15 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i lastFloat = m_floatingObjects->last(); } - lastHeight = m_height; - sNumMidpoints = 0; - sCurrMidpoint = 0; + lastHeight = height(); + lineMidpointState.reset(); resolver.setPosition(end); } if (endLine) { if (endLineMatched) { // Attach all the remaining lines, and then adjust their y-positions as needed. - int delta = m_height - endLineYPos; + int delta = height() - endLineYPos; for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) { line->attachLine(); if (delta) { @@ -1090,17 +1080,17 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i repaintBottom = max(repaintBottom, line->bottomOverflow() + max(delta, 0)); line->adjustPosition(0, delta); } - if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { - int floatTop = (*f)->yPos() - (*f)->marginTop(); + if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { + int floatTop = (*f)->y() - (*f)->marginTop(); insertFloatingObject(*f); - m_height = floatTop + delta; + setHeight(floatTop + delta); positionNewFloats(); } } } - m_height = lastRootBox()->blockHeight(); + setHeight(lastRootBox()->blockHeight()); } else { // Delete all the remaining lines. InlineRunBox* line = endLine; @@ -1132,20 +1122,17 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i } } - sNumMidpoints = 0; - sCurrMidpoint = 0; - // Now add in the bottom border/padding. - m_height += toAdd; + setHeight(height() + toAdd); // Always make sure this is at least our height. - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowHeight = max(height(), m_overflowHeight); // See if any lines spill out of the block. If so, we need to update our overflow width. checkLinesForOverflow(); if (!firstLineBox() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); // See if we have any lines that spill out of our block. If we do, then we will possibly need to // truncate text. @@ -1153,7 +1140,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i checkLinesForTextOverflow(); } -RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats) +RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, + InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats) { RootInlineBox* curr = 0; RootInlineBox* last = 0; @@ -1162,10 +1150,10 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR if (!fullLayout) { size_t floatIndex = 0; for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) { - if (Vector<RenderObject*>* cleanLineFloats = curr->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator o = cleanLineFloats->begin(); o != end; ++o) { - RenderObject* f = *o; + if (Vector<RenderBox*>* cleanLineFloats = curr->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator o = cleanLineFloats->begin(); o != end; ++o) { + RenderBox* f = *o; IntSize newSize(f->width() + f->marginLeft() +f->marginRight(), f->height() + f->marginTop() + f->marginBottom()); ASSERT(floatIndex < floats.size()); if (floats[floatIndex].object != f) { @@ -1209,7 +1197,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR // We have a dirty line. if (RootInlineBox* prevRootBox = curr->prevRootBox()) { // We have a previous line. - if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= static_cast<RenderText*>(prevRootBox->lineBreakObj())->textLength())) + if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength()))) // The previous line didn't break cleanly or broke at a newline // that has been deleted, so treat it as dirty too. curr = prevRootBox; @@ -1227,15 +1215,15 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR numCleanFloats = 0; if (!floats.isEmpty()) { - int savedHeight = m_height; + int savedHeight = height(); // Restore floats from clean lines. RootInlineBox* line = firstRootBox(); while (line != curr) { - if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { + if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { insertFloatingObject(*f); - m_height = (*f)->yPos() - (*f)->marginTop(); + setHeight((*f)->y() - (*f)->marginTop()); positionNewFloats(); ASSERT(floats[numCleanFloats].object == *f); numCleanFloats++; @@ -1243,16 +1231,16 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR } line = line->nextRootBox(); } - m_height = savedHeight; + setHeight(savedHeight); } - m_firstLine = !last; + firstLine = !last; previousLineBrokeCleanly = !last || last->endsWithBreak(); RenderObject* startObj; int pos = 0; if (last) { - m_height = last->blockHeight(); + setHeight(last->blockHeight()); startObj = last->lineBreakObj(); pos = last->lineBreakPos(); resolver.setStatus(last->lineBreakBidiStatus()); @@ -1263,12 +1251,12 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR #endif ; - BidiContext* context = new BidiContext(ltr ? 0 : 1, ltr ? LeftToRight : RightToLeft, style()->unicodeBidi() == Override); + Direction direction = ltr ? LeftToRight : RightToLeft; + resolver.setLastStrongDir(direction); + resolver.setLastDir(direction); + resolver.setEorDir(direction); + resolver.setContext(BidiContext::create(ltr ? 0 : 1, direction, style()->unicodeBidi() == Override)); - resolver.setLastStrongDir(context->dir()); - resolver.setLastDir(context->dir()); - resolver.setEorDir(context->dir()); - resolver.setContext(context); startObj = bidiFirst(this, &resolver); } @@ -1312,12 +1300,12 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin if (resolver.status() != endLineStatus) return false; - int delta = m_height - endYPos; + int delta = height() - endYPos; if (!delta || !m_floatingObjects) return true; // See if any floats end in the range along which we want to shift the lines vertically. - int top = min(m_height, endYPos); + int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) @@ -1348,10 +1336,10 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin if (result) endYPos = line->blockHeight(); - int delta = m_height - endYPos; + int delta = height() - endYPos; if (delta && m_floatingObjects) { // See if any floats end in the range along which we want to shift the lines vertically. - int top = min(m_height, endYPos); + int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) @@ -1384,7 +1372,7 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin return false; } -static inline bool skipNonBreakingSpace(const InlineIterator& it) +static inline bool skipNonBreakingSpace(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) { if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace) return false; @@ -1400,7 +1388,7 @@ static inline bool skipNonBreakingSpace(const InlineIterator& it) return true; } -static inline bool shouldCollapseWhiteSpace(const RenderStyle* style) +static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, bool isLineEmpty, bool previousLineBrokeCleanly) { return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly)); } @@ -1415,35 +1403,36 @@ static inline bool shouldPreserveNewline(RenderObject* object) return object->style()->preserveNewline(); } -static bool inlineFlowRequiresLineBox(RenderObject* flow) +static bool inlineFlowRequiresLineBox(RenderInline* flow) { // FIXME: Right now, we only allow line boxes for inlines that are truly empty. // We need to fix this, though, because at the very least, inlines containing only // ignorable whitespace should should also have line boxes. - return flow->isInlineFlow() && !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); + return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); } -static inline bool requiresLineBox(const InlineIterator& it) +static inline bool requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) { if (it.obj->isFloatingOrPositioned()) return false; - if (it.obj->isInlineFlow() && !inlineFlowRequiresLineBox(it.obj)) + if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj))) return false; - if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR()) + if (!shouldCollapseWhiteSpace(it.obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.obj->isBR()) return true; UChar current = it.current(); - return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) && !skipNonBreakingSpace(it); + return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) + && !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly); } -bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) +bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool isLineEmpty, bool previousLineBrokeCleanly) { ASSERT(inlineObj->parent() == this); InlineIterator it(this, inlineObj, 0); - while (!it.atEnd() && !requiresLineBox(it)) + while (!it.atEnd() && !requiresLineBox(it, isLineEmpty, previousLineBrokeCleanly)) it.increment(); return !it.atEnd(); @@ -1455,68 +1444,70 @@ bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) // object iteration process. // NB. this function will insert any floating elements that would otherwise // be skipped but it will not position them. -void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator) +void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEmpty, bool previousLineBrokeCleanly) { - while (!iterator.atEnd() && !requiresLineBox(iterator)) { + while (!iterator.atEnd() && !requiresLineBox(iterator, isLineEmpty, previousLineBrokeCleanly)) { RenderObject* object = iterator.obj; if (object->isFloating()) { - insertFloatingObject(object); + insertFloatingObject(toRenderBox(object)); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); - if (c->isInlineFlow()) { + if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. - c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height)); - c->setStaticY(m_height); + toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), false) : rightOffset(height(), false)); + toRenderInline(c)->layer()->setStaticY(height()); } - if (object->hasStaticX()) { - if (object->style()->isOriginalDisplayInlineType()) - object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height)); + RenderBox* box = toRenderBox(object); + if (box->style()->hasStaticX()) { + if (box->style()->isOriginalDisplayInlineType()) + box->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), false) : width() - rightOffset(height(), false)); else - object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); + box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } - if (object->hasStaticY()) - object->setStaticY(m_height); + if (box->style()->hasStaticY()) + box->layer()->setStaticY(height()); } iterator.increment(); } } -int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver) +int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly) { - int availableWidth = lineWidth(m_height); - while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) { + int availableWidth = lineWidth(height(), firstLine); + while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) { RenderObject* object = resolver.position().obj; if (object->isFloating()) { - insertFloatingObject(object); + insertFloatingObject(toRenderBox(object)); positionNewFloats(); - availableWidth = lineWidth(m_height); + availableWidth = lineWidth(height(), firstLine); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); - if (c->isInlineFlow()) { + if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. - c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height)); - c->setStaticY(m_height); + toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), firstLine) : rightOffset(height(), firstLine)); + toRenderInline(c)->layer()->setStaticY(height()); } - if (object->hasStaticX()) { - if (object->style()->isOriginalDisplayInlineType()) - object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height)); + RenderBox* box = toRenderBox(object); + if (box->style()->hasStaticX()) { + if (box->style()->isOriginalDisplayInlineType()) + box->layer()->setStaticX(style()->direction() == LTR ? leftOffset(height(), firstLine) : width() - rightOffset(height(), firstLine)); else - object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); + box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } - if (object->hasStaticY()) - object->setStaticY(m_height); + if (box->style()->hasStaticY()) + box->layer()->setStaticY(height()); } resolver.increment(); } @@ -1526,14 +1517,14 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver) // This is currently just used for list markers and inline flows that have line boxes. Neither should // have an effect on whitespace at the start of the line. -static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o) +static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState) { RenderObject* next = bidiNext(block, o); - if (next && !next->isBR() && next->isText() && static_cast<RenderText*>(next)->textLength() > 0) { - RenderText* nextText = static_cast<RenderText*>(next); + if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) { + RenderText* nextText = toRenderText(next); UChar nextChar = nextText->characters()[0]; if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) { - addMidpoint(InlineIterator(0, o, 0)); + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); return true; } } @@ -1541,37 +1532,46 @@ static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObjec return false; } -void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth) +void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth) { ASSERT(widthToFit > availableWidth); int floatBottom; - int lastFloatBottom = m_height; + int lastFloatBottom = height(); int newLineWidth = availableWidth; while (true) { floatBottom = nextFloatBottomBelow(lastFloatBottom); if (!floatBottom) break; - newLineWidth = lineWidth(floatBottom); + newLineWidth = lineWidth(floatBottom, firstLine); lastFloatBottom = floatBottom; if (newLineWidth >= widthToFit) break; } if (newLineWidth > availableWidth) { - m_height = lastFloatBottom; + setHeight(lastFloatBottom); availableWidth = newLineWidth; } } -InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, EClear* clear) +static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, int xPos, bool isFixedPitch, bool collapseWhiteSpace) +{ + if (isFixedPitch || (!from && len == text->textLength())) + return text->width(from, len, font, xPos); + return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos)); +} + +InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, + EClear* clear) { ASSERT(resolver.position().block == this); bool appliedStartWidth = resolver.position().pos > 0; - - int width = skipLeadingWhitespace(resolver); + LineMidpointState& lineMidpointState = resolver.midpointState(); + + int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly); int w = 0; int tmpW = 0; @@ -1653,22 +1653,24 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (o->isFloatingOrPositioned()) { // add to special objects... if (o->isFloating()) { - insertFloatingObject(o); + RenderBox* floatBox = toRenderBox(o); + insertFloatingObject(floatBox); // check if it fits in the current line. // If it does, position it now, otherwise, position // it after moving to next line (in newLine() func) - if (floatsFitOnLine && o->width() + o->marginLeft() + o->marginRight() + w + tmpW <= width) { + if (floatsFitOnLine && floatBox->width() + floatBox->marginLeft() + floatBox->marginRight() + w + tmpW <= width) { positionNewFloats(); - width = lineWidth(m_height); + width = lineWidth(height(), firstLine); } else floatsFitOnLine = false; } else if (o->isPositioned()) { // If our original display wasn't an inline type, then we can // go ahead and determine our static x position now. - bool isInlineType = o->style()->isOriginalDisplayInlineType(); - bool needToSetStaticX = o->hasStaticX(); - if (o->hasStaticX() && !isInlineType) { - o->setStaticX(o->parent()->style()->direction() == LTR ? + RenderBox* box = toRenderBox(o); + bool isInlineType = box->style()->isOriginalDisplayInlineType(); + bool needToSetStaticX = box->style()->hasStaticX(); + if (box->style()->hasStaticX() && !isInlineType) { + box->layer()->setStaticX(o->parent()->style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); needToSetStaticX = false; @@ -1676,15 +1678,15 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // If our original display was an INLINE type, then we can go ahead // and determine our static y position now. - bool needToSetStaticY = o->hasStaticY(); - if (o->hasStaticY() && isInlineType) { - o->setStaticY(m_height); + bool needToSetStaticY = box->style()->hasStaticY(); + if (box->style()->hasStaticY() && isInlineType) { + box->layer()->setStaticY(height()); needToSetStaticY = false; } bool needToCreateLineBox = needToSetStaticX || needToSetStaticY; RenderObject* c = o->container(); - if (c->isInlineFlow() && (!needToSetStaticX || !needToSetStaticY)) + if (c->isRenderInline() && (!needToSetStaticX || !needToSetStaticY)) needToCreateLineBox = true; // If we're ignoring spaces, we have to stop and include this object and @@ -1694,28 +1696,30 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle ignoreStart.obj = o; ignoreStart.pos = 0; if (ignoringSpaces) { - addMidpoint(ignoreStart); // Stop ignoring spaces. - addMidpoint(ignoreStart); // Start ignoring again. + addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces. + addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again. } } } - } else if (o->isInlineFlow()) { + } else if (o->isRenderInline()) { // Right now, we should only encounter empty inlines here. ASSERT(!o->firstChild()); + RenderInline* flowBox = toRenderInline(o); + // Now that some inline flows have line boxes, if we are already ignoring spaces, we need // to make sure that we stop to include this object and then start ignoring spaces again. // If this object is at the start of the line, we need to behave like list markers and // start ignoring spaces. - if (inlineFlowRequiresLineBox(o)) { + if (inlineFlowRequiresLineBox(flowBox)) { isLineEmpty = false; if (ignoringSpaces) { trailingSpaceObject = 0; - addMidpoint(InlineIterator(0, o, 0)); // Stop ignoring spaces. - addMidpoint(InlineIterator(0, o, 0)); // Start ignoring again. + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Stop ignoring spaces. + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Start ignoring again. } else if (style()->collapseWhiteSpace() && resolver.position().obj == o - && shouldSkipWhitespaceAfterStartObject(this, o)) { + && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { // Like with list markers, we start ignoring spaces to make sure that any // additional spaces we see will be discarded. currentCharacterIsSpace = true; @@ -1724,9 +1728,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } } - tmpW += o->marginLeft() + o->borderLeft() + o->paddingLeft() + - o->marginRight() + o->borderRight() + o->paddingRight(); + tmpW += flowBox->marginLeft() + flowBox->borderLeft() + flowBox->paddingLeft() + + flowBox->marginRight() + flowBox->borderRight() + flowBox->paddingRight(); } else if (o->isReplaced()) { + RenderBox* replacedBox = toRenderBox(o); + // Break on replaced elements if either has normal white-space. if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) { w += tmpW; @@ -1737,7 +1743,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } if (ignoringSpaces) - addMidpoint(InlineIterator(0, o, 0)); + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); isLineEmpty = false; ignoringSpaces = false; @@ -1748,7 +1754,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // Optimize for a common case. If we can't find whitespace after the list // item, then this is all moot. -dwh if (o->isListMarker() && !static_cast<RenderListMarker*>(o)->isInside()) { - if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o)) { + 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. currentCharacterIsSpace = true; @@ -1756,18 +1762,19 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle ignoringSpaces = true; } } else - tmpW += o->width() + o->marginLeft() + o->marginRight() + inlineWidth(o); + tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o); } else if (o->isText()) { if (!pos) appliedStartWidth = false; - RenderText* t = static_cast<RenderText*>(o); + RenderText* t = toRenderText(o); int strlen = t->textLength(); int len = strlen - pos; const UChar* str = t->characters(); - const Font& f = t->style(m_firstLine)->font(); + const Font& f = t->style(firstLine)->font(); + bool isFixedPitch = f.isFixedPitch(); int lastSpace = pos; int wordSpacing = o->style()->wordSpacing(); @@ -1808,24 +1815,25 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (pos) beforeSoftHyphen = InlineIterator(0, o, pos - 1); else - beforeSoftHyphen = InlineIterator(0, last, last->isText() ? static_cast<RenderText*>(last)->textLength() - 1 : 0); + beforeSoftHyphen = InlineIterator(0, last, last->isText() ? toRenderText(last)->textLength() - 1 : 0); // Two consecutive soft hyphens. Avoid overlapping midpoints. - if (sNumMidpoints && smidpoints->at(sNumMidpoints - 1).obj == o && smidpoints->at(sNumMidpoints - 1).pos == pos) - sNumMidpoints--; + if (lineMidpointState.numMidpoints && lineMidpointState.midpoints[lineMidpointState.numMidpoints - 1].obj == o && + lineMidpointState.midpoints[lineMidpointState.numMidpoints - 1].pos == pos) + lineMidpointState.numMidpoints--; else - addMidpoint(beforeSoftHyphen); + addMidpoint(lineMidpointState, beforeSoftHyphen); // Add the width up to but not including the hyphen. - tmpW += t->width(lastSpace, pos - lastSpace, f, w + tmpW) + lastSpaceWordSpacing; + tmpW += textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; // For wrapping text only, include the hyphen. We need to ensure it will fit // on the line if it shows when we break. if (autoWrap) - tmpW += t->width(pos, 1, f, w + tmpW); + tmpW += textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace); InlineIterator afterSoftHyphen(0, o, pos); afterSoftHyphen.increment(); - addMidpoint(afterSoftHyphen); + addMidpoint(lineMidpointState, afterSoftHyphen); } pos++; @@ -1841,7 +1849,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if ((breakAll || breakWords) && !midWordBreak) { wrapW += charWidth; - charWidth = t->width(pos, 1, f, w + wrapW); + charWidth = textWidth(t, pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace); midWordBreak = w + wrapW + charWidth > width; } @@ -1856,7 +1864,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle ignoringSpaces = false; lastSpaceWordSpacing = 0; lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - addMidpoint(InlineIterator(0, o, pos)); + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); stoppedIgnoringSpaces = true; } else { // Just keep ignoring these spaces. @@ -1866,7 +1874,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } } - int additionalTmpW = t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing; + int additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; tmpW += additionalTmpW; if (!appliedStartWidth) { tmpW += inlineWidth(o, true, false); @@ -1876,14 +1884,14 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace; if (!w && autoWrap && tmpW > width) - fitBelowFloats(tmpW, width); + fitBelowFloats(tmpW, firstLine, width); if (autoWrap || breakWords) { // If we break only after white-space, consider the current character // as candidate width for this line. bool lineWasTooWide = false; if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) { - int charWidth = t->width(pos, 1, f, w + tmpW) + (applyWordSpacing ? wordSpacing : 0); + int charWidth = textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); // Check if line is too big even without the extra space // at the end of the line. If it is not, do nothing. // If the line needs the extra whitespace to be too long, @@ -1894,15 +1902,15 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle lBreak.obj = o; lBreak.pos = pos; lBreak.nextBreakablePosition = nextBreakable; - skipTrailingWhitespace(lBreak); + skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly); } } if (lineWasTooWide || w + tmpW > width) { - if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !static_cast<RenderText*>(lBreak.obj)->isWordBreak() && static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos] == '\n') { + if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !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(InlineIterator(0, o, pos - 1)); // Stop - addMidpoint(InlineIterator(0, o, pos)); // Start + addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start } lBreak.increment(); previousLineBrokeCleanly = true; @@ -1913,15 +1921,15 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle tmpW -= additionalTmpW; if (pos > 0 && str[pos-1] == softHyphen) // Subtract the width of the soft hyphen out since we fit on a line. - tmpW -= t->width(pos-1, 1, f, w+tmpW); + tmpW -= textWidth(t, pos - 1, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace); } } if (c == '\n' && preserveNewline) { if (!stoppedIgnoringSpaces && pos > 0) { // We need to stop right before the newline and then start up again. - addMidpoint(InlineIterator(0, o, pos - 1)); // Stop - addMidpoint(InlineIterator(0, o, pos)); // Start + addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start } lBreak.obj = o; lBreak.pos = pos; @@ -1967,7 +1975,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // We just entered a mode where we are ignoring // spaces. Create a midpoint to terminate the run // before the second space. - addMidpoint(ignoreStart); + addMidpoint(lineMidpointState, ignoreStart); } } } else if (ignoringSpaces) { @@ -1976,7 +1984,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle ignoringSpaces = false; lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - addMidpoint(InlineIterator(0, o, pos)); + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); } if (currentCharacterIsSpace && !previousCharacterIsSpace) { @@ -2004,7 +2012,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // IMPORTANT: pos is > length here! if (!ignoringSpaces) - tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing; + tmpW += textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; tmpW += inlineWidth(o, !appliedStartWidth, true); } else ASSERT_NOT_REACHED(); @@ -2019,7 +2027,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle checkForBreak = true; else { checkForBreak = false; - RenderText* nextText = static_cast<RenderText*>(next); + RenderText* nextText = toRenderText(next); if (nextText->textLength()) { UChar c = nextText->characters()[0]; if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next))) @@ -2031,7 +2039,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle checkForBreak = true; bool willFitOnLine = w + tmpW <= width; if (!willFitOnLine && !w) { - fitBelowFloats(tmpW, width); + fitBelowFloats(tmpW, firstLine, width); willFitOnLine = tmpW <= width; } bool canPlaceOnLine = willFitOnLine || !autoWrapWasEverTrueOnLine; @@ -2054,7 +2062,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (w) goto end; - fitBelowFloats(tmpW, width); + fitBelowFloats(tmpW, firstLine, width); // |width| may have been adjusted because we got shoved down past a float (thus // giving us more room), so we need to retest, and only jump to @@ -2094,8 +2102,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } end: - - if (lBreak == resolver.position() && !lBreak.obj->isBR()) { + if (lBreak == resolver.position() && (!lBreak.obj || !lBreak.obj->isBR())) { // we just add as much as possible if (style()->whiteSpace() == PRE) { // FIXME: Don't really understand this case. @@ -2129,25 +2136,25 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle lBreak.increment(); // Sanity check our midpoints. - checkMidpoints(lBreak); + checkMidpoints(lineMidpointState, lBreak); if (trailingSpaceObject) { // This object is either going to be part of the last midpoint, or it is going // to be the actual endpoint. In both cases we just decrease our pos by 1 level to // exclude the space, allowing it to - in effect - collapse into the newline. - if (sNumMidpoints%2==1) { - InlineIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints-1].pos--; + if (lineMidpointState.numMidpoints % 2) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + midpoints[lineMidpointState.numMidpoints - 1].pos--; } //else if (lBreak.pos > 0) // lBreak.pos--; else if (lBreak.obj == 0 && trailingSpaceObject->isText()) { // Add a new end midpoint that stops right at the very end. - RenderText* text = static_cast<RenderText *>(trailingSpaceObject); + RenderText* text = toRenderText(trailingSpaceObject); unsigned length = text->textLength(); unsigned pos = length >= 2 ? length - 2 : UINT_MAX; InlineIterator endMid(0, trailingSpaceObject, pos); - addMidpoint(endMid); + addMidpoint(lineMidpointState, endMid); } } @@ -2163,9 +2170,9 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) { // For soft hyphens on line breaks, we have to chop out the midpoints that made us // ignore the hyphen so that it will render at the end of the line. - UChar c = static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos-1]; + UChar c = toRenderText(lBreak.obj)->characters()[lBreak.pos - 1]; if (c == softHyphen) - chopMidpointsAt(lBreak.obj, lBreak.pos-2); + chopMidpointsAt(lineMidpointState, lBreak.obj, lBreak.pos - 2); } return lBreak; @@ -2173,7 +2180,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle void RenderBlock::checkLinesForOverflow() { - m_overflowWidth = m_width; + m_overflowWidth = width(); for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft); m_overflowTop = min(curr->topOverflow(), m_overflowTop); @@ -2205,16 +2212,18 @@ void RenderBlock::checkLinesForTextOverflow() // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()" bool ltr = style()->direction() == LTR; for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos()); - int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos(); - if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) { + int blockRightEdge = rightOffset(curr->y(), curr == firstRootBox()); + int blockLeftEdge = leftOffset(curr->y(), curr == firstRootBox()); + int lineBoxEdge = ltr ? curr->x() + curr->width() : curr->x(); + if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) { // This line spills out of our box in the appropriate direction. Now we need to see if the line // can be truncated. In order for truncation to be possible, the line must have sufficient space to // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis // space. int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth; + int blockEdge = ltr ? blockRightEdge : blockLeftEdge; if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) - curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width); + curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width); } } } diff --git a/src/3rdparty/webkit/WebCore/rendering/bidi.h b/src/3rdparty/webkit/WebCore/rendering/bidi.h index fc6de5b..9058eeb 100644 --- a/src/3rdparty/webkit/WebCore/rendering/bidi.h +++ b/src/3rdparty/webkit/WebCore/rendering/bidi.h @@ -38,7 +38,6 @@ struct BidiRun : BidiCharacterRun { : BidiCharacterRun(start, stop, context, dir) , m_object(object) , m_box(0) - , m_compact(false) { } @@ -59,7 +58,6 @@ private: public: RenderObject* m_object; InlineBox* m_box; - bool m_compact; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp index 05748ac..9b46cd2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp @@ -68,7 +68,7 @@ static inline bool needsLineBreakIterator(UChar ch) return ch > 0x7F && ch != noBreakSpace; } -#ifdef BUILDING_ON_TIGER +#if PLATFORM(MAC) && defined(BUILDING_ON_TIGER) static inline TextBreakLocatorRef lineBreakLocator() { TextBreakLocatorRef locator = 0; @@ -79,7 +79,7 @@ static inline TextBreakLocatorRef lineBreakLocator() int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakSpaceAsBreak) { -#ifndef BUILDING_ON_TIGER +#if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) TextBreakIterator* breakIterator = 0; #endif int nextBreak = -1; @@ -93,7 +93,7 @@ int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakS if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { if (nextBreak < i && i) { -#ifndef BUILDING_ON_TIGER +#if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) if (!breakIterator) breakIterator = lineBreakIterator(str, len); if (breakIterator) diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp index b38cc49..410cad4 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp @@ -30,22 +30,9 @@ namespace WebCore { void ContentData::clear() { - switch (m_type) { - case CONTENT_NONE: - break; - case CONTENT_OBJECT: - m_content.m_image->deref(); - break; - case CONTENT_TEXT: - m_content.m_text->deref(); - break; - case CONTENT_COUNTER: - delete m_content.m_counter; - break; - } + deleteContent(); ContentData* n = m_next; - m_type = CONTENT_NONE; m_next = 0; // Reverse the list so we can delete without recursing. @@ -63,4 +50,47 @@ void ContentData::clear() } } +bool ContentData::dataEquivalent(const ContentData& other) const +{ + if (type() != other.type()) + return false; + + switch (type()) { + case CONTENT_NONE: + return true; + break; + case CONTENT_TEXT: + return equal(text(), other.text()); + break; + case CONTENT_OBJECT: + return StyleImage::imagesEquivalent(image(), other.image()); + break; + case CONTENT_COUNTER: + return *counter() == *other.counter(); + break; + } + + ASSERT_NOT_REACHED(); + return false; +} + +void ContentData::deleteContent() +{ + switch (m_type) { + case CONTENT_NONE: + break; + case CONTENT_OBJECT: + m_content.m_image->deref(); + break; + case CONTENT_TEXT: + m_content.m_text->deref(); + break; + case CONTENT_COUNTER: + delete m_content.m_counter; + break; + } + + m_type = CONTENT_NONE; +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h index d924d1a..24d5f86 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h @@ -25,16 +25,18 @@ #ifndef ContentData_h #define ContentData_h +#include "PlatformString.h" #include "RenderStyleConstants.h" +#include "StringImpl.h" +#include "StyleImage.h" #include <wtf/Noncopyable.h> namespace WebCore { class CounterContent; -class StringImpl; -class StyleImage; struct ContentData : Noncopyable { +public: ContentData() : m_type(CONTENT_NONE) , m_next(0) @@ -48,7 +50,49 @@ struct ContentData : Noncopyable { void clear(); - ContentType m_type; + bool isCounter() const { return m_type == CONTENT_COUNTER; } + bool isImage() const { return m_type == CONTENT_OBJECT; } + bool isNone() const { return m_type == CONTENT_NONE; } + bool isText() const { return m_type == CONTENT_TEXT; } + + StyleContentType type() const { return m_type; } + + bool dataEquivalent(const ContentData&) const; + + StyleImage* image() const { return m_content.m_image; } + void setImage(PassRefPtr<StyleImage> image) + { + deleteContent(); + m_type = CONTENT_OBJECT; + m_content.m_image = image.releaseRef(); + } + + StringImpl* text() const { return m_content.m_text; } + void setText(PassRefPtr<StringImpl> text) + { + deleteContent(); + m_type = CONTENT_TEXT; + m_content.m_text = text.releaseRef(); + } + + CounterContent* counter() const { return m_content.m_counter; } + void setCounter(CounterContent* counter) + { + deleteContent(); + m_type = CONTENT_COUNTER; + m_content.m_counter = counter; + } + + ContentData* next() const { return m_next; } + void setNext(ContentData* next) + { + m_next = next; + } + +private: + void deleteContent(); + + StyleContentType m_type; union { StyleImage* m_image; StringImpl* m_text; diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h index 06440ad..cf11813 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h @@ -49,11 +49,11 @@ private: AtomicString m_separator; }; -static inline bool operator!=(const CounterContent& a, const CounterContent& b) +static inline bool operator==(const CounterContent& a, const CounterContent& b) { - return a.identifier() != b.identifier() - || a.listStyle() != b.listStyle() - || a.separator() != b.separator(); + return a.identifier() == b.identifier() + && a.listStyle() == b.listStyle() + && a.separator() == b.separator(); } diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp index 872ee9c..e4027db 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp @@ -32,9 +32,9 @@ #include <wtf/StdLibExtras.h> #include <algorithm> -namespace WebCore { +using namespace std; -TransformOperations RenderStyle::s_initialTransform; +namespace WebCore { inline RenderStyle* defaultStyle() { @@ -58,14 +58,7 @@ PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other) } RenderStyle::RenderStyle() - : box(defaultStyle()->box) - , visual(defaultStyle()->visual) - , background(defaultStyle()->background) - , surround(defaultStyle()->surround) - , rareNonInheritedData(defaultStyle()->rareNonInheritedData) - , rareInheritedData(defaultStyle()->rareInheritedData) - , inherited(defaultStyle()->inherited) - , m_pseudoState(PseudoUnknown) + : m_pseudoState(PseudoUnknown) , m_affectedByAttributeSelectors(false) , m_unique(false) , m_affectedByEmpty(false) @@ -78,6 +71,13 @@ RenderStyle::RenderStyle() , m_firstChildState(false) , m_lastChildState(false) , m_childIndex(0) + , box(defaultStyle()->box) + , visual(defaultStyle()->visual) + , background(defaultStyle()->background) + , surround(defaultStyle()->surround) + , rareNonInheritedData(defaultStyle()->rareNonInheritedData) + , rareInheritedData(defaultStyle()->rareInheritedData) + , inherited(defaultStyle()->inherited) #if ENABLE(SVG) , m_svgStyle(defaultStyle()->m_svgStyle) #endif @@ -121,15 +121,6 @@ RenderStyle::RenderStyle(bool) RenderStyle::RenderStyle(const RenderStyle& o) : RefCounted<RenderStyle>() - , inherited_flags(o.inherited_flags) - , noninherited_flags(o.noninherited_flags) - , box(o.box) - , visual(o.visual) - , background(o.background) - , surround(o.surround) - , rareNonInheritedData(o.rareNonInheritedData) - , rareInheritedData(o.rareInheritedData) - , inherited(o.inherited) , m_pseudoState(o.m_pseudoState) , m_affectedByAttributeSelectors(false) , m_unique(false) @@ -143,9 +134,18 @@ RenderStyle::RenderStyle(const RenderStyle& o) , m_firstChildState(false) , m_lastChildState(false) , m_childIndex(0) + , box(o.box) + , visual(o.visual) + , background(o.background) + , surround(o.surround) + , rareNonInheritedData(o.rareNonInheritedData) + , rareInheritedData(o.rareInheritedData) + , inherited(o.inherited) #if ENABLE(SVG) , m_svgStyle(o.m_svgStyle) #endif + , inherited_flags(o.inherited_flags) + , noninherited_flags(o.noninherited_flags) { } @@ -187,7 +187,7 @@ bool RenderStyle::isStyleAvailable() const return this != CSSStyleSelector::styleNotYetAvailable(); } -static inline int pseudoBit(RenderStyle::PseudoId pseudo) +static inline int pseudoBit(PseudoId pseudo) { return 1 << (pseudo - 1); } @@ -206,7 +206,7 @@ void RenderStyle::setHasPseudoStyle(PseudoId pseudo) noninherited_flags._pseudoBits |= pseudoBit(pseudo); } -RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) +RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const { if (!m_cachedPseudoStyle || styleType() != NOPSEUDO) return 0; @@ -225,7 +225,7 @@ RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo) return m_cachedPseudoStyle.get(); } -bool RenderStyle::inheritedNotEqual(RenderStyle* other) const +bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const { return inherited_flags != other->inherited_flags || inherited != other->inherited || @@ -235,7 +235,7 @@ bool RenderStyle::inheritedNotEqual(RenderStyle* other) const rareInheritedData != other->rareInheritedData; } -bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) +static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) { // If any unit types are different, then we can't guarantee // that this was just a movement. @@ -273,14 +273,16 @@ bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) optimisations are unimplemented, and currently result in the worst case result causing a relayout of the containing block. */ -RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const +StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const { + changedContextSensitiveProperties = ContextSensitivePropertyNone; + #if ENABLE(SVG) // This is horribly inefficient. Eventually we'll have to integrate // this more directly by calling: Diff svgDiff = svgStyle->diff(other) // and then checking svgDiff and returning from the appropriate places below. if (m_svgStyle != other->m_svgStyle) - return Layout; + return StyleDifferenceLayout; #endif if (box->width != other->box->width || @@ -289,19 +291,19 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const box->height != other->box->height || box->min_height != other->box->min_height || box->max_height != other->box->max_height) - return Layout; + return StyleDifferenceLayout; if (box->vertical_align != other->box->vertical_align || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) - return Layout; + return StyleDifferenceLayout; if (box->boxSizing != other->box->boxSizing) - return Layout; + return StyleDifferenceLayout; if (surround->margin != other->surround->margin) - return Layout; + return StyleDifferenceLayout; if (surround->padding != other->surround->padding) - return Layout; + return StyleDifferenceLayout; if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance || @@ -309,30 +311,47 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const rareNonInheritedData->marginBottomCollapse != other->rareNonInheritedData->marginBottomCollapse || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) - return Layout; + return StyleDifferenceLayout; if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() && *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get()) - return Layout; + return StyleDifferenceLayout; if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get())) - return Layout; + return StyleDifferenceLayout; if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) - return Layout; + return StyleDifferenceLayout; if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) - return Layout; + return StyleDifferenceLayout; if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() && - *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) - return Layout; + *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { +#if USE(ACCELERATED_COMPOSITING) + changedContextSensitiveProperties |= ContextSensitivePropertyTransform; + // Don't return; keep looking for another change +#else + return StyleDifferenceLayout; +#endif + } + +#if !USE(ACCELERATED_COMPOSITING) + if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { + if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || + rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || + rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || + rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || + rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) + return StyleDifferenceLayout; + } +#endif #if ENABLE(DASHBOARD_SUPPORT) // If regions change, trigger a relayout to re-calc regions. if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions) - return Layout; + return StyleDifferenceLayout; #endif } @@ -344,13 +363,13 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const rareInheritedData->nbspMode != other->rareInheritedData->nbspMode || rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity) - return Layout; + return StyleDifferenceLayout; if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) - return Layout; + return StyleDifferenceLayout; if (textStrokeWidth() != other->textStrokeWidth()) - return Layout; + return StyleDifferenceLayout; } if (inherited->indent != other->inherited->indent || @@ -365,7 +384,7 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const noninherited_flags._position != other->noninherited_flags._position || noninherited_flags._floating != other->noninherited_flags._floating || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) - return Layout; + return StyleDifferenceLayout; if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { @@ -373,26 +392,26 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const inherited_flags._empty_cells != other->inherited_flags._empty_cells || inherited_flags._caption_side != other->inherited_flags._caption_side || noninherited_flags._table_layout != other->noninherited_flags._table_layout) - return Layout; + return StyleDifferenceLayout; // In the collapsing border model, 'hidden' suppresses other borders, while 'none' // does not, so these style differences can be width differences. if (inherited_flags._border_collapse && - (borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE || - borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN || - borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE || - borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN || - borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE || - borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN || - borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE || - borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)) - return Layout; + ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) || + (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) || + (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) || + (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) || + (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) || + (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) || + (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) || + (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) + return StyleDifferenceLayout; } if (noninherited_flags._effectiveDisplay == LIST_ITEM) { if (inherited_flags._list_style_type != other->inherited_flags._list_style_type || inherited_flags._list_style_position != other->inherited_flags._list_style_position) - return Layout; + return StyleDifferenceLayout; } if (inherited_flags._text_align != other->inherited_flags._text_align || @@ -400,12 +419,12 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const inherited_flags._direction != other->inherited_flags._direction || inherited_flags._white_space != other->inherited_flags._white_space || noninherited_flags._clear != other->noninherited_flags._clear) - return Layout; + return StyleDifferenceLayout; // Overflow returns a layout hint. if (noninherited_flags._overflowX != other->noninherited_flags._overflowX || noninherited_flags._overflowY != other->noninherited_flags._overflowY) - return Layout; + return StyleDifferenceLayout; // If our border widths change, then we need to layout. Other changes to borders // only necessitate a repaint. @@ -413,19 +432,19 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const borderTopWidth() != other->borderTopWidth() || borderBottomWidth() != other->borderBottomWidth() || borderRightWidth() != other->borderRightWidth()) - return Layout; + return StyleDifferenceLayout; // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get(); const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) - return Layout; + return StyleDifferenceLayout; if (visual->counterIncrement != other->visual->counterIncrement || visual->counterReset != other->visual->counterReset) - return Layout; + return StyleDifferenceLayout; if (inherited->m_effectiveZoom != other->inherited->m_effectiveZoom) - return Layout; + return StyleDifferenceLayout; // Make sure these left/top/right/bottom checks stay below all layout checks and above // all visible checks. @@ -433,7 +452,7 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const if (surround->offset != other->surround->offset) { // Optimize for the case where a positioned layer is moving but not changing size. if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset)) - return LayoutPositionedMovementOnly; + return StyleDifferenceLayoutPositionedMovementOnly; // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we // can stop doing a layout when relative positioned objects move. In particular, we'll need @@ -441,16 +460,24 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const //if (other->position() == RelativePosition) // return RepaintLayer; //else - return Layout; + return StyleDifferenceLayout; } else if (box->z_index != other->box->z_index || box->z_auto != other->box->z_auto || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip) - return RepaintLayer; + return StyleDifferenceRepaintLayer; + } + + if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) { +#if USE(ACCELERATED_COMPOSITING) + changedContextSensitiveProperties |= ContextSensitivePropertyOpacity; + // Don't return; keep looking for another change. +#else + return StyleDifferenceRepaintLayer; +#endif } - if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity || - rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask || + if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) - return RepaintLayer; + return StyleDifferenceRepaintLayer; if (inherited->color != other->inherited->color || inherited_flags._visibility != other->inherited_flags._visibility || @@ -465,19 +492,30 @@ RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor) - return Repaint; + return StyleDifferenceRepaint; + +#if USE(ACCELERATED_COMPOSITING) + if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { + if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || + rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || + rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || + rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || + rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) + return StyleDifferenceRecompositeLayer; + } +#endif // Cursors are not checked, since they will be set appropriately in response to mouse events, // so they don't need to cause any repaint or layout. // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off // the resulting transition properly. - return Equal; + return StyleDifferenceEqual; } void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) { - StyleVisualData *data = visual.access(); + StyleVisualData* data = visual.access(); data->clip.m_top = top; data->clip.m_right = right; data->clip.m_bottom = bottom; @@ -501,40 +539,8 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other) void RenderStyle::clearCursorList() { - inherited.access()->cursorData = CursorList::create(); -} - -bool RenderStyle::contentDataEquivalent(const RenderStyle* otherStyle) const -{ - ContentData* c1 = rareNonInheritedData->m_content.get(); - ContentData* c2 = otherStyle->rareNonInheritedData->m_content.get(); - - while (c1 && c2) { - if (c1->m_type != c2->m_type) - return false; - - switch (c1->m_type) { - case CONTENT_NONE: - break; - case CONTENT_TEXT: - if (!equal(c1->m_content.m_text, c2->m_content.m_text)) - return false; - break; - case CONTENT_OBJECT: - if (!StyleImage::imagesEquivalent(c1->m_content.m_image, c2->m_content.m_image)) - return false; - break; - case CONTENT_COUNTER: - if (*c1->m_content.m_counter != *c2->m_content.m_counter) - return false; - break; - } - - c1 = c1->m_next; - c2 = c2->m_next; - } - - return !c1 && !c2; + if (inherited->cursorData) + inherited.access()->cursorData = 0; } void RenderStyle::clearContent() @@ -550,8 +556,8 @@ void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); - while (lastContent && lastContent->m_next) - lastContent = lastContent->m_next; + while (lastContent && lastContent->next()) + lastContent = lastContent->next(); bool reuseContent = !add; ContentData* newContentData; @@ -562,34 +568,30 @@ void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) newContentData = new ContentData; if (lastContent && !reuseContent) - lastContent->m_next = newContentData; + lastContent->setNext(newContentData); else content.set(newContentData); - newContentData->m_content.m_image = image.releaseRef(); - newContentData->m_type = CONTENT_OBJECT; + newContentData->setImage(image); } -void RenderStyle::setContent(StringImpl* s, bool add) +void RenderStyle::setContent(PassRefPtr<StringImpl> s, bool add) { if (!s) return; // The string is null. Nothing to do. Just bail. OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); - while (lastContent && lastContent->m_next) - lastContent = lastContent->m_next; + while (lastContent && lastContent->next()) + lastContent = lastContent->next(); bool reuseContent = !add; if (add && lastContent) { - if (lastContent->m_type == CONTENT_TEXT) { + if (lastContent->isText()) { // We can augment the existing string and share this ContentData node. - StringImpl* oldStr = lastContent->m_content.m_text; - String newStr = oldStr; - newStr.append(s); - newStr.impl()->ref(); - oldStr->deref(); - lastContent->m_content.m_text = newStr.impl(); + String newStr = lastContent->text(); + newStr.append(s.get()); + lastContent->setText(newStr.impl()); return; } } @@ -602,13 +604,11 @@ void RenderStyle::setContent(StringImpl* s, bool add) newContentData = new ContentData; if (lastContent && !reuseContent) - lastContent->m_next = newContentData; + lastContent->setNext(newContentData); else content.set(newContentData); - newContentData->m_content.m_text = s; - newContentData->m_content.m_text->ref(); - newContentData->m_type = CONTENT_TEXT; + newContentData->setText(s); } void RenderStyle::setContent(CounterContent* c, bool add) @@ -618,8 +618,8 @@ void RenderStyle::setContent(CounterContent* c, bool add) OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); - while (lastContent && lastContent->m_next) - lastContent = lastContent->m_next; + while (lastContent && lastContent->next()) + lastContent = lastContent->next(); bool reuseContent = !add; ContentData* newContentData = 0; @@ -630,15 +630,14 @@ void RenderStyle::setContent(CounterContent* c, bool add) newContentData = new ContentData; if (lastContent && !reuseContent) - lastContent->m_next = newContentData; + lastContent->setNext(newContentData); else content.set(newContentData); - newContentData->m_content.m_counter = c; - newContentData->m_type = CONTENT_COUNTER; + newContentData->setCounter(c); } -void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, bool includeTransformOrigin) const +void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const { // transform-origin brackets the transform with translate operations. // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant @@ -646,26 +645,31 @@ void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& bool applyTransformOrigin = false; unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size(); unsigned i; - if (includeTransformOrigin) { + if (applyOrigin == IncludeTransformOrigin) { for (i = 0; i < s; i++) { TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType(); if (type != TransformOperation::TRANSLATE_X && type != TransformOperation::TRANSLATE_Y && - type != TransformOperation::TRANSLATE) { + type != TransformOperation::TRANSLATE && + type != TransformOperation::TRANSLATE_Z && + type != TransformOperation::TRANSLATE_3D + ) { applyTransformOrigin = true; break; } } } - if (applyTransformOrigin) - transform.translate(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height())); + if (applyTransformOrigin) { + transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ()); + } for (i = 0; i < s; i++) rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize); - if (applyTransformOrigin) - transform.translate(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height())); + if (applyTransformOrigin) { + transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); + } } #if ENABLE(XBL) @@ -707,6 +711,58 @@ void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add) rareData->m_boxShadow.set(shadowData); } +void RenderStyle::getBorderRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) const +{ + topLeft = surround->border.topLeft; + topRight = surround->border.topRight; + + bottomLeft = surround->border.bottomLeft; + bottomRight = surround->border.bottomRight; + + // Constrain corner radii using CSS3 rules: + // http://www.w3.org/TR/css3-background/#the-border-radius + + float factor = 1; + unsigned radiiSum; + + // top + radiiSum = static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()); // Casts to avoid integer overflow. + if (radiiSum > static_cast<unsigned>(r.width())) + factor = min(static_cast<float>(r.width()) / radiiSum, factor); + + // bottom + radiiSum = static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()); + if (radiiSum > static_cast<unsigned>(r.width())) + factor = min(static_cast<float>(r.width()) / radiiSum, factor); + + // left + radiiSum = static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()); + if (radiiSum > static_cast<unsigned>(r.height())) + factor = min(static_cast<float>(r.height()) / radiiSum, factor); + + // right + radiiSum = static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()); + if (radiiSum > static_cast<unsigned>(r.height())) + factor = min(static_cast<float>(r.height()) / radiiSum, factor); + + // Scale all radii by f if necessary. + if (factor < 1) { + // If either radius on a corner becomes zero, reset both radii on that corner. + topLeft.scale(factor); + if (!topLeft.width() || !topLeft.height()) + topLeft = IntSize(); + topRight.scale(factor); + if (!topRight.width() || !topRight.height()) + topRight = IntSize(); + bottomLeft.scale(factor); + if (!bottomLeft.width() || !bottomLeft.height()) + bottomLeft = IntSize(); + bottomRight.scale(factor); + if (!bottomRight.width() || !bottomRight.height()) + bottomRight = IntSize(); + } +} + const CounterDirectiveMap* RenderStyle::counterDirectives() const { return rareNonInheritedData->m_counterDirectives.get(); @@ -753,7 +809,7 @@ void RenderStyle::adjustAnimations() if (!animationList) return; - // get rid of empty transitions and anything beyond them + // Get rid of empty animations and anything beyond them for (size_t i = 0; i < animationList->size(); ++i) { if (animationList->animation(i)->isEmpty()) { animationList->resize(i); @@ -776,7 +832,7 @@ void RenderStyle::adjustTransitions() if (!transitionList) return; - // get rid of empty transitions and anything beyond them + // Get rid of empty transitions and anything beyond them for (size_t i = 0; i < transitionList->size(); ++i) { if (transitionList->animation(i)->isEmpty()) { transitionList->resize(i); @@ -819,7 +875,7 @@ AnimationList* RenderStyle::accessTransitions() return rareNonInheritedData->m_transitions.get(); } -const Animation* RenderStyle::transitionForProperty(int property) +const Animation* RenderStyle::transitionForProperty(int property) const { if (transitions()) { for (size_t i = 0; i < transitions()->size(); ++i) { diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h index f38f943..46c91cd 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h @@ -106,20 +106,46 @@ class StyleImage; class RenderStyle: public RefCounted<RenderStyle> { friend class CSSStyleSelector; +protected: -public: - // static pseudo styles. Dynamic ones are produced on the fly. - enum PseudoId { 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_TIME_DISPLAY, - MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON , MEDIA_CONTROLS_FULLSCREEN_BUTTON, - SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER }; - static const int FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON; + // The following bitfield is 32-bits long, which optimizes padding with the + // int refCount in the base class. Beware when adding more bits. + unsigned m_pseudoState : 3; // PseudoState + bool m_affectedByAttributeSelectors : 1; + bool m_unique : 1; -private: - static TransformOperations s_initialTransform; + // Bits for dynamic child matching. + bool m_affectedByEmpty : 1; + bool m_emptyState : 1; -protected: + // We optimize for :first-child and :last-child. The other positional child selectors like nth-child or + // *-child-of-type, we will just give up and re-evaluate whenever children change at all. + bool m_childrenAffectedByFirstChildRules : 1; + bool m_childrenAffectedByLastChildRules : 1; + bool m_childrenAffectedByDirectAdjacentRules : 1; + bool m_childrenAffectedByForwardPositionalRules : 1; + bool m_childrenAffectedByBackwardPositionalRules : 1; + bool m_firstChildState : 1; + bool m_lastChildState : 1; + unsigned m_childIndex : 18; // Plenty of bits to cache an index. + + // non-inherited attributes + DataRef<StyleBoxData> box; + DataRef<StyleVisualData> visual; + DataRef<StyleBackgroundData> background; + DataRef<StyleSurroundData> surround; + DataRef<StyleRareNonInheritedData> rareNonInheritedData; + + // inherited attributes + DataRef<StyleRareInheritedData> rareInheritedData; + DataRef<StyleInheritedData> inherited; + + // list of associated pseudo styles + RefPtr<RenderStyle> m_cachedPseudoStyle; + +#if ENABLE(SVG) + DataRef<SVGRenderStyle> m_svgStyle; +#endif // !START SYNC!: Keep this in sync with the copy constructor in RenderStyle.cpp @@ -162,12 +188,14 @@ 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 + // non CSS2 inherited bool _visuallyOrdered : 1; - bool _htmlHacks :1; + bool _htmlHacks : 1; bool _force_backgrounds_to_white : 1; unsigned _pointerEvents : 4; // EPointerEvents + // 39 bits } inherited_flags; // don't inherit @@ -214,45 +242,9 @@ protected: bool _affectedByDrag : 1; unsigned _pseudoBits : 7; unsigned _unicodeBidi : 2; // EUnicodeBidi + // 48 bits } noninherited_flags; - // non-inherited attributes - DataRef<StyleBoxData> box; - DataRef<StyleVisualData> visual; - DataRef<StyleBackgroundData> background; - DataRef<StyleSurroundData> surround; - DataRef<StyleRareNonInheritedData> rareNonInheritedData; - - // inherited attributes - DataRef<StyleRareInheritedData> rareInheritedData; - DataRef<StyleInheritedData> inherited; - - // list of associated pseudo styles - RefPtr<RenderStyle> m_cachedPseudoStyle; - - unsigned m_pseudoState : 3; // PseudoState - bool m_affectedByAttributeSelectors : 1; - bool m_unique : 1; - - // Bits for dynamic child matching. - bool m_affectedByEmpty : 1; - bool m_emptyState : 1; - - // We optimize for :first-child and :last-child. The other positional child selectors like nth-child or - // *-child-of-type, we will just give up and re-evaluate whenever children change at all. - bool m_childrenAffectedByFirstChildRules : 1; - bool m_childrenAffectedByLastChildRules : 1; - bool m_childrenAffectedByDirectAdjacentRules : 1; - bool m_childrenAffectedByForwardPositionalRules : 1; - bool m_childrenAffectedByBackwardPositionalRules : 1; - bool m_firstChildState : 1; - bool m_lastChildState : 1; - unsigned m_childIndex : 18; // Plenty of bits to cache an index. - -#if ENABLE(SVG) - DataRef<SVGRenderStyle> m_svgStyle; -#endif - // !END SYNC! protected: @@ -309,10 +301,10 @@ public: void inheritFrom(const RenderStyle* inheritParent); - PseudoId styleType() { return static_cast<PseudoId>(noninherited_flags._styleType); } + PseudoId styleType() const { return static_cast<PseudoId>(noninherited_flags._styleType); } void setStyleType(PseudoId styleType) { noninherited_flags._styleType = styleType; } - RenderStyle* getCachedPseudoStyle(PseudoId); + RenderStyle* getCachedPseudoStyle(PseudoId) const; RenderStyle* addCachedPseudoStyle(PassRefPtr<RenderStyle>); bool affectedByHoverRules() const { return noninherited_flags._affectedByHover; } @@ -337,6 +329,7 @@ public: return true; return background->m_background.hasImage(); } + bool hasBackgroundImage() const { return background->m_background.hasImage(); } bool hasFixedBackgroundImage() const { return background->m_background.hasFixedImage(); } bool hasAppearance() const { return appearance() != NoControlPart; } @@ -358,6 +351,11 @@ public: Length top() const { return surround->offset.top(); } Length bottom() const { return surround->offset.bottom(); } + // Whether or not a positioned element requires normal flow x/y to be computed + // to determine its position. + bool hasStaticX() const { return (left().isAuto() && right().isAuto()) || left().isStatic() || right().isStatic(); } + bool hasStaticY() const { return (top().isAuto() && bottom().isAuto()) || top().isStatic(); } + EPosition position() const { return static_cast<EPosition>(noninherited_flags._position); } EFloat floating() const { return static_cast<EFloat>(noninherited_flags._floating); } @@ -448,6 +446,19 @@ public: TextDirection direction() const { return static_cast<TextDirection>(inherited_flags._direction); } Length lineHeight() const { return inherited->line_height; } + int computedLineHeight() const + { + Length lh = lineHeight(); + + // Negative value means the line height is not set. Use the font's built-in spacing. + if (lh.isNegative()) + return font().lineSpacing(); + + if (lh.isPercent()) + return lh.calcMinValue(fontSize()); + + return lh.value(); + } EWhiteSpace whiteSpace() const { return static_cast<EWhiteSpace>(inherited_flags._white_space); } static bool autoWrap(EWhiteSpace ws) @@ -630,8 +641,16 @@ public: const TransformOperations& transform() const { return rareNonInheritedData->m_transform->m_operations; } Length transformOriginX() const { return rareNonInheritedData->m_transform->m_x; } Length transformOriginY() const { return rareNonInheritedData->m_transform->m_y; } + float transformOriginZ() const { return rareNonInheritedData->m_transform->m_z; } bool hasTransform() const { return !rareNonInheritedData->m_transform->m_operations.operations().isEmpty(); } - void applyTransform(TransformationMatrix&, const IntSize& borderBoxSize, bool includeTransformOrigin = true) const; + + // Return true if any transform related property (currently transform, transformStyle3D or perspective) + // indicates that we are transforming + bool hasTransformRelatedProperty() const { return hasTransform() || preserves3D() || hasPerspective(); } + + enum ApplyTransformOrigin { IncludeTransformOrigin, ExcludeTransformOrigin }; + void applyTransform(TransformationMatrix&, const IntSize& borderBoxSize, ApplyTransformOrigin = IncludeTransformOrigin) const; + bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); } // End CSS3 Getters @@ -647,7 +666,21 @@ public: bool hasTransitions() const { return rareNonInheritedData->m_transitions && rareNonInheritedData->m_transitions->size() > 0; } // return the first found Animation (including 'all' transitions) - const Animation* transitionForProperty(int property); + const Animation* transitionForProperty(int property) const; + + ETransformStyle3D transformStyle3D() const { return rareNonInheritedData->m_transformStyle3D; } + bool preserves3D() const { return rareNonInheritedData->m_transformStyle3D == TransformStyle3DPreserve3D; } + + EBackfaceVisibility backfaceVisibility() const { return rareNonInheritedData->m_backfaceVisibility; } + float perspective() const { return rareNonInheritedData->m_perspective; } + bool hasPerspective() const { return rareNonInheritedData->m_perspective > 0; } + Length perspectiveOriginX() const { return rareNonInheritedData->m_perspectiveOriginX; } + Length perspectiveOriginY() const { return rareNonInheritedData->m_perspectiveOriginY; } + +#if USE(ACCELERATED_COMPOSITING) + // When set, this ensures that styles compare as different. Used during accelerated animations. + bool isRunningAcceleratedAnimation() const { return rareNonInheritedData->m_runningAcceleratedAnimation; } +#endif int lineClamp() const { return rareNonInheritedData->lineClamp; } bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; } @@ -708,6 +741,10 @@ public: void setBackgroundColor(const Color& v) { SET_VAR(background, m_color, v) } + void setBackgroundXPosition(Length l) { SET_VAR(background, m_background.m_xPosition, l) } + void setBackgroundYPosition(Length l) { SET_VAR(background, m_background.m_yPosition, l) } + void setBackgroundSize(LengthSize l) { SET_VAR(background, m_background.m_size, l) } + void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.image, b) } void setBorderTopLeftRadius(const IntSize& s) { SET_VAR(surround, border.topLeft, s) } @@ -722,6 +759,8 @@ public: setBorderBottomLeftRadius(s); setBorderBottomRightRadius(s); } + + void getBorderRadiiForRect(const IntRect&, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) const; void setBorderLeftWidth(unsigned short v) { SET_VAR(surround, border.left.width, v) } void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.left.m_style, v) } @@ -815,6 +854,9 @@ public: } void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b) } + void setMaskXPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, l) } + void setMaskYPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, l) } + void setMaskSize(LengthSize l) { SET_VAR(rareNonInheritedData, m_mask.m_size, l) } void setBorderCollapse(bool collapse) { inherited_flags._border_collapse = collapse; } void setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v) } @@ -924,6 +966,7 @@ public: void setTransform(const TransformOperations& ops) { SET_VAR(rareNonInheritedData.access()->m_transform, m_operations, ops); } void setTransformOriginX(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); } void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); } + void setTransformOriginZ(float f) { SET_VAR(rareNonInheritedData.access()->m_transform, m_z, f); } // End CSS3 Setters // Apple-specific property setters @@ -944,6 +987,16 @@ public: void adjustAnimations(); void adjustTransitions(); + void setTransformStyle3D(ETransformStyle3D b) { SET_VAR(rareNonInheritedData, m_transformStyle3D, b); } + void setBackfaceVisibility(EBackfaceVisibility b) { SET_VAR(rareNonInheritedData, m_backfaceVisibility, b); } + void setPerspective(float p) { SET_VAR(rareNonInheritedData, m_perspective, p); } + void setPerspectiveOriginX(Length l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginX, l); } + void setPerspectiveOriginY(Length l) { SET_VAR(rareNonInheritedData, m_perspectiveOriginY, l); } + +#if USE(ACCELERATED_COMPOSITING) + void setIsRunningAcceleratedAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_runningAcceleratedAnimation, b); } +#endif + void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); } void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); } void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); } @@ -963,24 +1016,18 @@ public: #endif const ContentData* contentData() const { return rareNonInheritedData->m_content.get(); } - bool contentDataEquivalent(const RenderStyle* otherStyle) const; + bool contentDataEquivalent(const RenderStyle* otherStyle) const { return const_cast<RenderStyle*>(this)->rareNonInheritedData->contentDataEquivalent(*const_cast<RenderStyle*>(otherStyle)->rareNonInheritedData); } void clearContent(); - void setContent(StringImpl*, bool add = false); + void setContent(PassRefPtr<StringImpl>, bool add = false); void setContent(PassRefPtr<StyleImage>, bool add = false); void setContent(CounterContent*, bool add = false); const CounterDirectiveMap* counterDirectives() const; CounterDirectiveMap& accessCounterDirectives(); - bool inheritedNotEqual(RenderStyle*) const; + bool inheritedNotEqual(const RenderStyle*) const; - // The difference between two styles. The following values are used: - // (1) Equal - The two styles are identical - // (2) Repaint - The object just needs to be repainted. - // (3) RepaintLayer - The layer and its descendant layers needs to be repainted. - // (4) Layout - A layout is required. - enum Diff { Equal, Repaint, RepaintLayer, LayoutPositionedMovementOnly, Layout }; - Diff diff(const RenderStyle*) const; + StyleDifference diff(const RenderStyle*, unsigned& changedContextSensitiveProperties) const; bool isDisplayReplacedType() const { @@ -1109,10 +1156,16 @@ public: static bool initialVisuallyOrdered() { return false; } static float initialTextStrokeWidth() { return 0; } static unsigned short initialColumnCount() { return 1; } - static const TransformOperations& initialTransform() { return s_initialTransform; } + static const TransformOperations& initialTransform() { DEFINE_STATIC_LOCAL(TransformOperations, ops, ()); return ops; } static Length initialTransformOriginX() { return Length(50.0, Percent); } static Length initialTransformOriginY() { return Length(50.0, Percent); } static EPointerEvents initialPointerEvents() { return PE_AUTO; } + static float initialTransformOriginZ() { return 0; } + static ETransformStyle3D initialTransformStyle3D() { return TransformStyle3DFlat; } + static EBackfaceVisibility initialBackfaceVisibility() { return BackfaceVisibilityVisible; } + static float initialPerspective() { return 0; } + static Length initialPerspectiveOriginX() { return Length(50.0, Percent); } + static Length initialPerspectiveOriginY() { return Length(50.0, Percent); } // Keep these at the end. static int initialLineClamp() { return -1; } diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h index 40ad3cc..405cf7c 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h @@ -36,6 +36,44 @@ namespace WebCore { * and produce invalid results. */ +// The difference between two styles. The following values are used: +// (1) StyleDifferenceEqual - The two styles are identical +// (2) StyleDifferenceRecompositeLayer - The layer needs its position and transform updated, but no repaint +// (3) StyleDifferenceRepaint - The object just needs to be repainted. +// (4) StyleDifferenceRepaintLayer - The layer and its descendant layers needs to be repainted. +// (5) StyleDifferenceLayout - A layout is required. +enum StyleDifference { + StyleDifferenceEqual, +#if USE(ACCELERATED_COMPOSITING) + StyleDifferenceRecompositeLayer, +#endif + StyleDifferenceRepaint, + StyleDifferenceRepaintLayer, + StyleDifferenceLayoutPositionedMovementOnly, + StyleDifferenceLayout +}; + +// When some style properties change, different amounts of work have to be done depending on +// context (e.g. whether the property is changing on an element which has a compositing layer). +// A simple StyleDifference does not provide enough information so we return a bit mask of +// StyleDifferenceContextSensitiveProperties from RenderStyle::diff() too. +enum StyleDifferenceContextSensitiveProperty { + ContextSensitivePropertyNone = 0, + ContextSensitivePropertyTransform = (1 << 0), + ContextSensitivePropertyOpacity = (1 << 1) +}; + +// Static pseudo styles. Dynamic ones are produced on the fly. +enum PseudoId { + 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_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, MEDIA_CONTROLS_SEEK_BACK_BUTTON, + MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, + SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, + + FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON +}; // These have been defined in the order of their precedence for border-collapsing. Do // not change this order! @@ -163,7 +201,7 @@ enum EListStyleType { HIRAGANA, KATAKANA, HIRAGANA_IROHA, KATAKANA_IROHA, LNONE }; -enum ContentType { +enum StyleContentType { CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER }; @@ -171,11 +209,6 @@ enum EBorderFit { BorderFitBorder, BorderFitLines }; enum ETimingFunctionType { LinearTimingFunction, CubicBezierTimingFunction }; -enum EAnimPlayState { - AnimPlayStatePlaying = 0x0, - AnimPlayStatePaused = 0x1 -}; - enum EWhiteSpace { NORMAL, PRE, PRE_WRAP, PRE_LINE, NOWRAP, KHTML_NOWRAP }; @@ -263,6 +296,14 @@ enum EPointerEvents { PE_VISIBLE_STROKE, PE_VISIBLE_FILL, PE_VISIBLE_PAINTED, PE_ALL }; +enum ETransformStyle3D { + TransformStyle3DFlat, TransformStyle3DPreserve3D +}; + +enum EBackfaceVisibility { + BackfaceVisibilityVisible, BackfaceVisibilityHidden +}; + } // namespace WebCore #endif // RenderStyleConstants_h diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp index 1749978..c5f0648 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp @@ -128,7 +128,7 @@ float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* v return defaultValue; if (cssType == CSSPrimitiveValue::CSS_PERCENTAGE) { - SVGStyledElement* element = static_cast<SVGStyledElement*>(item->element()); + SVGStyledElement* element = static_cast<SVGStyledElement*>(item->node()); SVGElement* viewportElement = (element ? element->viewportElement() : 0); if (viewportElement) { float result = primitive->getFloatValue() / 100.0f; diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp index fa361e8..610e73d 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp @@ -34,11 +34,26 @@ PassRefPtr<CSSValue> StyleGeneratedImage::cssValue() return m_generator; } -IntSize StyleGeneratedImage::imageSize(const RenderObject* renderer, float /* multiplier */) const +IntSize StyleGeneratedImage::imageSize(const RenderObject* renderer, float multiplier) const { - // We can ignore the multiplier, since we always store a raw zoomed size. - if (m_fixedSize) - return m_generator->fixedSize(renderer); + if (m_fixedSize) { + IntSize fixedSize = m_generator->fixedSize(renderer); + if (multiplier == 1.0f) + return fixedSize; + + int width = fixedSize.width() * multiplier; + int height = fixedSize.height() * multiplier; + + // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. + if (fixedSize.width() > 0) + width = max(1, width); + + if (fixedSize.height() > 0) + height = max(1, height); + + return IntSize(width, height); + } + return m_containerSize; } diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp index 56d2686..f59c0c2 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp @@ -66,7 +66,7 @@ static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2) { if (c1 == c2) return true; - if (!c1 && c2 || c1 && !c2) + if ((!c1 && c2) || (c1 && !c2)) return false; return (*c1 == *c2); } diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp index b8fb2dd..ce21720 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -80,12 +80,13 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && nbspMode == o.nbspMode && khtmlLineBreak == o.khtmlLineBreak && textSizeAdjust == o.textSizeAdjust + && resize == o.resize && userSelect == o.userSelect; } bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const { - if (!textShadow && o.textShadow || textShadow && !o.textShadow) + if ((!textShadow && o.textShadow) || (textShadow && !o.textShadow)) return false; if (textShadow && o.textShadow && (*textShadow != *o.textShadow)) return false; diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp index e8ceeeb..401c04f 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -23,7 +23,10 @@ #include "StyleRareNonInheritedData.h" #include "CSSStyleSelector.h" +#include "ContentData.h" +#include "RenderCounter.h" #include "RenderStyle.h" +#include "StyleImage.h" namespace WebCore { @@ -39,10 +42,18 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , matchNearestMailBlockquoteColor(RenderStyle::initialMatchNearestMailBlockquoteColor()) , m_appearance(RenderStyle::initialAppearance()) , m_borderFit(RenderStyle::initialBorderFit()) +#if USE(ACCELERATED_COMPOSITING) + , m_runningAcceleratedAnimation(false) +#endif , m_boxShadow(0) , m_animations(0) , m_transitions(0) , m_mask(FillLayer(MaskFillLayer)) + , m_transformStyle3D(RenderStyle::initialTransformStyle3D()) + , m_backfaceVisibility(RenderStyle::initialBackfaceVisibility()) + , m_perspective(RenderStyle::initialPerspective()) + , m_perspectiveOriginX(RenderStyle::initialPerspectiveOriginX()) + , m_perspectiveOriginY(RenderStyle::initialPerspectiveOriginY()) #if ENABLE(XBL) , bindingURI(0) #endif @@ -66,12 +77,20 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , matchNearestMailBlockquoteColor(o.matchNearestMailBlockquoteColor) , m_appearance(o.m_appearance) , m_borderFit(o.m_borderFit) +#if USE(ACCELERATED_COMPOSITING) + , m_runningAcceleratedAnimation(o.m_runningAcceleratedAnimation) +#endif , m_boxShadow(o.m_boxShadow ? new ShadowData(*o.m_boxShadow) : 0) , m_boxReflect(o.m_boxReflect) , m_animations(o.m_animations ? new AnimationList(*o.m_animations) : 0) , m_transitions(o.m_transitions ? new AnimationList(*o.m_transitions) : 0) , m_mask(o.m_mask) , m_maskBoxImage(o.m_maskBoxImage) + , m_transformStyle3D(o.m_transformStyle3D) + , m_backfaceVisibility(o.m_backfaceVisibility) + , m_perspective(o.m_perspective) + , m_perspectiveOriginX(o.m_perspectiveOriginX) + , m_perspectiveOriginY(o.m_perspectiveOriginY) #if ENABLE(XBL) , bindingURI(o.bindingURI ? o.bindingURI->copy() : 0) #endif @@ -105,7 +124,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && marquee == o.marquee && m_multiCol == o.m_multiCol && m_transform == o.m_transform - && m_content == o.m_content + && contentDataEquivalent(o) && m_counterDirectives == o.m_counterDirectives && userDrag == o.userDrag && textOverflow == o.textOverflow @@ -114,6 +133,9 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && matchNearestMailBlockquoteColor == o.matchNearestMailBlockquoteColor && m_appearance == o.m_appearance && m_borderFit == o.m_borderFit +#if USE(ACCELERATED_COMPOSITING) + && !m_runningAcceleratedAnimation && !o.m_runningAcceleratedAnimation +#endif && shadowDataEquivalent(o) && reflectionDataEquivalent(o) && animationDataEquivalent(o) @@ -123,12 +145,32 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c #if ENABLE(XBL) && bindingsEquivalent(o) #endif + && (m_transformStyle3D == o.m_transformStyle3D) + && (m_backfaceVisibility == o.m_backfaceVisibility) + && (m_perspective == o.m_perspective) + && (m_perspectiveOriginX == o.m_perspectiveOriginX) + && (m_perspectiveOriginY == o.m_perspectiveOriginY) ; } +bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInheritedData& o) const +{ + ContentData* c1 = m_content.get(); + ContentData* c2 = o.m_content.get(); + + while (c1 && c2) { + if (!c1->dataEquivalent(*c2)) + return false; + c1 = c1->next(); + c2 = c2->next(); + } + + return !c1 && !c2; +} + bool StyleRareNonInheritedData::shadowDataEquivalent(const StyleRareNonInheritedData& o) const { - if (!m_boxShadow && o.m_boxShadow || m_boxShadow && !o.m_boxShadow) + if ((!m_boxShadow && o.m_boxShadow) || (m_boxShadow && !o.m_boxShadow)) return false; if (m_boxShadow && o.m_boxShadow && (*m_boxShadow != *o.m_boxShadow)) return false; @@ -148,7 +190,7 @@ bool StyleRareNonInheritedData::reflectionDataEquivalent(const StyleRareNonInher bool StyleRareNonInheritedData::animationDataEquivalent(const StyleRareNonInheritedData& o) const { - if (!m_animations && o.m_animations || m_animations && !o.m_animations) + if ((!m_animations && o.m_animations) || (m_animations && !o.m_animations)) return false; if (m_animations && o.m_animations && (*m_animations != *o.m_animations)) return false; @@ -157,7 +199,7 @@ bool StyleRareNonInheritedData::animationDataEquivalent(const StyleRareNonInheri bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInheritedData& o) const { - if (!m_transitions && o.m_transitions || m_transitions && !o.m_transitions) + if ((!m_transitions && o.m_transitions) || (m_transitions && !o.m_transitions)) return false; if (m_transitions && o.m_transitions && (*m_transitions != *o.m_transitions)) return false; diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h index 6ce6a33..8dd22b3 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -30,6 +30,7 @@ #include "DataRef.h" #include "FillLayer.h" #include "NinePieceImage.h" +#include "StyleTransformData.h" #include <wtf/OwnPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> @@ -69,7 +70,8 @@ public: bool operator==(const StyleRareNonInheritedData&) const; bool operator!=(const StyleRareNonInheritedData& o) const { return !(*this == o); } - + + bool contentDataEquivalent(const StyleRareNonInheritedData& o) const; bool shadowDataEquivalent(const StyleRareNonInheritedData& o) const; bool reflectionDataEquivalent(const StyleRareNonInheritedData& o) const; bool animationDataEquivalent(const StyleRareNonInheritedData&) const; @@ -96,6 +98,9 @@ public: unsigned matchNearestMailBlockquoteColor : 1; // EMatchNearestMailBlockquoteColor, FIXME: This property needs to be eliminated. It should never have been added. unsigned m_appearance : 6; // EAppearance unsigned m_borderFit : 1; // EBorderFit +#if USE(ACCELERATED_COMPOSITING) + bool m_runningAcceleratedAnimation : 1; +#endif OwnPtr<ShadowData> m_boxShadow; // For box-shadow decorations. RefPtr<StyleReflection> m_boxReflect; @@ -106,6 +111,12 @@ public: FillLayer m_mask; NinePieceImage m_maskBoxImage; + ETransformStyle3D m_transformStyle3D; + EBackfaceVisibility m_backfaceVisibility; + float m_perspective; + Length m_perspectiveOriginX; + Length m_perspectiveOriginY; + #if ENABLE(XBL) OwnPtr<BindingURI> bindingURI; // The XBL binding URI list. #endif diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp index de20e77..2baebf9 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp @@ -30,6 +30,7 @@ StyleTransformData::StyleTransformData() : m_operations(RenderStyle::initialTransform()) , m_x(RenderStyle::initialTransformOriginX()) , m_y(RenderStyle::initialTransformOriginY()) + , m_z(RenderStyle::initialTransformOriginZ()) { } @@ -38,12 +39,13 @@ StyleTransformData::StyleTransformData(const StyleTransformData& o) , m_operations(o.m_operations) , m_x(o.m_x) , m_y(o.m_y) + , m_z(o.m_z) { } bool StyleTransformData::operator==(const StyleTransformData& o) const { - return m_x == o.m_x && m_y == o.m_y && m_operations == o.m_operations; + return m_x == o.m_x && m_y == o.m_y && m_z == o.m_z && m_operations == o.m_operations; } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h index 157e600..6039824 100644 --- a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h +++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h @@ -46,6 +46,7 @@ public: TransformOperations m_operations; Length m_x; Length m_y; + float m_z; private: StyleTransformData(); |