summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/EllipsisBox.cpp17
-rw-r--r--WebCore/rendering/EllipsisBox.h11
-rw-r--r--WebCore/rendering/HitTestRequest.h34
-rw-r--r--WebCore/rendering/InlineBox.cpp53
-rw-r--r--WebCore/rendering/InlineBox.h72
-rw-r--r--WebCore/rendering/InlineFlowBox.cpp464
-rw-r--r--WebCore/rendering/InlineFlowBox.h56
-rw-r--r--WebCore/rendering/InlineTextBox.cpp213
-rw-r--r--WebCore/rendering/InlineTextBox.h10
-rw-r--r--WebCore/rendering/LayoutState.cpp7
-rw-r--r--WebCore/rendering/ListMarkerBox.cpp2
-rw-r--r--WebCore/rendering/MediaControlElements.cpp87
-rw-r--r--WebCore/rendering/MediaControlElements.h10
-rw-r--r--WebCore/rendering/PointerEventsHitRules.h2
-rw-r--r--WebCore/rendering/RenderBR.cpp15
-rw-r--r--WebCore/rendering/RenderBR.h8
-rw-r--r--WebCore/rendering/RenderBlock.cpp1315
-rw-r--r--WebCore/rendering/RenderBlock.h176
-rw-r--r--WebCore/rendering/RenderBox.cpp1207
-rw-r--r--WebCore/rendering/RenderBox.h157
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp1111
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h133
-rw-r--r--WebCore/rendering/RenderButton.cpp27
-rw-r--r--WebCore/rendering/RenderButton.h22
-rw-r--r--WebCore/rendering/RenderContainer.cpp726
-rw-r--r--WebCore/rendering/RenderContainer.h82
-rw-r--r--WebCore/rendering/RenderCounter.cpp15
-rw-r--r--WebCore/rendering/RenderCounter.h1
-rw-r--r--WebCore/rendering/RenderFieldset.cpp18
-rw-r--r--WebCore/rendering/RenderFieldset.h2
-rw-r--r--WebCore/rendering/RenderFileUploadControl.cpp7
-rw-r--r--WebCore/rendering/RenderFileUploadControl.h2
-rw-r--r--WebCore/rendering/RenderFlexibleBox.cpp74
-rw-r--r--WebCore/rendering/RenderFlow.cpp744
-rw-r--r--WebCore/rendering/RenderFlow.h145
-rw-r--r--WebCore/rendering/RenderForeignObject.cpp24
-rw-r--r--WebCore/rendering/RenderForeignObject.h2
-rw-r--r--WebCore/rendering/RenderFrame.h2
-rw-r--r--WebCore/rendering/RenderFrameSet.cpp23
-rw-r--r--WebCore/rendering/RenderFrameSet.h12
-rw-r--r--WebCore/rendering/RenderHTMLCanvas.cpp1
-rw-r--r--WebCore/rendering/RenderImage.cpp57
-rw-r--r--WebCore/rendering/RenderImage.h16
-rw-r--r--WebCore/rendering/RenderImageGeneratedContent.h14
-rw-r--r--WebCore/rendering/RenderInline.cpp772
-rw-r--r--WebCore/rendering/RenderInline.h108
-rw-r--r--WebCore/rendering/RenderLayer.cpp1214
-rw-r--r--WebCore/rendering/RenderLayer.h212
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp1067
-rw-r--r--WebCore/rendering/RenderLayerBacking.h178
-rw-r--r--WebCore/rendering/RenderLayerCompositor.cpp803
-rw-r--r--WebCore/rendering/RenderLayerCompositor.h140
-rw-r--r--WebCore/rendering/RenderLegend.cpp36
-rw-r--r--WebCore/rendering/RenderLegend.h42
-rw-r--r--WebCore/rendering/RenderLineBoxList.cpp333
-rw-r--r--WebCore/rendering/RenderLineBoxList.h86
-rw-r--r--WebCore/rendering/RenderListBox.cpp31
-rw-r--r--WebCore/rendering/RenderListBox.h4
-rw-r--r--WebCore/rendering/RenderListItem.cpp14
-rw-r--r--WebCore/rendering/RenderListItem.h2
-rw-r--r--WebCore/rendering/RenderListMarker.cpp31
-rw-r--r--WebCore/rendering/RenderListMarker.h10
-rw-r--r--WebCore/rendering/RenderMarquee.cpp29
-rw-r--r--WebCore/rendering/RenderMarquee.h3
-rw-r--r--WebCore/rendering/RenderMedia.cpp62
-rw-r--r--WebCore/rendering/RenderMedia.h13
-rw-r--r--WebCore/rendering/RenderMenuList.cpp30
-rw-r--r--WebCore/rendering/RenderMenuList.h2
-rw-r--r--WebCore/rendering/RenderObject.cpp1810
-rw-r--r--WebCore/rendering/RenderObject.h505
-rw-r--r--WebCore/rendering/RenderObjectChildList.cpp426
-rw-r--r--WebCore/rendering/RenderObjectChildList.h67
-rw-r--r--WebCore/rendering/RenderPart.cpp33
-rw-r--r--WebCore/rendering/RenderPart.h6
-rw-r--r--WebCore/rendering/RenderPartObject.cpp59
-rw-r--r--WebCore/rendering/RenderPartObject.h2
-rw-r--r--WebCore/rendering/RenderPath.cpp28
-rw-r--r--WebCore/rendering/RenderPath.h4
-rw-r--r--WebCore/rendering/RenderReplaced.cpp114
-rw-r--r--WebCore/rendering/RenderReplaced.h16
-rw-r--r--WebCore/rendering/RenderReplica.cpp8
-rw-r--r--WebCore/rendering/RenderSVGContainer.cpp157
-rw-r--r--WebCore/rendering/RenderSVGContainer.h30
-rw-r--r--WebCore/rendering/RenderSVGGradientStop.cpp4
-rw-r--r--WebCore/rendering/RenderSVGGradientStop.h9
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.cpp2
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.h2
-rw-r--r--WebCore/rendering/RenderSVGImage.cpp21
-rw-r--r--WebCore/rendering/RenderSVGImage.h2
-rw-r--r--WebCore/rendering/RenderSVGInline.cpp23
-rw-r--r--WebCore/rendering/RenderSVGInline.h14
-rw-r--r--WebCore/rendering/RenderSVGInlineText.cpp58
-rw-r--r--WebCore/rendering/RenderSVGInlineText.h10
-rw-r--r--WebCore/rendering/RenderSVGRoot.cpp83
-rw-r--r--WebCore/rendering/RenderSVGRoot.h14
-rw-r--r--WebCore/rendering/RenderSVGTSpan.cpp12
-rw-r--r--WebCore/rendering/RenderSVGText.cpp48
-rw-r--r--WebCore/rendering/RenderSVGText.h6
-rw-r--r--WebCore/rendering/RenderSVGTextPath.cpp20
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.cpp2
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.cpp30
-rw-r--r--WebCore/rendering/RenderScrollbar.cpp14
-rw-r--r--WebCore/rendering/RenderScrollbar.h5
-rw-r--r--WebCore/rendering/RenderScrollbarPart.cpp6
-rw-r--r--WebCore/rendering/RenderScrollbarPart.h4
-rw-r--r--WebCore/rendering/RenderSelectionInfo.h104
-rw-r--r--WebCore/rendering/RenderSlider.cpp397
-rw-r--r--WebCore/rendering/RenderSlider.h41
-rw-r--r--WebCore/rendering/RenderTable.cpp145
-rw-r--r--WebCore/rendering/RenderTable.h39
-rw-r--r--WebCore/rendering/RenderTableCell.cpp102
-rw-r--r--WebCore/rendering/RenderTableCell.h13
-rw-r--r--WebCore/rendering/RenderTableCol.cpp12
-rw-r--r--WebCore/rendering/RenderTableCol.h12
-rw-r--r--WebCore/rendering/RenderTableRow.cpp35
-rw-r--r--WebCore/rendering/RenderTableRow.h17
-rw-r--r--WebCore/rendering/RenderTableSection.cpp128
-rw-r--r--WebCore/rendering/RenderTableSection.h19
-rw-r--r--WebCore/rendering/RenderText.cpp253
-rw-r--r--WebCore/rendering/RenderText.h34
-rw-r--r--WebCore/rendering/RenderTextControl.cpp109
-rw-r--r--WebCore/rendering/RenderTextControl.h38
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.cpp52
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.h1
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.cpp120
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.h20
-rw-r--r--WebCore/rendering/RenderTextFragment.cpp4
-rw-r--r--WebCore/rendering/RenderTheme.cpp52
-rw-r--r--WebCore/rendering/RenderTheme.h12
-rw-r--r--WebCore/rendering/RenderThemeChromiumGtk.cpp532
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.cpp421
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.h (renamed from WebCore/rendering/RenderThemeChromiumGtk.h)30
-rw-r--r--WebCore/rendering/RenderThemeChromiumMac.h3
-rw-r--r--WebCore/rendering/RenderThemeChromiumMac.mm17
-rw-r--r--WebCore/rendering/RenderThemeChromiumWin.cpp197
-rw-r--r--WebCore/rendering/RenderThemeChromiumWin.h12
-rw-r--r--WebCore/rendering/RenderThemeMac.h2
-rw-r--r--WebCore/rendering/RenderThemeMac.mm32
-rw-r--r--WebCore/rendering/RenderThemeSafari.cpp9
-rw-r--r--WebCore/rendering/RenderThemeWin.cpp33
-rw-r--r--WebCore/rendering/RenderThemeWin.h8
-rw-r--r--WebCore/rendering/RenderTreeAsText.cpp66
-rw-r--r--WebCore/rendering/RenderVideo.cpp5
-rw-r--r--WebCore/rendering/RenderView.cpp220
-rw-r--r--WebCore/rendering/RenderView.h72
-rw-r--r--WebCore/rendering/RenderWidget.cpp67
-rw-r--r--WebCore/rendering/RenderWidget.h4
-rw-r--r--WebCore/rendering/RootInlineBox.cpp110
-rw-r--r--WebCore/rendering/RootInlineBox.h33
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.cpp4
-rw-r--r--WebCore/rendering/SVGInlineFlowBox.h7
-rw-r--r--WebCore/rendering/SVGInlineTextBox.cpp75
-rw-r--r--WebCore/rendering/SVGInlineTextBox.h5
-rw-r--r--WebCore/rendering/SVGRenderSupport.cpp6
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.cpp22
-rw-r--r--WebCore/rendering/SVGRootInlineBox.cpp109
-rw-r--r--WebCore/rendering/SVGRootInlineBox.h5
-rw-r--r--WebCore/rendering/ScrollBehavior.cpp55
-rw-r--r--WebCore/rendering/ScrollBehavior.h78
-rw-r--r--WebCore/rendering/TextControlInnerElements.cpp37
-rw-r--r--WebCore/rendering/TransformState.cpp162
-rw-r--r--WebCore/rendering/TransformState.h132
-rw-r--r--WebCore/rendering/bidi.cpp272
-rw-r--r--WebCore/rendering/style/ContentData.cpp58
-rw-r--r--WebCore/rendering/style/ContentData.h50
-rw-r--r--WebCore/rendering/style/CounterContent.h8
-rw-r--r--WebCore/rendering/style/RenderStyle.cpp225
-rw-r--r--WebCore/rendering/style/RenderStyle.h85
-rw-r--r--WebCore/rendering/style/RenderStyleConstants.h53
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.cpp2
-rw-r--r--WebCore/rendering/style/StyleInheritedData.cpp2
-rw-r--r--WebCore/rendering/style/StyleRareInheritedData.cpp2
-rw-r--r--WebCore/rendering/style/StyleRareNonInheritedData.cpp50
-rw-r--r--WebCore/rendering/style/StyleRareNonInheritedData.h13
-rw-r--r--WebCore/rendering/style/StyleTransformData.cpp4
-rw-r--r--WebCore/rendering/style/StyleTransformData.h1
176 files changed, 12941 insertions, 8265 deletions
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp
index fcce87d..db9a101 100644
--- a/WebCore/rendering/EllipsisBox.cpp
+++ b/WebCore/rendering/EllipsisBox.cpp
@@ -31,7 +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);
+ RenderStyle* style = m_renderer->style(m_firstLine);
Color textColor = style->color();
if (textColor != context->fillColor())
context->setFillColor(textColor);
@@ -43,15 +43,15 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
}
const String& str = m_str;
- context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + 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);
}
}
@@ -63,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/WebCore/rendering/EllipsisBox.h b/WebCore/rendering/EllipsisBox.h
index dbb30cd..9dbd27f 100644
--- a/WebCore/rendering/EllipsisBox.h
+++ b/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/WebCore/rendering/HitTestRequest.h b/WebCore/rendering/HitTestRequest.h
index 11dca4b..46dd7b8 100644
--- a/WebCore/rendering/HitTestRequest.h
+++ b/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/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp
index 6f7324a..89cd4b8 100644
--- a/WebCore/rendering/InlineBox.cpp
+++ b/WebCore/rendering/InlineBox.cpp
@@ -80,19 +80,24 @@ 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
+{
+ return toRenderBox(m_renderer)->height();
+}
+
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
@@ -109,36 +114,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()) {
- RenderBox* box = toRenderBox(m_object);
+ 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
@@ -147,16 +154,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);
}
}
@@ -165,7 +172,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()
@@ -228,13 +243,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);
diff --git a/WebCore/rendering/InlineBox.h b/WebCore/rendering/InlineBox.h
index e17b6e8..e66574a 100644
--- a/WebCore/rendering/InlineBox.h
+++ b/WebCore/rendering/InlineBox.h
@@ -21,27 +21,25 @@
#ifndef InlineBox_h
#define InlineBox_h
-#include "RenderBox.h"
+#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_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)
@@ -50,9 +48,6 @@ public:
, m_bidiEmbeddingLevel(0)
, m_dirty(false)
, m_extracted(false)
- , m_includeLeftEdge(false)
- , m_includeRightEdge(false)
- , m_hasTextChildren(true)
, m_endsWithBreak(false)
, m_hasSelectedChildren(false)
, m_hasEllipsisBox(false)
@@ -69,14 +64,12 @@ 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_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)
@@ -85,9 +78,6 @@ public:
, m_bidiEmbeddingLevel(0)
, m_dirty(dirty)
, m_extracted(extracted)
- , m_includeLeftEdge(false)
- , m_includeRightEdge(false)
- , m_hasTextChildren(true)
, m_endsWithBreak(false)
, m_hasSelectedChildren(false)
, m_hasEllipsisBox(false)
@@ -134,10 +124,9 @@ 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; }
#endif
@@ -178,7 +167,7 @@ public:
InlineBox* nextLeafChild();
InlineBox* prevLeafChild();
- RenderObject* object() const { return m_object; }
+ RenderObject* renderer() const { return m_renderer; }
InlineFlowBox* parent() const
{
@@ -187,29 +176,24 @@ 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; }
+ 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; }
+ void setY(int y) { m_y = y; }
+ int y() const { return m_y; }
- bool hasTextChildren() const { return m_hasTextChildren; }
+ virtual 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;
@@ -237,19 +221,22 @@ public:
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; }
// Use with caution! The type is not checked!
- RenderBox* renderBox() const { return toRenderBox(m_object); }
+ RenderBoxModelObject* boxModelObject() const
+ {
+ if (!m_renderer->isText())
+ return static_cast<RenderBoxModelObject*>(m_renderer);
+ return 0;
+ }
public:
- RenderObject* m_object;
+ RenderObject* m_renderer;
int m_x;
int m_y;
int m_width;
- int m_height;
- int m_baseline;
private:
InlineBox* m_next; // The next element on the same line as us.
@@ -269,11 +256,6 @@ protected:
bool m_dirty : 1;
bool m_extracted : 1;
- // for InlineFlowBox
- bool m_includeLeftEdge : 1;
- bool m_includeRightEdge : 1;
- bool m_hasTextChildren : 1;
-
// for RootInlineBox
bool m_endsWithBreak : 1; // Whether the line ends with a <br>.
bool m_hasSelectedChildren : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index 74f4151..2e23bb6 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/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,45 +51,19 @@ InlineFlowBox::~InlineFlowBox()
#endif
-RenderFlow* InlineFlowBox::flowObject()
+int InlineFlowBox::height() const
{
- 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 renderBox()->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 renderBox()->marginRight();
-}
-
-int InlineFlowBox::marginBorderPaddingLeft()
-{
- return marginLeft() + borderLeft() + paddingLeft();
-}
-
-int InlineFlowBox::marginBorderPaddingRight()
-{
- return marginRight() + borderRight() + paddingRight();
+ const Font& font = renderer()->style(m_firstLine)->font();
+ int result = font.height();
+ bool strictMode = renderer()->document()->inStrictMode();
+ RenderBoxModelObject* box = boxModelObject();
+ result += box->borderTop() + box->paddingTop() + box->borderBottom() + box->paddingBottom();
+ if (!strictMode && !hasTextChildren() && !box->hasHorizontalBordersOrPadding()) {
+ int bottomOverflow = root()->bottomOverflow();
+ if (y() + result > bottomOverflow)
+ result = bottomOverflow - y();
+ }
+ return result;
}
int InlineFlowBox::getFlowSpacingWidth()
@@ -121,7 +95,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 +142,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 +184,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 +217,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 +238,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 && !flow->continuation()) || nextOnLineExists() || onEndChain(endObject)))
+ ((lastLine && !inlineFlow->continuation()) || nextOnLineExists() || onEndChain(endObject)))
includeRightEdge = true;
} else {
if ((!prevLineBox() || prevLineBox()->isConstructed()) &&
- ((lastLine && !flow->continuation()) || prevOnLineExists() || onEndChain(endObject)))
+ ((lastLine && !inlineFlow->continuation()) || prevOnLineExists() || onEndChain(endObject)))
includeLeftEdge = true;
}
}
@@ -270,32 +263,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 = toRenderText(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,41 +306,41 @@ 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()->block()->width()-x);
+ curr->setX(root()->block()->width() - xPos);
continue; // The positioned object has no effect on the width.
}
- if (curr->object()->isRenderInline()) {
+ if (curr->renderer()->isRenderInline()) {
InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
- x += flow->marginLeft();
- x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing);
- x += flow->marginRight();
- } else if (!curr->object()->isListMarker() || static_cast<RenderListMarker*>(curr->object())->isInside()) {
- x += curr->renderBox()->marginLeft();
- curr->setXPos(x);
- leftPosition = min(x + curr->renderBox()->overflowLeft(false), leftPosition);
- rightPosition = max(x + curr->renderBox()->overflowWidth(false), rightPosition);
- x += curr->width() + curr->renderBox()->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;
}
int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock)
@@ -359,8 +352,8 @@ int 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());
@@ -378,10 +371,6 @@ int 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;
@@ -394,16 +383,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))
@@ -415,22 +405,25 @@ 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)
@@ -439,23 +432,25 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
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();
+ bool isInlineFlow = curr->isInlineFlowBox();
+
+ int lineHeight = curr->renderer()->lineHeight(m_firstLine);
+ int baseline = curr->renderer()->baselinePosition(m_firstLine);
+ curr->setY(verticalPositionForBox(curr, m_firstLine));
+ if (curr->y() == PositionTop) {
+ if (maxPositionTop < lineHeight)
+ maxPositionTop = lineHeight;
}
- else if (curr->yPos() == PositionBottom) {
- if (maxPositionBottom < curr->height())
- maxPositionBottom = curr->height();
+ else if (curr->y() == PositionBottom) {
+ if (maxPositionBottom < lineHeight)
+ maxPositionBottom = lineHeight;
}
- else if (curr->hasTextChildren() || curr->renderBox()->hasHorizontalBordersOrPadding() || strictMode) {
- int ascent = curr->baseline() - curr->yPos();
- int descent = curr->height() - ascent;
+ 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)
@@ -467,135 +462,106 @@ 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->renderBox()->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();
+ 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->renderBox()->reflectionBox().y());
- overflowBottom = max(overflowBottom, curr->renderBox()->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->renderBox()->borderTop() + curr->renderBox()->paddingTop() +
- curr->renderBox()->borderBottom() + curr->renderBox()->paddingBottom();
- newY -= curr->renderBox()->borderTop() + curr->renderBox()->paddingTop();
- newBaseline += curr->renderBox()->borderTop() + curr->renderBox()->paddingTop();
- }
- } else if (!curr->object()->isBR()) {
- newY += curr->renderBox()->marginTop();
- newHeight = curr->height() - (curr->renderBox()->marginTop() + curr->renderBox()->marginBottom());
- overflowTop = curr->renderBox()->overflowTop(false);
- overflowBottom = curr->renderBox()->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) {
selectionTop = min(selectionTop, newY);
- selectionBottom = max(selectionBottom, newY + newHeight);
+ selectionBottom = max(selectionBottom, newY + curr->height());
topPosition = min(topPosition, newY + overflowTop);
- bottomPosition = max(bottomPosition, newY + newHeight + overflowBottom);
+ bottomPosition = max(bottomPosition, newY + curr->height() + 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() && !renderBox()->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;
}
@@ -604,15 +570,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);
}
@@ -624,14 +590,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 ((flowObject()->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);
@@ -651,12 +618,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);
}
}
@@ -679,9 +646,9 @@ void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, con
int my, int mh, 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, my, mh, 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.
@@ -700,7 +667,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, my, mh, startX, ty, totalWidth, h, this, op);
paintInfo.context->restore();
}
}
@@ -708,17 +675,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.
@@ -739,8 +706,8 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int
// 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);
@@ -750,8 +717,8 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int
// :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.
@@ -759,7 +726,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.
@@ -778,7 +745,7 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int
totalWidth += curr->width();
context->save();
context->clip(IntRect(tx, ty, width(), height()));
- object()->paintBorder(context, startX, ty, totalWidth, h, object()->style());
+ boxModelObject()->paintBorder(context, startX, ty, totalWidth, h, renderer()->style());
context->restore();
}
}
@@ -787,7 +754,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.
@@ -807,9 +774,9 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty
// 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;
@@ -819,16 +786,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(), my, mh, 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.
@@ -841,7 +808,7 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty
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);
+ boxModelObject()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, renderer()->style(), maskNinePieceImage, compositeOp);
paintInfo.context->restore();
}
@@ -857,7 +824,7 @@ static bool shouldDrawTextDecoration(RenderObject* obj)
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())
@@ -873,8 +840,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.
@@ -884,16 +851,16 @@ 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 = rootLine->ellipsisBox()->x();
int ellipsisWidth = rootLine->ellipsisBox()->width();
// FIXME: Will need to work with RTL
@@ -914,9 +881,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;
@@ -925,13 +892,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);
@@ -939,7 +910,7 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int
}
context->save();
context->clip(clipRect);
- extraOffset += m_baseline + 2;
+ extraOffset += baselinePos + 2;
ty += extraOffset;
setClip = true;
}
@@ -959,16 +930,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);
diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h
index 62f8f69..df75d06 100644
--- a/WebCore/rendering/InlineFlowBox.h
+++ b/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,9 +55,7 @@ public:
virtual ~InlineFlowBox();
#endif
- RenderFlow* flowObject();
-
- virtual bool isInlineFlowBox() { return true; }
+ virtual int height() const;
InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); }
InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); }
@@ -80,6 +81,10 @@ 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);
@@ -93,17 +98,23 @@ public:
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 renderBox()->borderLeft(); return 0; }
- int borderRight() { if (includeRightEdge()) return renderBox()->borderRight(); return 0; }
- int paddingLeft() { if (includeLeftEdge()) return renderBox()->paddingLeft(); return 0; }
- int paddingRight() { if (includeRightEdge()) return renderBox()->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;
@@ -122,11 +133,10 @@ public:
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);
@@ -135,13 +145,21 @@ public:
virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
virtual int placeEllipsisBox(bool ltr, int blockEdge, 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;
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index ca965e9..809c071 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -41,6 +41,11 @@ using namespace std;
namespace WebCore {
+int InlineTextBox::height() const
+{
+ return m_treatAsText ? renderer()->style(m_firstLine)->font().height() : 0;
+}
+
int InlineTextBox::selectionTop()
{
return root()->selectionTop();
@@ -60,10 +65,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 +97,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 +113,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
void InlineTextBox::deleteLine(RenderArena* arena)
{
- toRenderText(m_object)->removeTextBox(this);
+ toRenderText(renderer())->removeTextBox(this);
destroy(arena);
}
@@ -117,7 +122,7 @@ void InlineTextBox::extractLine()
if (m_extracted)
return;
- toRenderText(m_object)->extractTextBox(this);
+ toRenderText(renderer())->extractTextBox(this);
}
void InlineTextBox::attachLine()
@@ -125,7 +130,7 @@ void InlineTextBox::attachLine()
if (!m_extracted)
return;
- toRenderText(m_object)->attachTextBox(this);
+ toRenderText(renderer())->attachTextBox(this);
}
int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
@@ -137,36 +142,40 @@ int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth,
int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + 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.
- m_truncation = cFullTruncation;
- foundBox = true;
- return -1;
- }
+ // 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 = ltr && ellipsisX <= m_x;
+ bool rtlFullTruncation = !ltr && 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;
+ }
- if (ellipsisX < m_x + m_width) {
- if (direction() == RTL)
- return -1; // FIXME: Support LTR truncation when the last run is RTL someday.
+ bool ltrEllipsisWithinBox = ltr && (ellipsisX < m_x + m_width);
+ bool rtlEllipsisWithinBox = !ltr && (ellipsisX > m_x);
+ if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) {
+ if ((ltr && direction() == RTL) || (!ltr && direction() == LTR))
+ return -1; // FIXME: Support cases in which the last run's directionality differs from the context.
- foundBox = true;
+ foundBox = true;
- 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 + toRenderText(m_object)->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);
}
- }
- else {
- // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR)
+
+ // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character.
+ m_truncation = offset;
+ if (ltr)
+ return m_x + toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine);
+ else
+ return m_x + (m_width - toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine)) - ellipsisWidth;
}
return -1;
}
@@ -216,7 +225,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,9 +233,9 @@ 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;
@@ -278,7 +287,7 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con
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;
@@ -289,7 +298,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;
@@ -300,11 +309,11 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
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();
@@ -319,8 +328,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);
@@ -367,14 +376,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)
@@ -400,8 +409,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;
@@ -447,7 +457,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) {
@@ -476,14 +486,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;
}
@@ -500,7 +510,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;
@@ -514,7 +524,7 @@ 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(font, TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd,
+ 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();
@@ -537,7 +547,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx,
int y = selectionTop();
int h = selectionHeight();
- context->drawHighlightForText(font, TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd,
+ 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 +557,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 +565,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 +580,33 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
if (m_truncation == cFullTruncation)
return;
-
- int width = (m_truncation == cNoTruncation) ? m_width
- : toRenderText(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 +614,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 +635,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);
@@ -640,7 +660,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
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,7 +687,7 @@ 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(font.selectionRectForText(run, startPoint, h, startPosition, endPosition));
@@ -677,7 +697,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
// Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to
// display a toolTip. We don't do this for misspelling markers.
if (grammar)
- 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,14 +707,15 @@ 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);
}
@@ -708,15 +729,15 @@ 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(font.selectionRectForText(run, startPoint, h, sPos, ePos));
- object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect);
+ renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect);
// Optionally highlight the text
- if (object()->document()->frame()->markedTextMatchesAreHighlighted()) {
+ if (renderer()->document()->frame()->markedTextMatchesAreHighlighted()) {
Color color = theme()->platformTextSearchHighlightColor();
pt->save();
updateGraphicsContext(pt, color, color, 0); // Don't draw text at all!
@@ -728,7 +749,10 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do
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.
@@ -797,7 +821,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int
if (paintStart <= underline.startOffset) {
paintStart = underline.startOffset;
useWholeWidth = false;
- start = toRenderText(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 +832,15 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int
useWholeWidth = false;
}
if (!useWholeWidth) {
- width = toRenderText(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 +850,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 +870,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 +883,10 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
if (isLineBreak())
return 0;
- RenderText* text = toRenderText(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 +898,12 @@ int InlineTextBox::positionForOffset(int offset) const
if (isLineBreak())
return m_x;
- RenderText* text = toRenderText(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();
}
diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h
index 0c2dd8a..222e973 100644
--- a/WebCore/rendering/InlineTextBox.h
+++ b/WebCore/rendering/InlineTextBox.h
@@ -24,7 +24,7 @@
#define InlineTextBox_h
#include "InlineRunBox.h"
-#include "RenderText.h" // so textObject() can be inline
+#include "RenderText.h" // so textRenderer() can be inline
namespace WebCore {
@@ -50,6 +50,8 @@ public:
InlineTextBox* nextTextBox() const { return static_cast<InlineTextBox*>(nextLineBox()); }
InlineTextBox* prevTextBox() const { return static_cast<InlineTextBox*>(prevLineBox()); }
+ virtual int height() const;
+
unsigned start() const { return m_start; }
unsigned end() const { return m_len ? m_start + m_len - 1 : m_start; }
unsigned len() const { return m_len; }
@@ -73,7 +75,7 @@ private:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
public:
- RenderText* textObject() const;
+ RenderText* textRenderer() const;
private:
virtual void deleteLine(RenderArena*);
@@ -135,9 +137,9 @@ private:
void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&);
};
-inline RenderText* InlineTextBox::textObject() const
+inline RenderText* InlineTextBox::textRenderer() const
{
- return toRenderText(m_object);
+ return toRenderText(renderer());
}
} // namespace WebCore
diff --git a/WebCore/rendering/LayoutState.cpp b/WebCore/rendering/LayoutState.cpp
index 6c196ac..883f74d 100644
--- a/WebCore/rendering/LayoutState.cpp
+++ b/WebCore/rendering/LayoutState.cpp
@@ -27,6 +27,7 @@
#include "LayoutState.h"
#include "RenderArena.h"
+#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderView.h"
@@ -52,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;
diff --git a/WebCore/rendering/ListMarkerBox.cpp b/WebCore/rendering/ListMarkerBox.cpp
index 0455eae..6089ebd 100644
--- a/WebCore/rendering/ListMarkerBox.cpp
+++ b/WebCore/rendering/ListMarkerBox.cpp
@@ -39,7 +39,7 @@ ListMarkerBox::ListMarkerBox(RenderObject* obj)
bool ListMarkerBox::isText() const
{
- return static_cast<RenderListMarker*>(object())->isText();
+ return static_cast<RenderListMarker*>(renderer())->isText();
}
} // namespace WebCore
diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp
index 8ad2bd6..d84e9ad 100644
--- a/WebCore/rendering/MediaControlElements.cpp
+++ b/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
@@ -68,13 +68,22 @@ MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTML
setInDocument(true);
}
+void MediaControlShadowRootElement::updateStyle()
+{
+ if (renderer()) {
+ RenderStyle* timelineContainerStyle = m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
+ renderer()->setStyle(timelineContainerStyle);
+ }
+}
+
// ----------------------------
-MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, RenderStyle::PseudoId pseudo, HTMLMediaElement* mediaElement)
+MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement)
: HTMLDivElement(divTag, doc)
, m_mediaElement(mediaElement)
+ , m_pseudoStyleId(pseudo)
{
- 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);
@@ -97,19 +106,28 @@ void MediaTextDisplayElement::update()
renderer()->updateFromElement();
}
+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 ? RenderStyle::MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : RenderStyle::MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element)
+ : MediaTextDisplayElement(doc, currentTime ? MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element)
{
}
// ----------------------------
-MediaControlInputElement::MediaControlInputElement(Document* doc, RenderStyle::PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
+MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
: HTMLInputElement(inputTag, 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);
@@ -131,6 +149,14 @@ void MediaControlInputElement::update()
renderer()->updateFromElement();
}
+void MediaControlInputElement::updateStyle()
+{
+ if (renderer() && m_mediaElement->renderer()) {
+ RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
+ renderer()->setStyle(style);
+ }
+}
+
bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
{
if (renderer() && renderer()->style()->hasAppearance())
@@ -142,7 +168,7 @@ bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
// ----------------------------
MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
+ : MediaControlInputElement(doc, MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
{
}
@@ -158,18 +184,14 @@ void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
// ----------------------------
MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
+ : MediaControlInputElement(doc, MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
{
}
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);
@@ -178,7 +200,7 @@ void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
// ----------------------------
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)
, m_forward(forward)
, m_seeking(false)
, m_capturing(false)
@@ -193,8 +215,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) {
@@ -228,40 +249,34 @@ void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonE
// ----------------------------
MediaControlTimelineElement::MediaControlTimelineElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_TIMELINE, "range", element)
+ : MediaControlInputElement(doc, MEDIA_CONTROLS_TIMELINE, "range", element)
{
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);
- float time = narrowPrecisionToFloat(value().toDouble());
- if (oldTime != time || event->type() == eventNames().inputEvent) {
- ExceptionCode ec;
- m_mediaElement->setCurrentTime(time, ec);
+ if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent ) {
+ return;
}
- // 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()) {
+ float time = narrowPrecisionToFloat(value().toDouble());
+ if (time != m_mediaElement->currentTime()) {
ExceptionCode ec;
- m_mediaElement->pause(ec);
+ m_mediaElement->setCurrentTime(time, 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);
- if (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)
@@ -276,7 +291,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)
{
}
diff --git a/WebCore/rendering/MediaControlElements.h b/WebCore/rendering/MediaControlElements.h
index c1c9574..fa0fb30 100644
--- a/WebCore/rendering/MediaControlElements.h
+++ b/WebCore/rendering/MediaControlElements.h
@@ -56,6 +56,8 @@ public:
virtual bool isShadowNode() const { return true; }
virtual Node* shadowParentNode() { return m_mediaElement; }
+
+ void updateStyle();
private:
HTMLMediaElement* m_mediaElement;
@@ -66,11 +68,13 @@ private:
class MediaTextDisplayElement : public HTMLDivElement
{
public:
- MediaTextDisplayElement(Document*, RenderStyle::PseudoId, HTMLMediaElement*);
+ MediaTextDisplayElement(Document*, PseudoId, HTMLMediaElement*);
void attachToParent(Element*);
void update();
+ void updateStyle();
protected:
HTMLMediaElement* m_mediaElement;
+ PseudoId m_pseudoStyleId;
};
// ----------------------------
@@ -84,12 +88,14 @@ public:
class MediaControlInputElement : public HTMLInputElement {
public:
- MediaControlInputElement(Document*, RenderStyle::PseudoId, const String& type, HTMLMediaElement*);
+ MediaControlInputElement(Document*, PseudoId, const String& type, HTMLMediaElement*);
void attachToParent(Element*);
void update();
+ void updateStyle();
bool hitTest(const IntPoint& absPoint);
protected:
HTMLMediaElement* m_mediaElement;
+ PseudoId m_pseudoStyleId;
};
// ----------------------------
diff --git a/WebCore/rendering/PointerEventsHitRules.h b/WebCore/rendering/PointerEventsHitRules.h
index e2dae3b..3d8939a 100644
--- a/WebCore/rendering/PointerEventsHitRules.h
+++ b/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/WebCore/rendering/RenderBR.cpp b/WebCore/rendering/RenderBR.cpp
index 2532c5b..f407099 100644
--- a/WebCore/rendering/RenderBR.cpp
+++ b/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/WebCore/rendering/RenderBR.h b/WebCore/rendering/RenderBR.h
index b65bb58..7eae8ea 100644
--- a/WebCore/rendering/RenderBR.h
+++ b/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/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 725bdb6..5b45501 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -25,6 +25,7 @@
#include "Document.h"
#include "Element.h"
+#include "FloatQuad.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
@@ -58,6 +59,12 @@ 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)
@@ -77,7 +84,7 @@ static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
-typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderFlow*>*> 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)
@@ -114,15 +121,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()
@@ -131,7 +141,7 @@ RenderBlock::~RenderBlock()
delete m_positionedObjects;
delete m_maxMargin;
- if (m_hasColumns)
+ if (hasColumns())
delete gColumnInfoMap->take(this);
if (gPercentHeightDescendantsMap) {
@@ -154,11 +164,49 @@ 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());
- if (style() && parent() && diff == RenderStyle::Layout && style()->position() != newStyle->position()) {
+ 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.
@@ -176,16 +224,16 @@ void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* new
}
if (cb->isRenderBlock())
- static_cast<RenderBlock*>(cb)->removePositionedObjects(this);
+ toRenderBlock(cb)->removePositionedObjects(this);
}
}
- RenderFlow::styleWillChange(diff, newStyle);
+ 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()) {
@@ -201,13 +249,21 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS
// Update pseudos for :before and :after now.
if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
- updateBeforeAfterContent(RenderStyle::BEFORE);
- updateBeforeAfterContent(RenderStyle::AFTER);
+ 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()))
@@ -231,13 +287,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()) {
@@ -253,7 +309,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;
@@ -263,7 +319,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.
@@ -277,17 +333,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
}
@@ -333,14 +388,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)
@@ -355,7 +415,7 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
ASSERT(isInlineBlockOrInlineTable() || !isInline());
ASSERT(!insertionPoint || insertionPoint->parent() == this);
- m_childrenInline = false;
+ setChildrenInline(false);
RenderObject *child = firstChild();
if (!child)
@@ -372,16 +432,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
@@ -392,7 +452,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
@@ -400,7 +502,7 @@ void RenderBlock::removeChild(RenderObject *oldChild)
RenderObject* prev = oldChild->previousSibling();
RenderObject* next = oldChild->nextSibling();
bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() &&
- !oldChild->virtualContinuation() &&
+ (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) &&
(!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
(!next || (next->isAnonymousBlock() && next->childrenInline()));
if (canDeleteAnonymousBlocks && prev && next) {
@@ -408,20 +510,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()) {
@@ -429,13 +533,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.
@@ -615,15 +719,8 @@ 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(x(), y()), m_hasColumns || hasTransform() || hasReflection());
+ LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
int oldWidth = width();
int oldColumnWidth = desiredColumnWidth();
@@ -670,11 +767,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);
@@ -684,9 +781,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;
@@ -714,7 +811,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
// 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);
+ RenderBlock* block = toRenderBlock(child);
if (block->floatBottom() + block->y() > height())
addOverhangingFloats(block, -block->x(), -block->y(), false);
}
@@ -762,12 +859,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);
@@ -800,19 +895,19 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
- return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || m_hasColumns || isTableCell() || isFieldset();
+ 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()) {
+ if (child->style()->hasStaticY()) {
int y = height();
if (!marginInfo.canCollapseWithTop()) {
child->calcVerticalMargins();
@@ -828,7 +923,7 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
}
y += (collapsedTopPos - collapsedTopNeg) - marginTop;
}
- child->setStaticY(y);
+ child->layer()->setStaticY(y);
}
}
@@ -892,24 +987,27 @@ RenderBox* RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo&
return 0;
}
-RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
+RenderBox* RenderBlock::handleRunInChild(RenderBox* child, bool& handled)
{
// 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 (blockRunIn->isRunIn() && (blockRunIn->childrenInline() || blockRunIn->isReplaced())) {
+ if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
+ 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())) {
+ RenderBlock* currBlock = toRenderBlock(curr);
+
// The block acts like an inline, so just null out its
// position.
handled = true;
// Remove the old child.
RenderBox* next = blockRunIn->nextSiblingBox();
- removeChildNode(blockRunIn);
+ children()->removeChildNode(this, blockRunIn);
// Create an inline.
RenderInline* inlineRunIn = new (renderArena()) RenderInline(blockRunIn->node());
@@ -918,18 +1016,18 @@ RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
// 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 (runInChild->style()->styleType() != RenderStyle::BEFORE && runInChild->style()->styleType() != RenderStyle::AFTER) {
- blockRunIn->removeChildNode(runInChild, false);
+ if (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.
}
}
- // Now insert the new child under |curr|.
- curr->insertChildNode(inlineRunIn, curr->firstChild());
+ // 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 (blockRunIn->element())
- blockRunIn->element()->setRenderer(inlineRunIn);
+ if (blockRunIn->node())
+ blockRunIn->node()->setRenderer(inlineRunIn);
// Destroy the block run-in.
blockRunIn->destroy();
@@ -940,7 +1038,7 @@ RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
return 0;
}
-void RenderBlock::collapseMargins(RenderBox* 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);
@@ -969,7 +1067,7 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
// 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);
}
@@ -979,7 +1077,7 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
// 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))
@@ -1028,34 +1126,15 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
marginInfo.setSelfCollapsingBlockClearedFloat(false);
}
-
- view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos));
- child->setLocation(child->x(), 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())
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout();
-
- // Our guess was wrong. Make the child lay itself out again.
- child->layoutIfNeeded();
- }
+
+ return ypos;
}
-void RenderBlock::clearFloatsIfNeeded(RenderBox* 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->setLocation(child->x(), child->y() + heightIncrease);
+ return yPos;
if (child->isSelfCollapsingBlock()) {
// For self-collapsing blocks that clear, they can still collapse their
@@ -1084,19 +1163,8 @@ void RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo,
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())
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout();
- child->layoutIfNeeded();
+
+ return yPos + heightIncrease;
}
int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo)
@@ -1108,6 +1176,7 @@ int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& ma
int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
yPosEstimate += max(marginInfo.margin(), childMarginTop);
}
+ yPosEstimate += getClearDelta(child, yPosEstimate);
return yPosEstimate;
}
@@ -1122,7 +1191,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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(height());
+ int leftOff = leftOffset(height(), false);
if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) {
if (child->marginLeft() < 0)
leftOff += child->marginLeft();
@@ -1134,7 +1203,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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.
- child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y()));
+ child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
chPos = leftOff + child->marginLeft();
}
}
@@ -1144,7 +1213,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* child)
int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth();
int chPos = xPos - (child->width() + child->marginRight());
if (child->avoidsFloats()) {
- int rightOff = rightOffset(height());
+ int rightOff = rightOffset(height(), false);
if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) {
if (child->marginRight() < 0)
rightOff -= child->marginRight();
@@ -1155,7 +1224,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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.
- toRenderBox(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y()));
+ child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
chPos = rightOff - child->marginRight() - child->width();
}
}
@@ -1172,13 +1241,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);
}
}
@@ -1304,21 +1373,22 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
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 > height() || fb > yPosEstimate)
+ if (fb > yPosEstimate)
markDescendantsWithFloats = true;
}
- if (markDescendantsWithFloats)
- static_cast<RenderBlock*>(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();
@@ -1327,10 +1397,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.
@@ -1348,7 +1436,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
}
// 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->x(), -child->y(), !childNeededLayout));
+ if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
// Update our overflow in case the child spills out the block.
m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false));
@@ -1384,7 +1473,7 @@ bool RenderBlock::layoutOnlyPositionedObjects()
if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
return false;
- LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), m_hasColumns || hasTransform() || hasReflection());
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
if (needsPositionedMovementLayout()) {
tryLayoutDoingPositionedMovementOnly();
@@ -1398,7 +1487,7 @@ bool RenderBlock::layoutOnlyPositionedObjects()
statePusher.pop();
if (hasOverflowClip())
- m_layer->updateScrollInfoAfterLayout();
+ layer()->updateScrollInfoAfterLayout();
#ifdef ANDROID_FIX
// iframe flatten will call FrameView::layout() which calls performPostLayoutTasks,
@@ -1422,11 +1511,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
@@ -1470,7 +1559,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 > 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();
}
@@ -1478,7 +1567,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
view()->enableLayoutState();
}
}
-
+
void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
{
tx += x();
@@ -1497,52 +1586,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++) {
@@ -1568,27 +1674,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;
}
}
@@ -1601,7 +1694,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);
}
@@ -1626,7 +1719,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
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.
@@ -1662,9 +1755,11 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
PaintPhase paintPhase = paintInfo.phase;
// 1. paint background, borders etc
- if ((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) {
@@ -1680,12 +1775,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);
}
@@ -1693,30 +1788,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 (!isPrinting && !m_hasColumns)
+ if (!isPrinting && !hasColumns())
paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
// 4. paint floats.
if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
- if (m_hasColumns)
- paintColumns(paintInfo, scrolledX, scrolledY, true);
+ if (hasColumns())
+ paintColumnContents(paintInfo, scrolledX, scrolledY, true);
else
paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
}
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
- RenderBox::paintOutline(paintInfo.context, tx, ty, width(), height(), style());
+ paintOutline(paintInfo.context, tx, ty, width(), height(), style());
// 6. paint continuation outlines.
if ((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 - x() + inlineFlow->containingBlock()->x(),
- ty - y() + inlineFlow->containingBlock()->y());
+ 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);
}
@@ -1739,7 +1834,7 @@ 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->x() + r->m_renderer->marginLeft();
@@ -1767,8 +1862,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;
@@ -1776,7 +1871,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);
@@ -1790,16 +1885,16 @@ static ContinuationOutlineTableMap* continuationOutlineTable()
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();
- ListHashSet<RenderFlow*>* continuations = table->get(this);
+ ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations) {
- continuations = new ListHashSet<RenderFlow*>;
+ continuations = new ListHashSet<RenderInline*>;
table->set(this, continuations);
}
@@ -1812,15 +1907,15 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
if (table->isEmpty())
return;
- ListHashSet<RenderFlow*>* continuations = table->get(this);
+ ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations)
return;
// Paint each continuation outline.
- ListHashSet<RenderFlow*>::iterator end = continuations->end();
- for (ListHashSet<RenderFlow*>::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->x();
@@ -1845,9 +1940,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())
@@ -1856,12 +1951,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.
@@ -1874,22 +1969,22 @@ 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
+ // FIXME: this is broken with transforms and a non-null repaintContainer
FloatPoint absContentPoint = localToAbsolute(FloatPoint());
if (hasOverflowClip())
absContentPoint -= layer()->scrolledContentOffset();
@@ -1952,7 +2047,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());
@@ -1966,7 +2061,7 @@ 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))
+ if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(),
rootBlock, blockX, blockY, paintInfo));
return result;
@@ -2004,14 +2099,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) {
@@ -2079,7 +2174,7 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX,
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->x(), ty + curr->y(),
+ result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(),
lastTop, lastLeft, lastRight, paintInfo));
}
return result;
@@ -2161,7 +2256,7 @@ void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& left
int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos)
{
- int left = leftOffset(yPos);
+ int left = leftOffset(yPos, false);
if (left == borderLeft() + paddingLeft()) {
if (rootBlock != this)
// The border can potentially be further extended by our containingBlock().
@@ -2181,7 +2276,7 @@ int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos)
int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos)
{
- int right = rightOffset(yPos);
+ int right = rightOffset(yPos, false);
if (right == (contentWidth() + (borderLeft() + paddingLeft()))) {
if (rootBlock != this)
// The border can potentially be further extended by our containingBlock().
@@ -2273,7 +2368,7 @@ void RenderBlock::insertFloatingObject(RenderBox* 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;
@@ -2458,15 +2553,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) {
@@ -2484,7 +2581,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();
@@ -2494,15 +2591,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;
@@ -2521,7 +2615,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();
@@ -2532,9 +2626,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;
}
@@ -2575,7 +2669,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);
@@ -2597,8 +2691,10 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
// 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->isRenderInline())
- bottom = max(bottom, toRenderBox(c)->y() + c->lowestPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ bottom = max(bottom, childBox->y() + childBox->lowestPosition(false));
+ }
}
}
@@ -2631,7 +2727,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
}
}
- 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);
@@ -2642,16 +2738,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());
+ if (childrenInline()) {
+ if (lastLineBox()) {
+ int childBottomEdge = lastLineBox()->y() + lastLineBox()->height();
+ bottom = max(bottom, childBottomEdge + paddingBottom());
+ }
+ } 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());
+ }
+ }
}
return bottom;
@@ -2670,8 +2780,10 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
// 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() && !c->isRenderInline())
- right = max(right, toRenderBox(c)->x() + c->rightmostPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ right = max(right, childBox->x() + childBox->rightmostPosition(false));
+ }
}
}
@@ -2705,7 +2817,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
}
}
- if (m_hasColumns) {
+ if (hasColumns()) {
// This only matters for LTR
if (style()->direction() == LTR)
right = max(columnRects()->last().right() + relativeOffset, right);
@@ -2716,21 +2828,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());
+ 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());
+ }
+ } 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());
+ }
}
}
@@ -2749,8 +2873,10 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
// 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() && !c->isRenderInline())
- left = min(left, toRenderBox(c)->x() + c->leftmostPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ left = min(left, childBox->x() + childBox->leftmostPosition(false));
+ }
}
}
@@ -2784,7 +2910,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
}
}
- if (m_hasColumns) {
+ if (hasColumns()) {
// This only matters for RTL
if (style()->direction() == RTL)
left = min(columnRects()->last().x() + relativeOffset, left);
@@ -2795,7 +2921,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);
}
@@ -2804,7 +2930,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());
}
return left;
@@ -2882,7 +3008,7 @@ void RenderBlock::clearFloats()
// to avoid floats.
bool parentHasFloats = false;
RenderObject* prev = previousSibling();
- while (prev && (!prev->isBox() || !prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) {
+ while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
if (prev->isFloating())
parentHasFloats = true;
prev = prev->previousSibling();
@@ -2891,7 +3017,7 @@ void RenderBlock::clearFloats()
// First add in floats from the parent.
int offset = y();
if (parentHasFloats) {
- RenderBlock* parentBlock = static_cast<RenderBlock *>(parent());
+ RenderBlock* parentBlock = toRenderBlock(parent());
addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset);
}
@@ -2907,7 +3033,7 @@ void RenderBlock::clearFloats()
if (!prev || !prev->isRenderBlock())
return;
- RenderBlock* block = static_cast<RenderBlock *>(prev);
+ RenderBlock* block = toRenderBlock(prev);
if (block->m_floatingObjects && block->floatBottom() > offset)
addIntrudingFloats(block, xoffset, offset);
@@ -2978,8 +3104,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;
@@ -2991,7 +3117,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.
@@ -2999,7 +3126,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);
@@ -3059,7 +3186,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)
@@ -3085,14 +3212,16 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove
// Iterate over our children and mark them as needed.
if (!childrenInline()) {
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isRenderBlock() && !child->isFloatingOrPositioned() &&
- ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats()))
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
+ 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(RenderBox* child)
+int RenderBlock::getClearDelta(RenderBox* child, int yPos)
{
// There is no need to compute clearance if we have no floats.
if (!containsFloats())
@@ -3120,11 +3249,11 @@ int RenderBlock::getClearDelta(RenderBox* 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->y()) : 0;
+ int result = clearSet ? max(0, bottom - yPos) : 0;
if (!result && child->avoidsFloats() && child->style()->width().isFixed() &&
- child->minPrefWidth() > lineWidth(child->y()) && child->minPrefWidth() <= availableWidth() &&
+ child->minPrefWidth() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth() &&
document()->inStrictMode())
- result = max(0, floatBottom() - child->y());
+ result = max(0, floatBottom() - yPos);
return result;
}
@@ -3159,41 +3288,41 @@ 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()) {
+ 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)) {
@@ -3255,7 +3384,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;
}
@@ -3264,10 +3393,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->isRenderInline() && 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;
}
@@ -3282,156 +3409,153 @@ 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 positionForCoordinates recurs could call this instead to
+// prevent crossing editable boundaries. This would require many tests.
+static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& parentCoords)
{
- if (isTable())
- return RenderFlow::positionForCoordinates(x, y);
+ int xInChildCoords = parentCoords.x() - child->x();
+ int yInChildCoords = parentCoords.y() - child->y();
- int top = borderTop();
- int bottom = top + paddingTop() + contentHeight() + paddingBottom();
+ // If this is an anonymous renderer, we just recur normally
+ Node* childNode = child->node();
+ if (!childNode)
+ return child->positionForCoordinates(xInChildCoords, yInChildCoords);
- 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->positionForCoordinates(xInChildCoords, yInChildCoords);
- 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 (xInChildCoords < 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 (RenderBox* c = firstChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc.
- VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y());
- 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);
- }
+static VisiblePosition positionForPointWithInlineChildren(RenderBlock* block, const IntPoint& pointInContents)
+{
+ ASSERT(block->childrenInline());
- if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) {
- if (!isEditableRoot)
- if (RenderBox* c = lastChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc.
- VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y());
- 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 (!block->firstRootBox())
+ return block->createVisiblePosition(0, DOWNSTREAM);
+
+ InlineBox* closestBox = 0;
+ // look for the closest line box in the root box which is at the passed-in y coordinate
+ for (RootInlineBox* root = block->firstRootBox(); root; root = root->nextRootBox()) {
+ int bottom;
+ // 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 (pointInContents.y() < bottom && root->firstChild()) {
+ closestBox = root->closestLeafChildForXPos(pointInContents.x());
+ if (closestBox)
+ // pass the box a y position that is inside it
+ break;
}
}
- if (childrenInline()) {
- if (!firstRootBox())
- return VisiblePosition(n, 0, DOWNSTREAM);
+ // y coordinate is below last root line box, pretend we hit it
+ if (!closestBox)
+ closestBox = block->lastRootBox()->closestLeafChildForXPos(pointInContents.x());
- 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 (closestBox) {
+ // pass the box a y position that is inside it
+ return closestBox->renderer()->positionForCoordinates(pointInContents.x(), closestBox->m_y);
+ }
+
+ // 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 codepath.
+ return block->createVisiblePosition(0, DOWNSTREAM);
+}
+
+VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
+{
+ if (isTable())
+ return RenderBox::positionForPoint(point);
+
+ int contentsX = point.x();
+ int contentsY = point.y();
+ offsetForContents(contentsX, contentsY);
+ IntPoint pointInContents(contentsX, contentsY);
- if (lastRootBox())
- // y coordinate is below last root line box
- return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM);
+ 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);
+ }
- return VisiblePosition(n, 0, DOWNSTREAM);
+ if (childrenInline()) {
+ return positionForPointWithInlineChildren(this, pointInContents);
}
-
- // See if any child blocks exist at this y coordinate.
+
+ // Check top/bottom child-margin/parent-padding for clicks and place them in the first/last child
+ // FIXME: This will not correctly handle first or last children being positioned or non-visible
if (firstChildBox() && contentsY < firstChildBox()->y())
- return VisiblePosition(n, 0, DOWNSTREAM);
- for (RenderBox* renderer = firstChildBox(); renderer; renderer = renderer->nextSiblingBox()) {
- if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned())
+ return positionForPointRespectingEditingBoundaries(this, firstChildBox(), pointInContents);
+ if (lastChildBox() && contentsY > lastChildBox()->y())
+ return positionForPointRespectingEditingBoundaries(this, lastChildBox(), pointInContents);
+
+ for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
+ if (childBox->height() == 0 || childBox->style()->visibility() != VISIBLE || childBox->isFloatingOrPositioned())
continue;
- RenderBox* next = renderer->nextSiblingBox();
- while (next && next->isFloatingOrPositioned())
- next = next->nextSiblingBox();
- if (next)
- bottom = next->y();
- else
- bottom = top + scrollHeight();
- if (contentsY >= renderer->y() && contentsY < bottom)
- return renderer->positionForCoordinates(contentsX - renderer->x(), contentsY - renderer->y());
+ // We hit this child if our click was above the bottom of its padding box (like IE6/7 and FF3)
+ if (contentsY < childBox->y() + childBox->height())
+ return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
}
-
- return RenderFlow::positionForCoordinates(x, y);
+
+ // We only get here if there are no, or only floated/positioned, or only
+ // non-visible block children below the click.
+ return RenderBox::positionForPoint(point);
}
void RenderBlock::offsetForContents(int& tx, int& ty) const
{
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();
@@ -3442,7 +3566,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();
}
@@ -3500,20 +3624,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;
@@ -3522,21 +3646,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;
}
@@ -3544,7 +3668,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);
@@ -3596,9 +3720,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)
@@ -3656,7 +3780,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();
@@ -3685,7 +3809,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();
@@ -3742,7 +3866,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;
}
@@ -3844,7 +3968,7 @@ static int getBPMWidth(int childValue, Length cssUnit)
return 0;
}
-static int getBorderPaddingMargin(const RenderBox* child, bool endOfInline)
+static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
{
RenderStyle* cstyle = child->style();
int result = 0;
@@ -3947,7 +4071,7 @@ void RenderBlock::calcInlinePrefWidths()
if (child->isRenderInline()) {
// Add in padding/border/margin from the appropriate side of
// the element.
- int bpm = getBorderPaddingMargin(static_cast<RenderFlow*>(child), childIterator.endOfInline);
+ int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
childMin += bpm;
childMax += bpm;
@@ -3979,14 +4103,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;
}
@@ -4152,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);
@@ -4186,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.
@@ -4242,11 +4366,11 @@ void RenderBlock::calcBlockPrefWidths()
bool RenderBlock::hasLineIfEmpty() const
{
- return element() && (element()->isContentEditable() && element()->rootEditableElement() == element() ||
- element()->isShadowNode() && element()->shadowParentNode()->hasTagName(inputTag));
+ return node() && ((node()->isContentEditable() && node()->rootEditableElement() == node()) ||
+ (node()->isShadowNode() && node()->shadowParentNode()->hasTagName(inputTag)));
}
-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
@@ -4254,7 +4378,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
@@ -4276,29 +4410,29 @@ 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 (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
if (!curr->isFloatingOrPositioned()) {
- int result = curr->getBaselineOfFirstLineBox();
+ int result = curr->firstLineBoxBaseline();
if (result != -1)
return curr->y() + result; // Translate to our coordinate space.
}
@@ -4308,16 +4442,16 @@ 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 {
@@ -4325,13 +4459,13 @@ int RenderBlock::getBaselineOfLastLineBox() const
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->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;
@@ -4353,7 +4487,7 @@ RenderBlock* RenderBlock::firstLineBlock() const
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();
@@ -4361,7 +4495,7 @@ RenderBlock* RenderBlock::firstLineBlock() const
!parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
break;
ASSERT(parentBlock->isRenderBlock());
- firstLineBlock = static_cast<RenderBlock*>(parentBlock);
+ firstLineBlock = toRenderBlock(parentBlock);
}
if (!hasPseudo)
@@ -4374,8 +4508,8 @@ 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
@@ -4385,7 +4519,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;
@@ -4403,7 +4537,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
@@ -4421,8 +4555,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()) {
@@ -4433,7 +4567,7 @@ 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();
@@ -4441,14 +4575,19 @@ void RenderBlock::updateFirstLetter()
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
@@ -4470,10 +4609,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);
@@ -4482,7 +4621,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());
@@ -4526,7 +4665,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;
}
@@ -4549,7 +4688,7 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom,
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->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
}
@@ -4580,7 +4719,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;
}
@@ -4599,16 +4738,16 @@ 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 (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
if (!obj->isFloatingOrPositioned()) {
if (obj->isBlockFlow() && !obj->hasOverflowClip())
- static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->x(), 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->x());
@@ -4669,7 +4808,7 @@ void RenderBlock::clearTruncation()
else
for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
if (shouldCheckLines(obj))
- static_cast<RenderBlock*>(obj)->clearTruncation();
+ toRenderBlock(obj)->clearTruncation();
}
}
@@ -4695,6 +4834,218 @@ void RenderBlock::setMaxBottomMargins(int pos, int neg)
m_maxMargin->m_bottomNeg = neg;
}
+void RenderBlock::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 && inlineContinuation()) {
+ rects.append(IntRect(tx, ty - collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
+ inlineContinuation()->absoluteRects(rects,
+ tx - x() + inlineContinuation()->containingBlock()->x(),
+ ty - y() + inlineContinuation()->containingBlock()->y(), topLevel);
+ } else
+ rects.append(IntRect(tx, ty, width(), height()));
+}
+
+void RenderBlock::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 && inlineContinuation()) {
+ FloatRect localRect(0, -collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom());
+ quads.append(localToAbsoluteQuad(localRect));
+ inlineContinuation()->absoluteQuads(quads, topLevel);
+ } 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());
+ 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())
diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h
index 2e74e41..d7a26ef 100644
--- a/WebCore/rendering/RenderBlock.h
+++ b/WebCore/rendering/RenderBlock.h
@@ -27,7 +27,8 @@
#include "DeprecatedPtrList.h"
#include "GapRects.h"
-#include "RenderFlow.h"
+#include "RenderBox.h"
+#include "RenderLineBoxList.h"
#include "RootInlineBox.h"
#include <wtf/ListHashSet.h>
@@ -36,6 +37,7 @@ namespace WebCore {
class InlineIterator;
class BidiRun;
class Position;
+class RenderInline;
class RootInlineBox;
template <class Iterator, class Run> class BidiResolver;
@@ -43,11 +45,18 @@ typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver;
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.
@@ -58,10 +67,17 @@ public:
virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); }
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
@@ -77,8 +93,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(); }
@@ -100,7 +114,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);
@@ -117,11 +131,16 @@ public:
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; }
@@ -138,7 +157,7 @@ public:
};
void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end);
- RootInlineBox* determineStartPosition(bool& fullLayout, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats);
+ RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats);
RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart,
BidiStatus& cleanLineBidiStatus,
int& yPos);
@@ -146,12 +165,12 @@ public:
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);
+ int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine);
+ void fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth);
+ InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, 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();
@@ -162,7 +181,8 @@ 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);
@@ -175,16 +195,16 @@ public:
// Returns ture if and only if it has positioned any floats.
bool positionNewFloats();
void clearFloats();
- int getClearDelta(RenderBox* child);
+ 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() > 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);
@@ -194,18 +214,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);
@@ -213,7 +233,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;
@@ -222,8 +242,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()); }
@@ -237,38 +257,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,
@@ -289,6 +293,9 @@ public:
int leftSelectionOffset(RenderBlock* rootBlock, int y);
int rightSelectionOffset(RenderBlock* rootBlock, int y);
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
// Helper methods for computing line counts and heights for line counts.
RootInlineBox* lineAtIndex(int);
int lineCount();
@@ -299,12 +306,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
@@ -312,13 +331,15 @@ 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;
@@ -326,15 +347,6 @@ private:
// Adjust tx and ty from painting offsets to the local coords of this renderer
void offsetForContents(int& tx, int& ty) const;
- // columGap() is used by WebKit when hit-testing columns. It's called by
- // CacheBuilder when it duplicates the hit-testing logic.
-#ifdef ANDROID_EXPOSE_COLUMN_GAP
- public:
-#endif
- int columnGap() const;
-#ifdef ANDROID_EXPOSE_COLUMN_GAP
-private:
-#endif
void calcColumnWidth();
int layoutColumns(int endOfContent = -1);
@@ -443,8 +455,8 @@ protected:
RenderBox* handleFloatingChild(RenderBox* child, const MarginInfo&, bool& handled);
RenderBox* handlePositionedChild(RenderBox* child, const MarginInfo&, bool& handled);
RenderBox* handleRunInChild(RenderBox* child, bool& handled);
- void collapseMargins(RenderBox* child, MarginInfo&, int yPosEstimate);
- void clearFloatsIfNeeded(RenderBox* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin);
+ 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&);
@@ -455,7 +467,13 @@ private:
typedef ListHashSet<RenderBox*>::const_iterator Iterator;
DeprecatedPtrList<FloatingObject>* m_floatingObjects;
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)
@@ -480,13 +498,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/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index 7711f5e..5827f00 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -30,6 +30,7 @@
#include "Document.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "htmlediting.h"
#include "HTMLElement.h"
#include "HTMLNames.h"
#include "ImageBuffer.h"
@@ -40,13 +41,13 @@
#include "RenderFlexibleBox.h"
#include "RenderInline.h"
#include "RenderLayer.h"
-#include "RenderReplica.h"
#include "RenderTableCell.h"
#include "RenderTheme.h"
#ifdef ANDROID_LAYOUT
#include "Settings.h"
#endif
#include "RenderView.h"
+#include "TransformState.h"
#include <algorithm>
#include <math.h>
@@ -64,11 +65,10 @@ 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)
+ : RenderBoxModelObject(node)
#ifdef ANDROID_LAYOUT
, m_visibleWidth(0)
#endif
@@ -78,7 +78,6 @@ RenderBox::RenderBox(Node* node)
, m_marginBottom(0)
, m_minPrefWidth(-1)
, m_maxPrefWidth(-1)
- , m_layer(0)
, m_inlineBoxWrapper(0)
{
setIsBox();
@@ -96,51 +95,61 @@ 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::removeFloatingOrPositionedChildFromBlockLists()
+{
+ ASSERT(isFloatingOrPositioned());
+
+ 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, false);
+ }
+
+ if (isPositioned()) {
+ RenderObject* p;
+ for (p = parent(); p; p = p->parent()) {
+ if (p->isRenderBlock())
+ toRenderBlock(p)->removePositionedObject(this);
+ }
+ }
}
-void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
- s_wasFloating = isFloating();
s_hadOverflowClip = hasOverflowClip();
if (style()) {
- // If our z-index changes value or our visibility changes,
- // we need to dirty our stacking context's z-order list.
- if (newStyle) {
- 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();
- }
- }
-
// 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)))
+ if (diff >= StyleDifferenceRepaint && node() &&
+ (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
view()->repaint();
else if (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) {
+ if (diff == StyleDifferenceRepaintLayer) {
layer()->repaintIncludingDescendants();
if (!(style()->clip() == newStyle->clip()))
layer()->clearClipRectsIncludingDescendants();
- } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < style()->outlineSize())
+ } else if (diff == StyleDifferenceRepaint || newStyle->outlineSize() < style()->outlineSize())
repaint();
}
- if (diff == RenderStyle::Layout) {
+ 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()) {
@@ -165,26 +174,45 @@ void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newSt
if (style()->position() == StaticPosition)
repaint();
if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
- removeFromObjectLists();
+ removeFloatingOrPositionedChildFromBlockLists();
}
}
}
- RenderObject::styleWillChange(diff, newStyle);
+ RenderBoxModelObject::styleWillChange(diff, newStyle);
}
-void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
- // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen
- // during the style change (it's used by clippedOverflowRectForRepaint()).
- if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
- static_cast<RenderView*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
-
- RenderObject::styleDidChange(diff, oldStyle);
+ RenderBoxModelObject::styleDidChange(diff, oldStyle);
if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
RenderBlock::removePercentHeightDescendant(this);
+ // 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);
+ }
+ }
+
+ // Set the text color if we're the body.
+ if (isBody())
+ document()->setTextColor(style()->color());
+}
+
+void RenderBox::updateBoxModelInfoFromStyle()
+{
+ RenderBoxModelObject::updateBoxModelInfoFromStyle();
+
bool isRootObject = isRoot();
bool isViewObject = isRenderView();
@@ -192,23 +220,8 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty
if (isRootObject || isViewObject)
setHasBoxDecorations(true);
- setInline(style()->isDisplayInlineType());
-
- switch (style()->position()) {
- case AbsolutePosition:
- case FixedPosition:
- setPositioned(true);
- break;
- default:
- setPositioned(false);
-
- if (style()->isFloating())
- setFloating(true);
-
- if (style()->position() == RelativePosition)
- setRelPositioned(true);
- break;
- }
+ setPositioned(style()->position() == AbsolutePosition || style()->position() == FixedPosition);
+ setFloating(!isPositioned() && style()->isFloating());
// We also handle <body> and <html>, whose overflow applies to the viewport.
if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
@@ -219,7 +232,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;
}
@@ -234,133 +247,28 @@ 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 && !isRootObject && !isViewObject) {
- 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);
- }
-
- // 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);
- }
- }
-
- if (m_layer)
- m_layer->styleChanged(diff, oldStyle);
-
- // Set the text color if we're the body.
- if (isBody())
- document()->setTextColor(style()->color());
}
-
-int RenderBox::offsetLeft() const
+void RenderBox::layout()
{
- RenderBox* offsetPar = offsetParent();
- if (!offsetPar)
- return 0;
- int xPos = x() - 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->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
- xPos += offsetPar->x();
- }
- return xPos;
-}
+ ASSERT(needsLayout());
-int RenderBox::offsetTop() const
-{
- RenderBox* offsetPar = offsetParent();
- if (!offsetPar)
- return 0;
- int yPos = y() - 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->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
- yPos += offsetPar->y();
+ RenderObject* child = firstChild();
+ if (!child) {
+ setNeedsLayout(false);
+ return;
}
- return yPos;
-}
-
-RenderBox* RenderBox::offsetParent() 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;
- curr = curr->parent();
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
+ while (child) {
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ child = child->nextSibling();
}
- return curr && curr->isBox() ? toRenderBox(curr) : 0;
+ statePusher.pop();
+ setNeedsLayout(false);
}
// More IE extensions. clientWidth and clientHeight represent the interior of an object
@@ -382,104 +290,47 @@ int RenderBox::clientHeight() const
int RenderBox::scrollWidth() const
{
if (hasOverflowClip())
- return m_layer->scrollWidth();
+ return layer()->scrollWidth();
return overflowWidth();
}
int RenderBox::scrollHeight() const
{
if (hasOverflowClip())
- return m_layer->scrollHeight();
+ return layer()->scrollHeight();
return overflowHeight();
}
int RenderBox::scrollLeft() const
{
- return hasOverflowClip() ? m_layer->scrollXOffset() : 0;
+ return hasOverflowClip() ? layer()->scrollXOffset() : 0;
}
int RenderBox::scrollTop() const
{
- return hasOverflowClip() ? m_layer->scrollYOffset() : 0;
+ return hasOverflowClip() ? layer()->scrollYOffset() : 0;
}
void RenderBox::setScrollLeft(int newLeft)
{
if (hasOverflowClip())
- m_layer->scrollToXOffset(newLeft);
+ layer()->scrollToXOffset(newLeft);
}
void RenderBox::setScrollTop(int newTop)
{
if (hasOverflowClip())
- m_layer->scrollToYOffset(newTop);
-}
-
-int RenderBox::paddingTop(bool) const
-{
- int w = 0;
- Length padding = style()->paddingTop();
- if (padding.isPercent())
- w = containingBlock()->availableWidth();
- return padding.calcMinValue(w);
-}
-
-int RenderBox::paddingBottom(bool) const
-{
- int w = 0;
- Length padding = style()->paddingBottom();
- if (padding.isPercent())
- w = containingBlock()->availableWidth();
- return padding.calcMinValue(w);
-}
-
-int RenderBox::paddingLeft(bool) const
-{
- int w = 0;
- Length padding = style()->paddingLeft();
- if (padding.isPercent())
- w = containingBlock()->availableWidth();
- return padding.calcMinValue(w);
+ layer()->scrollToYOffset(newTop);
}
-int RenderBox::paddingRight(bool) const
+void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
{
- int w = 0;
- Length padding = style()->paddingRight();
- if (padding.isPercent())
- w = containingBlock()->availableWidth();
- return padding.calcMinValue(w);
+ rects.append(IntRect(tx, ty, width(), height()));
}
-void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
+void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool)
{
- // 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).
- RenderFlow* continuation = virtualContinuation();
- if (topLevel && continuation) {
- rects.append(IntRect(tx, ty - collapsedMarginTop(),
- width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
- continuation->absoluteRects(rects,
- tx - x() + continuation->containingBlock()->x(),
- ty - y() + continuation->containingBlock()->y(), topLevel);
- } else
- rects.append(IntRect(tx, ty, width(), height()));
-}
-
-void RenderBox::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).
- RenderFlow* continuation = virtualContinuation();
- 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())));
+ quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
}
IntRect RenderBox::absoluteContentBox() const
@@ -497,7 +348,7 @@ FloatQuad RenderBox::absoluteContentQuad() const
}
-IntRect RenderBox::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const
+IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const
{
IntRect box = borderBoundingBox();
adjustRectForOutlineAndShadow(box);
@@ -514,17 +365,7 @@ IntRect RenderBox::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) cons
void RenderBox::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).
- RenderFlow* continuation = virtualContinuation();
- if (continuation) {
- graphicsContext->addFocusRingRect(IntRect(tx, ty - collapsedMarginTop(), width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
- continuation->addFocusRingRects(graphicsContext,
- tx - x() + continuation->containingBlock()->x(),
- ty - y() + continuation->containingBlock()->y());
- } else
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
}
@@ -709,11 +550,7 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
// 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->isRenderInline() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
+ if (!child->hasLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
return true;
}
@@ -747,7 +584,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>
@@ -919,60 +756,20 @@ void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const
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());
-}
-
void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
{
if (!parent())
return;
- if (isRenderInline() || style()->borderImage().image() && style()->borderImage().image()->data() == image ||
- style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image) {
+ 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)
@@ -992,7 +789,7 @@ 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 {
@@ -1021,260 +818,6 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer
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();
-#ifdef ANDROID_ALLOW_TRANSPARENT_BACKGROUNDS
- }
-#else
- } else
- context->clearRect(rect);
-#endif
- }
-
- 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)
@@ -1289,7 +832,7 @@ 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 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 {
@@ -1300,7 +843,50 @@ void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, b
#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())
+ paintInfo.context->addRoundedRectClip(clipRect, style()->borderTopLeftRadius(),
+ style()->borderTopRightRadius(),
+ style()->borderBottomLeftRadius(),
+ style()->borderBottomRightRadius());
+ else
+ 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.
@@ -1314,15 +900,15 @@ IntRect RenderBox::getOverflowClipRect(int tx, int ty)
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;
@@ -1350,64 +936,28 @@ IntRect RenderBox::getClipRect(int tx, int ty)
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(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->isRenderInline())
- 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 (v->layoutStateEnabled()) {
LayoutState* layoutState = v->layoutState();
IntSize offset = layoutState->m_offset;
offset.expand(x(), y());
- localPoint += offset;
- if (style()->position() == RelativePosition && m_layer)
- localPoint += m_layer->relativePositionOffset();
- return localPoint;
+ if (style()->position() == RelativePosition && layer())
+ offset += layer()->relativePositionOffset();
+ transformState.move(offset);
+ return;
}
}
@@ -1415,21 +965,25 @@ 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->localToAbsolute(localPoint, fixed, useTransforms);
- }
-
- return FloatPoint();
+ IntSize containerOffset = offsetFromContainer(o);
+
+ bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
+ if (useTransforms && hasTransform)
+ transformState.applyTransform(transformFromContainer(o, containerOffset), preserve3D);
+ else
+ transformState.move(containerOffset.width(), containerOffset.height(), preserve3D);
+
+ 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()->layoutStateEnabled());
@@ -1437,41 +991,23 @@ FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, boo
if (style()->position() == FixedPosition)
fixed = true;
- if (useTransforms && m_layer && m_layer->transform())
- fixed = false;
+ bool hasTransform = hasLayer() && layer()->transform();
+ if (hasTransform)
+ fixed = false; // Elements with transforms act as a containing block for fixed position descendants
RenderObject* o = container();
- if (o) {
- FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
- localPoint -= offsetFromContainer(o);
- if (useTransforms && m_layer && m_layer->transform())
- localPoint = m_layer->transform()->inverse().mapPoint(localPoint);
- return localPoint;
- }
-
- return FloatPoint();
-}
+ if (!o)
+ return;
-FloatQuad RenderBox::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
-{
- if (repaintContainer == this)
- return localQuad;
+ o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
- if (style()->position() == FixedPosition)
- fixed = true;
+ IntSize containerOffset = offsetFromContainer(o);
- 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);
- }
- quad += offsetFromContainer(o);
- return o->localToContainerQuad(quad, repaintContainer, fixed);
- }
-
- return FloatQuad();
+ bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
+ if (useTransforms && hasTransform)
+ transformState.applyTransform(transformFromContainer(o, containerOffset), preserve3D);
+ else
+ transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D);
}
IntSize RenderBox::offsetFromContainer(RenderObject* o) const
@@ -1485,7 +1021,7 @@ 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()) {
+ && (cb = toRenderBlock(o))->hasColumns()) {
IntRect rect(x(), y(), 1, 1);
cb->adjustRectForColumns(rect);
offset.expand(rect.x(), rect.y());
@@ -1496,13 +1032,18 @@ IntSize RenderBox::offsetFromContainer(RenderObject* o) const
if (o->hasOverflowClip())
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) {
@@ -1513,23 +1054,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.
}
@@ -1537,7 +1078,7 @@ void RenderBox::position(InlineBox* box)
box->remove();
box->destroy(renderArena());
} else if (isReplaced()) {
- setLocation(box->xPos(), box->yPos());
+ setLocation(box->x(), box->y());
m_inlineBoxWrapper = box;
}
}
@@ -1552,7 +1093,7 @@ void RenderBox::deleteLineBoxWrapper()
}
}
-IntRect RenderBox::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
return IntRect();
@@ -1578,18 +1119,18 @@ IntRect RenderBox::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
r.inflate(v->maximalOutlineSize());
}
}
- computeRectForRepaint(r, repaintContainer);
+ computeRectForRepaint(repaintContainer, r);
return r;
}
-void RenderBox::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed)
+void RenderBox::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 && m_layer)
- rect.move(m_layer->relativePositionOffset());
+ if (style()->position() == RelativePosition && layer())
+ rect.move(layer()->relativePositionOffset());
rect.move(x(), y());
rect.move(layoutState->m_offset);
@@ -1616,7 +1157,7 @@ void RenderBox::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer
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);
@@ -1627,22 +1168,22 @@ void RenderBox::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer
// 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(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,
@@ -1663,7 +1204,7 @@ void RenderBox::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer
} else
rect.setLocation(topLeft);
- o->computeRectForRepaint(rect, repaintContainer, fixed);
+ o->computeRectForRepaint(repaintContainer, rect, fixed);
}
void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
@@ -1684,30 +1225,6 @@ void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
}
}
-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()
{
#ifdef ANDROID_LAYOUT
@@ -1744,7 +1261,7 @@ void RenderBox::calcWidth()
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();
@@ -2110,7 +1627,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));
}
@@ -2139,12 +1656,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());
@@ -2152,7 +1669,7 @@ int RenderBox::calcReplacedHeightUsing(Length height) const
return calcContentBoxHeight(height.calcValue(newHeight));
}
- int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : toRenderBox(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
@@ -2183,7 +1700,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
@@ -2195,7 +1712,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());
@@ -2222,75 +1739,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)
+int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const
{
- ASSERT(isPositioned() || isRelPositioned());
- m_layer->setStaticX(staticX);
-}
-
-void RenderBox::setStaticY(int staticY)
-{
- 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->isRenderInline()) {
- 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();
}
- const RenderBox* containingBlockBox = toRenderBox(containingBlock);
- return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth();
+ return max(0, (fromRight - fromLeft));
}
-int RenderBox::containingBlockHeightForPositioned(const RenderObject* containingBlock) const
-{
- const RenderBox* containingBlockBox = toRenderBox(containingBlock);
-
- int heightResult;
- if (containingBlock->isRenderInline()) {
+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 = static_cast<const RenderInline*>(containingBlock)->linesBoundingBox().height();
- } else
- heightResult = containingBlockBox->height();
-
- return heightResult - containingBlockBox->borderTop() - containingBlockBox->borderBottom();
+ heightResult = toRenderInline(containingBlock)->linesBoundingBox().height();
+ }
+ return heightResult - containingBlock->borderTop() - containingBlock->borderBottom();
}
void RenderBox::calcAbsoluteHorizontal()
@@ -2327,7 +1815,7 @@ void RenderBox::calcAbsoluteHorizontal()
// We don't use containingBlock(), since we may be positioned by an enclosing
// relative positioned inline.
- const RenderBox* containerBlock = toRenderBox(container());
+ const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const int containerWidth = containingBlockWidthForPositioned(containerBlock);
@@ -2370,16 +1858,22 @@ 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 (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox())
- staticPosition += po->x();
+ 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 {
- RenderBox* po = parentBox();
+ 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->parentBox())
- staticPosition -= po->x();
+ 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);
}
}
@@ -2447,7 +1941,7 @@ void RenderBox::calcAbsoluteHorizontal()
setWidth(width() + bordersPlusPadding);
}
-void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBox* 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)
@@ -2603,15 +2097,15 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBox* cont
// 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;
}
}
@@ -2634,7 +2128,7 @@ void RenderBox::calcAbsoluteVertical()
// We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
- const RenderBox* containerBlock = toRenderBox(container());
+ const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const int containerHeight = containingBlockHeightForPositioned(containerBlock);
@@ -2665,10 +2159,10 @@ 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();
- for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) {
- if (!po->isTableRow())
- staticTop += po->y();
+ int staticTop = layer()->staticY() - containerBlock->borderTop();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+ if (po->isBox() && !po->isTableRow())
+ staticTop += toRenderBox(po)->y();
}
top.setValue(Fixed, staticTop);
}
@@ -2728,7 +2222,7 @@ void RenderBox::calcAbsoluteVertical()
setHeight(h + bordersPlusPadding);
}
-void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBox* 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)
@@ -2857,7 +2351,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
// We don't use containingBlock(), since we may be positioned by an enclosing
// relative positioned inline.
- const RenderBox* containerBlock = toRenderBox(container());
+ const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const int containerWidth = containingBlockWidthForPositioned(containerBlock);
@@ -2892,16 +2386,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 (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox())
- staticPosition += po->x();
+ 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 {
- RenderBox* po = parentBox();
+ 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->parentBox())
- staticPosition -= po->x();
+ 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);
}
}
@@ -3009,11 +2507,11 @@ 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_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos()));
+ m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->x() - firstLine->x()));
return;
}
}
@@ -3030,7 +2528,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 RenderBox* containerBlock = toRenderBox(container());
+ const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const int containerHeight = containingBlockHeightForPositioned(containerBlock);
@@ -3058,10 +2556,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();
- for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) {
- if (!po->isTableRow())
- staticTop += po->y();
+ int staticTop = layer()->staticY() - containerBlock->borderTop();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+ if (po->isBox() && !po->isTableRow())
+ staticTop += toRenderBox(po)->y();
}
top.setValue(Fixed, staticTop);
}
@@ -3161,7 +2659,6 @@ 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(x(), y(), caretWidth, height());
TextDirection direction = box ? box->direction() : style()->direction();
@@ -3184,7 +2681,7 @@ 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)
@@ -3225,6 +2722,118 @@ int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSe
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
diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h
index 33e7411..182d4e3 100644
--- a/WebCore/rendering/RenderBox.h
+++ b/WebCore/rendering/RenderBox.h
@@ -23,24 +23,26 @@
#ifndef RenderBox_h
#define RenderBox_h
-#include "RenderObject.h"
+#include "RenderBoxModelObject.h"
#include "ScrollTypes.h"
namespace WebCore {
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 { ASSERT(!isRenderInline()); return m_frameRect.width(); }
- int height() const { ASSERT(!isRenderInline()); return m_frameRect.height(); }
+ 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); }
@@ -48,7 +50,7 @@ public:
void setHeight(int height) { m_frameRect.setHeight(height); }
IntPoint location() const { return m_frameRect.location(); }
- IntSize size() const { ASSERT(!isRenderInline()); return m_frameRect.size(); }
+ 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)); }
@@ -56,12 +58,12 @@ public:
void setSize(const IntSize& size) { m_frameRect.setSize(size); }
void move(int dx, int dy) { m_frameRect.move(dx, dy); }
- IntRect frameRect() const { ASSERT(!isRenderInline()); return m_frameRect; }
+ 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(); } // This will work on inlines to return the bounding box of all of the lines' border boxes.
-
+ 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.
@@ -70,7 +72,7 @@ public:
FloatQuad absoluteContentQuad() const;
// Bounds of the outline box in absolute coords. Respects transforms
- virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const;
+ virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const;
virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
// Use this with caution! No type checking is done!
@@ -96,9 +98,6 @@ public:
// 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(); }
- virtual int offsetLeft() const;
- virtual int offsetTop() const;
- virtual RenderBox* 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.
@@ -119,26 +118,12 @@ public:
virtual void setScrollLeft(int);
virtual void setScrollTop(int);
- bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; }
- bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; }
-
- int marginTop() const { return m_marginTop; }
- int marginBottom() const { return m_marginBottom; }
- int marginLeft() const { return m_marginLeft; }
- int marginRight() const { return m_marginRight; }
+ 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 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(); }
-
- // The following seven functions are used to implement collapsing margins.
+ // 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
@@ -147,8 +132,6 @@ public:
virtual bool isSelfCollapsingBlock() const { return false; }
int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); }
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 { 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()); }
@@ -160,6 +143,7 @@ public:
// 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);
@@ -168,14 +152,11 @@ 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 IntSize offsetFromContainer(RenderObject*) const;
int calcBorderBoxWidth(int width) const;
@@ -191,29 +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 clippedOverflowRectForRepaint(RenderBox* repaintContainer);
- virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false);
- IntSize offsetForPositionedInContainer(RenderObject*) const;
- virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) 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();
@@ -247,13 +227,6 @@ public:
void calcVerticalMargins();
- int relativePositionOffsetX() const;
- int relativePositionOffsetY() const;
- IntSize relativePositionOffset() const { return IntSize(relativePositionOffsetX(), relativePositionOffsetY()); }
-
- RenderLayer* layer() const { return m_layer; }
- virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); }
-
virtual int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
@@ -269,18 +242,14 @@ public:
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);
@@ -299,14 +268,25 @@ public:
}
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);
@@ -321,6 +301,9 @@ 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); }
@@ -328,18 +311,16 @@ private:
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 RenderBox* 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 RenderBox* 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);
@@ -350,7 +331,10 @@ 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:
+ bool isAfterContent(RenderObject* child) const;
private:
// The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent).
@@ -373,15 +357,11 @@ 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;
};
@@ -397,6 +377,9 @@ inline const RenderBox* toRenderBox(const RenderObject* o)
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());
@@ -412,6 +395,16 @@ 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/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
new file mode 100644
index 0000000..c79da7b
--- /dev/null
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -0,0 +1,1111 @@
+/*
+ * 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;
+
+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());
+ ASSERT(m_layer);
+ m_layer->destroy(renderArena());
+ m_layer = 0;
+ setHasLayer(false);
+}
+
+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();
+
+ // 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 (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 (m_layer)
+ m_layer->styleChanged(diff, oldStyle);
+}
+
+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 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->x(), ty - box->y());
+ 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();
+#ifdef ANDROID_ALLOW_TRANSPARENT_BACKGROUNDS
+ }
+#else
+ } else
+ context->clearRect(rect);
+#endif
+ }
+
+ 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;
+ 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();
+}
+
+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& 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();
+ }
+
+ drawLineForBoxSide(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
+ drawArcForBoxSide(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;
+ }
+
+ // Draw upper right arc
+ drawArcForBoxSide(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
+ BSTop, tc, style->color(), ts, false);
+ if (applyRightInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ 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();
+ }
+
+ drawLineForBoxSide(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
+ drawArcForBoxSide(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;
+
+ // Draw lower right arc
+ drawArcForBoxSide(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
+ BSBottom, bc, style->color(), bs, false);
+ if (applyRightInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ 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();
+ }
+
+ drawLineForBoxSide(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
+ drawArcForBoxSide(graphicsContext, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan,
+ BSLeft, lc, style->color(), ls, 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())
+ && (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;
+
+ // Draw bottom left arc
+ drawArcForBoxSide(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
+ BSLeft, lc, style->color(), ls, false);
+ if (applyBottomInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ 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();
+ }
+
+ drawLineForBoxSide(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());
+ }
+
+ firstAngleStart = 0;
+ firstAngleSpan = 45;
+
+ // Draw top right arc
+ drawArcForBoxSide(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
+ BSRight, rc, style->color(), rs, 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())
+ && (rs != 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, rc, style->color(), rs, 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 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();
+ }
+}
+
+int RenderBoxModelObject::containingBlockWidthForContent() const
+{
+ return containingBlock()->availableWidth();
+}
+
+} // namespace WebCore
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
new file mode 100644
index 0000000..161e5d2
--- /dev/null
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -0,0 +1,133 @@
+/*
+ * 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);
+ 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);
+
+ // 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;
+};
+
+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/WebCore/rendering/RenderButton.cpp b/WebCore/rendering/RenderButton.cpp
index f7ccd0c..d64d7c3 100644
--- a/WebCore/rendering/RenderButton.cpp
+++ b/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,12 +164,12 @@ 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
diff --git a/WebCore/rendering/RenderButton.h b/WebCore/rendering/RenderButton.h
index 24e4767..89f7cf8 100644
--- a/WebCore/rendering/RenderButton.h
+++ b/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/WebCore/rendering/RenderContainer.cpp b/WebCore/rendering/RenderContainer.cpp
deleted file mode 100644
index dd39d9f..0000000
--- a/WebCore/rendering/RenderContainer.cpp
+++ /dev/null
@@ -1,726 +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 "RenderInline.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 = toRenderText(newChild)->originalText();
- if (textToTransform)
- toRenderText(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)
-{
- // Double check that the document did in fact use generated content rules. Otherwise we should not have been called.
- ASSERT(document()->usesBeforeAfterRules());
-
- // 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() && static_cast<RenderInline*>(this)->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 (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() == 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(x(), 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 xPos, int yPos)
-{
- // 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 (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
- if (xPos <= right / 2)
- return VisiblePosition(Position(element(), 0));
- else
- return VisiblePosition(Position(element(), maxDeepOffset(element())));
- }
- }
-
- // 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 = m_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 = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->y());
- int bottom = top + renderer->contentHeight();
- int left = borderLeft() + 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 VisiblePosition(element(), 0, DOWNSTREAM);
-}
-
-void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool)
-{
- if (!m_firstChild && (isInline() || isAnonymousBlock())) {
- FloatPoint absPos = localToAbsolute(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->localToAbsolute(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);
- }
-}
-
-#ifdef ANDROID_LAYOUT
-bool RenderContainer::hasChildTable() const
-{
- if (!firstChild())
- return false;
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isTable()) {
- return true;
- } else if (child->hasChildTable() == true) {
- return true;
- }
- }
- return false;
-}
-#endif
-
-#undef DEBUG_LAYOUT
-
-} // namespace WebCore
diff --git a/WebCore/rendering/RenderContainer.h b/WebCore/rendering/RenderContainer.h
deleted file mode 100644
index 8ae5296..0000000
--- a/WebCore/rendering/RenderContainer.h
+++ /dev/null
@@ -1,82 +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; }
-
- // Use this with caution! No type checking is done!
- RenderBox* firstChildBox() const { ASSERT(!firstChild() || firstChild()->isBox()); return toRenderBox(m_firstChild); }
- RenderBox* lastChildBox() const { ASSERT(!lastChild() || lastChild()->isBox()); return toRenderBox(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);
-#ifdef ANDROID_LAYOUT
- virtual bool hasChildTable() const;
-#endif
-
- 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);
-
-protected:
- RenderObject* m_firstChild;
- RenderObject* m_lastChild;
-};
-
-} // namespace WebCore
-
-#endif // RenderContainer_h
diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp
index 598f40d..fd6d80d 100644
--- a/WebCore/rendering/RenderCounter.cpp
+++ b/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/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h
index 10be066..55aab73 100644
--- a/WebCore/rendering/RenderCounter.h
+++ b/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/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp
index 5baca3e..310dbe4 100644
--- a/WebCore/rendering/RenderFieldset.cpp
+++ b/WebCore/rendering/RenderFieldset.cpp
@@ -107,10 +107,10 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren)
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 toRenderBox(legend);
@@ -204,17 +204,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 +238,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 +262,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/WebCore/rendering/RenderFieldset.h b/WebCore/rendering/RenderFieldset.h
index 38f3236..ed57d3a 100644
--- a/WebCore/rendering/RenderFieldset.h
+++ b/WebCore/rendering/RenderFieldset.h
@@ -46,7 +46,7 @@ public:
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/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp
index cbf1409..33ffd98 100644
--- a/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/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)
@@ -157,7 +158,7 @@ int RenderFileUploadControl::maxFilenameWidth() const
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)
@@ -202,7 +203,7 @@ 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);
diff --git a/WebCore/rendering/RenderFileUploadControl.h b/WebCore/rendering/RenderFileUploadControl.h
index 60e7a7b..85bc09f 100644
--- a/WebCore/rendering/RenderFileUploadControl.h
+++ b/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/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp
index e6dd91a..ff9dad4 100644
--- a/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/WebCore/rendering/RenderFlexibleBox.cpp
@@ -205,14 +205,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
if (!relayoutChildren && layoutOnlyPositionedObjects())
return;
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout();
- if (checkForRepaint) {
- oldBounds = absoluteClippedOverflowRect();
- oldOutlineBox = absoluteOutlineBounds();
- }
-
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection());
int previousWidth = width();
@@ -248,9 +241,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())
@@ -316,11 +309,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);
}
@@ -393,9 +385,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.
@@ -435,13 +428,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;
}
@@ -450,7 +443,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
// fill the height of a containing box by default.
// Now do a layout.
int oldChildHeight = child->height();
- toRenderBox(child)->calcHeight();
+ child->calcHeight();
if (oldChildHeight != child->height())
child->setChildNeedsLayout(true, false);
child->layoutIfNeeded();
@@ -463,9 +456,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;
}
@@ -480,7 +474,7 @@ 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->y() + child->overflowTop(false));
@@ -719,13 +713,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();
}
@@ -738,7 +732,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;
@@ -767,9 +761,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);
@@ -786,8 +780,8 @@ 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)
@@ -795,9 +789,9 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (destBlock->style()->direction() != LTR)
continue;
- int blockEdge = destBlock->rightOffset(lastVisibleLine->yPos());
+ int blockEdge = destBlock->rightOffset(lastVisibleLine->y(), false);
if (!lastVisibleLine->canAccommodateEllipsis(true, blockEdge,
- lastVisibleLine->xPos() + lastVisibleLine->width(),
+ lastVisibleLine->x() + lastVisibleLine->width(),
totalWidth))
continue;
@@ -826,14 +820,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(height());
+ if (child->style()->hasStaticY())
+ child->layer()->setStaticY(height());
child = iterator.next();
continue;
}
@@ -873,7 +867,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
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->x() + child->overflowWidth(false), m_overflowWidth);
diff --git a/WebCore/rendering/RenderFlow.cpp b/WebCore/rendering/RenderFlow.cpp
deleted file mode 100644
index 94ec124..0000000
--- a/WebCore/rendering/RenderFlow.cpp
+++ /dev/null
@@ -1,744 +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() && !isRenderInline()) || 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 = toRenderText(curr)->lastTextBox();
- if (textBox)
- box = textBox->root();
- } else if (curr->isRenderInline()) {
- 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 && document()->usesFirstLineRules()) {
- 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 (isRenderInline())
- 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 = isRenderInline();
- if (inlineFlow)
- ASSERT(m_layer); // 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() - 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);
- ListHashSet<RenderFlow*> 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) {
- ListHashSet<RenderFlow*>::iterator end = info.outlineObjects->end();
- for (ListHashSet<RenderFlow*>::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 = isRenderInline();
- if (inlineFlow)
- ASSERT(m_layer); // The only way an inline can 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) {
- updateHitTestResult(result, IntPoint(x - tx, y - ty));
- return true;
- }
- }
- }
-
- return false;
-}
-
-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 = localToAbsolute(FloatPoint(myRight, 0));
-
- int containerRight = containingBlock()->x() + containingBlockWidth();
- FloatPoint absContainerPoint = localToAbsolute(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() && 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 (continuation()) {
- if (isInline())
- continuation()->addFocusRingRects(graphicsContext,
- tx - containingBlock()->x() + continuation()->x(),
- ty - containingBlock()->y() + continuation()->y());
- else
- continuation()->addFocusRingRects(graphicsContext,
- tx - x() + continuation()->containingBlock()->x(),
- ty - y() + continuation()->containingBlock()->y());
- }
-}
-
-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/WebCore/rendering/RenderFlow.h b/WebCore/rendering/RenderFlow.h
deleted file mode 100644
index 897e40a..0000000
--- a/WebCore/rendering/RenderFlow.h
+++ /dev/null
@@ -1,145 +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)
- , m_cellWidthChanged(false)
- {
- }
-#ifndef NDEBUG
- virtual ~RenderFlow();
-#endif
-
- virtual RenderFlow* virtualContinuation() const { return continuation(); }
- 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 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.
-
- // from RenderTableCell
- bool m_cellWidthChanged : 1;
-};
-
-#ifdef NDEBUG
-inline void RenderFlow::checkConsistency() const
-{
-}
-#endif
-
-} // namespace WebCore
-
-#endif // RenderFlow_h
diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp
index 523601c..0584c1c 100644
--- a/WebCore/rendering/RenderForeignObject.cpp
+++ b/WebCore/rendering/RenderForeignObject.cpp
@@ -40,7 +40,7 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node)
TransformationMatrix RenderForeignObject::translationForAttributes()
{
- SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(element());
+ SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node());
return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign));
}
@@ -53,7 +53,7 @@ void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY)
paintInfo.context->concatCTM(TransformationMatrix().translate(parentX, parentY));
paintInfo.context->concatCTM(localTransform());
paintInfo.context->concatCTM(translationForAttributes());
- paintInfo.context->clip(getClipRect(parentX, parentY));
+ paintInfo.context->clip(clipRect(parentX, parentY));
float opacity = style()->opacity();
if (opacity < 1.0f)
@@ -70,18 +70,18 @@ void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY)
paintInfo.context->restore();
}
-void RenderForeignObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed)
+void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
{
TransformationMatrix transform = translationForAttributes() * localTransform();
rect = transform.mapRect(rect);
- RenderBlock::computeRectForRepaint(rect, repaintContainer, fixed);
+ RenderBlock::computeRectForRepaint(repaintContainer, rect, fixed);
}
bool RenderForeignObject::calculateLocalTransform()
{
TransformationMatrix oldTransform = m_localTransform;
- m_localTransform = static_cast<SVGForeignObjectElement*>(element())->animatedLocalTransform();
+ m_localTransform = static_cast<SVGForeignObjectElement*>(node())->animatedLocalTransform();
return (oldTransform != m_localTransform);
}
@@ -92,13 +92,8 @@ void RenderForeignObject::layout()
// Arbitrary affine transforms are incompatible with LayoutState.
view()->disableLayoutState();
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout();
- if (checkForRepaint) {
- oldBounds = m_absoluteBounds;
- oldOutlineBox = absoluteOutlineBounds();
- }
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout(), &m_absoluteBounds);
calculateLocalTransform();
@@ -106,8 +101,7 @@ void RenderForeignObject::layout()
m_absoluteBounds = absoluteClippedOverflowRect();
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ repainter.repaintAfterLayout();
view()->enableLayoutState();
setNeedsLayout(false);
@@ -118,7 +112,7 @@ bool RenderForeignObject::nodeAtPoint(const HitTestRequest& request, HitTestResu
TransformationMatrix totalTransform = absoluteTransform();
totalTransform *= translationForAttributes();
double localX, localY;
- totalTransform.inverse().map(x, y, &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);
}
diff --git a/WebCore/rendering/RenderForeignObject.h b/WebCore/rendering/RenderForeignObject.h
index 28f4ddb..ab96785 100644
--- a/WebCore/rendering/RenderForeignObject.h
+++ b/WebCore/rendering/RenderForeignObject.h
@@ -42,7 +42,7 @@ public:
virtual TransformationMatrix localTransform() const { return m_localTransform; }
virtual bool calculateLocalTransform();
- virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
virtual bool requiresLayer() const { return false; }
virtual void layout();
diff --git a/WebCore/rendering/RenderFrame.h b/WebCore/rendering/RenderFrame.h
index d7c8c5a..9050077 100644
--- a/WebCore/rendering/RenderFrame.h
+++ b/WebCore/rendering/RenderFrame.h
@@ -41,7 +41,7 @@ public:
#ifdef FLATTEN_FRAMESET
virtual void layout();
#endif
- HTMLFrameElement* element() const { return static_cast<HTMLFrameElement*>(RenderPart::element()); }
+ HTMLFrameElement* element() const { return static_cast<HTMLFrameElement*>(RenderPart::node()); }
FrameEdgeInfo edgeInfo() const;
diff --git a/WebCore/rendering/RenderFrameSet.cpp b/WebCore/rendering/RenderFrameSet.cpp
index f6cd4df..0353bb1 100644
--- a/WebCore/rendering/RenderFrameSet.cpp
+++ b/WebCore/rendering/RenderFrameSet.cpp
@@ -42,7 +42,7 @@
namespace WebCore {
RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
- : RenderContainer(frameSet)
+ : RenderBox(frameSet)
, m_isResizing(false)
, m_isChildResizing(false)
#ifdef FLATTEN_FRAMESET
@@ -164,11 +164,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());
}
@@ -498,7 +498,7 @@ void RenderFrameSet::layout()
positionFrames();
- RenderContainer::layout();
+ RenderBox::layout();
computeEdgeInfo();
@@ -668,8 +668,8 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
return false;
if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
FloatPoint pos = localToAbsolute();
- startResizing(m_cols, evt->pageX() - pos.x());
- startResizing(m_rows, evt->pageY() - pos.y());
+ 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;
@@ -678,8 +678,8 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
} else {
if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
FloatPoint pos = localToAbsolute();
- continueResizing(m_cols, evt->pageX() - pos.x());
- continueResizing(m_rows, evt->pageY() - pos.y());
+ 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;
@@ -710,11 +710,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/WebCore/rendering/RenderFrameSet.h b/WebCore/rendering/RenderFrameSet.h
index 066dbab..0c80ad9 100644
--- a/WebCore/rendering/RenderFrameSet.h
+++ b/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; }
@@ -97,7 +102,6 @@ private:
inline HTMLFrameSetElement* frameSet() const;
- bool canResize(const IntPoint&) const;
void setIsResizing(bool);
void layOutAxis(GridAxis&, const Length*, int availableSpace);
@@ -114,6 +118,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/WebCore/rendering/RenderHTMLCanvas.cpp b/WebCore/rendering/RenderHTMLCanvas.cpp
index f4d88d8..1fc07f0 100644
--- a/WebCore/rendering/RenderHTMLCanvas.cpp
+++ b/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -31,6 +31,7 @@
#include "HTMLCanvasElement.h"
#include "HTMLNames.h"
#include "RenderView.h"
+#include "FrameView.h"
namespace WebCore {
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index e67a4ca..f48a219 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -38,6 +38,7 @@
#include "Page.h"
#include "RenderView.h"
#include <wtf/CurrentTime.h>
+#include <wtf/UnusedParam.h>
#ifdef ANDROID_LAYOUT
#include "Settings.h"
@@ -315,9 +316,32 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
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) {
@@ -406,7 +430,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
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);
}
@@ -419,41 +443,44 @@ 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()) {
+ 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());
+ inside = 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
}
@@ -516,7 +543,7 @@ int RenderImage::calcReplacedWidth(bool includeMaxWidth) const
width = max(minW, min(width, maxW));
// in SSR mode, we will fit the image to its container width
if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
- int cw = containingBlockWidth();
+ int cw = containingBlockWidthForContent();
if (cw && width>cw)
width = cw;
}
@@ -555,7 +582,7 @@ int RenderImage::calcReplacedHeight() const
calcReplacedWidthUsing(style()->maxWidth());
width = max(minW, min(width, maxW));
- int cw = containingBlockWidth();
+ int cw = containingBlockWidthForContent();
if (cw && width && width>cw)
height = cw * height / width; // preserve aspect ratio
}
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 71896d6..042452f 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/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/WebCore/rendering/RenderImageGeneratedContent.h b/WebCore/rendering/RenderImageGeneratedContent.h
index cab0192..9f8330d 100644
--- a/WebCore/rendering/RenderImageGeneratedContent.h
+++ b/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/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp
index 4f4412d..8f98427 100644
--- a/WebCore/rendering/RenderInline.cpp
+++ b/WebCore/rendering/RenderInline.cpp
@@ -26,28 +26,94 @@
#include "RenderInline.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()
{
- RenderFlow::styleDidChange(diff, oldStyle);
+ // 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);
+ }
- setInline(true);
- setHasReflection(false);
+ 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()
+{
+ RenderBoxModelObject::updateBoxModelInfoFromStyle();
+
+ 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
@@ -55,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() && document()->usesBeforeAfterRules()) {
- updateBeforeAfterContent(RenderStyle::BEFORE);
- updateBeforeAfterContent(RenderStyle::AFTER);
+ 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())
@@ -92,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()))
@@ -109,7 +205,7 @@ 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
@@ -117,7 +213,7 @@ void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeCh
// content gets properly destroyed.
bool isLastChild = (beforeChild == lastChild());
if (document()->usesBeforeAfterRules())
- updateBeforeAfterContent(RenderStyle::AFTER);
+ 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.
@@ -126,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);
@@ -153,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
@@ -173,24 +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.
if (document()->usesBeforeAfterRules())
- curr->updateBeforeAfterContent(RenderStyle::AFTER);
+ 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.
@@ -198,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.
@@ -218,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();
@@ -235,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.
@@ -246,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) {
@@ -256,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();
}
}
@@ -267,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
@@ -282,41 +378,78 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox
post->setNeedsLayoutAndPrefWidthsRecalc();
}
+void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
+{
+ 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 (newChild->isFloatingOrPositioned())
+ return beforeChildParent->addChildIgnoringContinuation(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->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);
+ }
+}
+
void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
{
- paintLines(paintInfo, tx, ty);
+ m_lineBoxes.paint(this, paintInfo, tx, ty);
}
void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
{
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
- rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
+ 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));
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isBox()) {
- RenderBox* box = toRenderBox(curr);
- curr->absoluteRects(rects, tx + box->x(), ty + box->y(), false);
- }
+ if (continuation() && topLevel) {
+ if (continuation()->isBox()) {
+ RenderBox* box = toRenderBox(continuation());
+ continuation()->absoluteRects(rects,
+ tx - containingBlock()->x() + box->x(),
+ ty - containingBlock()->y() + box->y(),
+ topLevel);
+ } else
+ continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y(), topLevel);
}
-
- if (continuation() && topLevel)
- continuation()->absoluteRects(rects,
- tx - containingBlock()->x() + continuation()->x(),
- ty - containingBlock()->y() + continuation()->y(),
- topLevel);
}
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);
- }
+ 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() && topLevel)
continuation()->absoluteQuads(quads, topLevel);
@@ -324,20 +457,44 @@ void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
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())
@@ -352,24 +509,31 @@ const char* RenderInline::renderName() const
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->x() + x;
- int parentBlockY = cb->y() + y;
- for (RenderFlow* c = continuation(); c; c = c->continuation()) {
- RenderFlow* 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->x(), parentBlockY - contBlock->y());
+ c = toRenderBlock(c)->inlineContinuation();
}
-
- return RenderFlow::positionForCoordinates(x, y);
+
+ return RenderBoxModelObject::positionForPoint(point);
}
IntRect RenderInline::linesBoundingBox() const
@@ -385,21 +549,21 @@ IntRect RenderInline::linesBoundingBox() const
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 (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()->yPos() + lastLineBox()->height() - firstLineBox()->yPos());
- result.setY(firstLineBox()->yPos());
+ result.setHeight(lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y());
+ result.setY(firstLineBox()->y());
}
return result;
}
-IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
// Only run-ins are allowed in here during layout.
ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
@@ -421,7 +585,7 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
inlineFlow = inlineFlow->parent()) {
if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
- toRenderBox(inlineFlow)->layer()->relativePositionOffset(left, top);
+ toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
}
IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
@@ -439,8 +603,11 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
IntRect repaintRect(x, y, r.width(), r.height());
r = intersection(repaintRect, boxRect);
}
- ASSERT(repaintContainer != this);
- cb->computeRectForRepaint(r, repaintContainer);
+
+ // 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()) {
@@ -459,4 +626,409 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
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/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h
index 83b8506..f3be72a 100644
--- a/WebCore/rendering/RenderInline.h
+++ b/WebCore/rendering/RenderInline.h
@@ -25,31 +25,39 @@
#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 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);
@@ -62,12 +70,20 @@ public:
virtual int offsetWidth() const { return linesBoundingBox().width(); }
virtual int offsetHeight() const { return linesBoundingBox().height(); }
- void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ // 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, bool topLevel = true);
virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed);
- virtual VisiblePosition positionForCoordinates(int x, int y);
+ virtual VisiblePosition positionForPoint(const IntPoint&);
IntRect linesBoundingBox() const;
@@ -77,13 +93,79 @@ public:
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(); }
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+
+ 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/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 1a538c6..fd88120 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -44,10 +44,13 @@
#include "config.h"
#include "RenderLayer.h"
+#include "CString.h"
#include "CSSPropertyNames.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"
@@ -73,8 +76,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 +99,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,7 +121,7 @@ void ClipRects::destroy(RenderArena* renderArena)
renderArena->free(*(size_t *)this, this);
}
-RenderLayer::RenderLayer(RenderBox* renderer)
+RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
: m_renderer(renderer)
, m_parent(0)
, m_previous(0)
@@ -138,15 +143,15 @@ RenderLayer::RenderLayer(RenderBox* renderer)
, 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,10 +161,15 @@ RenderLayer::RenderLayer(RenderBox* renderer)
, 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)
@@ -185,9 +195,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 +218,40 @@ RenderLayer::~RenderLayer()
m_resizer->destroy();
}
+#if USE(ACCELERATED_COMPOSITING)
+RenderLayerCompositor* RenderLayer::compositor() const
+{
+ ASSERT(renderer()->view());
+ return renderer()->view()->compositor();
+}
+
+void RenderLayer::rendererContentChanged()
+{
+ if (m_backing)
+ m_backing->rendererContentChanged();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+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) {
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,
@@ -231,16 +274,17 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
// from updateScrollInfoAfterLayout().
ASSERT(!view->layoutStateEnabled());
- IntRect newRect = renderer()->absoluteClippedOverflowRect();
- IntRect newOutlineBox = renderer()->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
- renderer()->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox);
+ renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox);
}
}
m_repaintRect = newRect;
@@ -258,6 +302,14 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(doFullRepaint, checkForRepaint);
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (!parent())
+ compositor()->updateRootLayerPosition();
+
+ if (isComposited())
+ backing()->updateAfterLayout();
+#endif
// With all our children positioned, now update our marquee if we need to.
if (m_marquee)
@@ -266,7 +318,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 +332,33 @@ void RenderLayer::updateTransform()
}
if (hasTransform) {
- m_transform->reset();
- renderer()->style()->applyTransform(*m_transform, renderer()->borderBoxRect().size());
+ RenderBox* box = renderBox();
+ ASSERT(box);
+ m_transform->makeIdentity();
+ box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+ makeMatrixRenderable(*m_transform);
}
+
+ 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);
+ return currTransform;
+ }
+#endif
+
+ return *m_transform;
}
void RenderLayer::setHasVisibleContent(bool b)
@@ -288,9 +368,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())
@@ -372,38 +453,84 @@ 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();
+ }
+ }
+
+ // 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 = renderer()->x();
- int y = renderer()->y();
+ RenderBox* rendererBox = renderBox();
+
+ int x = rendererBox ? rendererBox->x() : 0;
+ int y = rendererBox ? rendererBox->y() : 0;
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.
- RenderBox* curr = renderer()->parentBox();
+ 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->x();
- y += curr->y();
+ RenderBox* currBox = toRenderBox(curr);
+ x += currBox->x();
+ y += currBox->y();
}
- curr = curr->parentBox();
+ curr = curr->parent();
}
- if (curr->isTableRow()) {
+ if (curr->isBox() && curr->isTableRow()) {
// Put ourselves into the row coordinate space.
- x -= curr->x();
- y -= curr->y();
+ RenderBox* currBox = toRenderBox(curr);
+ x -= currBox->x();
+ y -= currBox->y();
}
}
m_relX = m_relY = 0;
if (renderer()->isRelPositioned()) {
- m_relX = toRenderBox(renderer())->relativePositionOffsetX();
- m_relY = toRenderBox(renderer())->relativePositionOffsetY();
+ m_relX = renderer()->relativePositionOffsetX();
+ m_relY = renderer()->relativePositionOffsetY();
x += m_relX; y += m_relY;
}
@@ -414,8 +541,8 @@ void RenderLayer::updateLayerPosition()
// For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
positionedParent->subtractScrolledContentOffset(x, y);
- if (renderer()->isPositioned()) {
- IntSize offset = toRenderBox(renderer())->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();
}
@@ -424,33 +551,74 @@ void RenderLayer::updateLayerPosition()
// FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
- setPos(x, y);
+ setLocation(x, y);
if (renderer()->isRenderInline()) {
- RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
+ RenderInline* inlineFlow = toRenderInline(renderer());
IntRect lineBox = inlineFlow->linesBoundingBox();
setWidth(lineBox.width());
setHeight(lineBox.height());
- } else {
- setWidth(renderer()->width());
- setHeight(renderer()->height());
-
- if (!renderer()->hasOverflowClip()) {
- if (renderer()->overflowWidth() > renderer()->width())
- setWidth(renderer()->overflowWidth());
- if (renderer()->overflowHeight() > renderer()->height())
- setHeight(renderer()->overflowHeight());
+ } 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->renderer()->isRenderView() && !curr->renderer()->isRoot() &&
- curr->renderer()->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
@@ -469,6 +637,27 @@ RenderLayer* RenderLayer::enclosingTransformedAncestor() const
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
@@ -487,18 +676,24 @@ bool RenderLayer::requiresSlowRepaints() const
bool RenderLayer::isTransparent() const
{
#if ENABLE(SVG)
- if (renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
+ if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
return false;
#endif
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)
@@ -507,16 +702,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.
@@ -550,14 +745,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));
@@ -577,7 +772,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.
@@ -601,10 +796,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.
@@ -614,10 +809,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());
@@ -629,9 +833,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.
@@ -654,6 +858,10 @@ void RenderLayer::removeOnlyThisLayer()
if (!m_parent)
return;
+#if USE(ACCELERATED_COMPOSITING)
+ compositor()->layerWillBeRemoved(m_parent, this);
+#endif
+
// Dirty the clip rects.
clearClipRectsIncludingDescendants();
@@ -674,8 +882,8 @@ void RenderLayer::removeOnlyThisLayer()
current->updateLayerPositions();
current = next;
}
-
- destroy(renderer()->renderArena());
+
+ m_renderer->destroyLayer();
}
void RenderLayer::insertOnlyThisLayer()
@@ -684,21 +892,21 @@ 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;
@@ -707,8 +915,8 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int&
// Add in the offset of the view. We can obtain this by calling
// localToAbsolute() on the RenderView.
FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
- x += absPos.x();
- y += absPos.y();
+ xPos += absPos.x();
+ yPos += absPos.y();
return;
}
@@ -720,10 +928,10 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int&
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)
@@ -804,14 +1012,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() - renderer()->clientWidth();
- int maxY = scrollHeight() - renderer()->clientHeight();
+ int maxX = scrollWidth() - box->clientWidth();
+ int maxY = scrollHeight() - box->clientHeight();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
@@ -831,6 +1043,11 @@ 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 (isComposited())
+ m_backing->updateGraphicsLayerGeometry();
+#endif
RenderView* view = renderer()->view();
@@ -865,7 +1082,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());
}
}
@@ -890,10 +1107,12 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor,
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 = renderer()->localToAbsolute();
- absPos.move(renderer()->borderLeft(), renderer()->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(), renderer()->clientWidth(), renderer()->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);
@@ -912,7 +1131,7 @@ 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 (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) {
IntRect viewRect = frameView->visibleContentRect();
@@ -956,17 +1175,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())
@@ -989,17 +1208,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())
@@ -1032,12 +1251,13 @@ 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() || !renderer()->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.
@@ -1073,7 +1293,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset
ExceptionCode ec;
if (difference.width()) {
- if (element && element->isControl()) {
+ 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);
@@ -1085,7 +1305,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset
}
if (difference.height()) {
- if (element && element->isControl()) {
+ 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);
@@ -1172,6 +1392,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);
@@ -1179,25 +1400,29 @@ static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds
bool RenderLayer::scrollbarCornerPresent() const
{
- return !scrollCornerRect(this, renderer()->borderBoxRect()).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 = renderer()->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, renderer()->node()->shadowAncestorNode()->renderBox());
+ widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer));
else
widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
renderer()->document()->view()->addChild(widget.get());
@@ -1287,19 +1512,23 @@ void RenderLayer::positionOverflowControls(int tx, int ty)
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
return;
- IntRect borderBox = renderer()->borderBoxRect();
+ 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() - renderer()->borderRight() - m_vBar->width(),
- absBounds.y() + renderer()->borderTop(),
+ m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(),
+ absBounds.y() + box->borderTop(),
m_vBar->width(),
- absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - scrollCorner.height()));
+ absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
if (m_hBar)
- m_hBar->setFrameRect(IntRect(absBounds.x() + renderer()->borderLeft(),
- absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(),
- absBounds.width() - (renderer()->borderLeft() + renderer()->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)
@@ -1324,19 +1553,22 @@ int RenderLayer::scrollHeight()
void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
{
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
m_scrollDimensionsDirty = false;
bool ltr = renderer()->style()->direction() == LTR;
- int clientWidth = renderer()->clientWidth();
- int clientHeight = renderer()->clientHeight();
+ int clientWidth = box->clientWidth();
+ int clientHeight = box->clientHeight();
- m_scrollLeftOverflow = ltr ? 0 : min(0, renderer()->leftmostPosition(true, false) - renderer()->borderLeft());
+ m_scrollLeftOverflow = ltr ? 0 : min(0, box->leftmostPosition(true, false) - box->borderLeft());
int rightPos = ltr ?
- renderer()->rightmostPosition(true, false) - renderer()->borderLeft() :
+ box->rightmostPosition(true, false) - box->borderLeft() :
clientWidth - m_scrollLeftOverflow;
- int bottomPos = renderer()->lowestPosition(true, false) - renderer()->borderTop();
+ int bottomPos = box->lowestPosition(true, false) - box->borderTop();
m_scrollWidth = max(rightPos, clientWidth);
m_scrollHeight = max(bottomPos, clientHeight);
@@ -1368,7 +1600,7 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve
if (FrameView* frameView = renderer()->document()->view()) {
frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
- EventTargetNodeCast(renderer()->element()));
+ renderer()->node());
}
}
}
@@ -1376,16 +1608,20 @@ 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 (renderer()->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() - renderer()->clientWidth()));
- int newY = max(0, min(m_scrollY, scrollHeight() - renderer()->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 = renderer()->view();
ASSERT(view);
@@ -1417,12 +1653,12 @@ RenderLayer::updateScrollInfoAfterLayout()
setHasVerticalScrollbar(false);
// overflow:auto may need to lay out again if scrollbars got added/removed.
- bool scrollbarsChanged = (renderer()->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
- (renderer()->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
+ bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
+ (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
if (scrollbarsChanged) {
- if (renderer()->hasAutoHorizontalScrollbar())
+ if (box->hasAutoHorizontalScrollbar())
setHasHorizontalScrollbar(horizontalOverflow);
- if (renderer()->hasAutoVerticalScrollbar())
+ if (box->hasAutoVerticalScrollbar())
setHasVerticalScrollbar(verticalOverflow);
#if ENABLE(DASHBOARD_SUPPORT)
@@ -1439,7 +1675,7 @@ RenderLayer::updateScrollInfoAfterLayout()
m_inOverflowRelayout = true;
renderer()->setNeedsLayout(true, false);
if (renderer()->isRenderBlock())
- static_cast<RenderBlock*>(renderer())->layoutBlock(true);
+ toRenderBlock(renderer())->layoutBlock(true);
else
renderer()->layout();
m_inOverflowRelayout = false;
@@ -1448,14 +1684,14 @@ RenderLayer::updateScrollInfoAfterLayout()
}
// If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
- if (m_hBar && renderer()->hasAutoHorizontalScrollbar())
+ if (m_hBar && box->hasAutoHorizontalScrollbar())
m_hBar->setEnabled(true);
- if (m_vBar && renderer()->hasAutoVerticalScrollbar())
+ if (m_vBar && box->hasAutoVerticalScrollbar())
m_vBar->setEnabled(true);
// Set up the range (and page step/line step).
if (m_hBar) {
- int clientWidth = renderer()->clientWidth();
+ int clientWidth = box->clientWidth();
int pageStep = (clientWidth - cAmountToKeepWhenPaging);
if (pageStep < 0) pageStep = clientWidth;
m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
@@ -1463,14 +1699,14 @@ RenderLayer::updateScrollInfoAfterLayout()
m_hBar->setValue(scrollXOffset());
}
if (m_vBar) {
- int clientHeight = renderer()->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 (renderer()->element() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
+ if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
updateOverflowStatus(horizontalOverflow, verticalOverflow);
}
@@ -1501,7 +1737,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, renderer()->borderBoxRect());
+ 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;
@@ -1524,7 +1763,10 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
if (renderer()->style()->resize() == RESIZE_NONE)
return;
- IntRect cornerRect = resizerCornerRect(this, renderer()->borderBoxRect());
+ 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;
@@ -1548,6 +1790,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)));
@@ -1563,9 +1806,12 @@ bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
return false;
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
IntPoint localPoint = absoluteToContents(absolutePoint);
- IntRect localBounds(0, 0, renderer()->width(), renderer()->height());
+ IntRect localBounds(0, 0, box->width(), box->height());
return resizerCornerRect(this, localBounds).contains(localPoint);
}
@@ -1574,10 +1820,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) {
@@ -1589,7 +1838,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;
@@ -1598,7 +1850,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;
@@ -1654,6 +1909,12 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction,
RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects)
{
+#if USE(ACCELERATED_COMPOSITING)
+ // Composited RenderLayers are painted via the backing's paintIntoLayer().
+ if (isComposited() && !backing()->paintingGoesToWindow())
+ 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().
@@ -1664,11 +1925,11 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (!renderer()->opacity())
return;
- if (isTransparent())
+ if (paintsWithTransparency())
haveTransparency = true;
// 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() && !appliedTransform) {
// If the transform can't be inverted, then don't paint anything.
if (!m_transform->isInvertible())
return;
@@ -1681,14 +1942,9 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// 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, temporaryClipRects);
+ clipRect = parentRects.overflowClipRect();
clipRect.intersect(paintDirtyRect);
}
@@ -1710,7 +1966,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Now do a paint with the root layer shifted to be us.
paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects);
-
+
p->restore();
// Restore the clip.
@@ -1732,12 +1988,11 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects);
int x = layerBounds.x();
int y = layerBounds.y();
- int tx = x - renderer()->x();
- int ty = y - renderer()->y();
+ 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;
@@ -1765,11 +2020,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);
}
@@ -1813,10 +2063,12 @@ 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) {
+ if (it[0]->isSelfPaintingLayer())
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+ }
+
// 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)
@@ -1834,7 +2086,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;
@@ -1855,9 +2107,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.
@@ -1880,135 +2142,302 @@ 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);
+ }
+
+ TransformationMatrix containerTransform = renderer()->transformFromContainer(containerLayer ? containerLayer->renderer() : 0, IntSize(offsetX, offsetY));
+ transformState->applyTransform(containerTransform, true);
+ 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 = compositor()->calculateCompositedBounds(this, this);
+ } 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);
+ if (!currLayer->isSelfPaintingLayer())
+ continue;
+
+ 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()->x(),
- layerBounds.y() - renderer()->y(),
- 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)) {
+ // 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()->x(),
- layerBounds.y() - renderer()->y(),
- 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)) {
+ 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)
@@ -2039,10 +2468,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;
}
@@ -2058,7 +2486,7 @@ 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.
@@ -2086,13 +2514,13 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl
}
if (renderer()->hasOverflowClip()) {
- IntRect newOverflowClip = renderer()->getOverflowClipRect(x,y);
+ IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x,y);
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
if (renderer()->isPositioned() || renderer()->isRelPositioned())
clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
}
if (renderer()->hasClip()) {
- IntRect newPosClip = renderer()->getClipRect(x,y);
+ 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()));
@@ -2100,24 +2528,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 = renderer()->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() :
- (renderer()->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);
@@ -2136,10 +2570,10 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
// This layer establishes a clip of some kind.
if (renderer()->hasOverflowClip())
- foregroundRect.intersect(renderer()->getOverflowClipRect(x,y));
+ 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 = renderer()->getClipRect(x,y);
+ IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y);
backgroundRect.intersect(newPosClip);
foregroundRect.intersect(newPosClip);
outlineRect.intersect(newPosClip);
@@ -2202,7 +2636,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
@@ -2216,56 +2650,64 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const
IntRect result;
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()->y()), 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 = toRenderBox(child)->borderBoxRect();
result.unite(bbox);
- IntRect overflowRect = renderer()->overflowRect(false);
+ 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()->borderBoxRect();
+ 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.
- result.move(m_x, m_y);
}
-
- // 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)
@@ -2288,6 +2730,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)
@@ -2303,28 +2777,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);
@@ -2334,7 +2808,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.
@@ -2354,18 +2828,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);
}
}
}
@@ -2383,6 +2857,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()
@@ -2392,18 +2871,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);
@@ -2411,27 +2895,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)
@@ -2439,7 +2924,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;
@@ -2462,6 +2947,19 @@ 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()
{
renderer()->repaint();
@@ -2469,23 +2967,62 @@ void RenderLayer::repaintIncludingDescendants()
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)
{
- return (renderer()->hasOverflowClip() || renderer()->hasReflection()) &&
+ 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);
+}
+#endif
+
+bool RenderLayer::shouldBeNormalFlowOnly() const
+{
+ return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask()) &&
!renderer()->isPositioned() &&
!renderer()->isRelPositioned() &&
!renderer()->hasTransform() &&
!isTransparent();
}
-void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
+bool RenderLayer::isSelfPaintingLayer() const
+{
+ return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow();
+}
+
+void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
{
- bool isOverflowOnly = shouldBeOverflowOnly();
- if (isOverflowOnly != m_isOverflowOnly) {
- m_isOverflowOnly = isOverflowOnly;
+ bool isNormalFlowOnly = shouldBeNormalFlowOnly();
+ if (isNormalFlowOnly != m_isNormalFlowOnly) {
+ m_isNormalFlowOnly = isNormalFlowOnly;
RenderLayer* p = parent();
if (p)
- p->dirtyOverflowList();
+ p->dirtyNormalFlowList();
dirtyStackingContextZOrderLists();
}
@@ -2516,12 +3053,21 @@ void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
updateScrollCornerStyle();
updateResizerStyle();
+
+#if USE(ACCELERATED_COMPOSITING)
+ updateTransform();
+
+ if (compositor()->updateLayerCompositingState(this, diff))
+ compositor()->setCompositingLayersNeedUpdate();
+#else
+ UNUSED_PARAM(diff);
+#endif
}
void RenderLayer::updateScrollCornerStyle()
{
- RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> corner = renderer()->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 (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
@@ -2536,8 +3082,8 @@ void RenderLayer::updateScrollCornerStyle()
void RenderLayer::updateResizerStyle()
{
- RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> resizer = renderer()->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 (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h
index 54c15e9..6e70a4b 100644
--- a/WebCore/rendering/RenderLayer.h
+++ b/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,16 +44,18 @@
#ifndef RenderLayer_h
#define RenderLayer_h
-#include "ScrollbarClient.h"
#include "RenderBox.h"
+#include "ScrollBehavior.h"
+#include "ScrollbarClient.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 RenderReplica;
@@ -63,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:
@@ -139,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();
@@ -154,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(RenderBox*);
+ RenderLayer(RenderBoxModelObject*);
~RenderLayer();
- RenderBox* renderer() const { return m_renderer; }
+ 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; }
@@ -200,17 +183,25 @@ 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
+#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 renderer()->hasReflection(); }
@@ -225,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; }
@@ -255,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);
@@ -288,6 +279,16 @@ 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
void updateLayerPosition();
void updateLayerPositions(bool doFullRepaint = false, bool checkForRepaint = true);
@@ -311,9 +312,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);
@@ -323,6 +324,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(); }
@@ -353,23 +361,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 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.
@@ -378,6 +402,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();
@@ -385,19 +428,34 @@ 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();
+
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);
+
+ 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&);
@@ -410,11 +468,21 @@ 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 parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false) const;
RenderLayer* enclosingTransformedAncestor() const;
@@ -424,8 +492,24 @@ private:
void updateScrollCornerStyle();
void updateResizerStyle();
-protected:
- RenderBox* m_renderer;
+#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;
@@ -474,7 +558,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
@@ -483,8 +567,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
@@ -501,6 +585,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.
@@ -515,6 +607,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/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
new file mode 100644
index 0000000..40805b5
--- /dev/null
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -0,0 +1,1067 @@
+/*
+ * 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 "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 {
+
+RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
+ : m_owningLayer(layer)
+ , m_ancestorClippingLayer(0)
+ , m_graphicsLayer(0)
+ , m_contentsLayer(0)
+ , m_clippingLayer(0)
+ , m_isSimpleContainerCompositingLayer(false)
+ , m_simpleCompositingLayerStatusDirty(true)
+ , m_compositingContentOffsetDirty(true)
+{
+ createGraphicsLayer();
+}
+
+RenderLayerBacking::~RenderLayerBacking()
+{
+ updateClippingLayers(false, false);
+ updateContentsLayer(false);
+ destroyGraphicsLayer();
+}
+
+void RenderLayerBacking::createGraphicsLayer()
+{
+ m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this);
+
+#ifndef NDEBUG
+ 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());
+ }
+#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);
+ }
+
+ m_graphicsLayer->setTransform(t);
+}
+
+void RenderLayerBacking::updateAfterLayout()
+{
+ invalidateDrawingOptimizations();
+ detectDrawingOptimizations();
+
+ updateGraphicsLayerGeometry();
+}
+
+bool RenderLayerBacking::updateGraphicsLayers(bool needsContentsLayer, bool needsUpperClippingLayer, bool needsLowerClippingLayer, bool needsRepaint)
+{
+ bool layerConfigChanged = false;
+ if (updateContentsLayer(needsContentsLayer))
+ layerConfigChanged = true;
+
+ if (updateClippingLayers(needsUpperClippingLayer, needsLowerClippingLayer))
+ layerConfigChanged = true;
+
+ // See if we can now use any drawing optimizations.
+ bool didDrawContent = graphicsLayer()->drawsContent();
+ invalidateDrawingOptimizations();
+ detectDrawingOptimizations();
+ if (!didDrawContent && graphicsLayer()->drawsContent())
+ needsRepaint = true;
+
+ // 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);
+
+ updateGraphicsLayerGeometry();
+
+ m_graphicsLayer->updateContentsRect();
+
+ if (needsRepaint) {
+ m_graphicsLayer->setNeedsDisplay();
+ if (m_contentsLayer)
+ m_contentsLayer->setNeedsDisplay();
+ }
+
+ 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();
+
+ m_compositingContentOffsetDirty = true;
+
+ RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
+
+ // We compute everything relative to the enclosing compositing layer.
+ IntRect ancestorCompositingBounds;
+ if (compAncestor)
+ ancestorCompositingBounds = compositor()->calculateCompositedBounds(compAncestor, compAncestor);
+
+ IntRect localCompositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
+
+ 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();
+
+ IntRect layerBounds = IntRect(m_owningLayer->x(), m_owningLayer->y(), borderBox.width(), borderBox.height());
+ // Convert to absolute coords to match bbox.
+ int x = 0, y = 0;
+ m_owningLayer->convertToLayerCoords(compAncestor, x, y);
+ layerBounds.move(x - m_owningLayer->x(), y - m_owningLayer->y());
+
+ // 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();
+}
+
+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()->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()->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();
+}
+
+bool RenderLayerBacking::canBeSimpleContainerCompositingLayer() 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()->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?
+ Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList();
+ if (negZOrderList && negZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (!curLayer->isComposited())
+ return true;
+ }
+ }
+
+ Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList();
+ if (posZOrderList && posZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (!curLayer->isComposited())
+ return true;
+ }
+ }
+ }
+
+ Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList();
+ if (normalFlowList && normalFlowList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ 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())
+ return false;
+
+ if (renderObject->hasMask() || renderObject->hasReflection())
+ return false;
+
+ // 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());
+}
+
+// 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()
+{
+ if (m_simpleCompositingLayerStatusDirty) {
+ m_isSimpleContainerCompositingLayer = canBeSimpleContainerCompositingLayer();
+ m_simpleCompositingLayerStatusDirty = false;
+ }
+
+ return m_isSimpleContainerCompositingLayer;
+}
+
+void RenderLayerBacking::detectDrawingOptimizations()
+{
+ bool drawsContent = true;
+
+ // Check if a replaced layer can be further simplified.
+ if (canUseDirectCompositing()) {
+ if (renderer()->isImage()) {
+ updateImageContents();
+ drawsContent = false;
+ }
+
+ if (rendererHasBackground())
+ m_graphicsLayer->setBackgroundColor(rendererBackgroundColor());
+ else
+ m_graphicsLayer->clearBackgroundColor();
+
+ } else {
+ m_graphicsLayer->clearBackgroundColor();
+ m_graphicsLayer->clearContents();
+
+ if (isSimpleContainerCompositingLayer())
+ drawsContent = false;
+ }
+
+ if (paintingGoesToWindow())
+ drawsContent = false;
+
+ m_graphicsLayer->setDrawsContent(drawsContent);
+}
+
+void RenderLayerBacking::invalidateDrawingOptimizations()
+{
+ m_simpleCompositingLayerStatusDirty = true;
+}
+
+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()
+{
+ if (!m_compositingContentOffsetDirty)
+ return m_compositingContentOffset;
+
+ IntRect relativeCompositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
+ m_compositingContentOffset = IntSize(-relativeCompositingBounds.x(), -relativeCompositingBounds.y());
+ m_compositingContentOffsetDirty = false;
+
+ return m_compositingContentOffset;
+}
+
+IntRect RenderLayerBacking::contentsBox(const GraphicsLayer*)
+{
+ if (!renderer()->isBox())
+ return IntRect();
+
+ IntRect 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()
+{
+ if (m_graphicsLayer)
+ m_graphicsLayer->setNeedsDisplay();
+ if (m_contentsLayer)
+ m_contentsLayer->setNeedsDisplay();
+}
+
+// r is in the coordinate space of the layer's render object
+void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
+{
+ if (m_graphicsLayer) {
+ 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);
+ }
+
+ if (m_contentsLayer) {
+ // FIXME: do incremental repaint
+ m_contentsLayer->setNeedsDisplay();
+ }
+}
+
+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
+ bool haveTransparency, PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase,
+ RenderObject* paintingRoot)
+{
+ if (paintingGoesToWindow()) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ m_owningLayer->updateLayerListsIfNeeded();
+
+ // 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;
+
+ if (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()->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 (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, haveTransparency, 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, haveTransparency, 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, haveTransparency, 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 = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
+
+ 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, false, 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();
+}
+
+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/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h
new file mode 100644
index 0000000..46b81ad
--- /dev/null
+++ b/WebCore/rendering/RenderLayerBacking.h
@@ -0,0 +1,178 @@
+/*
+ * 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 updateGraphicsLayers(bool needsContentsLayer, bool needsUpperClippingLayer, bool needsLowerClippingLayer, bool needsRepaint);
+ void updateGraphicsLayerGeometry();
+ void updateInternalHierarchy();
+
+ 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();
+
+ FloatPoint graphicsLayerToContentsCoordinates(const GraphicsLayer*, const FloatPoint&);
+ FloatPoint contentsToGraphicsLayerCoordinates(const GraphicsLayer*, const FloatPoint&);
+
+ void detectDrawingOptimizations();
+ void invalidateDrawingOptimizations();
+
+ // 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();
+ // 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 canBeSimpleContainerCompositingLayer() const;
+ bool hasNonCompositingContent() const;
+
+ void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect,
+ bool haveTransparency, 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
+
+ IntSize m_compositingContentOffset;
+
+ bool m_isSimpleContainerCompositingLayer : 1; // is this compositing layer able to be simplified
+ bool m_simpleCompositingLayerStatusDirty : 1; // set if the test for simple layers needs to be redone
+
+ bool m_compositingContentOffsetDirty: 1;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // RenderLayerBacking_h
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
new file mode 100644
index 0000000..cbb3df7
--- /dev/null
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -0,0 +1,803 @@
+/*
+ * 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 "RenderView.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_subtreeIsCompositing(false)
+ , m_compositingAncestor(compAncestor)
+#ifndef NDEBUG
+ , m_depth(0)
+#endif
+ {
+ }
+
+ bool m_subtreeIsCompositing;
+ RenderLayer* m_compositingAncestor;
+#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)
+#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();
+ }
+}
+
+void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate)
+{
+ if (inCompositingMode())
+ m_compositingLayersNeedUpdate = needUpdate;
+}
+
+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)
+ fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n"
+ m_rootLayerUpdateCount, 1000.0 * (endTime - startTime));
+#endif
+ ASSERT(updateRoot || !m_compositingLayersNeedUpdate);
+}
+
+bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, StyleDifference diff)
+{
+ bool needsLayer = needsToBeComposited(layer);
+ bool layerChanged = false;
+
+ RenderBoxModelObject* repaintContainer = 0;
+ IntRect repaintRect;
+
+ if (needsLayer) {
+ enableCompositingMode();
+ if (!layer->backing()) {
+ // Get the repaint container before we make backing for this layer
+ repaintContainer = layer->renderer()->containerForRepaint();
+ repaintRect = calculateCompositedBounds(layer, repaintContainer ? repaintContainer->layer() : layer->root());
+
+ layer->ensureBacking();
+ layerChanged = true;
+ }
+ } else {
+ if (layer->backing()) {
+ layer->clearBacking();
+ // Get the repaint container now that we've cleared the backing
+ repaintContainer = layer->renderer()->containerForRepaint();
+ repaintRect = calculateCompositedBounds(layer, repaintContainer ? repaintContainer->layer() : layer->root());
+ layerChanged = true;
+ }
+ }
+
+ if (layerChanged) {
+ // Invalidate the destination into which this layer used to render.
+ layer->renderer()->repaintUsingContainer(repaintContainer, repaintRect);
+
+ if (!repaintContainer || 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();
+ }
+ }
+
+ if (!needsLayer)
+ return layerChanged;
+
+ if (layer->backing()->updateGraphicsLayers(needsContentsCompositingLayer(layer),
+ clippedByAncestor(layer),
+ clipsCompositingDescendants(layer),
+ diff >= StyleDifferenceRepaint))
+ layerChanged = true;
+
+ return layerChanged;
+}
+
+// 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* layerBoundingBox)
+{
+ IntRect boundingBoxRect, unionBounds;
+ boundingBoxRect = unionBounds = layer->localBoundingBox();
+
+ ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0));
+
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
+ if (negZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (!curLayer->isComposited()) {
+ IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer);
+ unionBounds.unite(childUnionBounds);
+ }
+ }
+ }
+
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
+ if (posZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (!curLayer->isComposited()) {
+ IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer);
+ unionBounds.unite(childUnionBounds);
+ }
+ }
+ }
+
+ Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
+ if (normalFlowList) {
+ for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (!curLayer->isComposited()) {
+ IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer);
+ unionBounds.unite(curAbsBounds);
+ }
+ }
+ }
+
+ if (!layer->isComposited() && layer->transform()) {
+ 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);
+
+ if (layerBoundingBox) {
+ boundingBoxRect.move(ancestorRelX, ancestorRelY);
+ *layerBoundingBox = boundingBoxRect;
+ }
+
+ return unionBounds;
+}
+
+void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/)
+{
+ setCompositingLayersNeedUpdate();
+}
+
+void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child)
+{
+ if (child->isComposited())
+ setCompositingParent(child, 0);
+
+ // If the document is being torn down (document's renderer() is null), then there's
+ // no need to do any layer updating.
+ if (parent->renderer()->documentBeingDestroyed())
+ return;
+
+ RenderLayer* compLayer = parent->enclosingCompositingLayer();
+ if (compLayer) {
+ IntRect ancestorRect = calculateCompositedBounds(child, compLayer);
+ compLayer->setBackingNeedsRepaintInRect(ancestorRect);
+ // 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& ioCompState)
+{
+ layer->updateLayerPosition();
+ layer->updateZOrderLists();
+ layer->updateNormalFlowList();
+
+ // Clear the flag
+ layer->setHasCompositingDescendant(false);
+ layer->setMustOverlayCompositedLayers(ioCompState.m_subtreeIsCompositing);
+
+ const bool isCompositingLayer = needsToBeComposited(layer);
+ ioCompState.m_subtreeIsCompositing = isCompositingLayer;
+
+ CompositingState childState = ioCompState;
+ if (isCompositingLayer)
+ childState.m_compositingAncestor = layer;
+
+ // 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;
+
+#ifndef NDEBUG
+ ++childState.m_depth;
+#endif
+
+ if (layer->isStackingContext()) {
+ ASSERT(!layer->m_zOrderListsDirty);
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
+ if (negZOrderList && negZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ 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 |this| compositing
+ layer->setMustOverlayCompositedLayers(true);
+ childState.m_compositingAncestor = layer;
+ }
+ }
+ }
+ }
+
+ ASSERT(!layer->m_normalFlowListDirty);
+ Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
+ if (normalFlowList && normalFlowList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ computeCompositingRequirements(curLayer, childState);
+ }
+ }
+
+ if (layer->isStackingContext()) {
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
+ if (posZOrderList && posZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ 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)
+ ioCompState.m_subtreeIsCompositing = true;
+
+ // 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);
+}
+
+void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer)
+{
+ ASSERT(childLayer->isComposited());
+ ASSERT(!parentLayer || parentLayer->isComposited());
+
+ if (parentLayer) {
+ GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers();
+ GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers();
+
+ hostingLayer->addChild(hostedLayer);
+ } else
+ childLayer->backing()->childForSuperlayers()->removeFromParent();
+
+ // FIXME: setCompositingParent() is only called at present by rebuildCompositingLayerTree(),
+ // which calls updateGraphicsLayerGeometry via updateLayerCompositingState(), so this should
+ // be optimized.
+ if (parentLayer)
+ childLayer->backing()->updateGraphicsLayerGeometry();
+}
+
+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);
+ }
+}
+
+void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState)
+{
+ updateLayerCompositingState(layer, StyleDifferenceEqual);
+
+ // host the document layer in the RenderView's root layer
+ if (layer->isRootLayer())
+ parentInRootLayer(layer);
+
+ CompositingState childState = ioCompState;
+ if (layer->isComposited())
+ childState.m_compositingAncestor = layer;
+
+#ifndef NDEBUG
+ ++childState.m_depth;
+#endif
+
+ RenderLayerBacking* layerBacking = layer->backing();
+
+ // FIXME: make this more incremental
+ if (layer->isComposited()) {
+ layerBacking->parentForSublayers()->removeAllChildren();
+ layerBacking->updateInternalHierarchy();
+ }
+
+ // 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);
+
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
+ if (negZOrderList && negZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ 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);
+ Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
+ if (normalFlowList && normalFlowList->size() > 0) {
+ for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ rebuildCompositingLayerTree(curLayer, childState);
+ if (curLayer->isComposited())
+ setCompositingParent(curLayer, childState.m_compositingAncestor);
+ }
+ }
+
+ if (layer->isStackingContext()) {
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
+ if (posZOrderList && posZOrderList->size() > 0) {
+ for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ rebuildCompositingLayerTree(curLayer, childState);
+ if (curLayer->isComposited())
+ setCompositingParent(curLayer, childState.m_compositingAncestor);
+ }
+ }
+ }
+}
+
+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()) {
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
+ if (negZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ int x = 0, y = 0;
+ curLayer->convertToLayerCoords(layer, x, y);
+ IntRect childRect(rect);
+ childRect.move(-x, -y);
+ recursiveRepaintLayerRect(curLayer, childRect);
+ }
+ }
+
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
+ if (posZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ int x = 0, y = 0;
+ curLayer->convertToLayerCoords(layer, x, y);
+ IntRect childRect(rect);
+ childRect.move(-x, -y);
+ recursiveRepaintLayerRect(curLayer, childRect);
+ }
+ }
+
+ Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
+ if (normalFlowList) {
+ for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ 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->docWidth(), m_renderView->docHeight()));
+}
+
+bool RenderLayerCompositor::has3DContent() const
+{
+ return layerHas3DContent(rootRenderLayer());
+}
+
+bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
+{
+ return requiresCompositingLayer(layer) || layer->mustOverlayCompositedLayers();
+}
+
+#define VERBOSE_COMPOSITINGLAYER 0
+
+// 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
+{
+ // FIXME: cache the result of these tests?
+#if VERBOSE_COMPOSITINGLAYER
+ bool gotReason = false;
+
+ if (!gotReason && inCompositingMode() && layer->isRootLayer()) {
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it's the document root\n", layer);
+ gotReason = true;
+ }
+
+ if (!gotReason && requiresCompositingForTransform(layer->renderer())) {
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has 3d transform, perspective, backface, or animating transform\n", layer);
+ gotReason = true;
+ }
+
+ if (!gotReason && layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has backface-visibility: hidden\n", layer);
+ gotReason = true;
+ }
+
+ if (!gotReason && clipsCompositingDescendants(layer)) {
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has overflow clip\n", layer);
+ gotReason = true;
+ }
+
+ if (!gotReason && requiresCompositingForAnimation(layer->renderer())) {
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has a running transition for opacity or transform\n", layer);
+ gotReason = true;
+ }
+
+ if (!gotReason)
+ fprintf(stderr, "RenderLayer %p does not require compositing layer\n", layer);
+#endif
+
+ // The root layer always has a compositing layer, but it may not have backing.
+ return (inCompositingMode() && layer->isRootLayer()) ||
+ requiresCompositingForTransform(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)
+{
+ 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::requiresCompositingForAnimation(RenderObject* renderer)
+{
+ AnimationController* animController = renderer->animation();
+ if (animController)
+ return animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) ||
+ 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->docWidth(), m_renderView->docHeight()));
+ m_rootPlatformLayer->setPosition(FloatPoint(0, 0));
+
+ if (GraphicsLayer::graphicsContextsFlipped())
+ m_rootPlatformLayer->setChildrenTransform(flipTransform());
+
+ // Need to clip to prevent transformed content showing outside this frame
+ m_rootPlatformLayer->setMasksToBounds(true);
+
+ didMoveOnscreen();
+}
+
+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()) {
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList();
+ if (negZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (layerHas3DContent(curLayer))
+ return true;
+ }
+ }
+
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList();
+ if (posZOrderList) {
+ for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (layerHas3DContent(curLayer))
+ return true;
+ }
+ }
+ }
+
+ Vector<RenderLayer*>* normalFlowList = layer->normalFlowList();
+ if (normalFlowList) {
+ for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) {
+ RenderLayer* curLayer = (*it);
+ if (layerHas3DContent(curLayer))
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h
new file mode 100644
index 0000000..dfceb1f
--- /dev/null
+++ b/WebCore/rendering/RenderLayerCompositor.h
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+// 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);
+
+ void setCompositingLayersNeedUpdate(bool needUpdate = true);
+ bool compositingLayersNeedUpdate() const { return m_compositingLayersNeedUpdate; }
+
+ // 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
+ bool updateLayerCompositingState(RenderLayer*, StyleDifference);
+
+ // 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, IntRect* layerBoundingBox = 0);
+
+ // 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();
+
+ // 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;
+
+ // Whether we need a graphics layer to do clipping by an ancestor (non-stacking-context parent with overflow).
+ bool clippedByAncestor(RenderLayer*) const;
+ // Whether we need 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;
+
+ // 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();
+
+ // Whether a running transition or animation enforces the need for a compositing layer.
+ static bool requiresCompositingForAnimation(RenderObject*);
+ static bool requiresCompositingForTransform(RenderObject*);
+
+private:
+ RenderView* m_renderView;
+ GraphicsLayer* m_rootPlatformLayer;
+ bool m_compositing;
+ bool m_rootLayerAttached;
+ bool m_compositingLayersNeedUpdate;
+#if PROFILE_LAYER_REBUILD
+ int m_rootLayerUpdateCount;
+#endif
+};
+
+
+} // namespace WebCore
+
+#endif // RenderLayerCompositor_h
diff --git a/WebCore/rendering/RenderLegend.cpp b/WebCore/rendering/RenderLegend.cpp
deleted file mode 100644
index 1fac53f..0000000
--- a/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/WebCore/rendering/RenderLegend.h b/WebCore/rendering/RenderLegend.h
deleted file mode 100644
index 649f132..0000000
--- a/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/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp
new file mode 100644
index 0000000..00566b8
--- /dev/null
+++ b/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/WebCore/rendering/RenderLineBoxList.h b/WebCore/rendering/RenderLineBoxList.h
new file mode 100644
index 0000000..52d7542
--- /dev/null
+++ b/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/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp
index 3dddc13..50b406b 100644
--- a/WebCore/rendering/RenderListBox.cpp
+++ b/WebCore/rendering/RenderListBox.cpp
@@ -87,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());
@@ -527,7 +527,7 @@ void RenderListBox::valueChanged(Scrollbar*)
m_indexOffset = newOffset;
repaint();
// Fire the scroll DOM event.
- EventTargetNodeCast(node())->dispatchEventForType(eventNames().scrollEvent, false, false);
+ node()->dispatchEventForType(eventNames().scrollEvent, false, false);
}
}
@@ -579,6 +579,29 @@ 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<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(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 (HTMLElement* 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 = contentBoxRect();
@@ -602,11 +625,11 @@ void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect&
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/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h
index b9cfcb1..acc313f 100644
--- a/WebCore/rendering/RenderListBox.h
+++ b/WebCore/rendering/RenderListBox.h
@@ -92,8 +92,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/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp
index 47158b6..fb965d2 100644
--- a/WebCore/rendering/RenderListItem.cpp
+++ b/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);
@@ -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;
}
@@ -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()) {
@@ -271,7 +271,7 @@ void RenderListItem::positionListMarker()
do {
o = o->parentBox();
if (o->isRenderBlock())
- static_cast<RenderBlock*>(o)->addVisualOverflow(markerRect);
+ toRenderBlock(o)->addVisualOverflow(markerRect);
markerRect.move(-o->x(), -o->y());
} while (o != this);
}
diff --git a/WebCore/rendering/RenderListItem.h b/WebCore/rendering/RenderListItem.h
index d4dd675..91844f7 100644
--- a/WebCore/rendering/RenderListItem.h
+++ b/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/WebCore/rendering/RenderListMarker.cpp b/WebCore/rendering/RenderListMarker.cpp
index 340db50..32b5999 100644
--- a/WebCore/rendering/RenderListMarker.cpp
+++ b/WebCore/rendering/RenderListMarker.cpp
@@ -159,7 +159,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 +170,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 +473,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 +485,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 +493,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,9 +506,8 @@ void RenderListMarker::styleDidChange(RenderStyle::Diff diff, const RenderStyle*
}
}
-InlineBox* RenderListMarker::createInlineBox(bool, bool unusedIsRootLineBox, bool)
+InlineBox* RenderListMarker::createInlineBox()
{
- ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox);
ListMarkerBox* box = new (renderArena()) ListMarkerBox(this);
m_inlineBoxWrapper = box;
return box;
@@ -546,8 +545,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;
}
@@ -557,8 +558,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);
@@ -874,14 +877,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());
@@ -892,11 +895,9 @@ IntRect RenderListMarker::selectionRect(bool clipToVisibleContent)
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/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h
index 738427c..57580a8 100644
--- a/WebCore/rendering/RenderListMarker.h
+++ b/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/WebCore/rendering/RenderMarquee.cpp b/WebCore/rendering/RenderMarquee.cpp
index 2b4dcfd..48659f7 100644
--- a/WebCore/rendering/RenderMarquee.cpp
+++ b/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)
{
- RenderBox* 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/WebCore/rendering/RenderMarquee.h b/WebCore/rendering/RenderMarquee.h
index d9d20cd..886c343 100644
--- a/WebCore/rendering/RenderMarquee.h
+++ b/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/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp
index 80bf586..42cd709 100644
--- a/WebCore/rendering/RenderMedia.cpp
+++ b/WebCore/rendering/RenderMedia.cpp
@@ -39,7 +39,6 @@
#include "MediaControlElements.h"
#include "MouseEvent.h"
#include "MediaPlayer.h"
-#include "RenderSlider.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
@@ -89,6 +88,7 @@ void RenderMedia::destroy()
removeChild(m_controlsShadowRoot->renderer());
m_controlsShadowRoot->detach();
+ m_controlsShadowRoot = 0;
}
RenderReplaced::destroy();
}
@@ -103,6 +103,28 @@ 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 = contentBoxRect().size();
@@ -123,16 +145,16 @@ void RenderMedia::layout()
}
}
-RenderObject* RenderMedia::firstChild() const
-{
- return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0;
+const RenderObjectChildList* RenderMedia::children() const
+{
+ return m_controlsShadowRoot ? m_controlsShadowRoot->renderer()->virtualChildren() : 0;
}
-RenderObject* RenderMedia::lastChild() const
-{
- return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0;
+RenderObjectChildList* RenderMedia::children()
+{
+ return m_controlsShadowRoot ? m_controlsShadowRoot->renderer()->virtualChildren() : 0;
}
-
+
void RenderMedia::removeChild(RenderObject* child)
{
ASSERT(m_controlsShadowRoot);
@@ -150,7 +172,7 @@ void RenderMedia::createControlsShadowRoot()
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) {
@@ -194,7 +216,7 @@ void RenderMedia::createSeekForwardButton()
void RenderMedia::createTimelineContainer()
{
ASSERT(!m_timelineContainer);
- RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_TIMELINE_CONTAINER);
+ RenderStyle* style = getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
m_timelineContainer = new HTMLDivElement(HTMLNames::divTag, document());
RenderObject* renderer = m_timelineContainer->createRenderer(renderArena(), style);
if (renderer) {
@@ -278,7 +300,7 @@ void RenderMedia::updateControls()
createFullscreenButton();
}
- if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA) {
+ 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 ) {
@@ -350,11 +372,11 @@ void RenderMedia::updateControlVisibility()
// 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;
@@ -403,7 +425,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);
@@ -427,8 +449,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();
}
}
@@ -440,7 +464,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf)
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return bottom;
- return max(bottom, m_controlsShadowRoot->renderBox()->y() + 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
@@ -449,7 +473,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return right;
- return max(right, m_controlsShadowRoot->renderBox()->x() + 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
@@ -458,7 +482,7 @@ int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return left;
- return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderer()->leftmostPosition(includeOverflowInterior, includeSelf));
+ return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf));
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h
index a4670e9..0e56dab 100644
--- a/WebCore/rendering/RenderMedia.h
+++ b/WebCore/rendering/RenderMedia.h
@@ -49,8 +49,11 @@ public:
RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize);
virtual ~RenderMedia();
- virtual RenderObject* firstChild() const;
- virtual RenderObject* lastChild() const;
+ virtual RenderObjectChildList* virtualChildren() { return children(); }
+ virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+ const RenderObjectChildList* children() const;
+ RenderObjectChildList* children();
+
virtual void removeChild(RenderObject*);
virtual void destroy();
@@ -95,6 +98,8 @@ private:
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;
@@ -106,8 +111,8 @@ private:
RefPtr<HTMLElement> m_timelineContainer;
RefPtr<MediaTimeDisplayElement> m_currentTimeDisplay;
RefPtr<MediaTimeDisplayElement> m_timeRemainingDisplay;
- EventTargetNode* m_lastUnderNode;
- EventTargetNode* m_nodeUnderMouse;
+ Node* m_lastUnderNode;
+ Node* m_nodeUnderMouse;
Timer<RenderMedia> m_timeUpdateTimer;
Timer<RenderMedia> m_opacityAnimationTimer;
diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp
index 71e9e15..d61c16b 100644
--- a/WebCore/rendering/RenderMenuList.cpp
+++ b/WebCore/rendering/RenderMenuList.cpp
@@ -115,7 +115,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);
@@ -143,7 +143,15 @@ void RenderMenuList::updateOptionsWidth()
continue;
String text = optionElement->textIndentedToRespectGroupLabel();
- if (!text.isEmpty())
+ 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())
+ optionWidth += style()->font().floatWidth(text);
+ maxOptionWidth = max(maxOptionWidth, optionWidth);
+ } else if (!text.isEmpty())
maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text));
}
@@ -315,9 +323,15 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
if (!element->hasTagName(optionTag))
return false;
bool groupEnabled = true;
- if (element->parentNode() && element->parentNode()->hasTagName(optgroupTag))
- groupEnabled = element->parentNode()->isEnabled();
- return element->isEnabled() && groupEnabled;
+ if (element->parentNode() && element->parentNode()->hasTagName(optgroupTag)) {
+ FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(element->parentNode()));
+ groupEnabled = formControlElement->isEnabled();
+ }
+
+ if (!groupEnabled)
+ return false;
+
+ return toFormControlElement(element)->isEnabled();
}
PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
@@ -326,7 +340,7 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
HTMLElement* 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
@@ -354,7 +368,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
@@ -365,7 +379,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
diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h
index a7530fa..f16525e 100644
--- a/WebCore/rendering/RenderMenuList.h
+++ b/WebCore/rendering/RenderMenuList.h
@@ -72,7 +72,7 @@ public:
String text() const;
private:
- virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
// PopupMenuClient methods
virtual String itemText(unsigned listIndex) const;
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index ea84f33..bb98c9f 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -28,6 +28,7 @@
#include "AXObjectCache.h"
#include "CSSStyleSelector.h"
#include "FloatQuad.h"
+#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLNames.h"
@@ -44,12 +45,18 @@
#include "RenderTableRow.h"
#include "RenderTheme.h"
#include "RenderView.h"
+#include "TransformState.h"
#include <algorithm>
#ifdef ANDROID_LAYOUT
#include "Settings.h"
#endif
#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"
@@ -89,10 +96,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;
}
@@ -164,7 +171,6 @@ RenderObject::RenderObject(Node* node)
, m_hasAXObject(false)
, m_setNeedsLayoutForbidden(false)
#endif
- , m_verticalPosition(PositionUndefined)
, m_needsLayout(false)
, m_needsPositionedMovementLayout(false)
, m_normalChildNeedsLayout(false)
@@ -187,10 +193,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,58 +228,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;
-}
-
-bool RenderObject::isInlineContinuation() const
-{
- return false;
+ return node() && node()->renderer() == this && node()->hasTagName(marqueeTag);
}
-void RenderObject::addChild(RenderObject*, RenderObject*)
+static void updateListMarkerNumbers(RenderObject* child)
{
- ASSERT_NOT_REACHED();
+ for (RenderObject* r = child; r; r = r->nextSibling())
+ if (r->isListItem())
+ static_cast<RenderListItem*>(r)->updateValue();
}
-RenderObject* RenderObject::removeChildNode(RenderObject*, bool)
+void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
- 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
@@ -336,20 +388,6 @@ RenderObject* RenderObject::childAt(unsigned index) const
return child;
}
-bool RenderObject::isEditable() const
-{
- RenderText* textRenderer = 0;
- if (isText())
- textRenderer = toRenderText(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();
@@ -387,7 +425,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*
beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
newObject = 0;
}
- parentLayer->addChild(toRenderBox(obj)->layer(), beforeChild);
+ parentLayer->addChild(toRenderBoxModelObject(obj)->layer(), beforeChild);
return;
}
@@ -411,7 +449,7 @@ void RenderObject::removeLayers(RenderLayer* parentLayer)
return;
if (hasLayer()) {
- parentLayer->removeChild(toRenderBox(this)->layer());
+ parentLayer->removeChild(toRenderBoxModelObject(this)->layer());
return;
}
@@ -425,7 +463,7 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
return;
if (hasLayer()) {
- RenderLayer* layer = toRenderBox(this)->layer();
+ RenderLayer* layer = toRenderBoxModelObject(this)->layer();
if (oldParent)
oldParent->removeChild(layer);
newParent->addChild(layer);
@@ -444,7 +482,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 = hasLayer() ? toRenderBox(this)->layer() : 0;
+ RenderLayer* ourLayer = hasLayer() ? toRenderBoxModelObject(this)->layer() : 0;
if (ourLayer && ourLayer->parent() == parentLayer)
return ourLayer;
@@ -476,7 +514,7 @@ RenderLayer* RenderObject::enclosingLayer() const
{
const RenderObject* curr = this;
while (curr) {
- RenderLayer* layer = curr->hasLayer() ? toRenderBox(curr)->layer() : 0;
+ RenderLayer* layer = curr->hasLayer() ? toRenderBoxModelObject(curr)->layer() : 0;
if (layer)
return layer;
curr = curr->parent();
@@ -484,6 +522,18 @@ RenderLayer* RenderObject::enclosingLayer() const
return 0;
}
+RenderLayer* RenderObject::enclosingSelfPaintingLayer() const
+{
+ const RenderObject* curr = this;
+ while (curr) {
+ RenderLayer* layer = curr->hasLayer() ? toRenderBoxModelObject(curr)->layer() : 0;
+ if (layer && layer->isSelfPaintingLayer())
+ return layer;
+ curr = curr->parent();
+ }
+ return 0;
+}
+
RenderBox* RenderObject::enclosingBox() const
{
RenderObject* curr = const_cast<RenderObject*>(this);
@@ -502,16 +552,6 @@ RenderBlock* RenderObject::firstLineBlock() const
return 0;
}
-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();
-}
-
void RenderObject::setPrefWidthsDirty(bool b, bool markParents)
{
bool alreadyDirty = m_prefWidthsDirty;
@@ -526,113 +566,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();
- }
-}
-
-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())
- toRenderBox(this)->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) {
- ASSERT(!isSetNeedsLayoutForbidden());
- 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())
- toRenderBox(this)->layer()->setNeedsFullRepaint();
+ o = container;
}
}
-static inline bool objectIsRelayoutBoundary(const RenderObject *obj)
+void RenderObject::setLayerNeedsFullRepaint()
{
- // 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;
- 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 = o->container();
- }
-
- if (scheduleRelayout)
- last->scheduleRelayout();
+ ASSERT(hasLayer());
+ toRenderBoxModelObject(this)->layer()->setNeedsFullRepaint(true);
}
RenderBlock* RenderObject::containingBlock() const
@@ -645,7 +597,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) {
@@ -675,19 +627,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)
@@ -736,97 +676,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);
@@ -889,34 +741,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;
@@ -944,27 +796,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;
}
@@ -1020,516 +872,91 @@ 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)
-{
- 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)
+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)
{
- 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;
- }
-
- // Draw upper right arc
- drawBorderArc(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
- BSTop, tc, style->color(), ts, false);
- if (applyRightInnerClip)
- graphicsContext->restore();
- }
- }
- }
-
- 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;
+ if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2))
+ style = SOLID;
- // Draw lower right arc
- drawBorderArc(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
- BSBottom, bc, style->color(), bs, 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 (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();
- }
-
- 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();
- }
-
- 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;
+ 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 bottom left arc
- drawBorderArc(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
- BSLeft, lc, style->color(), ls, false);
- if (applyBottomInnerClip)
- 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 (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();
+ 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 + 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());
- }
-
- firstAngleStart = 0;
- firstAngleSpan = 45;
-
- // Draw top right arc
- drawBorderArc(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
- BSRight, rc, style->color(), rs, 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())
- && (rs != 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
- drawBorderArc(graphicsContext, bottomX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
- BSRight, rc, style->color(), rs, false);
- if (applyBottomInnerClip)
- 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 (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();
-
- 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);
- }
+ graphicsContext->setStrokeStyle(SolidStroke);
+ graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
- 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);
+ 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;
}
- context->restore();
+ 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;
}
}
@@ -1537,13 +964,13 @@ void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect)
{
if (rect.isEmpty())
return;
- Node* node = element();
- if (!node || !node->isLink() || !node->isElementNode())
+ Node* n = node();
+ if (!n || !n->isLink() || !n->isElementNode())
return;
- const AtomicString& href = static_cast<Element*>(node)->getAttribute(hrefAttr);
+ const AtomicString& href = static_cast<Element*>(n)->getAttribute(hrefAttr);
if (href.isNull())
return;
- context->setURLForRect(node->document()->completeURL(href), rect);
+ context->setURLForRect(n->document()->completeURL(href), rect);
}
void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style)
@@ -1564,11 +991,11 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
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())
- addFocusRingRects(graphicsContext, tx, ty);
+ graphicsContext->drawFocusRing(oc);
else
addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
- graphicsContext->drawFocusRing(oc);
graphicsContext->clearFocusRing();
}
}
@@ -1584,21 +1011,52 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (h < 0 || w < 0)
return;
- drawBorder(graphicsContext, tx - ow, ty - ow, tx, ty + h + ow,
+ drawLineForBoxSide(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,
+ drawLineForBoxSide(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,
+ drawLineForBoxSide(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,
+ drawLineForBoxSide(graphicsContext, tx - ow, ty + h, tx + w + ow, ty + h + ow,
BSBottom, Color(oc), style->color(), os, ow, ow);
}
-void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned, unsigned, bool)
+
+void RenderObject::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool)
{
+ if (!firstChild()) {
+ if ((isInline() || isAnonymousBlock())) {
+ FloatPoint absPos = localToAbsolute(FloatPoint());
+ absoluteRects(rects, absPos.x(), absPos.y());
+ }
+ 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->localToAbsolute(FloatPoint());
+ child->absoluteRects(rects, absPos.x(), absPos.y());
+ }
+ }
+}
+
+void RenderObject::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool)
+{
+ if (!firstChild()) {
+ if (isInline() || isAnonymousBlock())
+ absoluteQuads(quads);
+ 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);
+ }
}
IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
@@ -1652,58 +1110,80 @@ void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/)
{
}
-RenderBox* RenderObject::containerForRepaint() const
+RenderBoxModelObject* RenderObject::containerForRepaint() const
{
- // For now, all repaints are root-relative.
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* v = view()) {
+ if (v->usesCompositing()) {
+ RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayer();
+ return compLayer ? compLayer->renderer() : 0;
+ }
+ }
+#endif
+ // Do root-relative repaint.
return 0;
}
+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);
+ 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
- absRect.move(view->layoutDelta());
+ dirtyRect.move(view->layoutDelta());
- computeAbsoluteRepaintRect(absRect);
- view->repaintViewRectangle(absRect, immediate);
+ 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();
@@ -1711,14 +1191,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;
}
@@ -1727,35 +1211,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).
- RenderFlow* continuation = virtualContinuation();
- 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());
@@ -1773,7 +1256,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());
@@ -1791,7 +1274,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;
@@ -1813,39 +1296,27 @@ bool RenderObject::checkForRepaintDuringLayout() const
return !document()->view()->needsFullRepaint() && !hasLayer();
}
-IntRect RenderObject::rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth)
+IntRect RenderObject::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
{
IntRect r(clippedOverflowRectForRepaint(repaintContainer));
r.inflate(outlineWidth);
-
- if (virtualContinuation() && !isInline())
- r.inflateY(toRenderBox(this)->collapsedMarginTop());
-
- if (isRenderInline()) {
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (!curr->isText())
- r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
- }
- }
-
return r;
}
-IntRect RenderObject::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderObject::clippedOverflowRectForRepaint(RenderBoxModelObject*)
{
- if (parent())
- return parent()->clippedOverflowRectForRepaint(repaintContainer);
+ ASSERT_NOT_REACHED();
return IntRect();
}
-void RenderObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, 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);
}
@@ -1866,7 +1337,7 @@ void RenderObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContai
return;
}
- o->computeRectForRepaint(rect, repaintContainer, fixed);
+ o->computeRectForRepaint(repaintContainer, rect, fixed);
}
}
@@ -1878,8 +1349,8 @@ void RenderObject::dirtyLinesFromChangedChild(RenderObject*)
void RenderObject::showTreeForThis() const
{
- if (element())
- element()->showTreeForThis();
+ if (node())
+ node()->showTreeForThis();
}
#endif // NDEBUG
@@ -1888,7 +1359,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
@@ -1906,7 +1377,7 @@ 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();
@@ -1924,7 +1395,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.
@@ -1958,17 +1429,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
@@ -1976,30 +1436,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 = parentInline->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));
}
}
}
@@ -2012,18 +1456,48 @@ 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());
@@ -2036,7 +1510,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)
@@ -2044,7 +1543,7 @@ 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,
@@ -2064,30 +1563,30 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne
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();
}
}
}
}
- if (m_parent && (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize()))
+ 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()->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;
@@ -2113,24 +1612,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();
if (!m_parent)
return;
- if (diff == RenderStyle::Layout)
+ if (diff == StyleDifferenceLayout)
setNeedsLayoutAndPrefWidthsRecalc();
- else if (diff == RenderStyle::LayoutPositionedMovementOnly)
+ else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout();
- else if (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)
@@ -2163,42 +1659,82 @@ IntRect RenderObject::viewRect() const
FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
{
- RenderObject* o = parent();
- if (o) {
- if (o->hasOverflowClip())
- localPoint -= toRenderBox(o)->layer()->scrolledContentOffset();
- return o->localToAbsolute(localPoint, fixed, useTransforms);
- }
-
- return FloatPoint();
+ 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
{
- RenderObject* o = parent();
- if (o) {
- FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
- if (o->hasOverflowClip())
- localPoint += toRenderBox(o)->layer()->scrolledContentOffset();
- return localPoint;
- }
- return FloatPoint();
+ TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint);
+ mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
+ transformState.flatten();
+
+ return transformState.lastPlanarPoint();
}
-FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
+void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
{
if (repaintContainer == this)
- return localQuad;
+ return;
RenderObject* o = parent();
+ if (!o)
+ return;
+
+ if (o->hasOverflowClip())
+ transformState.move(-toRenderBox(o)->layer()->scrolledContentOffset());
+
+ o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
+}
+
+void RenderObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
+{
+ RenderObject* o = parent();
if (o) {
- FloatQuad quad = localQuad;
+ o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
if (o->hasOverflowClip())
- quad -= toRenderBox(o)->layer()->scrolledContentOffset();
- return o->localToContainerQuad(quad, repaintContainer, fixed);
+ transformState.move(toRenderBox(o)->layer()->scrolledContentOffset());
}
+}
- return FloatQuad();
+TransformationMatrix RenderObject::transformFromContainer(const RenderObject* containerObject, const IntSize& offsetInContainer) const
+{
+ TransformationMatrix containerTransform;
+ containerTransform.translate(offsetInContainer.width(), offsetInContainer.height());
+ RenderLayer* layer;
+ if (hasLayer() && (layer = toRenderBox(this)->layer()) && layer->transform())
+ containerTransform.multLeft(layer->currentTransform());
+
+#if ENABLE(3D_RENDERING)
+ if (containerObject && 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());
+
+ containerTransform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0);
+ containerTransform.multiply(perspectiveMatrix);
+ containerTransform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0);
+ }
+#else
+ UNUSED_PARAM(containerObject);
+#endif
+
+ return containerTransform;
+}
+
+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
@@ -2222,12 +1758,27 @@ IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine
RenderView* RenderObject::view() const
{
- return static_cast<RenderView*>(document()->renderer());
+ return toRenderView(document()->renderer());
+}
+
+bool RenderObject::isRooted(RenderView** view)
+{
+ RenderObject* o = this;
+ while (o->parent())
+ o = o->parent();
+
+ if (!o->isRenderView())
+ return false;
+
+ if (view)
+ *view = toRenderView(o);
+
+ return true;
}
bool RenderObject::hasOutlineAnnotation() const
{
- return element() && element()->isLink() && document()->printing();
+ return node() && node()->isLink() && document()->printing();
}
RenderObject* RenderObject::container() const
@@ -2269,51 +1820,19 @@ 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() && virtualContinuation()) ? virtualContinuation() : 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(toRenderBox(this), false);
- }
-
- if (isPositioned()) {
- RenderObject* p;
- for (p = parent(); p; p = p->parent()) {
- if (p->isRenderBlock())
- static_cast<RenderBlock*>(p)->removePositionedObject(toRenderBox(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)
document()->frame()->eventHandler()->stopAutoscrollTimer(true);
@@ -2333,12 +1852,11 @@ void RenderObject::destroy()
remove();
- // FIXME: Would like to do this in RenderBox, but the timing is so complicated that this can't easily
- // be moved into RenderBox::destroy.
- RenderArena* arena = renderArena();
+ // 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())
- toRenderBox(this)->layer()->destroy(arena);
- arenaDelete(arena, this);
+ toRenderBoxModelObject(this)->destroyLayer();
+ arenaDelete(renderArena(), this);
}
void RenderObject::arenaDelete(RenderArena* arena, void* base)
@@ -2374,14 +1892,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& point)
+VisiblePosition RenderObject::positionForPoint(const IntPoint&)
{
- return positionForCoordinates(point.x(), point.y());
+ return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
}
void RenderObject::updateDragState(bool dragOn)
@@ -2389,12 +1907,9 @@ void RenderObject::updateDragState(bool dragOn)
bool valueChanged = (dragOn != m_isDragging);
m_isDragging = dragOn;
if (valueChanged && style()->affectedByDragRules())
- element()->setChanged();
+ node()->setChanged();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
curr->updateDragState(dragOn);
- RenderFlow* continuation = virtualContinuation();
- if (continuation)
- continuation->updateDragState(dragOn);
}
bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const IntPoint& point, int tx, int ty, HitTestFilter hitTestFilter)
@@ -2425,34 +1940,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() && virtualContinuation())
- // 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 = virtualContinuation()->element();
-
- if (node) {
- if (node->renderer() && node->renderer()->virtualContinuation() && 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.
- RenderBlock* firstBlock = node->renderer()->containingBlock();
-
- // Get our containing block.
- RenderBox* block = toRenderBox(this);
- if (isInline())
- block = containingBlock();
-
- localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
- }
-
- 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);
}
}
@@ -2461,78 +1954,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
@@ -2544,7 +1968,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()) {
@@ -2554,59 +1978,42 @@ void RenderObject::scheduleRelayout()
}
}
-void RenderObject::removeLeftoverAnonymousBlock(RenderBlock*)
-{
-}
-
-InlineBox* RenderObject::createInlineBox(bool, bool unusedIsRootLineBox, bool)
-{
- ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox);
- 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->isRenderInline()) {
- 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);
@@ -2619,26 +2026,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();
}
@@ -2681,10 +2088,10 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
}
}
curr = curr->parent();
- if (curr && curr->isRenderBlock() && curr->virtualContinuation())
- curr = curr->virtualContinuation();
- } 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) {
@@ -2697,10 +2104,6 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
}
}
-void RenderObject::updateWidgetPosition()
-{
-}
-
#if ENABLE(DASHBOARD_SUPPORT)
void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
{
@@ -2762,23 +2165,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();
-}
-
bool RenderObject::willRenderImage(CachedImage*)
{
// Without visibility we won't render (and therefore don't care about animation).
@@ -2794,7 +2180,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
@@ -2805,7 +2191,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;
@@ -2821,6 +2207,11 @@ int RenderObject::previousOffset(int current) const
return current - 1;
}
+int RenderObject::previousOffsetForBackwardDeletion(int current) const
+{
+ return current - 1;
+}
+
int RenderObject::nextOffset(int current) const
{
return current + 1;
@@ -2828,7 +2219,7 @@ int RenderObject::nextOffset(int current) const
void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const
{
- int outlineSize = !isInline() && virtualContinuation() ? virtualContinuation()->style()->outlineSize() : style()->outlineSize();
+ int outlineSize = outlineStyleForRepaint()->outlineSize();
if (ShadowData* boxShadow = style()->boxShadow()) {
int shadowLeft = 0;
int shadowRight = 0;
@@ -2861,6 +2252,107 @@ void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
imageChanged(static_cast<WrappedImagePtr>(image), rect);
}
+RenderBoxModelObject* RenderObject::offsetParent() const
+{
+ // 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 curr && curr->isBoxModelObject() ? toRenderBoxModelObject(curr) : 0;
+}
+
+VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
+{
+ // If is 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(node, numeric_limits<int>::max(), 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();
+}
+
+VisiblePosition RenderObject::createVisiblePosition(const Position& position)
+{
+ if (position.isNotNull())
+ return VisiblePosition(position);
+
+ ASSERT(!node());
+ return createVisiblePosition(0, DOWNSTREAM);
+}
+
#if ENABLE(SVG)
FloatRect RenderObject::relativeBBox(bool) const
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index 889ce9b..a601962 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -28,7 +28,11 @@
#include "CachedResourceClient.h"
#include "FloatQuad.h"
#include "Document.h"
+#include "RenderObjectChildList.h"
#include "RenderStyle.h"
+#include "TextAffinity.h"
+#include "TransformationMatrix.h"
+#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -36,9 +40,13 @@ class AnimationController;
class HitTestResult;
class InlineBox;
class InlineFlowBox;
+class Position;
+class RenderBoxModelObject;
+class RenderInline;
class RenderBlock;
class RenderFlow;
class RenderLayer;
+class TransformState;
class VisiblePosition;
/*
@@ -85,10 +93,16 @@ enum HitTestAction {
HitTestForeground
};
-// Values for verticalPosition.
-const int PositionTop = -0x7fffffff;
-const int PositionBottom = 0x7fffffff;
-const int PositionUndefined = 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 {
@@ -110,8 +124,10 @@ struct DashboardRegionValue {
// Base class for all rendering tree objects.
class RenderObject : public CachedResourceClient {
- friend class RenderContainer;
+ 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
@@ -119,7 +135,7 @@ public:
RenderObject(Node*);
virtual ~RenderObject();
- virtual const char* renderName() const { return "RenderObject"; }
+ virtual const char* renderName() const = 0;
RenderObject* parent() const { return m_parent; }
bool isDescendantOf(const RenderObject*) const;
@@ -127,8 +143,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;
@@ -140,10 +168,11 @@ public:
RenderObject* firstLeafChild() const;
RenderObject* lastLeafChild() const;
- // The following five functions are used when the render tree hierarchy changes to make sure layers get
+ // 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);
@@ -152,18 +181,8 @@ public:
// Convenience function for getting to the nearest enclosing box of a RenderObject.
RenderBox* enclosingBox() const;
- 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; }
-
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; }
@@ -179,35 +198,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:
@@ -219,6 +218,7 @@ protected:
//////////////////////////////////////////
private:
void addAbsoluteRectForLayer(IntRect& result);
+ void setLayerNeedsFullRepaint();
public:
#ifndef NDEBUG
@@ -244,19 +244,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 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; }
@@ -267,20 +268,23 @@ 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 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* virtualContinuation() const { return 0; }
+ 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)
virtual bool isSVGRoot() const { return false; }
@@ -295,15 +299,13 @@ public:
virtual TransformationMatrix absoluteTransform() const;
#endif
- virtual bool isEditable() const;
-
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
@@ -318,7 +320,7 @@ public:
bool hasBoxDecorations() const { return m_paintBackground; }
bool mustRepaintBackgroundOrBorder() const;
-
+
bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; }
bool selfNeedsLayout() const { return m_needsLayout; }
bool needsPositionedMovementLayout() const { return m_needsPositionedMovementLayout; }
@@ -330,28 +332,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 hasTransform() const { return m_hasTransform; }
bool hasMask() const { return style() && style()->hasMask(); }
+ 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(); }
@@ -361,7 +368,10 @@ 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;
void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0);
void setNeedsLayout(bool b, bool markParents = true);
@@ -369,7 +379,6 @@ public:
void setNeedsPositionedMovementLayout();
void setPrefWidthsDirty(bool, bool markParents = true);
void invalidateContainerPrefWidths();
- virtual void invalidateCounters() { }
void setNeedsLayoutAndPrefWidthsRecalc()
{
@@ -395,21 +404,9 @@ 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;
@@ -419,7 +416,7 @@ public:
*/
struct PaintInfo {
PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, bool newForceBlackText,
- RenderObject* newPaintingRoot, ListHashSet<RenderFlow*>* newOutlineObjects)
+ RenderObject* newPaintingRoot, ListHashSet<RenderInline*>* newOutlineObjects)
: context(newContext)
, rect(newRect)
, phase(newPhase)
@@ -434,38 +431,13 @@ public:
PaintPhase phase;
bool forceBlackText;
RenderObject* paintingRoot; // used to draw just one element and its visual kids
- ListHashSet<RenderFlow*>* 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
};
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 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(); }
@@ -478,19 +450,19 @@ public:
// repaint and do not need a relayout
virtual void updateFromElement() { }
- 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&);
+ VisiblePosition positionForCoordinates(int x, int y);
+ virtual VisiblePosition positionForPoint(const IntPoint&);
+ VisiblePosition createVisiblePosition(int offset, EAffinity);
+ VisiblePosition createVisiblePosition(const Position&);
virtual void dirtyLinesFromChangedChild(RenderObject*);
@@ -509,21 +481,10 @@ 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;
-
- // 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*/) { }
-
// 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;
// Convert a local quad to absolute coordinates, taking transforms into account.
FloatQuad localToAbsoluteQuad(const FloatQuad& quad, bool fixed = false) const
@@ -531,19 +492,19 @@ public:
return localToContainerQuad(quad, 0, fixed);
}
// Convert a local quad into the coordinate system of container, taking transforms into account.
- virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const;
+ FloatQuad localToContainerQuad(const FloatQuad&, RenderBoxModelObject* repaintContainer, bool fixed = false) const;
// Return the offset from the container() renderer (excluding transforms)
virtual IntSize offsetFromContainer(RenderObject*) const;
- virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+ virtual void absoluteRectsForRange(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
virtual void absoluteRects(Vector<IntRect>&, int, int, bool = true) { }
// 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 absoluteQuadsForRange(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
virtual void absoluteQuads(Vector<FloatQuad>&, bool /*topLevel*/ = true) { }
// the rect that will be painted if this object is passed as the paintingRoot
@@ -553,28 +514,23 @@ public:
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.
- RenderBox* containerForRepaint() const;
+ 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.
@@ -584,7 +540,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);
@@ -600,32 +556,22 @@ public:
{
return clippedOverflowRectForRepaint(0);
}
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
-
- IntRect rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth);
// 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(r, 0, fixed);
+ 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(IntRect&, RenderBox* repaintContainer, bool fixed = false);
+ 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 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(); }
@@ -635,6 +581,9 @@ public:
// 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
@@ -645,20 +594,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;
@@ -667,30 +617,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;
/**
@@ -701,12 +627,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.
@@ -724,13 +649,14 @@ public:
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
{
@@ -742,24 +668,22 @@ public:
{
return !paintInfo.paintingRoot || paintInfo.paintingRoot == this;
}
-#ifdef ANDROID_LAYOUT
- virtual bool hasChildTable() const { return false; }
-#endif
bool hasOverrideSize() const { return m_hasOverrideSize; }
void setHasOverrideSize(bool b) { m_hasOverrideSize = b; }
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;
+
+ TransformationMatrix transformFromContainer(const RenderObject* container, const IntSize& offsetInContainer) const;
virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { };
@@ -768,28 +692,60 @@ public:
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);
void paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*);
void addPDFURLRect(GraphicsContext*, const IntRect&);
virtual IntRect viewRect() const;
- int getVerticalPosition(bool firstLine) const;
-
void adjustRectForOutlineAndShadow(IntRect&) const;
void arenaDelete(RenderArena*, void* objectBase);
- virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const { return IntRect(); }
+ 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;
@@ -802,8 +758,8 @@ private:
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;
@@ -835,10 +791,145 @@ 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)
+{
+#if !ENABLE(3D_RENDERING)
+ matrix.makeAffine();
+#else
+ UNUSED_PARAM(matrix);
+#endif
+}
+
} // namespace WebCore
#ifndef NDEBUG
diff --git a/WebCore/rendering/RenderObjectChildList.cpp b/WebCore/rendering/RenderObjectChildList.cpp
new file mode 100644
index 0000000..32e856f
--- /dev/null
+++ b/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/WebCore/rendering/RenderObjectChildList.h b/WebCore/rendering/RenderObjectChildList.h
new file mode 100644
index 0000000..bf8800a
--- /dev/null
+++ b/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/WebCore/rendering/RenderPart.cpp b/WebCore/rendering/RenderPart.cpp
index 6f79a00..71e5f4e 100644
--- a/WebCore/rendering/RenderPart.cpp
+++ b/WebCore/rendering/RenderPart.cpp
@@ -37,7 +37,7 @@ namespace WebCore {
using namespace HTMLNames;
-RenderPart::RenderPart(HTMLFrameOwnerElement* node)
+RenderPart::RenderPart(Element* node)
: RenderWidget(node)
{
// init RenderObject attributes
@@ -81,35 +81,4 @@ void RenderPart::deleteWidget()
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()
-{
- if (!m_widget)
- return;
-
- FloatPoint absPos = localToAbsolute();
- absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
- int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight();
- int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom();
- IntRect newBounds(absPos.x(), absPos.y(), w, h);
- 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);
- }
-
- // 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();
- }
-}
-
}
diff --git a/WebCore/rendering/RenderPart.h b/WebCore/rendering/RenderPart.h
index e339468..5a7ba26 100644
--- a/WebCore/rendering/RenderPart.h
+++ b/WebCore/rendering/RenderPart.h
@@ -34,7 +34,7 @@ class HTMLFrameOwnerElement;
class RenderPart : public RenderWidget {
public:
- RenderPart(HTMLFrameOwnerElement*);
+ RenderPart(Element*);
virtual ~RenderPart();
virtual bool isRenderPart() const { return true; }
@@ -42,10 +42,6 @@ public:
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 viewCleared();
diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp
index 4df631f..828026e 100644
--- a/WebCore/rendering/RenderPartObject.cpp
+++ b/WebCore/rendering/RenderPartObject.cpp
@@ -34,21 +34,21 @@
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTMLParamElement.h"
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#include "HTMLVideoElement.h"
+#endif
#include "MIMETypeRegistry.h"
#include "Page.h"
#include "PluginData.h"
#include "RenderView.h"
#include "Text.h"
-#ifdef FLATTEN_IFRAME
-#include "RenderView.h"
-#endif
-
namespace WebCore {
using namespace HTMLNames;
-RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element)
+RenderPartObject::RenderPartObject(Element* element)
: RenderPart(element)
{
// init RenderObject attributes
@@ -132,10 +132,17 @@ static String serviceTypeForClassId(const String& classId, const PluginData* plu
static inline bool shouldUseEmbedDescendant(HTMLObjectElement* objectElement, const PluginData* pluginData)
{
+#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
}
void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
@@ -146,8 +153,8 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
Vector<String> paramValues;
Frame* frame = m_view->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())
@@ -261,8 +268,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();
@@ -294,6 +301,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()
@@ -349,8 +380,8 @@ void RenderPartObject::layout()
calcWidth();
calcHeight();
#endif
-
- adjustOverflowForBoxShadow();
+
+ adjustOverflowForBoxShadowAndReflect();
RenderPart::layout();
@@ -416,12 +447,12 @@ void RenderPartObject::calcHeight() {
void RenderPartObject::viewCleared()
{
- if (element() && m_widget && m_widget->isFrameView()) {
+ if (node() && m_widget && m_widget->isFrameView()) {
FrameView* view = static_cast<FrameView*>(m_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/WebCore/rendering/RenderPartObject.h b/WebCore/rendering/RenderPartObject.h
index 2b21644..9eb9f21 100644
--- a/WebCore/rendering/RenderPartObject.h
+++ b/WebCore/rendering/RenderPartObject.h
@@ -31,7 +31,7 @@ namespace WebCore {
class RenderPartObject : public RenderPart {
public:
- RenderPartObject(HTMLFrameOwnerElement*);
+ RenderPartObject(Element*);
virtual ~RenderPartObject();
virtual const char* renderName() const { return "RenderPartObject"; }
diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp
index 1f73c70..1340694 100644
--- a/WebCore/rendering/RenderPath.cpp
+++ b/WebCore/rendering/RenderPath.cpp
@@ -81,7 +81,7 @@ FloatPoint RenderPath::mapAbsolutePointToLocal(const FloatPoint& point) const
// absolute transform?
double localX;
double localY;
- absoluteTransform().inverse().map(point.x(), point.y(), &localX, &localY);
+ absoluteTransform().inverse().map(point.x(), point.y(), localX, localY);
return FloatPoint::narrowPrecision(localX, localY);
}
@@ -150,33 +150,27 @@ const Path& RenderPath::path() const
bool RenderPath::calculateLocalTransform()
{
TransformationMatrix oldTransform = m_localTransform;
- m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
return (m_localTransform != oldTransform);
}
void RenderPath::layout()
{
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
- if (checkForRepaint) {
- oldBounds = m_absoluteBounds;
- oldOutlineBox = absoluteOutlineBounds();
- }
-
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout(), &m_absoluteBounds);
+
calculateLocalTransform();
- setPath(static_cast<SVGStyledTransformableElement*>(element())->toPathData());
+ setPath(static_cast<SVGStyledTransformableElement*>(node())->toPathData());
m_absoluteBounds = absoluteClippedOverflowRect();
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ repainter.repaintAfterLayout();
setNeedsLayout(false);
}
-IntRect RenderPath::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/)
+IntRect RenderPath::clippedOverflowRectForRepaint(RenderBoxModelObject* /*repaintContainer*/)
{
// FIXME: handle non-root repaintContainer
FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
@@ -243,7 +237,7 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
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);
@@ -418,7 +412,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);
@@ -476,7 +470,7 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR
return bounds;
}
-IntRect RenderPath::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const
+IntRect RenderPath::outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const
{
// FIXME: handle non-root repaintContainer
IntRect result = m_absoluteBounds;
diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h
index 81b5c52..6157171 100644
--- a/WebCore/rendering/RenderPath.h
+++ b/WebCore/rendering/RenderPath.h
@@ -59,7 +59,7 @@ public:
virtual TransformationMatrix localTransform() const;
virtual void layout();
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual bool requiresLayer() const { return false; }
virtual int lineHeight(bool b, bool isRootLineBox = false) const;
virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
@@ -75,7 +75,7 @@ public:
private:
FloatPoint mapAbsolutePointToLocal(const FloatPoint&) const;
- virtual IntRect outlineBoundsForRepaint(RenderBox* repaintContainer) const;
+ virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const;
mutable Path m_path;
mutable FloatRect m_fillBBox;
diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp
index e74e227..783fc26 100644
--- a/WebCore/rendering/RenderReplaced.cpp
+++ b/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());
setHeight(minimumReplacedHeight());
calcWidth();
calcHeight();
- adjustOverflowForBoxShadow();
-
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ adjustOverflowForBoxShadowAndReflect();
+ repainter.repaintAfterLayout();
+
setNeedsLayout(false);
}
@@ -137,8 +127,24 @@ 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();
+ paintInfo.context->addRoundedRectClip(IntRect(tx, ty, width(), height()),
+ style()->borderTopLeftRadius(),
+ style()->borderTopRightRadius(),
+ style()->borderBottomLeftRadius(),
+ style()->borderBottomRightRadius());
+ }
+
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);
@@ -215,11 +221,11 @@ unsigned RenderReplaced::caretMaxRenderedOffset() const
return 1;
}
-VisiblePosition RenderReplaced::positionForCoordinates(int xPos, int yPos)
+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 +234,22 @@ VisiblePosition RenderReplaced::positionForCoordinates(int xPos, int yPos)
int top = root->topOverflow();
int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow();
- if (yPos + y() < top)
- return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); // coordinates are above
+ if (point.y() + y() < top)
+ return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above
- if (yPos + y() >= bottom)
- return VisiblePosition(element(), caretMaxOffset(), DOWNSTREAM); // coordinates are below
+ if (point.y() + y() >= bottom)
+ return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below
- if (element()) {
- if (xPos <= 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(xPos, yPos);
+ return RenderBox::positionForPoint(point);
}
-IntRect RenderReplaced::selectionRect(bool clipToVisibleContent)
+IntRect RenderReplaced::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent)
{
ASSERT(!needsLayout());
@@ -252,11 +258,9 @@ IntRect RenderReplaced::selectionRect(bool clipToVisibleContent)
IntRect rect = localSelectionRect();
if (clipToVisibleContent)
- computeAbsoluteRepaintRect(rect);
- else {
- FloatPoint absPos = localToAbsolute(FloatPoint());
- rect.move(absPos.x(), absPos.y());
- }
+ computeRectForRepaint(repaintContainer, rect);
+ else
+ rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
return rect;
}
@@ -280,7 +284,7 @@ IntRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const
void RenderReplaced::setSelectionState(SelectionState s)
{
- m_selectionState = s;
+ RenderBox::setSelectionState(s);
if (m_inlineBoxWrapper) {
RootInlineBox* line = m_inlineBoxWrapper->root();
if (line)
@@ -303,7 +307,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,7 +327,7 @@ 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) {
@@ -333,21 +337,29 @@ void RenderReplaced::adjustOverflowForBoxShadow()
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(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 +369,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 +379,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 +387,7 @@ int RenderReplaced::overflowLeft(bool) const
int RenderReplaced::overflowTop(bool) const
{
- if (m_hasOverflow)
+ if (replacedHasOverflow())
return gOverflowRectMap->get(this).y();
return 0;
@@ -383,20 +395,20 @@ int RenderReplaced::overflowTop(bool) const
IntRect RenderReplaced::overflowRect(bool) const
{
- if (m_hasOverflow)
+ if (replacedHasOverflow())
return gOverflowRectMap->find(this)->second;
return borderBoxRect();
}
-IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+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) {
@@ -412,7 +424,7 @@ IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBox* repaintContaine
if (v)
r.inflate(style()->outlineSize());
}
- computeRectForRepaint(r, repaintContainer);
+ computeRectForRepaint(repaintContainer, r);
return r;
}
diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h
index c87db58..4937446 100644
--- a/WebCore/rendering/RenderReplaced.h
+++ b/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 clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ 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/WebCore/rendering/RenderReplica.cpp b/WebCore/rendering/RenderReplica.cpp
index 183dd2e..0eb9f8f 100644
--- a/WebCore/rendering/RenderReplica.cpp
+++ b/WebCore/rendering/RenderReplica.cpp
@@ -35,7 +35,13 @@ 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()
{}
diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp
index 6e17c05..28c5672 100644
--- a/WebCore/rendering/RenderSVGContainer.cpp
+++ b/WebCore/rendering/RenderSVGContainer.cpp
@@ -39,8 +39,6 @@ namespace WebCore {
RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
: RenderObject(node)
- , m_firstChild(0)
- , m_lastChild(0)
, m_width(0)
, m_height(0)
, m_drawsContents(true)
@@ -51,143 +49,6 @@ 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;
@@ -226,13 +87,8 @@ void RenderSVGContainer::layout()
// Arbitrary affine transforms are incompatible with LayoutState.
view()->disableLayoutState();
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
- if (checkForRepaint) {
- oldBounds = m_absoluteBounds;
- oldOutlineBox = absoluteOutlineBounds();
- }
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfWillPaint(), &m_absoluteBounds);
calculateLocalTransform();
@@ -250,8 +106,7 @@ void RenderSVGContainer::layout()
calcBounds();
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ repainter.repaintAfterLayout();
view()->enableLayoutState();
setNeedsLayout(false);
@@ -264,7 +119,7 @@ int RenderSVGContainer::calcReplacedWidth() const
return max(0, style()->width().value());
case Percent:
{
- const int cw = containingBlockWidth();
+ const int cw = containingBlock()->availableWidth();
return cw > 0 ? max(0, style()->width().calcMinValue(cw)) : 0;
}
default:
@@ -357,7 +212,7 @@ TransformationMatrix RenderSVGContainer::viewportTransform() const
return TransformationMatrix();
}
-IntRect RenderSVGContainer::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderSVGContainer::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
FloatRect repaintRect;
@@ -425,7 +280,7 @@ bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResul
return false;
}
-IntRect RenderSVGContainer::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const
+IntRect RenderSVGContainer::outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const
{
// FIXME: handle non-root repaintContainer
IntRect result = m_absoluteBounds;
diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h
index e498a8a..2c1be65 100644
--- a/WebCore/rendering/RenderSVGContainer.h
+++ b/WebCore/rendering/RenderSVGContainer.h
@@ -37,29 +37,14 @@ public:
RenderSVGContainer(SVGStyledElement*);
~RenderSVGContainer();
- virtual RenderObject* firstChild() const { return m_firstChild; }
- virtual RenderObject* lastChild() const { return m_lastChild; }
+ virtual RenderObjectChildList* virtualChildren() { return children(); }
+ virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+ const RenderObjectChildList* children() const { return &m_children; }
+ RenderObjectChildList* children() { return &m_children; }
int width() const { return m_width; }
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 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
@@ -76,7 +61,7 @@ public:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
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);
@@ -95,14 +80,13 @@ protected:
void calcBounds();
- virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const;
+ virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const;
private:
int calcReplacedWidth() const;
int calcReplacedHeight() const;
- RenderObject* m_firstChild;
- RenderObject* m_lastChild;
+ RenderObjectChildList m_children;
int m_width;
int m_height;
diff --git a/WebCore/rendering/RenderSVGGradientStop.cpp b/WebCore/rendering/RenderSVGGradientStop.cpp
index d0dc881..b81e7f4 100644
--- a/WebCore/rendering/RenderSVGGradientStop.cpp
+++ b/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/WebCore/rendering/RenderSVGGradientStop.h b/WebCore/rendering/RenderSVGGradientStop.h
index 86de6d0..7b7df5c 100644
--- a/WebCore/rendering/RenderSVGGradientStop.h
+++ b/WebCore/rendering/RenderSVGGradientStop.h
@@ -41,14 +41,13 @@ 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 override is needed to prevent an assert on <svg><stop /></svg>
+ // RenderObject's default impl asserts.
// https://bugs.webkit.org/show_bug.cgi?id=20400
- virtual IntRect absoluteClippedOverflowRect() { return IntRect(); }
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); }
protected:
- virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
private:
SVGGradientElement* gradientElement() const;
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp
index 23ae13e..dd76946 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.cpp
+++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp
@@ -71,7 +71,7 @@ void RenderSVGHiddenContainer::paint(PaintInfo&, int, int)
// This subtree does not paint.
}
-IntRect RenderSVGHiddenContainer::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/)
+IntRect RenderSVGHiddenContainer::clippedOverflowRectForRepaint(RenderBoxModelObject* /*repaintContainer*/)
{
return IntRect();
}
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h
index 282e3f3..6568f3f 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.h
+++ b/WebCore/rendering/RenderSVGHiddenContainer.h
@@ -51,7 +51,7 @@ namespace WebCore {
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp
index 503663a..a13ee03 100644
--- a/WebCore/rendering/RenderSVGImage.cpp
+++ b/WebCore/rendering/RenderSVGImage.cpp
@@ -129,7 +129,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s
bool RenderSVGImage::calculateLocalTransform()
{
TransformationMatrix oldTransform = m_localTransform;
- m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
return (m_localTransform != oldTransform);
}
@@ -137,13 +137,7 @@ void RenderSVGImage::layout()
{
ASSERT(needsLayout());
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout();
- if (checkForRepaint) {
- oldBounds = absoluteClippedOverflowRect();
- oldOutlineBox = absoluteOutlineBounds();
- }
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
calculateLocalTransform();
@@ -158,9 +152,8 @@ void RenderSVGImage::layout()
calculateAbsoluteBounds();
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
-
+ repainter.repaintAfterLayout();
+
setNeedsLayout(false);
}
@@ -205,7 +198,7 @@ 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);
+ absoluteTransform().inverse().map(_x, _y, localX, localY);
if (hitRules.canHitFill) {
if (m_localBounds.contains(narrowPrecisionToFloat(localX), narrowPrecisionToFloat(localY))) {
@@ -228,7 +221,7 @@ 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()
@@ -249,7 +242,7 @@ void RenderSVGImage::calculateAbsoluteBounds()
m_absoluteBounds = enclosingIntRect(absoluteRect);
}
-IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/)
+IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* /*repaintContainer*/)
{
// FIXME: handle non-root repaintContainer
return m_absoluteBounds;
diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h
index cb440d2..4aedfef 100644
--- a/WebCore/rendering/RenderSVGImage.h
+++ b/WebCore/rendering/RenderSVGImage.h
@@ -43,7 +43,7 @@ namespace WebCore {
virtual TransformationMatrix localTransform() const { return m_localTransform; }
virtual FloatRect relativeBBox(bool includeStroke = true) const;
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
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);
diff --git a/WebCore/rendering/RenderSVGInline.cpp b/WebCore/rendering/RenderSVGInline.cpp
index 81e0924..a4016a1 100644
--- a/WebCore/rendering/RenderSVGInline.cpp
+++ b/WebCore/rendering/RenderSVGInline.cpp
@@ -36,28 +36,9 @@ RenderSVGInline::RenderSVGInline(Node* n)
{
}
-InlineBox* RenderSVGInline::createInlineBox(bool unusedMakePlaceHolderBox, bool unusedIsRootLineBox, bool)
+InlineFlowBox* RenderSVGInline::createFlowBox()
{
-#if ASSERT_DISABLED
- UNUSED_PARAM(unusedIsRootLineBox);
- UNUSED_PARAM(unusedMakePlaceHolderBox);
-#endif
-
- ASSERT(!(!unusedIsRootLineBox && (isReplaced() || unusedMakePlaceHolderBox)));
-
- ASSERT(isRenderInline());
-
- InlineFlowBox* flowBox = new (renderArena()) SVGInlineFlowBox(this);
-
- if (!m_firstLineBox)
- m_firstLineBox = m_lastLineBox = flowBox;
- else {
- m_lastLineBox->setNextLineBox(flowBox);
- flowBox->setPreviousLineBox(m_lastLineBox);
- m_lastLineBox = flowBox;
- }
-
- return flowBox;
+ return new (renderArena()) SVGInlineFlowBox(this);
}
}
diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h
index 060ba58..cb8bf95 100644
--- a/WebCore/rendering/RenderSVGInline.h
+++ b/WebCore/rendering/RenderSVGInline.h
@@ -28,13 +28,17 @@
#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() const { return false; }
- };
+ RenderSVGInline(Node*);
+ virtual const char* renderName() const { return "RenderSVGInline"; }
+ virtual bool requiresLayer() const { return false; }
+
+private:
+ virtual InlineFlowBox* createFlowBox();
+};
+
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGInlineText.cpp b/WebCore/rendering/RenderSVGInlineText.cpp
index 215e9fe..b98eba0 100644
--- a/WebCore/rendering/RenderSVGInlineText.cpp
+++ b/WebCore/rendering/RenderSVGInlineText.cpp
@@ -56,7 +56,7 @@ RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> str)
}
-void RenderSVGInlineText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
// Skip RenderText's work.
RenderObject::styleDidChange(diff, oldStyle);
@@ -68,25 +68,24 @@ void RenderSVGInlineText::styleDidChange(RenderStyle::Diff diff, const RenderSty
void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
{
- rects.append(computeAbsoluteRectForRange(0, textLength()));
+ rects.append(computeRepaintRectForRange(0, 0, textLength()));
}
void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads, bool)
{
- quads.append(FloatRect(computeAbsoluteRectForRange(0, textLength())));
+ quads.append(FloatRect(computeRepaintRectForRange(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
@@ -104,23 +103,22 @@ 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;
-
RenderBlock* cb = containingBlock();
if (!cb || !cb->container())
- return rect;
+ return IntRect();
RenderSVGRoot* root = findSVGRootObject(parent());
if (!root)
- return rect;
+ return IntRect();
+ IntRect rect;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
rect.unite(box->selectionRect(0, 0, startPos, endPos));
@@ -129,15 +127,15 @@ IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPo
// 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();
+ TransformationMatrix htmlParentCtm = root->RenderBox::absoluteTransform();
- FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - (firstTextBox() ? firstTextBox()->xPos() : 0) - htmlParentCtm.e()),
- narrowPrecisionToFloat(rect.y() + absPos.y() - (firstTextBox() ? firstTextBox()->yPos() : 0) - htmlParentCtm.f()), rect.width(), rect.height());
- // FIXME: broken with CSS transforms
+ FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - htmlParentCtm.e()),
+ narrowPrecisionToFloat(rect.y() + absPos.y() - htmlParentCtm.f()), rect.width(), rect.height());
+ // FIXME: broken with CSS transforms, and non-zero repaintContainer
return enclosingIntRect(absoluteTransform().mapRect(fixedRect));
}
-InlineTextBox* RenderSVGInlineText::createInlineTextBox()
+InlineTextBox* RenderSVGInlineText::createTextBox()
{
return new (renderArena()) SVGInlineTextBox(this);
}
@@ -149,35 +147,41 @@ IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*)
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();
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->x(), y + object->y(), 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/WebCore/rendering/RenderSVGInlineText.h b/WebCore/rendering/RenderSVGInlineText.h
index 55fd838..e7f776a 100644
--- a/WebCore/rendering/RenderSVGInlineText.h
+++ b/WebCore/rendering/RenderSVGInlineText.h
@@ -35,23 +35,23 @@ public:
RenderSVGInlineText(Node*, PassRefPtr<StringImpl>);
virtual const char* renderName() const { return "RenderSVGInlineText"; }
- virtual void styleDidChange(RenderStyle::Diff, const RenderStyle*);
+ 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 bool requiresLayer() const { return false; }
- virtual IntRect selectionRect(bool clipToVisibleContent = true);
+ 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);
};
}
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
index 54a30df..658b92d 100644
--- a/WebCore/rendering/RenderSVGRoot.cpp
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -27,24 +27,23 @@
#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"
+
+#if ENABLE(SVG_FILTERS)
+#include "SVGResourceFilter.h"
+#endif
using namespace std;
namespace WebCore {
RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
- : RenderContainer(node)
+ : RenderBox(node)
{
setReplaced(true);
}
@@ -91,17 +90,14 @@ void RenderSVGRoot::layout()
// Arbitrary affine transforms are incompatible with LayoutState.
view()->disableLayoutState();
- IntRect oldBounds = m_absoluteBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
- if (checkForRepaint)
- oldOutlineBox = absoluteOutlineBounds();
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout(), &m_absoluteBounds);
calcWidth();
calcHeight();
m_absoluteBounds = absoluteClippedOverflowRect();
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
setWidth(static_cast<int>(width() * svg->currentScale()));
setHeight(static_cast<int>(height() * svg->currentScale()));
@@ -113,8 +109,7 @@ void RenderSVGRoot::layout()
ASSERT(!child->needsLayout());
}
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ repainter.repaintAfterLayout();
view()->enableLayoutState();
setNeedsLayout(false);
@@ -135,10 +130,10 @@ void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, in
}
// Respect scroll offset caused by html parents
- TransformationMatrix ctm = RenderContainer::absoluteTransform();
+ TransformationMatrix ctm = RenderBox::absoluteTransform();
paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f()));
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
paintInfo.context->concatCTM(TransformationMatrix().scale(svg->currentScale()));
if (!viewport().isEmpty()) {
@@ -158,7 +153,6 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
calcViewport();
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
// A value of zero disables rendering of the element.
if (viewport().width() <= 0. || viewport().height() <= 0.)
return;
@@ -186,16 +180,17 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
FloatRect boundingBox = relativeBBox(true);
if (childPaintInfo.phase == PaintPhaseForeground)
- prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
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);
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());
}
@@ -207,31 +202,24 @@ FloatRect RenderSVGRoot::viewport() const
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;
-
- float w, h;
- 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);
+ if (!selfNeedsLayout() && !svg->hasRelativeValues())
+ return;
- m_viewport = FloatRect(0, 0, w, h);
+ SVGLength width = svg->width();
+ SVGLength height = svg->height();
+ if (!svg->hasSetContainerSize()) {
+ m_viewport = FloatRect(0, 0, width.value(svg), height.value(svg));
+ return;
}
+ m_viewport = FloatRect(0, 0, (width.unitType() == LengthTypePercentage) ?
+ svg->relativeWidthValue() : width.value(svg),
+ (height.unitType() == LengthTypePercentage) ?
+ svg->relativeHeightValue() : height.value(svg));
}
-IntRect RenderSVGRoot::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderSVGRoot::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
IntRect repaintRect;
@@ -267,9 +255,9 @@ void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool)
TransformationMatrix RenderSVGRoot::absoluteTransform() const
{
- TransformationMatrix ctm = RenderContainer::absoluteTransform();
+ TransformationMatrix ctm = RenderBox::absoluteTransform();
ctm.translate(x(), y());
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
ctm.scale(svg->currentScale());
ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y());
ctm.translate(viewport().x(), viewport().y());
@@ -300,7 +288,7 @@ TransformationMatrix RenderSVGRoot::localTransform() const
bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
{
- TransformationMatrix ctm = RenderContainer::absoluteTransform();
+ TransformationMatrix ctm = RenderBox::absoluteTransform();
int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset
int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset
@@ -316,7 +304,7 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
overflowBox.move(tx, ty);
ctm.translate(viewport().x(), viewport().y());
double localX, localY;
- ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
+ ctm.inverse().map(_x - _tx, _y - _ty, localX, localY);
if (!overflowBox.contains((int)localX, (int)localY))
return false;
}
@@ -333,13 +321,6 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
return false;
}
-void RenderSVGRoot::position(InlineBox* box)
-{
- RenderContainer::position(box);
- if (m_absoluteBounds.isEmpty())
- setNeedsLayout(true, false);
-}
-
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h
index 048fc8b..3d0a141 100644
--- a/WebCore/rendering/RenderSVGRoot.h
+++ b/WebCore/rendering/RenderSVGRoot.h
@@ -24,7 +24,7 @@
#define RenderSVGRoot_h
#if ENABLE(SVG)
-#include "RenderContainer.h"
+#include "RenderBox.h"
#include "FloatRect.h"
namespace WebCore {
@@ -32,11 +32,16 @@ namespace WebCore {
class SVGStyledElement;
class TransformationMatrix;
-class RenderSVGRoot : public RenderContainer {
+class RenderSVGRoot : public RenderBox {
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"; }
@@ -47,7 +52,7 @@ public:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
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);
@@ -63,13 +68,12 @@ public:
FloatRect viewport() const;
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
-
- virtual void position(InlineBox*);
private:
void calcViewport();
void applyContentTransforms(PaintInfo&, int parentX, int parentY);
+ RenderObjectChildList m_children;
FloatRect m_viewport;
IntRect m_absoluteBounds;
};
diff --git a/WebCore/rendering/RenderSVGTSpan.cpp b/WebCore/rendering/RenderSVGTSpan.cpp
index 49c45df..d493c45 100644
--- a/WebCore/rendering/RenderSVGTSpan.cpp
+++ b/WebCore/rendering/RenderSVGTSpan.cpp
@@ -48,11 +48,11 @@ void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool)
if (!object)
return;
- int xRef = object->x() + x();
- int yRef = object->y() + y();
+ int xRef = object->x();
+ int yRef = object->y();
for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
- FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height());
// FIXME: broken with CSS transforms
rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
}
@@ -68,11 +68,11 @@ void RenderSVGTSpan::absoluteQuads(Vector<FloatQuad>& quads, bool)
if (!object)
return;
- int xRef = object->x() + x();
- int yRef = object->y() + y();
+ int xRef = object->x();
+ int yRef = object->y();
for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
- FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height());
// FIXME: broken with CSS transforms
quads.append(absoluteTransform().mapRect(rect));
}
diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp
index ee5ab34..8fef1f3 100644
--- a/WebCore/rendering/RenderSVGText.cpp
+++ b/WebCore/rendering/RenderSVGText.cpp
@@ -49,7 +49,7 @@ RenderSVGText::RenderSVGText(SVGTextElement* node)
{
}
-IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/)
+IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* /*repaintContainer*/)
{
// FIXME: handle non-root repaintContainer
FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
@@ -70,7 +70,7 @@ IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBox* /*repaintContain
bool RenderSVGText::calculateLocalTransform()
{
TransformationMatrix oldTransform = m_localTransform;
- m_localTransform = static_cast<SVGTextElement*>(element())->animatedLocalTransform();
+ m_localTransform = static_cast<SVGTextElement*>(node())->animatedLocalTransform();
return (oldTransform != m_localTransform);
}
@@ -81,16 +81,11 @@ void RenderSVGText::layout()
// 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();
- }
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout(), &m_absoluteBounds);
// 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));
setLocation(xOffset, yOffset);
@@ -101,27 +96,14 @@ void RenderSVGText::layout()
m_absoluteBounds = absoluteClippedOverflowRect();
- bool repainted = false;
- if (checkForRepaint)
- repainted = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
-
+ repainter.repaintAfterLayout();
+
setNeedsLayout(false);
}
-InlineBox* RenderSVGText::createInlineBox(bool, bool, bool)
+RootInlineBox* RenderSVGText::createRootBox()
{
- ASSERT(!isRenderInline());
- 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;
+ return new (renderArena()) SVGRootInlineBox(this);
}
bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
@@ -133,7 +115,7 @@ bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
|| (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
TransformationMatrix totalTransform = absoluteTransform();
double localX, localY;
- totalTransform.inverse().map(_x, _y, &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);
}
@@ -150,7 +132,7 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
FloatPoint absPos = localToAbsolute();
- TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform();
+ TransformationMatrix htmlParentCtm = root->RenderBox::absoluteTransform();
// Don't use relativeBBox 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'.
@@ -159,7 +141,7 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
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());
+ FloatRect boxRect(box->x(), box->y(), 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)));
@@ -175,7 +157,7 @@ void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool)
FloatPoint absPos = localToAbsolute();
- TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform();
+ TransformationMatrix htmlParentCtm = root->RenderBox::absoluteTransform();
// Don't use relativeBBox 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'.
@@ -184,7 +166,7 @@ void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool)
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());
+ FloatRect boxRect(box->x(), box->y(), 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));
@@ -208,7 +190,7 @@ FloatRect RenderSVGText::relativeBBox(bool includeStroke) const
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()));
+ repaintRect.unite(FloatRect(box->x(), box->y(), box->width(), box->height()));
}
// SVG needs to include the strokeWidth(), not the textStrokeWidth().
diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h
index 4592f4e..2cd71fa 100644
--- a/WebCore/rendering/RenderSVGText.h
+++ b/WebCore/rendering/RenderSVGText.h
@@ -53,12 +53,12 @@ public:
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual FloatRect relativeBBox(bool includeStroke = true) const;
- virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false);
-
private:
+ virtual RootInlineBox* createRootBox();
+
TransformationMatrix m_localTransform;
IntRect m_absoluteBounds;
};
diff --git a/WebCore/rendering/RenderSVGTextPath.cpp b/WebCore/rendering/RenderSVGTextPath.cpp
index 2d2894f..4ae29bf 100644
--- a/WebCore/rendering/RenderSVGTextPath.cpp
+++ b/WebCore/rendering/RenderSVGTextPath.cpp
@@ -45,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))
@@ -65,17 +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;
+ return static_cast<SVGTextPathElement*>(node())->method() == SVG_TEXTPATH_METHODTYPE_STRETCH;
}
void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int)
@@ -88,11 +88,11 @@ void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int)
if (!object)
return;
- int xRef = object->x() + x();
- int yRef = object->y() + y();
+ int xRef = object->x();
+ int yRef = object->y();
for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
- FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height());
// FIXME: broken with CSS transforms
rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
}
@@ -108,11 +108,11 @@ void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool)
if (!object)
return;
- int xRef = object->x() + x();
- int yRef = object->y() + y();
+ int xRef = object->x();
+ int yRef = object->y();
for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
- FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ FloatRect rect(xRef + curr->x(), yRef + curr->y(), curr->width(), curr->height());
// FIXME: broken with CSS transforms
quads.append(absoluteTransform().mapRect(rect));
}
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.cpp b/WebCore/rendering/RenderSVGTransformableContainer.cpp
index 17d64f3..6d65b55 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.cpp
+++ b/WebCore/rendering/RenderSVGTransformableContainer.cpp
@@ -38,7 +38,7 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf
bool RenderSVGTransformableContainer::calculateLocalTransform()
{
TransformationMatrix oldTransform = m_localTransform;
- m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
return (m_localTransform != oldTransform);
}
diff --git a/WebCore/rendering/RenderSVGViewportContainer.cpp b/WebCore/rendering/RenderSVGViewportContainer.cpp
index 4282efc..7885c4c 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.cpp
+++ b/WebCore/rendering/RenderSVGViewportContainer.cpp
@@ -52,12 +52,9 @@ void RenderSVGViewportContainer::layout()
// Arbitrary affine transforms are incompatible with LayoutState.
view()->disableLayoutState();
- IntRect oldBounds = m_absoluteBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
- if (checkForRepaint)
- oldOutlineBox = absoluteOutlineBounds();
-
+ // FIXME: using m_absoluteBounds breaks if containerForRepaint() is not the root
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout(), &m_absoluteBounds);
+
calcBounds();
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
@@ -68,8 +65,7 @@ void RenderSVGViewportContainer::layout()
ASSERT(!child->needsLayout());
}
- if (checkForRepaint)
- repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ repainter.repaintAfterLayout();
view()->enableLayoutState();
setNeedsLayout(false);
@@ -109,9 +105,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;
@@ -125,7 +121,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);
@@ -134,11 +130,11 @@ 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());
}
@@ -163,7 +159,7 @@ bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitT
TransformationMatrix ctm = RenderObject::absoluteTransform();
ctm.translate(viewport().x(), viewport().y());
double localX, localY;
- ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
+ ctm.inverse().map(_x - _tx, _y - _ty, localX, localY);
if (!overflowBox.contains((int)localX, (int)localY))
return false;
}
@@ -173,7 +169,7 @@ bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitT
// Respect parent translation offset for non-outermost <svg> elements.
// Outermost <svg> element is handled by RenderSVGRoot.
- if (element()->hasTagName(SVGNames::svgTag)) {
+ if (node()->hasTagName(SVGNames::svgTag)) {
sx = _tx;
sy = _ty;
}
diff --git a/WebCore/rendering/RenderScrollbar.cpp b/WebCore/rendering/RenderScrollbar.cpp
index d6dd9cc..db24a06 100644
--- a/WebCore/rendering/RenderScrollbar.cpp
+++ b/WebCore/rendering/RenderScrollbar.cpp
@@ -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/WebCore/rendering/RenderScrollbar.h b/WebCore/rendering/RenderScrollbar.h
index cc43a00..524c4e8 100644
--- a/WebCore/rendering/RenderScrollbar.h
+++ b/WebCore/rendering/RenderScrollbar.h
@@ -26,13 +26,14 @@
#ifndef RenderScrollbar_h
#define RenderScrollbar_h
+#include "RenderStyleConstants.h"
#include "Scrollbar.h"
-#include "RenderStyle.h"
#include <wtf/HashMap.h>
namespace WebCore {
class RenderBox;
+class RenderStyle;
class RenderScrollbarPart;
class RenderStyle;
@@ -71,7 +72,7 @@ public:
int minimumThumbLength();
private:
- PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, RenderStyle::PseudoId);
+ PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, PseudoId);
void updateScrollbarPart(ScrollbarPart, bool destroy = false);
RenderBox* m_owner;
diff --git a/WebCore/rendering/RenderScrollbarPart.cpp b/WebCore/rendering/RenderScrollbarPart.cpp
index 6749d8c..0f29aeb 100644
--- a/WebCore/rendering/RenderScrollbarPart.cpp
+++ b/WebCore/rendering/RenderScrollbarPart.cpp
@@ -122,20 +122,20 @@ void RenderScrollbarPart::calcPrefWidths()
setPrefWidthsDirty(false);
}
-void RenderScrollbarPart::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+void RenderScrollbarPart::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
RenderBlock::styleWillChange(diff, newStyle);
setInline(false);
}
-void RenderScrollbarPart::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+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);
}
diff --git a/WebCore/rendering/RenderScrollbarPart.h b/WebCore/rendering/RenderScrollbarPart.h
index 7dae6e7..114bbff 100644
--- a/WebCore/rendering/RenderScrollbarPart.h
+++ b/WebCore/rendering/RenderScrollbarPart.h
@@ -48,8 +48,8 @@ public:
void paintIntoRect(GraphicsContext*, int tx, int ty, const IntRect&);
protected:
- virtual void styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle);
- 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/WebCore/rendering/RenderSelectionInfo.h b/WebCore/rendering/RenderSelectionInfo.h
new file mode 100644
index 0000000..e7b7b78
--- /dev/null
+++ b/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/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp
index 25f3e40..08ebadf 100644
--- a/WebCore/rendering/RenderSlider.cpp
+++ b/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
@@ -33,7 +32,9 @@
#include "HTMLNames.h"
#include "MediaControlElements.h"
#include "MouseEvent.h"
+#include "RenderLayer.h"
#include "RenderTheme.h"
+#include "RenderView.h"
#include <wtf/MathExtras.h>
#ifdef ANDROID_LAYOUT
@@ -46,44 +47,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;
+
+ 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");
-class HTMLSliderThumbElement : public HTMLDivElement {
+ // 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;
@@ -106,16 +178,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()
- + (renderBox()->width() / 2),
- m_initialPosition + curPoint.y() - m_initialClickPoint.y()
- + (renderBox()->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;
}
@@ -126,7 +193,6 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event)
RenderSlider::RenderSlider(HTMLInputElement* element)
: RenderBlock(element)
- , m_thumb(0)
{
}
@@ -171,20 +237,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);
@@ -195,16 +261,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);
@@ -212,54 +273,97 @@ PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parent
}
void RenderSlider::layout()
-{
- bool relayoutChildren = false;
-
- if (m_thumb && m_thumb->renderer()) {
-
-#ifdef ANDROID_LAYOUT
- int oldVisibleWidth = m_visibleWidth;
-#endif
-
- int oldWidth = width();
- calcWidth();
- int oldHeight = height();
- calcHeight();
-
- if (oldWidth != width() || oldHeight != height())
- relayoutChildren = true;
+{
+ ASSERT(needsLayout());
-#ifdef ANDROID_LAYOUT
- const Settings* settings = document()->settings();
- ASSERT(settings);
- if (oldVisibleWidth != m_visibleWidth
- && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
- relayoutChildren = true;
-#endif
-
- // Allow the theme to set the size of the thumb
- if (m_thumb->renderer()->style()->hasAppearance())
- theme()->adjustSliderThumbSize(m_thumb->renderer());
+ 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());
@@ -267,8 +371,7 @@ void RenderSlider::updateFromElement()
m_thumb->setInDocument(true);
addChild(m_thumb->renderer());
}
- setPositionFromValue();
- setNeedsLayout(true, false);
+ setNeedsLayout(true);
}
bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
@@ -279,92 +382,45 @@ bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
#if ENABLE(VIDEO)
if (style()->appearance() == MediaSliderPart) {
MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node());
- IntPoint absPoint(evt->pageX(), evt->pageY());
- return sliderThumb->hitTest(absPoint);
- } else
-#endif
- {
- FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true);
- IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
- return thumbBounds.contains(roundedIntPoint(localPoint));
+ 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));
}
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);
+ HTMLInputElement* element = static_cast<HTMLInputElement*>(node());
- static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val));
-
- if (position != currentPosition()) {
- setCurrentPosition(position);
- static_cast<HTMLInputElement*>(node())->onChange();
- }
-}
-
-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->onChange();
+ }
}
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->renderBox()->height() / 2;
@@ -374,55 +430,44 @@ int RenderSlider::positionForOffset(const IntPoint& p)
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->renderBox()->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->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/WebCore/rendering/RenderSlider.h b/WebCore/rendering/RenderSlider.h
index 95ceb0b..f1eab9c 100644
--- a/WebCore/rendering/RenderSlider.h
+++ b/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();
-
- virtual bool mouseEventIsInThumb(MouseEvent*);
+
+ 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/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp
index 784a59a..f4b1033 100644
--- a/WebCore/rendering/RenderTable.cpp
+++ b/WebCore/rendering/RenderTable.cpp
@@ -55,8 +55,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)
@@ -76,7 +74,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);
@@ -116,8 +114,8 @@ 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();
+ bool isTableElement = node() && node()->hasTagName(tableTag);
if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
// First caption wins.
@@ -129,7 +127,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;
@@ -172,21 +170,16 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
}
} else if (child->isTableCell() || child->isTableRow()) {
wrapInAnonymousSection = true;
- } else {
+ } 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;
- }
+ wrapInAnonymousSection = !isTableElement || !child->node() || !(child->node()->hasTagName(formTag) && document()->isHTMLDocument());
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;
}
@@ -214,6 +207,12 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
section->addChild(child);
}
+void RenderTable::removeChild(RenderObject* oldChild)
+{
+ RenderBox::removeChild(oldChild);
+ setNeedsSectionRecalc();
+}
+
void RenderTable::calcWidth()
{
#ifdef ANDROID_LAYOUT
@@ -240,7 +239,7 @@ void RenderTable::calcWidth()
} else {
// An auto width table should shrink to fit within the line width if necessary in order to
// avoid overlapping floats.
- availableWidth = cb->lineWidth(y());
+ availableWidth = cb->lineWidth(y(), false);
// Subtract out any fixed margins from our available width for auto width tables.
int marginTotal = 0;
@@ -278,14 +277,7 @@ void RenderTable::layout()
recalcSectionsIfNeeded();
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout();
- if (checkForRepaint) {
- oldBounds = absoluteClippedOverflowRect();
- oldOutlineBox = absoluteOutlineBounds();
- }
-
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
setHeight(0);
@@ -308,17 +300,29 @@ void RenderTable::layout()
else if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
// if the width of a table is wider than its container width, or it has a nested table,
// we will render it with single column.
- int cw = containingBlockWidth();
- if (width() > cw || hasChildTable()) {
+ int cw = containingBlockWidthForContent();
+ bool shouldRenderAsSingleColumn = (width() > cw);
+ if (!shouldRenderAsSingleColumn) {
+ RenderObject* child = firstChild();
+ while (child) {
+ if (child->isTable()) {
+ shouldRenderAsSingleColumn = true;
+ break;
+ }
+ child = child->nextInPreOrder();
+ }
+ }
+
+ if (shouldRenderAsSingleColumn) {
m_singleColumn = true;
if (width() > cw)
- setWidth(cw);
+ setWidth(cw);
if (m_minPrefWidth > cw)
- m_minPrefWidth = cw;
- if (m_maxPrefWidth > cw)
- m_maxPrefWidth = cw;
+ m_minPrefWidth = cw;
+ if (m_maxPrefWidth > cw)
+ m_maxPrefWidth = cw;
}
- }
+ }
#endif
if (m_caption && width() != oldWidth)
m_caption->setNeedsLayout(true, false);
@@ -339,18 +343,18 @@ 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?
#ifdef ANDROID_LAYOUT
- if ((relayoutChildren || child->needsLayout()) &&
- !(child->element() && child->element()->hasTagName(formTag))) {
- child->setNeedsLayout(true);
- child->layout();
+ if (relayoutChildren) {
+ child->setNeedsLayout(true, false);
+ if (!child->isTableSection()) {
+ child->layoutIfNeeded();
+ continue;
+ }
+ // fall through
}
-#else
- if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag) && !child->isTableSection()))
- child->layout();
#endif
if (child->isTableSection()) {
+ child->layoutIfNeeded();
RenderTableSection* section = static_cast<RenderTableSection*>(child);
calculatedHeight += section->calcRowHeight();
if (collapsing)
@@ -359,6 +363,10 @@ void RenderTable::layout()
}
}
+ // 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;
@@ -480,10 +488,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));
@@ -511,6 +517,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);
@@ -522,19 +537,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
@@ -717,7 +733,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;
@@ -777,12 +793,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()) {
@@ -1172,7 +1182,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())
@@ -1181,12 +1191,12 @@ int RenderTable::getBaselineOfFirstLineBox() const
if (!firstNonEmptySection)
return -1;
- return firstNonEmptySection->y() + 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
@@ -1202,4 +1212,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/WebCore/rendering/RenderTable.h b/WebCore/rendering/RenderTable.h
index e3168cb..2fb7a14 100644
--- a/WebCore/rendering/RenderTable.h
+++ b/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
{
@@ -197,7 +177,7 @@ public:
#endif
protected:
- virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
private:
void recalcSections() const;
@@ -214,9 +194,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/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp
index f5bf358..f5e6ae2 100644
--- a/WebCore/rendering/RenderTableCell.cpp
+++ b/WebCore/rendering/RenderTableCell.cpp
@@ -31,6 +31,7 @@
#include "HTMLTableCellElement.h"
#include "RenderTableCol.h"
#include "RenderView.h"
+#include "TransformState.h"
#ifdef ANDROID_LAYOUT
#include "Document.h"
@@ -68,9 +69,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;
@@ -110,10 +111,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
@@ -141,14 +142,14 @@ void RenderTableCell::updateWidth(int w)
{
if (w != width()) {
setWidth(w);
- m_cellWidthChanged = true;
+ setCellWidthChanged(true);
}
}
void RenderTableCell::layout()
{
- layoutBlock(m_cellWidthChanged);
- m_cellWidthChanged = false;
+ layoutBlock(cellWidthChanged());
+ setCellWidthChanged(false);
}
int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
@@ -167,7 +168,7 @@ void RenderTableCell::setOverrideSize(int size)
RenderBlock::setOverrideSize(size);
}
-IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+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
@@ -182,13 +183,13 @@ IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBox* repaintContain
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));
@@ -215,11 +216,11 @@ IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBox* repaintContain
// repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
r.move(v->layoutDelta());
}
- computeRectForRepaint(r, repaintContainer);
+ computeRectForRepaint(repaintContainer, r);
return r;
}
-void RenderTableCell::computeRectForRepaint(IntRect& r, RenderBox* repaintContainer, bool fixed)
+void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& r, bool fixed)
{
if (repaintContainer == this)
return;
@@ -227,54 +228,48 @@ void RenderTableCell::computeRectForRepaint(IntRect& r, RenderBox* repaintContai
RenderView* v = view();
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(r, repaintContainer, fixed);
+ 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->layoutStateEnabled()) && parent()) {
// Rows are in the same coordinate space, so don't add their offset in.
- localPoint.move(-parentBox()->x(), -parentBox()->y());
+ // 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(parentBox()->x(), parentBox()->y());
+ // FIXME: this is wrong with transforms
+ transformState.move(parentBox()->x(), parentBox()->y());
}
- return localPoint;
}
-FloatQuad RenderTableCell::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
+int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const
{
- if (repaintContainer == this)
- return localQuad;
-
- FloatQuad quad = localQuad;
- if (parent()) {
- // Rows are in the same coordinate space, so don't add their offset in.
- quad.move(-parentBox()->x(), -parentBox()->y());
- }
- return RenderBlock::localToContainerQuad(quad, repaintContainer, 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();
@@ -284,7 +279,7 @@ 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);
@@ -660,22 +655,17 @@ int RenderTableCell::borderHalfBottom(bool outer) const
void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
{
- tx += x();
- ty += 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 + height() + table()->outerBorderBottom() <= paintInfo.rect.y() - os)
- return;
- paintCollapsedBorder(paintInfo.context, tx, ty, width(), height());
- } else {
- if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
- return;
- RenderBlock::paintObject(paintInfo, tx, ty);
- }
+ 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)
@@ -689,7 +679,7 @@ static EBorderStyle collapsedBorderStyle(EBorderStyle style)
struct CollapsedBorder {
CollapsedBorderValue borderValue;
- RenderObject::BorderSide side;
+ BoxSide side;
bool shouldPaint;
int x1;
int y1;
@@ -705,7 +695,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) {
@@ -830,8 +820,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);
}
}
diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h
index 97e2dda..4b09032 100644
--- a/WebCore/rendering/RenderTableCell.h
+++ b/WebCore/rendering/RenderTableCell.h
@@ -99,10 +99,8 @@ public:
void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h);
void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject);
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
- virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, 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 IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
+ virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const;
@@ -120,10 +118,11 @@ public:
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 FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const;
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
+ virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
private:
int m_row;
diff --git a/WebCore/rendering/RenderTableCol.cpp b/WebCore/rendering/RenderTableCol.cpp
index 19538fa..f17963c 100644
--- a/WebCore/rendering/RenderTableCol.cpp
+++ b/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,7 +69,7 @@ bool RenderTableCol::canHaveChildren() const
return style()->display() == TABLE_COLUMN_GROUP;
}
-IntRect RenderTableCol::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/)
+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
@@ -79,7 +79,7 @@ IntRect RenderTableCol::clippedOverflowRectForRepaint(RenderBox* /*repaintContai
if (table && !table->isTable())
table = table->parent();
if (table && table->isTable())
- return table->absoluteClippedOverflowRect();
+ return table->clippedOverflowRectForRepaint(repaintContainer);
return IntRect();
}
diff --git a/WebCore/rendering/RenderTableCol.h b/WebCore/rendering/RenderTableCol.h
index 3472965..8c494b2 100644
--- a/WebCore/rendering/RenderTableCol.h
+++ b/WebCore/rendering/RenderTableCol.h
@@ -28,15 +28,20 @@
#ifndef RenderTableCol_h
#define RenderTableCol_h
-#include "RenderContainer.h"
+#include "RenderBox.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; }
@@ -46,13 +51,14 @@ public:
virtual bool canHaveChildren() const;
virtual bool requiresLayer() const { return false; }
- virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
int span() const { return m_span; }
void setSpan(int s) { m_span = s; }
private:
+ RenderObjectChildList m_children;
int m_span;
};
diff --git a/WebCore/rendering/RenderTableRow.cpp b/WebCore/rendering/RenderTableRow.cpp
index 6b83769..c0603a2 100644
--- a/WebCore/rendering/RenderTableRow.cpp
+++ b/WebCore/rendering/RenderTableRow.cpp
@@ -42,7 +42,7 @@ 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 +52,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,16 +74,16 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
if (!beforeChild && isAfterContent(lastChild()))
beforeChild = lastChild();
- bool isTableRow = element() && element()->hasTagName(trTag);
+ bool isTableRow = node() && node()->hasTagName(trTag);
#if ENABLE(WML)
- if (!isTableRow && element() && element()->isWMLElement())
- isTableRow = element()->hasTagName(WMLNames::trTag);
+ if (!isTableRow && node() && node()->isWMLElement())
+ isTableRow = node()->hasTagName(WMLNames::trTag);
#endif
if (!child->isTableCell()) {
- if (isTableRow && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) {
- RenderContainer::addChild(child, beforeChild);
+ if (isTableRow && child->node() && child->node()->hasTagName(formTag) && document()->isHTMLDocument()) {
+ RenderBox::addChild(child, beforeChild);
return;
}
@@ -121,8 +121,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() || isTableRow && beforeChild->node() && beforeChild->node()->hasTagName(formTag) && document()->isHTMLDocument());
+ RenderBox::addChild(cell, beforeChild);
if (beforeChild || nextSibling())
section()->setNeedsCellRecalc();
@@ -148,7 +148,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,7 +161,7 @@ void RenderTableRow::layout()
setNeedsLayout(false);
}
-IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+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
@@ -183,7 +183,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->isRenderInline() && 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;
}
@@ -194,10 +194,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.
@@ -205,7 +204,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/WebCore/rendering/RenderTableRow.h b/WebCore/rendering/RenderTableRow.h
index 79d32d8..9622480 100644
--- a/WebCore/rendering/RenderTableRow.h
+++ b/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 clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ 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() const { 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/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index ad2bfaf..59fb324 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -47,7 +47,7 @@ namespace WebCore {
using namespace HTMLNames;
RenderTableSection::RenderTableSection(Node* node)
- : RenderContainer(node)
+ : RenderBox(node)
, m_gridRows(0)
, m_cCol(0)
, m_cRow(-1)
@@ -75,7 +75,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.
@@ -89,11 +89,11 @@ 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));
+ bool isTableSection = node() && (node()->hasTagName(theadTag) || node()->hasTagName(tbodyTag) || node()->hasTagName(tfootTag));
if (!child->isTableRow()) {
- if (isTableSection && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) {
- RenderContainer::addChild(child, beforeChild);
+ if (isTableSection && child->node() && child->node()->hasTagName(formTag) && document()->isHTMLDocument()) {
+ RenderBox::addChild(child, beforeChild);
return;
}
@@ -147,8 +147,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() || isTableSection && beforeChild->node() && beforeChild->node()->hasTagName(formTag) && document()->isHTMLDocument());
+ RenderBox::addChild(child, beforeChild);
+}
+
+void RenderTableSection::removeChild(RenderObject* oldChild)
+{
+ setNeedsCellRecalc();
+ RenderBox::removeChild(oldChild);
}
bool RenderTableSection::ensureRows(int numRows)
@@ -242,7 +248,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* 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;
@@ -252,10 +258,8 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* 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()
@@ -425,6 +429,21 @@ int RenderTableSection::calcRowHeight()
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
@@ -598,17 +617,37 @@ 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->isBox() && toRenderBox(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.
@@ -702,14 +741,16 @@ int RenderTableSection::layoutRows(int toAdd)
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, static_cast<RenderTableCell*>(cell)->y() + 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));
+ }
}
}
@@ -718,14 +759,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, static_cast<RenderTableCell*>(cell)->x() + 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));
+ }
}
}
@@ -734,14 +777,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, static_cast<RenderTableCell*>(cell)->x() + 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));
+ }
}
}
@@ -957,7 +1002,7 @@ void RenderTableSection::recalcOuterBorder()
m_outerBorderRight = calcOuterBorderRight(rtl);
}
-int RenderTableSection::getBaselineOfFirstLineBox() const
+int RenderTableSection::firstLineBoxBaseline() const
{
if (!m_gridRows)
return -1;
@@ -994,8 +1039,20 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty)
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();
@@ -1102,10 +1159,10 @@ 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);
}
}
@@ -1190,12 +1247,6 @@ 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 xPos, int yPos, int tx, int ty, HitTestAction action)
{
@@ -1204,12 +1255,15 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
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->isRenderInline() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
+ 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/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h
index 71839d1..5c57714 100644
--- a/WebCore/rendering/RenderTableSection.h
+++ b/WebCore/rendering/RenderTableSection.h
@@ -35,20 +35,28 @@ 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*, RenderTableRow* row);
@@ -99,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; }
@@ -119,17 +129,16 @@ 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;
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index 084be71..2dfdb27 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -36,6 +36,7 @@
#include "RenderView.h"
#include "Text.h"
#include "TextBreakIterator.h"
+#include "VisiblePosition.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>
@@ -60,7 +61,6 @@ RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
, m_maxWidth(-1)
, m_beginMinWidth(0)
, m_endMinWidth(0)
- , m_selectionState(SelectionNone)
, m_hasTab(false)
, m_linesDirty(false)
, m_containsReversedText(false)
@@ -98,13 +98,13 @@ bool RenderText::isWordBreak() const
return false;
}
-void RenderText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* 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 == RenderStyle::Layout)
+ if (diff == StyleDifferenceLayout)
setNeedsLayoutAndPrefWidthsRecalc();
ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
@@ -200,17 +200,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)
{
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
@@ -227,7 +227,7 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne
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());
@@ -241,7 +241,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);
}
@@ -252,10 +252,10 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne
void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool)
{
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
@@ -270,7 +270,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());
@@ -284,7 +284,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)));
}
@@ -313,61 +313,61 @@ InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
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()->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()->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->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->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->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->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->start() + lastBoxAbove->len() : 0, DOWNSTREAM);
+ return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM);
}
IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
@@ -386,7 +386,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
int left = box->positionForOffset(caretOffset);
- int rootLeft = box->root()->xPos();
+ int rootLeft = box->root()->x();
// FIXME: should we use the width of the root inline box or the
// width of the containing block for this?
if (extraWidthToEndOfLine)
@@ -394,14 +394,13 @@ 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);
else
left = max(left, rootLeft);
}
- const int caretWidth = 1;
return IntRect(left, top, caretWidth, height);
}
@@ -709,7 +708,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);
@@ -750,7 +749,7 @@ 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);
@@ -968,7 +967,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();
@@ -979,16 +978,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 unusedIsRootLineBox, bool)
+InlineTextBox* RenderText::createInlineTextBox()
{
- ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox);
-
- InlineTextBox* textBox = createInlineTextBox();
+ InlineTextBox* textBox = createTextBox();
if (!m_firstTextBox)
m_firstTextBox = m_lastTextBox = textBox;
else {
@@ -999,7 +996,7 @@ InlineBox* RenderText::createInlineBox(bool, bool unusedIsRootLineBox, bool)
return textBox;
}
-void RenderText::position(InlineBox* box)
+void RenderText::positionLineBox(InlineBox* box)
{
InlineTextBox* s = static_cast<InlineTextBox*>(box);
@@ -1015,7 +1012,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) const
{
if (from >= textLength())
return 0;
@@ -1026,14 +1023,12 @@ unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bo
return width(from, len, style(firstLine)->font(), xPos);
}
-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) 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())
@@ -1056,36 +1051,35 @@ IntRect RenderText::linesBoundingBox() const
int leftSide = 0;
int rightSide = 0;
for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
- if (curr == firstTextBox() || curr->xPos() < leftSide)
- leftSide = curr->xPos();
- if (curr == firstTextBox() || curr->xPos() + curr->width() > rightSide)
- rightSide = curr->xPos() + curr->width();
+ 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()->yPos() + lastTextBox()->height() - firstTextBox()->yPos());
- result.setY(firstTextBox()->yPos());
+ result.setHeight(lastTextBox()->y() + lastTextBox()->height() - firstTextBox()->y());
+ result.setY(firstTextBox()->y());
}
return result;
}
-IntRect RenderText::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
+IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
RenderObject* cb = containingBlock();
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
@@ -1103,31 +1097,24 @@ 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();
@@ -1161,7 +1148,7 @@ unsigned RenderText::caretMaxRenderedOffset() const
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;
@@ -1169,13 +1156,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;
@@ -1183,6 +1279,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/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h
index 6a09605..649f155 100644
--- a/WebCore/rendering/RenderText.h
+++ b/WebCore/rendering/RenderText.h
@@ -52,21 +52,20 @@ 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 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 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;
@@ -88,21 +87,18 @@ public:
int firstRunX() const;
int firstRunY() const;
- virtual int verticalPositionHint(bool firstLine) 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 clippedOverflowRectForRepaint(RenderBox* repaintContainer);
+ virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
InlineTextBox* firstTextBox() const { return m_firstTextBox; }
InlineTextBox* lastTextBox() const { return m_lastTextBox; }
@@ -112,6 +108,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; }
@@ -122,13 +119,16 @@ public:
void checkConsistency() const;
+ virtual void calcPrefWidths(int leadWidth);
+
protected:
- virtual void styleWillChange(RenderStyle::Diff, const RenderStyle*) { }
- 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:
// Make length() private so that callers that have a RenderText*
@@ -155,7 +155,6 @@ private:
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').
@@ -181,6 +180,9 @@ inline const RenderText* toRenderText(const RenderObject* o)
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/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp
index 642ef1f..38d689b 100644
--- a/WebCore/rendering/RenderTextControl.cpp
+++ b/WebCore/rendering/RenderTextControl.cpp
@@ -31,17 +31,14 @@
#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"
-#ifdef ANDROID_LAYOUT
-#include "FrameView.h"
-#endif
-
using namespace std;
namespace WebCore {
@@ -84,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.
@@ -102,18 +99,34 @@ 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()) {
+ FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(node));
+ ASSERT(formControlElement);
+
+ isEnabled = formControlElement->isEnabled();
+ isReadOnlyControl = formControlElement->isReadOnlyControl();
+ }
+
+ 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()));
}
@@ -142,7 +155,7 @@ int RenderTextControl::textBlockWidth() const
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)
@@ -236,7 +249,7 @@ void RenderTextControl::setSelectionRange(int start, int end)
ASSERT(startPosition.isNotNull() && endPosition.isNotNull());
ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node());
- Selection newSelection = Selection(startPosition, endPosition);
+ VisibleSelection newSelection = VisibleSelection(startPosition, endPosition);
if (Frame* frame = document()->frame())
frame->selection()->setSelection(newSelection);
@@ -247,10 +260,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)
@@ -279,7 +292,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.m_offset, ec);
ASSERT(!ec);
return TextIterator::rangeLength(range.get());
}
@@ -367,7 +380,7 @@ String RenderTextControl::textWithHardLineBreaks()
if (!renderer)
return "";
- InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
+ InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : toRenderBox(renderer)->inlineBoxWrapper();
if (!box)
return "";
@@ -434,15 +447,16 @@ void RenderTextControl::calcHeight()
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))
+ if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
setHeight(height() + scrollbarThickness());
RenderBlock::calcHeight();
}
-void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int xPos, int yPos, int tx, int ty)
+void RenderTextControl::hitInnerTextElement(HitTestResult& result, int xPos, int yPos, int tx, int ty)
{
result.setInnerNode(m_innerText.get());
+ result.setInnerNonSharedNode(m_innerText.get());
result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(),
yPos - ty - y() - m_innerText->renderBox()->y()));
}
@@ -517,7 +531,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()->dispatchEventForType(eventNames().selectEvent, true, false);
}
}
@@ -526,61 +540,6 @@ void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int
graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
}
-void RenderTextControl::autoscroll()
-{
- RenderLayer* layer = m_innerText->renderBox()->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->renderBox()->layer();
- if (layer && layer->scroll(direction, granularity, multiplier))
- return true;
- return RenderBlock::scroll(direction, granularity, multiplier);
-}
-
HTMLElement* RenderTextControl::innerTextElement() const
{
return m_innerText.get();
diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h
index 86d3f8a..e4f7747 100644
--- a/WebCore/rendering/RenderTextControl.h
+++ b/WebCore/rendering/RenderTextControl.h
@@ -27,7 +27,7 @@
namespace WebCore {
class FormControlElement;
-class Selection;
+class VisibleSelection;
class TextControlInnerElement;
class TextControlInnerTextElement;
@@ -36,6 +36,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 +46,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 +58,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,16 +68,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);
VisiblePosition visiblePositionForIndex(int index);
int indexForVisiblePosition(const VisiblePosition&);
@@ -88,10 +79,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;
@@ -115,6 +106,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/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp
index 253f53f..271fb12 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.cpp
+++ b/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -55,54 +55,15 @@ void RenderTextControlMultiLine::subtreeHasChanged()
frame->textDidChangeInTextArea(static_cast<Element*>(node()));
}
-void RenderTextControlMultiLine::layout()
-{
- int oldHeight = height();
- calcHeight();
-
-#ifdef ANDROID_LAYOUT
- int oldVisibleWidth = m_visibleWidth;
-#endif
-
- int oldWidth = width();
- calcWidth();
-
- bool relayoutChildren = oldHeight != height() || oldWidth != width();
-#ifdef ANDROID_LAYOUT
- if (oldVisibleWidth != m_visibleWidth
- && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
- relayoutChildren = true;
- }
-#endif
-
- RenderBox* innerTextRenderer = innerTextElement()->renderBox();
-
- // 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)
@@ -146,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);
diff --git a/WebCore/rendering/RenderTextControlMultiLine.h b/WebCore/rendering/RenderTextControlMultiLine.h
index 591a65d..579047d 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.h
+++ b/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/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp
index fccea00..dd06501 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -174,8 +174,8 @@ void RenderTextControlSingleLine::subtreeHasChanged()
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->searchEventsShouldBeDispatched())
@@ -281,12 +281,14 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit
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, xPos, yPos, 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;
@@ -334,7 +336,7 @@ void RenderTextControlSingleLine::forwardEvent(Event* event)
return;
}
- FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true);
+ 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->borderBoxRect().right())
@@ -343,7 +345,7 @@ void RenderTextControlSingleLine::forwardEvent(Event* event)
RenderTextControl::forwardEvent(event);
}
-void RenderTextControlSingleLine::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderTextControl::styleDidChange(diff, oldStyle);
@@ -360,6 +362,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()
@@ -425,7 +429,7 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight)
{
if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) {
- static_cast<RenderBlock*>(resultsRenderer)->calcHeight();
+ toRenderBlock(resultsRenderer)->calcHeight();
setHeight(max(height(),
resultsRenderer->borderTop() + resultsRenderer->borderBottom() +
resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() +
@@ -434,7 +438,7 @@ void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineH
}
if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) {
- static_cast<RenderBlock*>(cancelRenderer)->calcHeight();
+ toRenderBlock(cancelRenderer)->calcHeight();
setHeight(max(height(),
cancelRenderer->borderTop() + cancelRenderer->borderBottom() +
cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() +
@@ -482,8 +486,8 @@ void RenderTextControlSingleLine::updateFromElement()
bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible();
m_placeholderVisible = placeholderShouldBeVisible();
- if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
- updateCancelButtonVisibility(cancelButtonRenderer->style());
+ if (m_cancelButton)
+ updateCancelButtonVisibility();
if (m_placeholderVisible) {
ExceptionCode ec = 0;
@@ -505,7 +509,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const
{
RefPtr<RenderStyle> textBlockStyle;
if (placeholderShouldBeVisible()) {
- RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::INPUT_PLACEHOLDER);
+ RenderStyle* pseudoStyle = getCachedPseudoStyle(INPUT_PLACEHOLDER);
textBlockStyle = RenderStyle::clone(pseudoStyle);
} else {
textBlockStyle = RenderStyle::create();
@@ -562,11 +566,11 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(co
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();
@@ -582,7 +586,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(con
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
@@ -591,15 +595,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
@@ -684,7 +703,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
@@ -768,10 +787,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
diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h
index a7b58e1..23352b4 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.h
+++ b/WebCore/rendering/RenderTextControlSingleLine.h
@@ -59,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);
@@ -69,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();
diff --git a/WebCore/rendering/RenderTextFragment.cpp b/WebCore/rendering/RenderTextFragment.cpp
index c8beba0..7da9e5a 100644
--- a/WebCore/rendering/RenderTextFragment.cpp
+++ b/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/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp
index e7fa5de..f82f48c 100644
--- a/WebCore/rendering/RenderTheme.cpp
+++ b/WebCore/rendering/RenderTheme.cpp
@@ -581,7 +581,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;
@@ -598,28 +598,43 @@ 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;
- return o->element()->isChecked();
+
+ InputElement* inputElement = toInputElement(static_cast<Element*>(o->node()));
+ if (!inputElement)
+ return false;
+
+ 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())
+ if (!o->node() || !o->node()->isElementNode())
+ return true;
+
+ FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(o->node()));
+ if (!formControlElement)
return true;
- return o->element()->isEnabled();
+
+ return formControlElement->isEnabled();
}
bool RenderTheme::isFocused(const RenderObject* o) const
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
Document* document = node->document();
@@ -629,23 +644,28 @@ 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())
+ if (!o->node() || !o->node()->isElementNode())
+ return false;
+
+ FormControlElement* formControlElement = toFormControlElement(static_cast<Element*>(o->node()));
+ if (!formControlElement)
return false;
- return o->element()->isReadOnlyControl();
+
+ return formControlElement->isReadOnlyControl();
}
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
@@ -721,10 +741,6 @@ void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Ele
{
}
-void RenderTheme::adjustButtonInnerStyle(RenderStyle*) const
-{
-}
-
void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const
{
}
diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h
index 828e789..15a81fa 100644
--- a/WebCore/rendering/RenderTheme.h
+++ b/WebCore/rendering/RenderTheme.h
@@ -29,6 +29,7 @@
#else
#include "ThemeTypes.h"
#endif
+#include "ScrollTypes.h"
namespace WebCore {
@@ -128,14 +129,21 @@ 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; };
diff --git a/WebCore/rendering/RenderThemeChromiumGtk.cpp b/WebCore/rendering/RenderThemeChromiumGtk.cpp
deleted file mode 100644
index 220ce07..0000000
--- a/WebCore/rendering/RenderThemeChromiumGtk.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * 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 "RenderThemeChromiumGtk.h"
-
-#include "ChromiumBridge.h"
-#include "CSSValueKeywords.h"
-#include "GraphicsContext.h"
-#include "NotImplemented.h"
-#include "PlatformContextSkia.h"
-#include "RenderObject.h"
-#include "ScrollbarTheme.h"
-#include "gtkdrawing.h"
-#include "GdkSkia.h"
-#include "TransformationMatrix.h"
-#include "UserAgentStyleSheets.h"
-
-#include <gdk/gdk.h>
-
-namespace WebCore {
-
-enum PaddingType {
- TopPadding,
- RightPadding,
- BottomPadding,
- LeftPadding
-};
-
-static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
-
-// 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 = 16.0;
-
-static Color makeColor(const GdkColor& c)
-{
- return Color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8));
-}
-
-// 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.
-static const char* defaultGUIFont(Document* document)
-{
- return "Arial";
-}
-
-// Converts points to pixels. One point is 1/72 of an inch.
-static float pointsToPixels(float points)
-{
- static float pixelsPerInch = 0.0f;
- if (!pixelsPerInch) {
- GdkScreen* screen = gdk_screen_get_default();
- // FIXME: I'm getting floating point values of ~75 and ~100,
- // and it's making my fonts look all wrong. Figure this out.
-#if 0
- if (screen)
- pixelsPerInch = gdk_screen_get_resolution(screen);
- else
-#endif
- pixelsPerInch = 96.0f; // Match the default we set on Windows.
- }
-
- static const float pointsPerInch = 72.0f;
- return points / pointsPerInch * pixelsPerInch;
-}
-
-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));
-}
-
-static bool supportsFocus(ControlPart appearance)
-{
- switch (appearance) {
- case PushButtonPart:
- case ButtonPart:
- case TextFieldPart:
- case TextAreaPart:
- case SearchFieldPart:
- case MenulistPart:
- case RadioPart:
- case CheckboxPart:
- return true;
- default:
- return false;
- }
-}
-
-static GtkTextDirection gtkTextDirection(TextDirection direction)
-{
- switch (direction) {
- case RTL:
- return GTK_TEXT_DIR_RTL;
- case LTR:
- return GTK_TEXT_DIR_LTR;
- default:
- return GTK_TEXT_DIR_NONE;
- }
-}
-
-static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject* o)
-{
- state->active = theme->isPressed(o);
- state->focused = theme->isFocused(o);
- state->inHover = theme->isHovered(o);
- // FIXME: Disabled does not always give the correct appearance for ReadOnly
- state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o);
- state->isDefault = false;
- state->canDefault = false;
- state->depressed = false;
-}
-
-static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- // Painting is disabled so just claim to have succeeded
- if (i.context->paintingDisabled())
- return false;
-
- GtkWidgetState mozState;
- setMozState(theme, &mozState, o);
-
- int flags;
-
- // We might want to make setting flags the caller's job at some point rather than doing it here.
- switch (type) {
- case MOZ_GTK_BUTTON:
- flags = GTK_RELIEF_NORMAL;
- break;
- case MOZ_GTK_CHECKBUTTON:
- case MOZ_GTK_RADIOBUTTON:
- flags = theme->isChecked(o);
- break;
- default:
- flags = 0;
- break;
- }
-
- PlatformContextSkia* pcs = i.context->platformContext();
- SkCanvas* canvas = pcs->canvas();
- if (!canvas)
- return false;
-
- GdkRectangle gdkRect;
- gdkRect.x = rect.x();
- gdkRect.y = rect.y();
- gdkRect.width = rect.width();
- gdkRect.height = rect.height();
-
- // getTotalClip returns the currently set clip region in device coordinates,
- // so we have to apply the current transform (actually we only support translations)
- // to get the page coordinates that our gtk widget rendering expects.
- // We invert it because we want to map from device coordinates to page coordinates.
- const SkIRect clipRegion = canvas->getTotalClip().getBounds();
- TransformationMatrix ctm = i.context->getCTM().inverse();
- IntPoint pos = ctm.mapPoint(IntPoint(SkScalarRound(clipRegion.fLeft), SkScalarRound(clipRegion.fTop)));
- GdkRectangle gdkClipRect;
- gdkClipRect.x = pos.x();
- gdkClipRect.y = pos.y();
- gdkClipRect.width = clipRegion.width();
- gdkClipRect.height = clipRegion.height();
-
- // moz_gtk_widget_paint will paint outside the bounds of gdkRect unless we further restrict |gdkClipRect|.
- gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);
-
- GtkTextDirection direction = gtkTextDirection(o->style()->direction());
-
- return moz_gtk_widget_paint(type, pcs->gdk_skia(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
-}
-
-static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme)
-{
- // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal.
- renderTheme->platformColorsDidChange();
-}
-
-static double querySystemBlinkInterval(double defaultInterval)
-{
- GtkSettings* settings = gtk_settings_get_default();
-
- gboolean shouldBlink;
- gint time;
-
- g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL);
-
- if (!shouldBlink)
- return 0;
-
- return time / 1000.0;
-}
-
-// Implement WebCore::theme() for getting the global RenderTheme.
-RenderTheme* theme()
-{
- static RenderThemeChromiumGtk gtkTheme;
- return &gtkTheme;
-}
-
-RenderThemeChromiumGtk::RenderThemeChromiumGtk()
- : m_gtkWindow(0)
- , m_gtkContainer(0)
- , m_gtkEntry(0)
- , m_gtkTreeView(0)
-{
-}
-
-// Use the Windows style sheets to match their metrics.
-String RenderThemeChromiumGtk::extraDefaultStyleSheet()
-{
- return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
-}
-
-String RenderThemeChromiumGtk::extraQuirksStyleSheet()
-{
- return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
-}
-
-bool RenderThemeChromiumGtk::supportsFocusRing(const RenderStyle* style) const
-{
- return supportsFocus(style->appearance());
-}
-
-Color RenderThemeChromiumGtk::platformActiveSelectionBackgroundColor() const
-{
- GtkWidget* widget = gtkEntry();
- return makeColor(widget->style->base[GTK_STATE_SELECTED]);
-}
-
-Color RenderThemeChromiumGtk::platformInactiveSelectionBackgroundColor() const
-{
- GtkWidget* widget = gtkEntry();
- return makeColor(widget->style->base[GTK_STATE_ACTIVE]);
-}
-
-Color RenderThemeChromiumGtk::platformActiveSelectionForegroundColor() const
-{
- GtkWidget* widget = gtkEntry();
- return makeColor(widget->style->text[GTK_STATE_SELECTED]);
-}
-
-Color RenderThemeChromiumGtk::platformInactiveSelectionForegroundColor() const
-{
- GtkWidget* widget = gtkEntry();
- return makeColor(widget->style->text[GTK_STATE_ACTIVE]);
-}
-
-Color RenderThemeChromiumGtk::platformTextSearchHighlightColor() const
-{
- return Color(255, 255, 150);
-}
-
-double RenderThemeChromiumGtk::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;
-
- // We cache the interval so we don't have to repeatedly request it from gtk.
- static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
- return blinkInterval;
-}
-
-void RenderThemeChromiumGtk::systemFont(int propId, Document* document, FontDescription& fontDescription) const
-{
- const char* faceName = 0;
- float fontSize = 0;
- // FIXME: see also RenderThemeChromiumWin.cpp
- switch (propId) {
- case CSSValueMenu:
- case CSSValueStatusBar:
- case CSSValueSmallCaption:
- // triggered by LayoutTests/fast/css/css2-system-fonts.html
- notImplemented();
- break;
- case CSSValueWebkitMiniControl:
- case CSSValueWebkitSmallControl:
- case CSSValueWebkitControl:
- faceName = defaultGUIFont(document);
- // Why 2 points smaller? Because that's what Gecko does.
- fontSize = DefaultFontSize - pointsToPixels(2);
- break;
- default:
- faceName = defaultGUIFont(document);
- fontSize = DefaultFontSize;
- }
-
- // Only update if the size makes sense.
- if (fontSize > 0) {
- fontDescription.firstFamily().setFamily(faceName);
- fontDescription.setSpecifiedSize(fontSize);
- fontDescription.setIsAbsoluteSize(true);
- fontDescription.setGenericFamily(FontDescription::NoFamily);
- fontDescription.setWeight(FontWeightNormal);
- fontDescription.setItalic(false);
- }
-}
-
-int RenderThemeChromiumGtk::minimumMenuListSize(RenderStyle* style) const
-{
- return 0;
-}
-
-bool RenderThemeChromiumGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect);
-}
-
-void RenderThemeChromiumGtk::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 RenderThemeChromiumGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect);
-}
-
-void RenderThemeChromiumGtk::setRadioSize(RenderStyle* style) const
-{
- // Use same sizing for radio box as checkbox.
- setCheckboxSize(style);
-}
-
-bool RenderThemeChromiumGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_BUTTON, o, i, rect);
-}
-
-bool RenderThemeChromiumGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_ENTRY, o, i, rect);
-}
-
-bool RenderThemeChromiumGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintTextField(o, i, rect);
-}
-
-bool RenderThemeChromiumGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
-}
-
-bool RenderThemeChromiumGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect);
-}
-
-bool RenderThemeChromiumGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
-}
-
-void RenderThemeChromiumGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
-{
- // Height is locked to auto on all browsers.
- style->setLineHeight(RenderStyle::initialLineHeight());
-}
-
-bool RenderThemeChromiumGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
-{
- return paintMozWidget(this, MOZ_GTK_DROPDOWN, o, i, rect);
-}
-
-void RenderThemeChromiumGtk::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 RenderThemeChromiumGtk::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
-{
- return paintMenuList(o, i, r);
-}
-
-int RenderThemeChromiumGtk::popupInternalPaddingLeft(RenderStyle* style) const
-{
- return menuListInternalPadding(style, LeftPadding);
-}
-
-int RenderThemeChromiumGtk::popupInternalPaddingRight(RenderStyle* style) const
-{
- return menuListInternalPadding(style, RightPadding);
-}
-
-int RenderThemeChromiumGtk::popupInternalPaddingTop(RenderStyle* style) const
-{
- return menuListInternalPadding(style, TopPadding);
-}
-
-int RenderThemeChromiumGtk::popupInternalPaddingBottom(RenderStyle* style) const
-{
- return menuListInternalPadding(style, BottomPadding);
-}
-
-void RenderThemeChromiumGtk::adjustButtonInnerStyle(RenderStyle* style) 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));
-}
-
-bool RenderThemeChromiumGtk::controlSupportsTints(const RenderObject* o) const
-{
- return isEnabled(o);
-}
-
-Color RenderThemeChromiumGtk::activeListBoxSelectionBackgroundColor() const
-{
- GtkWidget* widget = gtkTreeView();
- return makeColor(widget->style->base[GTK_STATE_SELECTED]);
-}
-
-Color RenderThemeChromiumGtk::activeListBoxSelectionForegroundColor() const
-{
- GtkWidget* widget = gtkTreeView();
- return makeColor(widget->style->text[GTK_STATE_SELECTED]);
-}
-
-Color RenderThemeChromiumGtk::inactiveListBoxSelectionBackgroundColor() const
-{
- GtkWidget* widget = gtkTreeView();
- return makeColor(widget->style->base[GTK_STATE_ACTIVE]);
-}
-
-Color RenderThemeChromiumGtk::inactiveListBoxSelectionForegroundColor() const
-{
- GtkWidget* widget = gtkTreeView();
- return makeColor(widget->style->text[GTK_STATE_ACTIVE]);
-}
-
-GtkWidget* RenderThemeChromiumGtk::gtkEntry() const
-{
- if (m_gtkEntry)
- return m_gtkEntry;
-
- m_gtkEntry = gtk_entry_new();
- g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), theme());
- gtk_container_add(gtkContainer(), m_gtkEntry);
- gtk_widget_realize(m_gtkEntry);
-
- return m_gtkEntry;
-}
-
-GtkWidget* RenderThemeChromiumGtk::gtkTreeView() const
-{
- if (m_gtkTreeView)
- return m_gtkTreeView;
-
- m_gtkTreeView = gtk_tree_view_new();
- g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), theme());
- gtk_container_add(gtkContainer(), m_gtkTreeView);
- gtk_widget_realize(m_gtkTreeView);
-
- return m_gtkTreeView;
-}
-
-GtkContainer* RenderThemeChromiumGtk::gtkContainer() const
-{
- if (m_gtkContainer)
- return m_gtkContainer;
-
- m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
- m_gtkContainer = GTK_CONTAINER(gtk_fixed_new());
- gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer));
- gtk_widget_realize(m_gtkWindow);
-
- return m_gtkContainer;
-}
-
-int RenderThemeChromiumGtk::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 bar_type = style->direction() == LTR ? RightPadding : LeftPadding;
- if (paddingType == bar_type && style->appearance() != NoControlPart)
- padding += ScrollbarTheme::nativeTheme()->scrollbarThickness();
-
- return padding;
-}
-
-} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeChromiumLinux.cpp b/WebCore/rendering/RenderThemeChromiumLinux.cpp
new file mode 100644
index 0000000..8c6874d
--- /dev/null
+++ b/WebCore/rendering/RenderThemeChromiumLinux.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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 "RenderThemeChromiumLinux.h"
+
+#include "ChromiumBridge.h"
+#include "CSSValueKeywords.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.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 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 const float DefaultFontSize = 16.0;
+
+static bool supportsFocus(ControlPart appearance)
+{
+ // This causes WebKit to draw the focus rings for us.
+ return false;
+}
+
+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));
+}
+
+// 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.
+static const char* defaultGUIFont(Document* document)
+{
+ return "Arial";
+}
+
+RenderTheme* theme()
+{
+ static RenderThemeChromiumLinux theme;
+ return &theme;
+}
+
+RenderThemeChromiumLinux::RenderThemeChromiumLinux()
+{
+}
+
+// Use the Windows style sheets to match their metrics.
+String RenderThemeChromiumLinux::extraDefaultStyleSheet()
+{
+ return String(themeChromiumWinUserAgentStyleSheet, sizeof(themeChromiumWinUserAgentStyleSheet));
+}
+
+String RenderThemeChromiumLinux::extraQuirksStyleSheet()
+{
+ return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
+}
+
+bool RenderThemeChromiumLinux::supportsFocusRing(const RenderStyle* style) const
+{
+ return supportsFocus(style->appearance());
+}
+
+Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const
+{
+ return Color(0x1e, 0x90, 0xff);
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const
+{
+ return Color(0xc8, 0xc8, 0xc8);
+}
+
+Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const
+{
+ return Color(0, 0, 0);
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const
+{
+ return Color(0x32, 0x32, 0x32);
+}
+
+Color RenderThemeChromiumLinux::platformTextSearchHighlightColor() const
+{
+ return Color(0xff, 0xff, 0x96);
+}
+
+double RenderThemeChromiumLinux::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;
+
+ // We cache the interval so we don't have to repeatedly request it from gtk.
+ return 0.5;
+}
+
+void RenderThemeChromiumLinux::systemFont(int propId, Document* document, 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(NULL));
+ fontDescription.setSpecifiedSize(fontSize);
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::NoFamily);
+ fontDescription.setWeight(FontWeightNormal);
+ fontDescription.setItalic(false);
+}
+
+int RenderThemeChromiumLinux::minimumMenuListSize(RenderStyle* style) const
+{
+ return 0;
+}
+
+bool RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::setRadioSize(RenderStyle* style) const
+{
+ // Use same sizing for radio box as checkbox.
+ setCheckboxSize(style);
+}
+
+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();
+
+ // If the button is too small, fallback to drawing a single, solid color
+ if (rect.width() < 5 || rect.height() < 5) {
+ paint.setARGB(0xff, 0xe9, 0xe9, 0xe9);
+ 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] = SkColorSetARGB(0xff, 0xf8, 0xf8, 0xf8);
+ colors[1] = SkColorSetARGB(0xff, 0xdd, 0xdd, 0xdd);
+
+ SkShader* s = SkGradientShader::CreateLinear(
+ p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setShader(s);
+ s->unref();
+
+ skrect.set(rect.x() + 1, rect.y() + 1, right - 1, bottom - 1);
+ canvas->drawRect(skrect, paint);
+
+ paint.setShader(NULL);
+ paint.setARGB(0xff, 0xce, 0xce, 0xce);
+ 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 RenderThemeChromiumLinux::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ paintButtonLike(this, o, i, rect);
+ return false;
+}
+
+bool RenderThemeChromiumLinux::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return true;
+}
+
+bool RenderThemeChromiumLinux::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return true;
+}
+
+bool RenderThemeChromiumLinux::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return true;
+}
+
+bool RenderThemeChromiumLinux::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return true;
+}
+
+bool RenderThemeChromiumLinux::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return true;
+}
+
+void RenderThemeChromiumLinux::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+{
+ // Height is locked to auto on all browsers.
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
+bool RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ return paintMenuList(o, i, rect);
+}
+
+int RenderThemeChromiumLinux::popupInternalPaddingLeft(RenderStyle* style) const
+{
+ return menuListInternalPadding(style, LeftPadding);
+}
+
+int RenderThemeChromiumLinux::popupInternalPaddingRight(RenderStyle* style) const
+{
+ return menuListInternalPadding(style, RightPadding);
+}
+
+int RenderThemeChromiumLinux::popupInternalPaddingTop(RenderStyle* style) const
+{
+ return menuListInternalPadding(style, TopPadding);
+}
+
+int RenderThemeChromiumLinux::popupInternalPaddingBottom(RenderStyle* style) const
+{
+ return menuListInternalPadding(style, BottomPadding);
+}
+
+int RenderThemeChromiumLinux::buttonInternalPaddingLeft() const
+{
+ return 3;
+}
+
+int RenderThemeChromiumLinux::buttonInternalPaddingRight() const
+{
+ return 3;
+}
+
+int RenderThemeChromiumLinux::buttonInternalPaddingTop() const
+{
+ return 1;
+}
+
+int RenderThemeChromiumLinux::buttonInternalPaddingBottom() const
+{
+ return 1;
+}
+
+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(0, 0, 0);
+}
+
+Color RenderThemeChromiumLinux::inactiveListBoxSelectionBackgroundColor() const
+{
+ return Color(0xc8, 0xc8, 0xc8);
+}
+
+Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const
+{
+ return Color(0x32, 0x32, 0x32);
+}
+
+int RenderThemeChromiumLinux::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 bar_type = style->direction() == LTR ? RightPadding : LeftPadding;
+ if (paddingType == bar_type && style->appearance() != NoControlPart)
+ padding += ScrollbarTheme::nativeTheme()->scrollbarThickness();
+
+ return padding;
+}
+
+} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeChromiumGtk.h b/WebCore/rendering/RenderThemeChromiumLinux.h
index 77d927f..dbe8dcc 100644
--- a/WebCore/rendering/RenderThemeChromiumGtk.h
+++ b/WebCore/rendering/RenderThemeChromiumLinux.h
@@ -25,19 +25,17 @@
*
*/
-#ifndef RenderThemeChromiumGtk_h
-#define RenderThemeChromiumGtk_h
+#ifndef RenderThemeChromiumLinux_h
+#define RenderThemeChromiumLinux_h
#include "RenderTheme.h"
-#include <gtk/gtk.h>
-
namespace WebCore {
- class RenderThemeChromiumGtk : public RenderTheme {
+ class RenderThemeChromiumLinux : public RenderTheme {
public:
- RenderThemeChromiumGtk();
- ~RenderThemeChromiumGtk() { }
+ RenderThemeChromiumLinux();
+ ~RenderThemeChromiumLinux() { }
virtual String extraDefaultStyleSheet();
virtual String extraQuirksStyleSheet();
@@ -100,7 +98,10 @@ namespace WebCore {
virtual int popupInternalPaddingTop(RenderStyle*) const;
virtual int popupInternalPaddingBottom(RenderStyle*) const;
- virtual void adjustButtonInnerStyle(RenderStyle* style) const;
+ virtual int buttonInternalPaddingLeft() const;
+ virtual int buttonInternalPaddingRight() const;
+ virtual int buttonInternalPaddingTop() const;
+ virtual int buttonInternalPaddingBottom() const;
// A method asking if the control changes its tint when the window has focus or not.
virtual bool controlSupportsTints(const RenderObject*) const;
@@ -115,20 +116,7 @@ namespace WebCore {
virtual Color inactiveListBoxSelectionForegroundColor() const;
private:
- // Hold the state
- GtkWidget* gtkEntry() const;
- GtkWidget* gtkTreeView() const;
-
- // Unmapped GdkWindow having a container. This is holding all our fake widgets
- GtkContainer* gtkContainer() const;
-
- private:
int menuListInternalPadding(RenderStyle*, int paddingType) const;
-
- mutable GtkWidget* m_gtkWindow;
- mutable GtkContainer* m_gtkContainer;
- mutable GtkWidget* m_gtkEntry;
- mutable GtkWidget* m_gtkTreeView;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeChromiumMac.h b/WebCore/rendering/RenderThemeChromiumMac.h
index b750213..29286d8 100644
--- a/WebCore/rendering/RenderThemeChromiumMac.h
+++ b/WebCore/rendering/RenderThemeChromiumMac.h
@@ -25,6 +25,7 @@
#define RenderThemeChromiumMac_h
#import "RenderTheme.h"
+#import <AppKit/AppKit.h>
#import <wtf/HashMap.h>
#import <wtf/RetainPtr.h>
@@ -77,6 +78,8 @@ namespace WebCore {
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;
diff --git a/WebCore/rendering/RenderThemeChromiumMac.mm b/WebCore/rendering/RenderThemeChromiumMac.mm
index 6318fd9..1eef0cb 100644
--- a/WebCore/rendering/RenderThemeChromiumMac.mm
+++ b/WebCore/rendering/RenderThemeChromiumMac.mm
@@ -565,7 +565,7 @@ void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject
void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o)
{
bool oldPressed = [cell isHighlighted];
- bool pressed = (o->element() && o->element()->active());
+ bool pressed = (o->node() && o->node()->active());
if (pressed != oldPressed)
[cell setHighlighted:pressed];
}
@@ -573,8 +573,13 @@ void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject
// 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->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
- return o->marginTop() + o->height() - 2 * o->style()->effectiveZoom(); // 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 * o->style()->effectiveZoom(); // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
+ }
return RenderTheme::baselinePosition(o);
}
@@ -1311,7 +1316,11 @@ void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, Ren
// 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);
+ bool isEnabled = true;
+ if (FormControlElement* formControlElement = toFormControlElement(e))
+ isEnabled = formControlElement->isEnabled();
+
+ style->setColor(isEnabled ? static_cast<RGBA32>(Color::black) : Color::darkGray);
// Set the button's vertical size.
setSizeFromFont(style, menuListButtonSizes());
diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp
index c304385..30f421b 100644
--- a/WebCore/rendering/RenderThemeChromiumWin.cpp
+++ b/WebCore/rendering/RenderThemeChromiumWin.cpp
@@ -35,9 +35,11 @@
#include "FontSelector.h"
#include "FontUtilsChromiumWin.h"
#include "GraphicsContext.h"
+#include "RenderBox.h"
+#include "RenderSlider.h"
#include "ScrollbarTheme.h"
#include "SkiaUtils.h"
-#include "ThemeHelperChromiumWin.h"
+#include "TransparencyWin.h"
#include "UserAgentStyleSheets.h"
#include "WindowsVersion.h"
@@ -52,6 +54,52 @@
namespace WebCore {
+namespace {
+
+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.
+}
+
+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 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;
@@ -89,6 +137,7 @@ static bool supportsFocus(ControlPart appearance)
case PushButtonPart:
case ButtonPart:
case DefaultButtonPart:
+ case SearchFieldPart:
case TextFieldPart:
case TextAreaPart:
return true;
@@ -212,7 +261,7 @@ RenderTheme* theme()
String RenderThemeChromiumWin::extraDefaultStyleSheet()
{
- return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
+ return String(themeChromiumWinUserAgentStyleSheet, sizeof(themeChromiumWinUserAgentStyleSheet));
}
String RenderThemeChromiumWin::extraQuirksStyleSheet()
@@ -347,6 +396,20 @@ int RenderThemeChromiumWin::minimumMenuListSize(RenderStyle* style) const
return 0;
}
+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));
+ }
+}
+
void RenderThemeChromiumWin::setCheckboxSize(RenderStyle* style) const
{
// If the width and height are both specified, then we have nothing to do.
@@ -372,12 +435,12 @@ bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::Pa
{
const ThemeData& themeData = getThemeData(o);
- WebCore::ThemeHelperWin helper(i.context, r);
- ChromiumBridge::paintButton(helper.context(),
+ WebCore::ThemePainter painter(i.context, r);
+ ChromiumBridge::paintButton(painter.context(),
themeData.m_part,
themeData.m_state,
themeData.m_classicState,
- helper.rect());
+ painter.drawRect());
return false;
}
@@ -386,6 +449,19 @@ bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const RenderObject:
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::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
@@ -400,10 +476,14 @@ void RenderThemeChromiumWin::adjustMenuListStyle(CSSStyleSelector* selector, Ren
// Used to paint unstyled menulists (i.e. with the default border)
bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
- int borderRight = o->borderRight();
- int borderLeft = o->borderLeft();
- int borderTop = o->borderTop();
- int borderBottom = o->borderBottom();
+ 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
@@ -418,10 +498,10 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::
// 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 + o->paddingLeft();
- int spacingRight = borderRight + o->paddingRight();
- int spacingTop = borderTop + o->paddingTop();
- int spacingBottom = borderBottom + o->paddingBottom();
+ 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)
@@ -436,12 +516,12 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::
r.height() - (spacingTop + spacingBottom));
// Get the correct theme data for a textfield and paint the menu.
- WebCore::ThemeHelperWin helper(i.context, rect);
- ChromiumBridge::paintMenuList(helper.context(),
+ WebCore::ThemePainter painter(i.context, rect);
+ ChromiumBridge::paintMenuList(painter.context(),
CP_DROPDOWNBUTTON,
determineState(o),
determineClassicState(o),
- helper.rect());
+ painter.drawRect());
return false;
}
@@ -476,13 +556,24 @@ int RenderThemeChromiumWin::popupInternalPaddingBottom(RenderStyle* style) const
return menuListInternalPadding(style, BottomPadding);
}
-void RenderThemeChromiumWin::adjustButtonInnerStyle(RenderStyle* style) const
+int RenderThemeChromiumWin::buttonInternalPaddingLeft() const
+{
+ return 3;
+}
+
+int RenderThemeChromiumWin::buttonInternalPaddingRight() const
+{
+ return 3;
+}
+
+int RenderThemeChromiumWin::buttonInternalPaddingTop() const
+{
+ return 1;
+}
+
+int RenderThemeChromiumWin::buttonInternalPaddingBottom() 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 1;
}
// static
@@ -499,7 +590,7 @@ unsigned RenderThemeChromiumWin::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 = ETS_READONLY; // Readonly is supported on textfields.
else if (isPressed(o)) // Active overrides hover and focused.
result = TS_PRESSED;
@@ -512,6 +603,20 @@ unsigned RenderThemeChromiumWin::determineState(RenderObject* o)
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;
@@ -530,37 +635,57 @@ ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o)
{
ThemeData result;
switch (o->style()->appearance()) {
- case PushButtonPart:
- case ButtonPart:
- result.m_part = BP_PUSHBUTTON;
- result.m_classicState = DFCS_BUTTONPUSH;
- break;
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 = ETS_NORMAL;
+ result.m_part = EP_EDITTEXT;
+ result.m_state = determineState(o);
break;
}
- result.m_state = determineState(o);
result.m_classicState |= determineClassicState(o);
return result;
}
bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
- const RenderObject::PaintInfo& i,
- const IntRect& r,
- bool drawEdges)
+ 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.
@@ -572,12 +697,12 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
const ThemeData& themeData = getThemeData(o);
- WebCore::ThemeHelperWin helper(i.context, r);
- ChromiumBridge::paintTextField(helper.context(),
+ WebCore::ThemePainter painter(i.context, r);
+ ChromiumBridge::paintTextField(painter.context(),
themeData.m_part,
themeData.m_state,
themeData.m_classicState,
- helper.rect(),
+ painter.drawRect(),
o->style()->backgroundColor(),
true,
drawEdges);
diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h
index 2d335c2..f1ef306 100644
--- a/WebCore/rendering/RenderThemeChromiumWin.h
+++ b/WebCore/rendering/RenderThemeChromiumWin.h
@@ -70,6 +70,8 @@ namespace WebCore {
virtual int minimumMenuListSize(RenderStyle*) const;
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+
virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); }
virtual void setCheckboxSize(RenderStyle*) const;
@@ -82,6 +84,10 @@ namespace WebCore {
virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); }
+ virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintSliderTrack(o, i, r); }
+
virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
// MenuList refers to an unstyled menulist (meaning a menulist without
@@ -104,7 +110,10 @@ namespace WebCore {
virtual int popupInternalPaddingTop(RenderStyle*) const;
virtual int popupInternalPaddingBottom(RenderStyle*) const;
- virtual void adjustButtonInnerStyle(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
@@ -119,6 +128,7 @@ namespace WebCore {
private:
unsigned determineState(RenderObject*);
+ unsigned determineSliderThumbState(RenderObject*);
unsigned determineClassicState(RenderObject*);
ThemeData getThemeData(RenderObject*);
diff --git a/WebCore/rendering/RenderThemeMac.h b/WebCore/rendering/RenderThemeMac.h
index 0d31603..63f1d97 100644
--- a/WebCore/rendering/RenderThemeMac.h
+++ b/WebCore/rendering/RenderThemeMac.h
@@ -60,6 +60,8 @@ public:
virtual Color platformInactiveListBoxSelectionBackgroundColor() const;
virtual Color platformInactiveListBoxSelectionForegroundColor() const;
+ virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; }
+
virtual void platformColorsDidChange();
// System fonts.
diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm
index b2d320a..7d1a60e 100644
--- a/WebCore/rendering/RenderThemeMac.mm
+++ b/WebCore/rendering/RenderThemeMac.mm
@@ -548,7 +548,7 @@ void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
{
bool oldPressed = [cell isHighlighted];
- bool pressed = (o->element() && o->element()->active());
+ bool pressed = (o->node() && o->node()->active());
if (pressed != oldPressed)
[cell setHighlighted:pressed];
}
@@ -951,7 +951,11 @@ void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle
// 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);
+ bool isEnabled = true;
+ if (FormControlElement* formControlElement = toFormControlElement(e))
+ isEnabled = formControlElement->isEnabled();
+
+ style->setColor(isEnabled ? static_cast<RGBA32>(Color::black) : Color::darkGray);
// Set the button's vertical size.
setSizeFromFont(style, menuListButtonSizes());
@@ -1451,8 +1455,8 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const
height = size.height;
}
- o->style()->setWidth(Length(width, Fixed));
- o->style()->setHeight(Length(height, Fixed));
+ o->style()->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
+ o->style()->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
}
#endif
}
@@ -1462,7 +1466,7 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const
bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1473,7 +1477,7 @@ bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObj
bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
@@ -1489,7 +1493,7 @@ bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::P
bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
@@ -1505,7 +1509,7 @@ bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const RenderObject::P
bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1516,7 +1520,7 @@ bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const RenderObjec
bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1527,7 +1531,7 @@ bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const RenderOb
bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
@@ -1551,7 +1555,7 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::
bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1562,7 +1566,7 @@ bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::
bool RenderThemeMac::paintMediaTimelineContainer(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1573,7 +1577,7 @@ bool RenderThemeMac::paintMediaTimelineContainer(RenderObject* o, const RenderOb
bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
@@ -1584,7 +1588,7 @@ bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const RenderObject::
bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
if (!node)
return false;
diff --git a/WebCore/rendering/RenderThemeSafari.cpp b/WebCore/rendering/RenderThemeSafari.cpp
index ef39a3e..cf73fdb 100644
--- a/WebCore/rendering/RenderThemeSafari.cpp
+++ b/WebCore/rendering/RenderThemeSafari.cpp
@@ -31,6 +31,7 @@
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "FormControlElement.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
@@ -834,7 +835,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->isFormControlElement() && toFormControlElement(e)->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
// Set the button's vertical size.
setButtonSize(style);
@@ -1145,7 +1146,7 @@ bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const Render
bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
@@ -1164,7 +1165,7 @@ bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const RenderObject
bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
@@ -1203,7 +1204,7 @@ bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const Rende
bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- Node* node = o->element();
+ Node* node = o->node();
Node* mediaNode = node ? node->shadowAncestorNode() : 0;
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp
index e4717a1..0518ef0 100644
--- a/WebCore/rendering/RenderThemeWin.cpp
+++ b/WebCore/rendering/RenderThemeWin.cpp
@@ -712,28 +712,29 @@ void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const
}
}
-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;
}
-bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+int RenderThemeWin::buttonInternalPaddingRight() const
{
- return paintTextField(o, i, r);
+ return 3;
}
-void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
-{
- // Override padding size 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));
+int RenderThemeWin::buttonInternalPaddingTop() const
+{
+ return 1;
+}
+
+int RenderThemeWin::buttonInternalPaddingBottom() const
+{
+ return 1;
+}
+
+bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ return paintTextField(o, i, r);
}
bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h
index 5d5bd4b..664094f 100644
--- a/WebCore/rendering/RenderThemeWin.h
+++ b/WebCore/rendering/RenderThemeWin.h
@@ -92,9 +92,13 @@ 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&);
virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp
index cf7e027..2350491 100644
--- a/WebCore/rendering/RenderTreeAsText.cpp
+++ b/WebCore/rendering/RenderTreeAsText.cpp
@@ -170,13 +170,13 @@ 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*";
}
}
@@ -192,21 +192,19 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o)
r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height());
if (adjustForTableCells && !text.firstTextBox())
adjustForTableCells = false;
- } else if (o.isBox()) {
- if (o.isRenderInline()) {
- // FIXME: Would be better not to just dump 0, 0 as the x and y here.
- const RenderInline& inlineFlow = static_cast<const RenderInline&>(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
- r = toRenderBox(&o)->frameRect();
- }
+ } 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)
@@ -237,10 +235,10 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o)
o.style()->textStrokeWidth() > 0)
ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]";
- if (!o.isBox())
+ if (!o.isBoxModelObject())
return ts;
- const RenderBox& box = *toRenderBox(&o);
+ const RenderBoxModelObject& box = *toRenderBoxModelObject(&o);
if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) {
ts << " [border:";
@@ -405,7 +403,7 @@ void write(TextStream& ts, const RenderObject& o, int indent)
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);
}
}
}
@@ -433,9 +431,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();
}
@@ -459,7 +457,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();
@@ -474,10 +472,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();
@@ -509,7 +507,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;
@@ -518,15 +516,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().m_offset << " 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().m_offset << " of " << nodePosition(selection.start().node()) << "\n"
+ << "selection end: position " << selection.end().m_offset << " of " << nodePosition(selection.end().node()) << "\n";
}
String externalRepresentation(RenderObject* o)
@@ -542,7 +540,7 @@ String externalRepresentation(RenderObject* o)
o->view()->frameView()->layout();
if (o->hasLayer()) {
RenderLayer* l = toRenderBox(o)->layer();
- writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height()));
+ writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()));
writeSelection(ts, o);
}
return ts.release();
diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp
index be75997..d6e98e7 100644
--- a/WebCore/rendering/RenderVideo.cpp
+++ b/WebCore/rendering/RenderVideo.cpp
@@ -125,12 +125,9 @@ void RenderVideo::updatePlayer()
return;
}
- // 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);
}
diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp
index 7ce4998..ab2f085 100644
--- a/WebCore/rendering/RenderView.cpp
+++ b/WebCore/rendering/RenderView.cpp
@@ -27,7 +27,15 @@
#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
#ifdef ANDROID_LAYOUT
#include "Settings.h"
@@ -139,39 +147,20 @@ void RenderView::layout()
setNeedsLayout(false);
}
-FloatPoint RenderView::localToAbsolute(FloatPoint localPoint, bool fixed, bool) const
-{
- // This disables the css position:fixed to the Browser window. Instead
- // the fixed element will be always fixed to the top page.
-#ifndef ANDROID_DISABLE_POSITION_FIXED
- if (fixed && m_frameView)
- localPoint += m_frameView->scrollOffset();
-#endif
- return localPoint;
-}
-
-FloatPoint RenderView::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool) const
-{
- // This disables the css position:fixed to the Browser window. Instead
- // the fixed element will be always fixed to the top page.
-#ifndef ANDROID_DISABLE_POSITION_FIXED
- if (fixed && m_frameView)
- containerPoint -= m_frameView->scrollOffset();
-#endif
- return containerPoint;
-}
-
-FloatQuad RenderView::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
+void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool /*useTransforms*/, TransformState& transformState) const
{
// 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);
- FloatQuad quad = localQuad;
if (fixed && m_frameView)
- quad += m_frameView->scrollOffset();
+ transformState.move(m_frameView->scrollOffset());
+}
- return quad;
+void RenderView::mapAbsoluteToLocalPoint(bool fixed, bool /*useTransforms*/, TransformState& transformState) const
+{
+ if (fixed && m_frameView)
+ transformState.move(-m_frameView->scrollOffset());
}
void RenderView::paint(PaintInfo& paintInfo, int tx, int ty)
@@ -230,12 +219,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
@@ -258,7 +255,25 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate)
}
}
-void RenderView::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, 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.
@@ -294,21 +309,11 @@ static 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();
- typedef HashMap<RenderObject*, SelectionInfo*> SelectionMap;
+ typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectionMap;
SelectionMap selectedObjects;
RenderObject* os = m_selectionStart;
@@ -316,13 +321,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();
}
}
@@ -334,13 +339,28 @@ 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;
}
+#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)
{
// Make sure both our start and end objects are defined.
@@ -359,14 +379,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;
@@ -375,13 +395,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();
}
}
@@ -424,13 +444,13 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
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));
+ newSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb));
cb = cb->containingBlock();
}
}
@@ -451,14 +471,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;
}
@@ -469,8 +489,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;
}
@@ -478,12 +498,12 @@ 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());
+ oldInfo->repaint();
if (newInfo) {
- repaintViewRectangle(newInfo->rects());
+ newInfo->repaint();
newSelectedBlocks.remove(block);
delete newInfo;
}
@@ -494,8 +514,8 @@ 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;
}
}
@@ -518,17 +538,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);
}
@@ -598,9 +618,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, RenderBox* 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)
@@ -613,9 +641,10 @@ void RenderView::setBestTruncatedAt(int y, RenderBox* forRenderer, bool forcedBr
return;
}
- // prefer the widest object who tries to move the pagination point
- if (forRenderer->width() > m_truncatorWidth) {
- m_truncatorWidth = forRenderer->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;
}
}
@@ -629,4 +658,49 @@ void RenderView::pushLayoutState(RenderObject* root)
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/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h
index 8e7bf95..1c6925c 100644
--- a/WebCore/rendering/RenderView.h
+++ b/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,8 +50,6 @@ 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;
int docHeight() const;
int docWidth() const;
@@ -54,14 +58,15 @@ public:
int viewHeight() const;
int viewWidth() const;
- float zoomFactor() const { return m_frameView->frame() && m_frameView->frame()->shouldApplyPageZoom() ? m_frameView->frame()->zoomFactor() : 1.0f; }
+ float zoomFactor() const;
FrameView* frameView() const { return m_frameView; }
- virtual bool hasOverhangingFloats() { return false; }
-
- virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, 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);
@@ -75,7 +80,7 @@ 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, RenderBox* 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; }
@@ -85,19 +90,23 @@ public:
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.
@@ -144,12 +153,24 @@ public:
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 FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const;
+ 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;
protected:
FrameView* m_frameView;
@@ -166,9 +187,9 @@ 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:
int m_bestTruncatedAt;
@@ -176,8 +197,27 @@ private:
bool m_forcedPageBreak;
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:
diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp
index 9bf8111..2f30c59 100644
--- a/WebCore/rendering/RenderWidget.cpp
+++ b/WebCore/rendering/RenderWidget.cpp
@@ -91,20 +91,19 @@ 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();
+ 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()
@@ -115,9 +114,9 @@ RenderWidget::~RenderWidget()
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);
}
@@ -157,7 +156,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) {
@@ -192,6 +191,17 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
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();
+ paintInfo.context->addRoundedRectClip(IntRect(tx, ty, width(), height()),
+ style()->borderTopLeftRadius(),
+ style()->borderTopRightRadius(),
+ style()->borderBottomLeftRadius(),
+ style()->borderBottomRightRadius());
+ }
+
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
@@ -203,9 +213,14 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
m_widget->paint(paintInfo.context, paintInfo.rect);
}
+ 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::deref(RenderArena *arena)
@@ -228,22 +243,22 @@ void RenderWidget::updateWidgetPosition()
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)
@@ -271,7 +286,7 @@ 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())
+ if (inside && !hadResult && result.innerNode() == node())
result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
return inside;
}
diff --git a/WebCore/rendering/RenderWidget.h b/WebCore/rendering/RenderWidget.h
index a64bb54..cca2165 100644
--- a/WebCore/rendering/RenderWidget.h
+++ b/WebCore/rendering/RenderWidget.h
@@ -50,14 +50,14 @@ public:
virtual void setSelectionState(SelectionState);
- virtual void updateWidgetPosition();
+ void updateWidgetPosition();
virtual void setWidget(Widget*);
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:
void setWidgetGeometry(const IntRect&);
diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp
index 6d42aa7..e582e5e 100644
--- a/WebCore/rendering/RootInlineBox.cpp
+++ b/WebCore/rendering/RootInlineBox.cpp
@@ -74,10 +74,28 @@ void RootInlineBox::detachEllipsisBox(RenderArena* arena)
}
}
+int RootInlineBox::height() const
+{
+ const Font& font = renderer()->style(m_firstLine)->font();
+ int result = font.height();
+ bool strictMode = renderer()->document()->inStrictMode();
+ if (!strictMode && !hasTextChildren() && !boxModelObject()->hasHorizontalBordersOrPadding()) {
+ int bottom = bottomOverflow();
+ if (y() + result > bottom)
+ result = bottom - y();
+ }
+ return result;
+}
+
+RenderLineBoxList* RootInlineBox::rendererLineBoxes() const
+{
+ return block()->lineBoxes();
+}
+
void RootInlineBox::clearTruncation()
{
if (m_hasEllipsisBox) {
- detachEllipsisBox(m_object->renderArena());
+ detachEllipsisBox(renderer()->renderArena());
InlineFlowBox::clearTruncation();
}
}
@@ -98,9 +116,9 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, in
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 +126,8 @@ 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();
+ if (ltr && (x() + width() + ellipsisWidth) <= blockEdge) {
+ ellipsisBox->m_x = x() + width();
return;
}
@@ -130,7 +148,7 @@ int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth,
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 +157,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 +166,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 +184,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 +197,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 +207,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 +228,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,12 +250,12 @@ 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.
@@ -249,15 +267,15 @@ GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBl
// 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) {
- if (isPreviousBoxSelected) // Selection may be non-contiguous, see comment above.
- result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(),
+ if (isPreviousBoxSelected) // VisibleSelection may be non-contiguous, see comment above.
+ result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->renderer(),
lastX + tx, selTop + ty,
- box->xPos() - lastX, selHeight, paintInfo));
- lastX = box->xPos() + box->width();
+ box->x() - lastX, selHeight, paintInfo));
+ lastX = box->x() + box->width();
}
if (box == lastBox)
break;
@@ -326,10 +344,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;
}
@@ -339,12 +357,12 @@ int RootInlineBox::selectionTop()
RenderBlock* RootInlineBox::block() const
{
- return static_cast<RenderBlock*>(m_object);
+ return toRenderBlock(renderer());
}
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)
@@ -355,19 +373,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.
@@ -404,12 +422,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/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h
index a16d1e5..e190a48 100644
--- a/WebCore/rendering/RootInlineBox.h
+++ b/WebCore/rendering/RootInlineBox.h
@@ -43,7 +43,9 @@ public:
{
}
- virtual bool isRootInlineBox() { return true; }
+ virtual bool isRootInlineBox() const { return true; }
+
+ virtual int height() const;
virtual void destroy(RenderArena*);
void detachEllipsisBox(RenderArena*);
@@ -53,16 +55,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
@@ -114,7 +118,7 @@ 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);
@@ -123,12 +127,16 @@ public:
{
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<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
// that spills out above the height of our font (e.g, a tall image), or something that extends further
@@ -138,11 +146,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())
{
}
@@ -184,7 +192,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 +201,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/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp
index 89bab2d..8871a75 100644
--- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp
+++ b/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/WebCore/rendering/SVGInlineFlowBox.h b/WebCore/rendering/SVGInlineFlowBox.h
index bb31807..2742ca0 100644
--- a/WebCore/rendering/SVGInlineFlowBox.h
+++ b/WebCore/rendering/SVGInlineFlowBox.h
@@ -33,12 +33,19 @@ class SVGInlineFlowBox : public InlineFlowBox {
public:
SVGInlineFlowBox(RenderObject* obj)
: InlineFlowBox(obj)
+ , m_height(0)
{
}
+ virtual int height() 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 int verticallyAlignBoxes(int heightOfBlock);
+
+private:
+ int m_height;
};
} // namespace WebCore
diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp
index 620aea5..f424ef2 100644
--- a/WebCore/rendering/SVGInlineTextBox.cpp
+++ b/WebCore/rendering/SVGInlineTextBox.cpp
@@ -44,6 +44,7 @@ namespace WebCore {
SVGInlineTextBox::SVGInlineTextBox(RenderObject* obj)
: InlineTextBox(obj)
+ , m_height(0)
{
}
@@ -77,7 +78,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 +126,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 +165,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 +174,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 +188,7 @@ private:
int m_x;
int m_y;
- int m_offset;
+ int m_offsetOfHitCharacter;
};
// Helper class for selectionRect()
@@ -199,7 +200,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 +222,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 +233,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++;
- // FIXME: todo list
- // (#13910) This code does not handle bottom-to-top/top-to-bottom vertical text.
+ // The caller actually the closest offset before/after the hit char
+ // closestCharacterToPosition returns us offsetOfHitCharacter.
+ closestOffsetInBox = offsetOfHitCharacter;
+
+ // 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 +264,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 +302,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 +330,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();
@@ -444,7 +450,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;
@@ -471,7 +477,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar
p->save();
int adjust = startPos >= boxStartOffset ? boxStartOffset : 0;
- p->drawHighlightForText(font, svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x),
+ 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);
@@ -496,7 +502,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.
@@ -508,10 +514,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/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h
index 9882128..6287c81 100644
--- a/WebCore/rendering/SVGInlineTextBox.h
+++ b/WebCore/rendering/SVGInlineTextBox.h
@@ -37,6 +37,9 @@ namespace WebCore {
public:
SVGInlineTextBox(RenderObject* obj);
+ virtual int height() const { return m_height; }
+ void setHeight(int h) { m_height = h; }
+
virtual int selectionTop();
virtual int selectionHeight();
@@ -67,6 +70,8 @@ namespace WebCore {
private:
friend class RenderSVGInlineText;
bool svgCharacterHitsPosition(int x, int y, int& offset) const;
+
+ int m_height;
};
} // namespace WebCore
diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp
index 9ffc533..dd154c7 100644
--- a/WebCore/rendering/SVGRenderSupport.cpp
+++ b/WebCore/rendering/SVGRenderSupport.cpp
@@ -46,9 +46,9 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa
UNUSED_PARAM(rootFilter);
#endif
- SVGElement* svgElement = static_cast<SVGElement*>(object->element());
- ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
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();
@@ -160,7 +160,7 @@ void clampImageBufferSizeToViewport(RenderObject* object, IntSize& size)
if (!object || !object->isRenderView())
return;
- RenderView* view = static_cast<RenderView*>(object);
+ RenderView* view = toRenderView(object);
if (!view->frameView())
return;
diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp
index 74a8af9..1f97c47 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.cpp
+++ b/WebCore/rendering/SVGRenderTreeAsText.cpp
@@ -432,7 +432,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++;
}
@@ -459,8 +459,8 @@ void write(TextStream& ts, const RenderSVGContainer& container, int indent)
writeIndent(ts, indent);
ts << container.renderName();
- if (container.element()) {
- String tagName = getTagName(static_cast<SVGStyledElement*>(container.element()));
+ if (container.node()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(container.node()));
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
}
@@ -476,8 +476,8 @@ 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 (root.node()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(root.node()));
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
}
@@ -493,8 +493,8 @@ 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 (text.node()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(text.node()));
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
}
@@ -510,8 +510,8 @@ 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 (text.node()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(text.node()));
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
}
@@ -527,8 +527,8 @@ 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 (path.node()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(path.node()));
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
}
diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp
index 62a8b04..88c7542 100644
--- a/WebCore/rendering/SVGRootInlineBox.cpp
+++ b/WebCore/rendering/SVGRootInlineBox.cpp
@@ -344,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)
@@ -396,14 +396,14 @@ 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();
if (!flowBox->isRootInlineBox())
- m_paintInfo.context->concatCTM(m_rootBox->object()->localTransform());
+ m_paintInfo.context->concatCTM(m_rootBox->renderer()->localTransform());
m_paintInfo.context->concatCTM(object->localTransform());
@@ -420,7 +420,7 @@ struct SVGRootInlineBoxPaintWalker {
InlineFlowBox* flowBox = box->parent();
- RenderObject* object = flowBox->object();
+ RenderObject* object = flowBox->renderer();
ASSERT(object);
// Clean up last used paint server
@@ -443,7 +443,7 @@ struct SVGRootInlineBoxPaintWalker {
InlineFlowBox* flowBox = box->parent();
// Setup fill paint server
- RenderObject* object = flowBox->object();
+ RenderObject* object = flowBox->renderer();
ASSERT(object);
ASSERT(!m_strokePaintServer);
@@ -464,7 +464,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.
@@ -485,7 +485,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());
@@ -581,12 +581,12 @@ 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());
+ paintInfo.context->concatCTM(renderer()->localTransform());
+ prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter);
+ paintInfo.context->concatCTM(renderer()->localTransform().inverse());
// Render text, chunk-by-chunk
SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty);
@@ -600,7 +600,7 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
walkTextChunks(&walker);
// Finalize text rendering
- finishRenderSVGContent(object(), paintInfo, boundingBox, filter, savedInfo.context);
+ finishRenderSVGContent(renderer(), paintInfo, boundingBox, filter, savedInfo.context);
paintInfo.context->restore();
}
@@ -625,7 +625,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));
@@ -638,7 +638,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());
@@ -652,7 +652,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
@@ -672,7 +672,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);
@@ -791,13 +791,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));
}
}
@@ -820,9 +819,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;
}
@@ -898,9 +897,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());
@@ -910,20 +909,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());
@@ -933,13 +932,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
@@ -1008,10 +1007,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();
@@ -1039,12 +1036,11 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::
int minY = enclosedStringRect.y();
int maxY = minY + enclosedStringRect.height();
- curr->setXPos(minX - block()->x());
+ curr->setX(minX - block()->x());
curr->setWidth(enclosedStringRect.width());
- curr->setYPos(minY - block()->y());
- curr->setBaseline(font.ascent());
- curr->setHeight(enclosedStringRect.height());
+ curr->setY(minY - block()->y());
+ textBox->setHeight(enclosedStringRect.height());
if (minX < lowX)
lowX = minX;
@@ -1067,17 +1063,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 - block()->x());
+ curr->setX(minX - block()->x());
curr->setWidth(maxX - minX);
- curr->setYPos(minY - block()->y());
- 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;
@@ -1093,15 +1088,15 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::
}
}
- if (start->isRootInlineBox()) {
+ if (start->isSVGRootInlineBox()) {
int top = lowY - block()->y();
int bottom = highY - block()->y();
- start->setXPos(lowX - block()->x());
- 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);
@@ -1110,7 +1105,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());
@@ -1141,11 +1136,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;
@@ -1195,7 +1190,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;
@@ -1370,7 +1365,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();
@@ -1382,12 +1377,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);
@@ -1525,10 +1520,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/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h
index bfe9889..10c43ea 100644
--- a/WebCore/rendering/SVGRootInlineBox.h
+++ b/WebCore/rendering/SVGRootInlineBox.h
@@ -47,11 +47,15 @@ class SVGRootInlineBox : public RootInlineBox {
public:
SVGRootInlineBox(RenderObject* obj)
: RootInlineBox(obj)
+ , m_height(0)
{
}
virtual bool isSVGRootInlineBox() { return true; }
+ virtual int height() 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);
@@ -80,6 +84,7 @@ private:
SVGTextDecorationInfo retrievePaintServersForTextDecoration(RenderObject* start);
private:
+ int m_height;
Vector<SVGChar> m_svgChars;
Vector<SVGTextChunk> m_svgTextChunks;
};
diff --git a/WebCore/rendering/ScrollBehavior.cpp b/WebCore/rendering/ScrollBehavior.cpp
new file mode 100644
index 0000000..232ea19
--- /dev/null
+++ b/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/WebCore/rendering/ScrollBehavior.h b/WebCore/rendering/ScrollBehavior.h
new file mode 100644
index 0000000..390c68a
--- /dev/null
+++ b/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/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp
index 452333c..cd067de 100644
--- a/WebCore/rendering/TextControlInnerElements.cpp
+++ b/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/WebCore/rendering/TransformState.cpp b/WebCore/rendering/TransformState.cpp
new file mode 100644
index 0000000..5021d1f
--- /dev/null
+++ b/WebCore/rendering/TransformState.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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, bool accumulateTransform)
+{
+ 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 (!accumulateTransform)
+ 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 = accumulateTransform;
+}
+
+void TransformState::applyTransform(const TransformationMatrix& transformFromContainer, bool accumulateTransform)
+{
+ // 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 (accumulateTransform) {
+ // Make one if we started to accumulate
+ m_accumulatedTransform.set(new TransformationMatrix(transformFromContainer));
+ }
+
+ if (!accumulateTransform) {
+ const TransformationMatrix* finalTransform = m_accumulatedTransform ? m_accumulatedTransform.get() : &transformFromContainer;
+ flattenWithTransform(*finalTransform);
+ }
+ m_accumulatingTransform = 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::move(int x, int y)
+{
+ if (m_accumulatingTransform)
+ flatten();
+
+ m_lastPlanarPoint.move(x, y);
+ m_lastPlanarQuad.move(x, y);
+}
+
+void HitTestingTransformState::applyTransform(const TransformationMatrix& transformFromContainer, bool accumulateTransform)
+{
+ m_accumulatedTransform.multLeft(transformFromContainer);
+ if (!accumulateTransform)
+ flatten();
+
+ m_accumulatingTransform = accumulateTransform;
+}
+
+void HitTestingTransformState::flatten()
+{
+ m_lastPlanarPoint = mappedPoint();
+ m_lastPlanarQuad = mappedQuad();
+ 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/WebCore/rendering/TransformState.h b/WebCore/rendering/TransformState.h
new file mode 100644
index 0000000..5190118
--- /dev/null
+++ b/WebCore/rendering/TransformState.h
@@ -0,0 +1,132 @@
+/*
+ * 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 };
+ // 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, bool accumulateTransform = false)
+ {
+ move(s.width(), s.height(), accumulateTransform);
+ }
+
+ void move(int x, int y, bool accumulateTransform = false);
+ void applyTransform(const TransformationMatrix& transformFromContainer, bool accumulateTransform = false);
+ 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));
+ }
+
+ void move(const IntSize& s)
+ {
+ move(s.width(), s.height());
+ }
+
+ void move(int x, int y);
+ void applyTransform(const TransformationMatrix& transformFromContainer, bool accumulateTransform);
+ 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)
+ {
+ }
+};
+
+} // namespace WebCore
+
+#endif // TransformState_h
diff --git a/WebCore/rendering/bidi.cpp b/WebCore/rendering/bidi.cpp
index 3b0e7c4..bfb5291 100644
--- a/WebCore/rendering/bidi.cpp
+++ b/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"
@@ -95,7 +96,7 @@ static bool betweenMidpoints;
static bool isLineEmpty = true;
static bool previousLineBrokeCleanly = true;
-static int getBorderPaddingMargin(RenderBox* child, bool endOfInline)
+static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
{
bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline;
if (leftSide)
@@ -108,11 +109,11 @@ static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
unsigned lineDepth = 1;
int extraWidth = 0;
RenderObject* parent = child->parent();
- while (parent->isBox() && parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) {
- if (start && parent->firstChild() == child)
- extraWidth += getBorderPaddingMargin(toRenderBox(parent), false);
- if (end && parent->lastChild() == child)
- extraWidth += getBorderPaddingMargin(toRenderBox(parent), true);
+ while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) {
+ if (start && !child->previousSibling())
+ extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), false);
+ if (end && !child->nextSibling())
+ extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), true);
child = parent;
parent = child->parent();
}
@@ -179,7 +180,7 @@ 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->isRenderInline()) {
EUnicodeBidi ub = next->style()->unicodeBidi();
@@ -393,7 +394,7 @@ static void addMidpoint(const InlineIterator& 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()->isRenderInline()))
+ (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline()))
return;
bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints);
@@ -462,7 +463,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.
@@ -472,10 +503,9 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj)
InlineFlowBox* result = 0;
do {
ASSERT(obj->isRenderInline() || obj == this);
- RenderFlow* flow = static_cast<RenderFlow*>(obj);
-
+
// 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
@@ -486,10 +516,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;
}
@@ -516,7 +546,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);
@@ -527,16 +557,16 @@ 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())
+ 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());
+ parentBox = createLineBoxes(r->m_object->parent(), firstLine);
// Append the inline box to this line.
parentBox->addToLine(box);
@@ -570,10 +600,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(height());
+ int availableWidth = lineWidth(height(), firstLine);
int totWidth = lineBox->getFlowSpacingWidth();
bool needsWordSpacing = false;
unsigned numSpaces = 0;
@@ -598,10 +628,10 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi
if (int length = rt->textLength()) {
if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
- totWidth += rt->style(m_firstLine)->font().wordSpacing();
+ 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));
+ r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, firstLine));
} else if (!r->m_object->isRenderInline()) {
RenderBox* renderBox = toRenderBox(r->m_object);
renderBox->calcWidth();
@@ -616,7 +646,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi
// 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(height());
+ int x = leftOffset(height(), firstLine);
switch(textAlign) {
case LEFT:
case WEBKIT_LEFT:
@@ -741,11 +771,14 @@ void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRu
// 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(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.
@@ -772,8 +805,6 @@ static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom)
{
bool useRepaintBounds = false;
-
- invalidateVerticalPosition();
m_overflowHeight = 0;
@@ -785,7 +816,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.
@@ -824,9 +855,7 @@ 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);
@@ -842,27 +871,23 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
else {
#ifdef ANDROID_LAYOUT
// ignore text wrap for textField or menuList
- if (doTextWrap && (o->isTextField() || o->isMenuList()))
- doTextWrap = false;
+ if (doTextWrap && (o->isTextField() || o->isMenuList()))
+ doTextWrap = false;
#endif
if (o->isFloating())
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->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->isRenderInline())
- static_cast<RenderFlow*>(o)->calcMargins(containerWidth);
+ dirtyLineBoxesForRenderer(o, fullLayout);
o->setNeedsLayout(false);
#ifdef ANDROID_LAYOUT
if (doTextWrap && !hasTextToWrap && o->isText()) {
- Node* node = o->element();
+ Node* node = o->node();
// as it is very common for sites to use a serial of <a> or
// <li> as tabs, we don't force text to wrap if all the text
// are short and within an <a> or <li> tag, and only separated
@@ -880,6 +905,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
}
}
#endif
+ if (!o->isText())
+ toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything.
}
o = bidiNext(this, o, 0, false, &endOfInline);
}
@@ -921,18 +948,19 @@ 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;
+ RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, 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.
RenderView* v = view();
- if (v && !v->doingFullRepaint() && m_layer) {
+ 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.
- v->repaintViewRectangle(m_layer->repaintRect());
+ repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
}
}
@@ -974,9 +1002,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)
@@ -999,7 +1027,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
isLineEmpty = true;
EClear clear = CNONE;
- end = findNextLineBreak(resolver, &clear);
+ end = findNextLineBreak(resolver, firstLine, &clear);
if (resolver.position().atEnd()) {
resolver.deleteRuns();
checkForFloatsFromLastLine = true;
@@ -1031,26 +1059,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) {
@@ -1072,12 +1092,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());
@@ -1105,7 +1125,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
}
}
- m_firstLine = false;
+ firstLine = false;
newLine(clear);
}
@@ -1208,7 +1228,7 @@ 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, InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats)
{
RootInlineBox* curr = 0;
RootInlineBox* last = 0;
@@ -1264,7 +1284,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() >= toRenderText(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;
@@ -1301,7 +1321,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR
setHeight(savedHeight);
}
- m_firstLine = !last;
+ firstLine = !last;
previousLineBrokeCleanly = !last || last->endsWithBreak();
RenderObject* startObj;
@@ -1470,12 +1490,12 @@ static inline bool shouldPreserveNewline(RenderObject* object)
return object->style()->preserveNewline();
}
-static bool inlineFlowRequiresLineBox(RenderBox* 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->isRenderInline() && !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();
+ return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();
}
static inline bool requiresLineBox(const InlineIterator& it)
@@ -1483,7 +1503,7 @@ static inline bool requiresLineBox(const InlineIterator& it)
if (it.obj->isFloatingOrPositioned())
return false;
- if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderBox(it.obj)))
+ if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj)))
return false;
if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR())
@@ -1524,33 +1544,34 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator)
// 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(height()) : rightOffset(height()));
- c->setStaticY(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(height()) : width() - rightOffset(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(height());
+ if (box->style()->hasStaticY())
+ box->layer()->setStaticY(height());
}
iterator.increment();
}
}
-int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver)
+int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine)
{
- int availableWidth = lineWidth(height());
+ int availableWidth = lineWidth(height(), firstLine);
while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) {
RenderObject* object = resolver.position().obj;
if (object->isFloating()) {
insertFloatingObject(toRenderBox(object));
positionNewFloats();
- availableWidth = lineWidth(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
@@ -1559,19 +1580,20 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver)
// 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(height()) : rightOffset(height()));
- c->setStaticY(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(height()) : width() - rightOffset(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(height());
+ if (box->style()->hasStaticY())
+ box->layer()->setStaticY(height());
}
resolver.increment();
}
@@ -1596,7 +1618,7 @@ 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);
@@ -1608,7 +1630,7 @@ void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth)
if (!floatBottom)
break;
- newLineWidth = lineWidth(floatBottom);
+ newLineWidth = lineWidth(floatBottom, firstLine);
lastFloatBottom = floatBottom;
if (newLineWidth >= widthToFit)
break;
@@ -1620,13 +1642,20 @@ void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth)
}
}
-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, EClear* clear)
{
ASSERT(resolver.position().block == this);
bool appliedStartWidth = resolver.position().pos > 0;
- int width = skipLeadingWhitespace(resolver);
+ int width = skipLeadingWhitespace(resolver, firstLine);
int w = 0;
int tmpW = 0;
@@ -1715,16 +1744,17 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle
// it after moving to next line (in newLine() func)
if (floatsFitOnLine && floatBox->width() + floatBox->marginLeft() + floatBox->marginRight() + w + tmpW <= width) {
positionNewFloats();
- width = lineWidth(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;
@@ -1732,9 +1762,9 @@ 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(height());
+ bool needToSetStaticY = box->style()->hasStaticY();
+ if (box->style()->hasStaticY() && isInlineType) {
+ box->layer()->setStaticY(height());
needToSetStaticY = false;
}
@@ -1760,7 +1790,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle
// Right now, we should only encounter empty inlines here.
ASSERT(!o->firstChild());
- RenderBox* flowBox = toRenderBox(o);
+ 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.
@@ -1827,7 +1857,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle
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();
@@ -1876,12 +1907,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle
addMidpoint(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();
@@ -1901,7 +1932,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;
}
@@ -1926,7 +1957,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);
@@ -1936,14 +1967,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,
@@ -1973,7 +2004,7 @@ 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);
}
}
@@ -2064,7 +2095,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();
@@ -2091,7 +2122,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;
@@ -2114,7 +2145,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
@@ -2154,8 +2185,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.
@@ -2265,8 +2295,8 @@ 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();
+ int blockEdge = ltr ? rightOffset(curr->y(), curr == firstRootBox()) : leftOffset(curr->y(), curr == firstRootBox());
+ int lineBoxEdge = ltr ? curr->x() + curr->width() : curr->x();
if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
// 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
diff --git a/WebCore/rendering/style/ContentData.cpp b/WebCore/rendering/style/ContentData.cpp
index b38cc49..410cad4 100644
--- a/WebCore/rendering/style/ContentData.cpp
+++ b/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/WebCore/rendering/style/ContentData.h b/WebCore/rendering/style/ContentData.h
index d924d1a..24d5f86 100644
--- a/WebCore/rendering/style/ContentData.h
+++ b/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/WebCore/rendering/style/CounterContent.h b/WebCore/rendering/style/CounterContent.h
index 06440ad..cf11813 100644
--- a/WebCore/rendering/style/CounterContent.h
+++ b/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/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp
index 09445b9..fe53d30 100644
--- a/WebCore/rendering/style/RenderStyle.cpp
+++ b/WebCore/rendering/style/RenderStyle.cpp
@@ -185,7 +185,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);
}
@@ -271,14 +271,16 @@ static 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 ||
@@ -287,19 +289,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 ||
@@ -307,30 +309,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
}
@@ -342,13 +361,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 ||
@@ -363,7 +382,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) {
@@ -371,26 +390,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 ||
@@ -398,12 +417,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.
@@ -411,19 +430,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.
@@ -431,7 +450,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
@@ -439,16 +458,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 ||
@@ -463,19 +490,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;
@@ -503,39 +541,6 @@ void RenderStyle::clearCursorList()
inherited.access()->cursorData = 0;
}
-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;
-}
-
void RenderStyle::clearContent()
{
if (rareNonInheritedData->m_content)
@@ -549,8 +554,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;
@@ -561,34 +566,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;
}
}
@@ -601,13 +602,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)
@@ -617,8 +616,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;
@@ -629,15 +628,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
@@ -645,26 +643,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)
@@ -818,7 +821,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/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h
index fed3057..32c0cf4 100644
--- a/WebCore/rendering/style/RenderStyle.h
+++ b/WebCore/rendering/style/RenderStyle.h
@@ -106,17 +106,6 @@ class StyleImage;
class RenderStyle: public RefCounted<RenderStyle> {
friend class CSSStyleSelector;
-
-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_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 };
- static const int FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON;
-
protected:
// !START SYNC!: Keep this in sync with the copy constructor in RenderStyle.cpp
@@ -335,6 +324,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; }
@@ -356,6 +346,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); }
@@ -446,6 +441,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)
@@ -628,8 +636,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
@@ -645,7 +661,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; }
@@ -926,6 +956,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
@@ -946,6 +977,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); }
@@ -969,9 +1010,9 @@ 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);
@@ -980,13 +1021,7 @@ public:
bool inheritedNotEqual(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
{
@@ -1119,6 +1154,12 @@ public:
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/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h
index 40ad3cc..405cf7c 100644
--- a/WebCore/rendering/style/RenderStyleConstants.h
+++ b/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/WebCore/rendering/style/SVGRenderStyle.cpp b/WebCore/rendering/style/SVGRenderStyle.cpp
index 1749978..c5f0648 100644
--- a/WebCore/rendering/style/SVGRenderStyle.cpp
+++ b/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/WebCore/rendering/style/StyleInheritedData.cpp b/WebCore/rendering/style/StyleInheritedData.cpp
index 56d2686..f59c0c2 100644
--- a/WebCore/rendering/style/StyleInheritedData.cpp
+++ b/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/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp
index 2294568..f26baa6 100644
--- a/WebCore/rendering/style/StyleRareInheritedData.cpp
+++ b/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -94,7 +94,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
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/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/WebCore/rendering/style/StyleRareNonInheritedData.cpp
index e8ceeeb..401c04f 100644
--- a/WebCore/rendering/style/StyleRareNonInheritedData.cpp
+++ b/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/WebCore/rendering/style/StyleRareNonInheritedData.h b/WebCore/rendering/style/StyleRareNonInheritedData.h
index 6ce6a33..8dd22b3 100644
--- a/WebCore/rendering/style/StyleRareNonInheritedData.h
+++ b/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/WebCore/rendering/style/StyleTransformData.cpp b/WebCore/rendering/style/StyleTransformData.cpp
index de20e77..2baebf9 100644
--- a/WebCore/rendering/style/StyleTransformData.cpp
+++ b/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/WebCore/rendering/style/StyleTransformData.h b/WebCore/rendering/style/StyleTransformData.h
index 157e600..6039824 100644
--- a/WebCore/rendering/style/StyleTransformData.h
+++ b/WebCore/rendering/style/StyleTransformData.h
@@ -46,6 +46,7 @@ public:
TransformOperations m_operations;
Length m_x;
Length m_y;
+ float m_z;
private:
StyleTransformData();