summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/AutoTableLayout.cpp6
-rw-r--r--WebCore/rendering/CounterNode.cpp96
-rw-r--r--WebCore/rendering/CounterNode.h14
-rw-r--r--WebCore/rendering/EllipsisBox.cpp43
-rw-r--r--WebCore/rendering/EllipsisBox.h6
-rw-r--r--WebCore/rendering/InlineFlowBox.cpp43
-rw-r--r--WebCore/rendering/InlineTextBox.cpp45
-rw-r--r--WebCore/rendering/InlineTextBox.h2
-rw-r--r--WebCore/rendering/RenderArena.cpp2
-rw-r--r--WebCore/rendering/RenderBR.cpp2
-rw-r--r--WebCore/rendering/RenderBlock.cpp131
-rw-r--r--WebCore/rendering/RenderBlock.h13
-rw-r--r--WebCore/rendering/RenderBlockLineLayout.cpp34
-rw-r--r--WebCore/rendering/RenderBox.cpp88
-rw-r--r--WebCore/rendering/RenderBox.h6
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp171
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h4
-rw-r--r--WebCore/rendering/RenderCounter.cpp191
-rw-r--r--WebCore/rendering/RenderCounter.h3
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.cpp352
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.h64
-rw-r--r--WebCore/rendering/RenderFileUploadControl.cpp6
-rw-r--r--WebCore/rendering/RenderFileUploadControl.h1
-rw-r--r--WebCore/rendering/RenderForeignObject.cpp11
-rw-r--r--WebCore/rendering/RenderForeignObject.h6
-rw-r--r--WebCore/rendering/RenderImage.cpp74
-rw-r--r--WebCore/rendering/RenderImage.h14
-rw-r--r--WebCore/rendering/RenderInline.cpp22
-rw-r--r--WebCore/rendering/RenderInline.h2
-rw-r--r--WebCore/rendering/RenderLayer.cpp114
-rw-r--r--WebCore/rendering/RenderLayer.h7
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp184
-rw-r--r--WebCore/rendering/RenderLayerBacking.h17
-rw-r--r--WebCore/rendering/RenderLayerCompositor.cpp119
-rw-r--r--WebCore/rendering/RenderLayerCompositor.h10
-rw-r--r--WebCore/rendering/RenderListItem.cpp49
-rw-r--r--WebCore/rendering/RenderListMarker.cpp609
-rw-r--r--WebCore/rendering/RenderListMarker.h1
-rw-r--r--WebCore/rendering/RenderMedia.cpp30
-rw-r--r--WebCore/rendering/RenderMedia.h9
-rw-r--r--WebCore/rendering/RenderMenuList.cpp76
-rw-r--r--WebCore/rendering/RenderMenuList.h6
-rw-r--r--WebCore/rendering/RenderObject.cpp92
-rw-r--r--WebCore/rendering/RenderObject.h17
-rw-r--r--WebCore/rendering/RenderPart.cpp1
-rw-r--r--WebCore/rendering/RenderPart.h4
-rw-r--r--WebCore/rendering/RenderPartObject.cpp268
-rw-r--r--WebCore/rendering/RenderPartObject.h4
-rw-r--r--WebCore/rendering/RenderPath.cpp274
-rw-r--r--WebCore/rendering/RenderPath.h18
-rw-r--r--WebCore/rendering/RenderReplaced.h2
-rw-r--r--WebCore/rendering/RenderReplica.h4
-rw-r--r--WebCore/rendering/RenderRuby.h20
-rw-r--r--WebCore/rendering/RenderRubyBase.cpp150
-rw-r--r--WebCore/rendering/RenderRubyBase.h12
-rw-r--r--WebCore/rendering/RenderRubyRun.cpp8
-rw-r--r--WebCore/rendering/RenderRubyRun.h11
-rw-r--r--WebCore/rendering/RenderSVGBlock.h2
-rw-r--r--WebCore/rendering/RenderSVGContainer.cpp59
-rw-r--r--WebCore/rendering/RenderSVGContainer.h11
-rw-r--r--WebCore/rendering/RenderSVGGradientStop.cpp2
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.cpp12
-rw-r--r--WebCore/rendering/RenderSVGImage.cpp124
-rw-r--r--WebCore/rendering/RenderSVGImage.h13
-rw-r--r--WebCore/rendering/RenderSVGInline.h5
-rw-r--r--WebCore/rendering/RenderSVGModelObject.cpp1
-rw-r--r--WebCore/rendering/RenderSVGModelObject.h2
-rw-r--r--WebCore/rendering/RenderSVGRoot.cpp39
-rw-r--r--WebCore/rendering/RenderSVGRoot.h4
-rw-r--r--WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp101
-rw-r--r--WebCore/rendering/RenderSVGShadowTreeRootContainer.h50
-rw-r--r--WebCore/rendering/RenderSVGText.cpp27
-rw-r--r--WebCore/rendering/RenderSVGText.h5
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.cpp16
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.h2
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.cpp33
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.h15
-rw-r--r--WebCore/rendering/RenderTableCell.cpp4
-rw-r--r--WebCore/rendering/RenderTableCell.h2
-rw-r--r--WebCore/rendering/RenderTableSection.cpp5
-rw-r--r--WebCore/rendering/RenderText.cpp39
-rw-r--r--WebCore/rendering/RenderTextControl.cpp7
-rw-r--r--WebCore/rendering/RenderTextControl.h2
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.cpp8
-rw-r--r--WebCore/rendering/RenderTheme.cpp22
-rw-r--r--WebCore/rendering/RenderTheme.h7
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.cpp40
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.h15
-rw-r--r--WebCore/rendering/RenderThemeChromiumSkia.cpp22
-rw-r--r--WebCore/rendering/RenderThemeMac.mm5
-rw-r--r--WebCore/rendering/RenderThemeWince.cpp23
-rw-r--r--WebCore/rendering/RenderTreeAsText.cpp79
-rw-r--r--WebCore/rendering/RenderTreeAsText.h10
-rw-r--r--WebCore/rendering/RenderVideo.cpp158
-rw-r--r--WebCore/rendering/RenderVideo.h17
-rw-r--r--WebCore/rendering/RenderView.cpp11
-rw-r--r--WebCore/rendering/RenderView.h2
-rw-r--r--WebCore/rendering/RenderWidget.cpp23
-rw-r--r--WebCore/rendering/RootInlineBox.cpp1
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.h30
-rw-r--r--WebCore/rendering/SVGInlineTextBox.cpp47
-rw-r--r--WebCore/rendering/SVGInlineTextBox.h16
-rw-r--r--WebCore/rendering/SVGMarkerData.h134
-rw-r--r--WebCore/rendering/SVGMarkerLayoutInfo.cpp124
-rw-r--r--WebCore/rendering/SVGMarkerLayoutInfo.h74
-rw-r--r--WebCore/rendering/SVGRenderSupport.cpp102
-rw-r--r--WebCore/rendering/SVGRenderSupport.h20
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.cpp4
-rw-r--r--WebCore/rendering/SVGRootInlineBox.cpp79
-rw-r--r--WebCore/rendering/SVGRootInlineBox.h7
-rw-r--r--WebCore/rendering/SVGShadowTreeElements.cpp80
-rw-r--r--WebCore/rendering/SVGShadowTreeElements.h67
-rw-r--r--WebCore/rendering/TrailingFloatsRootInlineBox.h48
-rw-r--r--WebCore/rendering/TransformState.cpp2
-rw-r--r--WebCore/rendering/break_lines.cpp65
-rw-r--r--WebCore/rendering/style/FillLayer.cpp11
-rw-r--r--WebCore/rendering/style/FillLayer.h1
-rw-r--r--WebCore/rendering/style/RenderStyle.cpp2
-rw-r--r--WebCore/rendering/style/RenderStyle.h57
-rw-r--r--WebCore/rendering/style/RenderStyleConstants.h63
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.cpp53
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.h340
-rw-r--r--WebCore/rendering/style/StyleInheritedData.cpp5
-rw-r--r--WebCore/rendering/style/StyleInheritedData.h1
124 files changed, 4316 insertions, 1709 deletions
diff --git a/WebCore/rendering/AutoTableLayout.cpp b/WebCore/rendering/AutoTableLayout.cpp
index 0e001c7..2a4958a 100644
--- a/WebCore/rendering/AutoTableLayout.cpp
+++ b/WebCore/rendering/AutoTableLayout.cpp
@@ -382,7 +382,7 @@ int AutoTableLayout::calcEffectiveWidth()
float spanMax = max(maxWidth, cMaxWidth);
tMaxWidth = max(tMaxWidth, spanMax * 100 * percentScaleFactor / w.rawValue());
- // all non percent columns in the span get percent vlaues to sum up correctly.
+ // all non percent columns in the span get percent values to sum up correctly.
int percentMissing = w.rawValue() - totalPercent;
float totalWidth = 0;
for (unsigned int pos = col; pos < lastCol; pos++) {
@@ -668,8 +668,8 @@ void AutoTableLayout::layout()
}
}
- // if we have overallocated, reduce every cell according to the difference between desired width and minwidth
- // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing.
+ // If we have overallocated, reduce every cell according to the difference between desired width and minwidth
+ // this seems to produce to the pixel exact results with IE. Wonder is some of this also holds for width distributing.
if (available < 0) {
// Need to reduce cells with the following prioritization:
// (1) Auto
diff --git a/WebCore/rendering/CounterNode.cpp b/WebCore/rendering/CounterNode.cpp
index 95a3748..c164c81 100644
--- a/WebCore/rendering/CounterNode.cpp
+++ b/WebCore/rendering/CounterNode.cpp
@@ -22,20 +22,14 @@
#include "config.h"
#include "CounterNode.h"
+#include "RenderCounter.h"
#include "RenderObject.h"
#include <stdio.h>
-// FIXME: There's currently no strategy for getting the counter tree updated when new
-// elements with counter-reset and counter-increment styles are added to the render tree.
-// Also, the code can't handle changes where an existing node needs to change into a
-// "reset" node, or from a "reset" node back to not a "reset" node. As of this writing,
-// at least some of these problems manifest as failures in the t1204-increment and
-// t1204-reset tests in the CSS 2.1 test suite.
-
namespace WebCore {
-CounterNode::CounterNode(RenderObject* o, bool isReset, int value)
- : m_isReset(isReset)
+CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value)
+ : m_hasResetType(hasResetType)
, m_value(value)
, m_countInParent(0)
, m_renderer(o)
@@ -52,18 +46,14 @@ CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWit
if (this == stayWithin)
return 0;
- CounterNode* next = m_nextSibling;
- if (next)
- return next;
- next = m_parent;
- while (next && !next->m_nextSibling) {
- if (next == stayWithin)
+ const CounterNode* current = this;
+ CounterNode* next;
+ while (!(next = current->m_nextSibling)) {
+ current = current->m_parent;
+ if (!current || current == stayWithin)
return 0;
- next = next->m_parent;
}
- if (next)
- return next->m_nextSibling;
- return 0;
+ return next;
}
CounterNode* CounterNode::nextInPreOrder(const CounterNode* stayWithin) const
@@ -100,14 +90,13 @@ CounterNode* CounterNode::previousInPreOrder() const
int CounterNode::computeCountInParent() const
{
- int increment = m_isReset ? 0 : m_value;
+ int increment = actsAsReset() ? 0 : m_value;
if (m_previousSibling)
return m_previousSibling->m_countInParent + increment;
ASSERT(m_parent->m_firstChild == this);
return m_parent->m_value + increment;
}
-
void CounterNode::resetRenderer(const AtomicString& identifier) const
{
if (!m_renderer || m_renderer->documentBeingDestroyed())
@@ -145,6 +134,11 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, cons
ASSERT(!newChild->m_nextSibling);
ASSERT(!refChild || refChild->m_parent == this);
+ if (newChild->m_hasResetType) {
+ while (m_lastChild != refChild)
+ RenderCounter::destroyCounterNode(m_lastChild->renderer(), identifier);
+ }
+
CounterNode* next;
if (refChild) {
@@ -155,21 +149,57 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, cons
m_firstChild = newChild;
}
- if (next) {
- ASSERT(next->m_previousSibling == refChild);
- next->m_previousSibling = newChild;
- } else {
- ASSERT(m_lastChild == refChild);
- m_lastChild = newChild;
- }
-
newChild->m_parent = this;
newChild->m_previousSibling = refChild;
- newChild->m_nextSibling = next;
- newChild->m_countInParent = newChild->computeCountInParent();
+ if (!newChild->m_firstChild || newChild->m_hasResetType) {
+ newChild->m_nextSibling = next;
+ if (next) {
+ ASSERT(next->m_previousSibling == refChild);
+ next->m_previousSibling = newChild;
+ } else {
+ ASSERT(m_lastChild == refChild);
+ m_lastChild = newChild;
+ }
+
+ newChild->m_countInParent = newChild->computeCountInParent();
+ newChild->resetRenderers(identifier);
+ if (next)
+ next->recount(identifier);
+ return;
+ }
+
+ // The code below handles the case when a formerly root increment counter is loosing its root position
+ // and therefore its children become next siblings.
+ CounterNode* last = newChild->m_lastChild;
+ CounterNode* first = newChild->m_firstChild;
+
+ newChild->m_nextSibling = first;
+ first->m_previousSibling = newChild;
+ // The case when the original next sibling of the inserted node becomes a child of
+ // one of the former children of the inserted node is not handled as it is believed
+ // to be impossible since:
+ // 1. if the increment counter node lost it's root position as a result of another
+ // counter node being created, it will be inserted as the last child so next is null.
+ // 2. if the increment counter node lost it's root position as a result of a renderer being
+ // inserted into the document's render tree, all its former children counters are attached
+ // to children of the inserted renderer and hence cannot be in scope for counter nodes
+ // attached to renderers that were already in the document's render tree.
+ last->m_nextSibling = next;
if (next)
- next->recount(identifier);
+ next->m_previousSibling = last;
+ else
+ m_lastChild = last;
+ for (next = first; ; next = next->m_nextSibling) {
+ next->m_parent = this;
+ if (last == next)
+ break;
+ }
+ newChild->m_firstChild = 0;
+ newChild->m_lastChild = 0;
+ newChild->m_countInParent = newChild->computeCountInParent();
+ newChild->resetRenderer(identifier);
+ first->recount(identifier);
}
void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identifier)
@@ -216,7 +246,7 @@ static void showTreeAndMark(const CounterNode* node)
for (const CounterNode* parent = current; parent && parent != root; parent = parent->parent())
fwrite(" ", 1, 2, stderr);
fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n",
- current, current->isReset() ? "reset____" : "increment", current->value(),
+ current, current->actsAsReset() ? "reset____" : "increment", current->value(),
current->countInParent(), current->parent(), current->previousSibling(),
current->nextSibling(), current->renderer());
}
diff --git a/WebCore/rendering/CounterNode.h b/WebCore/rendering/CounterNode.h
index 8081dc6..15f2eb8 100644
--- a/WebCore/rendering/CounterNode.h
+++ b/WebCore/rendering/CounterNode.h
@@ -42,7 +42,8 @@ class CounterNode : public Noncopyable {
public:
CounterNode(RenderObject*, bool isReset, int value);
- bool isReset() const { return m_isReset; }
+ bool actsAsReset() const { return m_hasResetType || !m_parent; }
+ bool hasResetType() const { return m_hasResetType; }
int value() const { return m_value; }
int countInParent() const { return m_countInParent; }
RenderObject* renderer() const { return m_renderer; }
@@ -58,15 +59,24 @@ public:
CounterNode* nextInPreOrderAfterChildren(const CounterNode* stayWithin = 0) const;
void insertAfter(CounterNode* newChild, CounterNode* beforeChild, const AtomicString& identifier);
+
+ // identifier must match the identifier of this counter.
void removeChild(CounterNode*, const AtomicString& identifier);
private:
int computeCountInParent() const;
void recount(const AtomicString& identifier);
+
+ // Invalidates the text in the renderer of this counter, if any.
+ // identifier must match the identifier of this counter.
void resetRenderer(const AtomicString& identifier) const;
+
+ // Invalidates the text in the renderer of this counter, if any,
+ // and in the renderers of all descendants of this counter, if any.
+ // identifier must match the identifier of this counter.
void resetRenderers(const AtomicString& identifier) const;
- bool m_isReset;
+ bool m_hasResetType;
int m_value;
int m_countInParent;
RenderObject* m_renderer;
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp
index bea9d73..6ec3195 100644
--- a/WebCore/rendering/EllipsisBox.cpp
+++ b/WebCore/rendering/EllipsisBox.cpp
@@ -23,6 +23,7 @@
#include "Document.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
+#include "RootInlineBox.h"
namespace WebCore {
@@ -40,9 +41,22 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
setShadow = true;
}
+ if (selectionState() != RenderObject::SelectionNone) {
+ paintSelection(context, tx, ty, style, style->font());
+
+ // Select the correct color for painting the text.
+ Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor();
+ if (foreground.isValid() && foreground != textColor)
+ context->setFillColor(foreground, style->colorSpace());
+ }
+
const String& str = m_str;
context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->font().ascent()));
+ // Restore the regular fill color.
+ if (textColor != context->fillColor())
+ context->setFillColor(textColor, style->colorSpace());
+
if (setShadow)
context->clearShadow();
@@ -54,6 +68,35 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
}
}
+IntRect EllipsisBox::selectionRect(int tx, int ty)
+{
+ RenderStyle* style = m_renderer->style(m_firstLine);
+ const Font& f = style->font();
+ return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()),
+ IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight()));
+}
+
+void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font)
+{
+ Color textColor = style->color();
+ Color c = m_renderer->selectionBackgroundColor();
+ if (!c.isValid() || !c.alpha())
+ return;
+
+ // If the text color ends up being the same as the selection background, invert the selection
+ // background.
+ if (textColor == c)
+ c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
+
+ context->save();
+ int y = root()->selectionTop();
+ int h = root()->selectionHeight();
+ context->clip(IntRect(m_x + tx, y + ty, m_width, h));
+ context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()),
+ IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace());
+ context->restore();
+}
+
bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
{
tx += m_x;
diff --git a/WebCore/rendering/EllipsisBox.h b/WebCore/rendering/EllipsisBox.h
index a228d7a..087fc72 100644
--- a/WebCore/rendering/EllipsisBox.h
+++ b/WebCore/rendering/EllipsisBox.h
@@ -35,18 +35,24 @@ public:
, m_height(height)
, m_str(ellipsisStr)
, m_markupBox(markupBox)
+ , m_selectionState(RenderObject::SelectionNone)
{
}
virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+ void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; }
+ IntRect selectionRect(int tx, int ty);
private:
virtual int height() const { return m_height; }
+ virtual RenderObject::SelectionState selectionState() { return m_selectionState; }
+ void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&);
int m_height;
AtomicString m_str;
InlineBox* m_markupBox;
+ RenderObject::SelectionState m_selectionState;
};
} // namespace WebCore
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index 2bd1683..34eec30 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/WebCore/rendering/InlineFlowBox.cpp
@@ -429,7 +429,7 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
lineHeight = baseline + baselineToBottom;
} else if (parentLineHeight.isPercent()) {
- lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize(), true);
+ lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize());
baseline = 0;
for (size_t i = 0; i < usedFonts.size(); ++i) {
int halfLeading = (lineHeight - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2;
@@ -532,9 +532,6 @@ void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool st
// Any spillage outside of the line top and bottom is not considered overflow. We just ignore this, since it only happens
// from the "your ascent/descent don't affect the line" quirk.
- // FIXME: Technically this means there can be repaint errors in the case where a line box has a shadow or background that spills
- // outside of the block. We should consider making any line box that has anything to render just stop respecting the quirk or making
- // boxes that render something set visual overflow.
int topOverflow = max(y(), lineTop);
int bottomOverflow = min(y() + boxHeight, lineBottom);
@@ -735,13 +732,24 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int
if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
return;
- // Move x/y to our coordinates.
- tx += m_x;
- ty += m_y;
-
+ int x = m_x;
+ int y = m_y;
int w = width();
int h = height();
+ // Constrain our background/border painting to the line top and bottom if necessary.
+ bool strictMode = renderer()->document()->inStrictMode();
+ if (!hasTextChildren() && !strictMode) {
+ RootInlineBox* rootBox = root();
+ int bottom = min(rootBox->lineBottom(), y + h);
+ y = max(rootBox->lineTop(), y);
+ h = bottom - y;
+ }
+
+ // Move x/y to our coordinates.
+ tx += x;
+ ty += y;
+
GraphicsContext* context = paintInfo.context;
// You can use p::first-line to specify a background. If so, the root line boxes for
@@ -800,13 +808,24 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty
if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
return;
- // Move x/y to our coordinates.
- tx += m_x;
- ty += m_y;
-
+ int x = m_x;
+ int y = m_y;
int w = width();
int h = height();
+ // Constrain our background/border painting to the line top and bottom if necessary.
+ bool strictMode = renderer()->document()->inStrictMode();
+ if (!hasTextChildren() && !strictMode) {
+ RootInlineBox* rootBox = root();
+ int bottom = min(rootBox->lineBottom(), y + h);
+ y = max(rootBox->lineTop(), y);
+ h = bottom - y;
+ }
+
+ // Move x/y to our coordinates.
+ tx += x;
+ ty += y;
+
const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index 31e6967..b7e6de2 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -23,9 +23,11 @@
#include "config.h"
#include "InlineTextBox.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "Editor.h"
+#include "EllipsisBox.h"
#include "Frame.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
@@ -81,6 +83,23 @@ RenderObject::SelectionState InlineTextBox::selectionState()
else if (state == RenderObject::SelectionBoth)
state = RenderObject::SelectionNone;
}
+
+ // If there are ellipsis following, make sure their selection is updated.
+ if (m_truncation != cNoTruncation && root()->ellipsisBox()) {
+ EllipsisBox* ellipsis = root()->ellipsisBox();
+ if (state != RenderObject::SelectionNone) {
+ int start, end;
+ selectionStartEnd(start, end);
+ // The ellipsis should be considered to be selected if the end of
+ // the selection is past the beginning of the truncation and the
+ // beginning of the selection is before or at the beginning of the
+ // truncation.
+ ellipsis->setSelectionState(end >= m_truncation && start <= m_truncation ?
+ RenderObject::SelectionInside : RenderObject::SelectionNone);
+ } else
+ ellipsis->setSelectionState(RenderObject::SelectionNone);
+ }
+
return state;
}
@@ -89,7 +108,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
int sPos = max(startPos - m_start, 0);
int ePos = min(endPos - m_start, (int)m_len);
- if (sPos >= ePos)
+ if (sPos > ePos)
return IntRect();
RenderText* textObj = textRenderer();
@@ -254,7 +273,7 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in
return false;
}
-static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
+static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
{
Color fillColor = context->fillColor();
ColorSpace fillColorSpace = context->fillColorSpace();
@@ -289,8 +308,8 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con
else {
if (endOffset > 0)
context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset);
- if (startOffset < textRun.length())
- context->drawText(font, textRun, textOrigin + extraOffset, startOffset);
+ if (startOffset < truncationPoint)
+ context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
}
if (!shadow)
@@ -460,6 +479,13 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
if (paintSelectedTextOnly || paintSelectedTextSeparately)
selectionStartEnd(sPos, ePos);
+ int length = m_len;
+ if (m_truncation != cNoTruncation) {
+ sPos = min<int>(sPos, m_truncation);
+ ePos = min<int>(ePos, m_truncation);
+ length = m_truncation;
+ }
+
if (!paintSelectedTextOnly) {
// For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side
// effect, so only when we know we're stroking, do a save/restore.
@@ -469,9 +495,9 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
if (!paintSelectedTextSeparately || ePos <= sPos) {
// FIXME: Truncate right-to-left text correctly.
- paintTextWithShadows(context, font, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+ paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
} else
- paintTextWithShadows(context, font, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+ paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
if (textStrokeWidth > 0)
context->restore();
@@ -483,7 +509,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
context->save();
updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth, styleToUse->colorSpace());
- paintTextWithShadows(context, font, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
+ paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
if (selectionStrokeWidth > 0)
context->restore();
@@ -565,8 +591,11 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren
updateGraphicsContext(context, c, c, 0, style->colorSpace()); // Don't draw text at all!
int y = selectionTop();
int h = selectionHeight();
+ // If the text is truncated, let the thing being painted in the truncation
+ // draw its own highlight.
+ int length = m_truncation != cNoTruncation ? m_truncation : m_len;
context->clip(IntRect(m_x + tx, y + ty, m_width, h));
- context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd,
+ context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, length, textRenderer()->allowTabs(), textPos(), m_toAdd,
direction() == RTL, m_dirOverride || style->visuallyOrdered()),
IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos);
context->restore();
diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h
index 80af2e3..0a83ddd 100644
--- a/WebCore/rendering/InlineTextBox.h
+++ b/WebCore/rendering/InlineTextBox.h
@@ -62,6 +62,8 @@ public:
void setFallbackFonts(const HashSet<const SimpleFontData*>&);
void takeFallbackFonts(Vector<const SimpleFontData*>&);
+ unsigned short truncation() { return m_truncation; }
+
private:
virtual int selectionTop();
virtual int selectionHeight();
diff --git a/WebCore/rendering/RenderArena.cpp b/WebCore/rendering/RenderArena.cpp
index 3ab4dff..41f33de 100644
--- a/WebCore/rendering/RenderArena.cpp
+++ b/WebCore/rendering/RenderArena.cpp
@@ -114,7 +114,7 @@ void RenderArena::free(size_t size, void* ptr)
// Use standard free so that memory debugging tools work.
RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1;
ASSERT(header->signature == signature);
- ASSERT(header->size == size);
+ ASSERT_UNUSED(size, header->size == size);
ASSERT(header->arena == this);
header->signature = signatureDead;
::free(header);
diff --git a/WebCore/rendering/RenderBR.cpp b/WebCore/rendering/RenderBR.cpp
index 012a433..340d6b7 100644
--- a/WebCore/rendering/RenderBR.cpp
+++ b/WebCore/rendering/RenderBR.cpp
@@ -62,7 +62,7 @@ int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
return s->font().lineSpacing();
}
if (lh.isPercent())
- return lh.calcMinValue(s->fontSize(), true);
+ return lh.calcMinValue(s->fontSize());
return lh.value();
}
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 4d60569..bffade7 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -415,6 +415,31 @@ void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildLi
toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
}
+void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList)
+{
+ RenderObject* nextChild = children()->firstChild();
+ while (nextChild) {
+ RenderObject* child = nextChild;
+ nextChild = child->nextSibling();
+ toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false);
+ }
+}
+
+void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild)
+{
+ ASSERT(!beforeChild || to == beforeChild->parent());
+ if (!beforeChild) {
+ moveAllChildrenTo(to, toChildList);
+ return;
+ }
+ RenderObject* nextChild = children()->firstChild();
+ while (nextChild) {
+ RenderObject* child = nextChild;
+ nextChild = child->nextSibling();
+ toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
+ }
+}
+
void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
{
// makeChildrenNonInline takes a block whose children are *all* inline and it
@@ -521,20 +546,12 @@ void RenderBlock::removeChild(RenderObject* oldChild)
// Take all the children out of the |next| block and put them in
// the |prev| block.
prev->setNeedsLayoutAndPrefWidthsRecalc();
- RenderObject* o = next->firstChild();
-
RenderBlock* nextBlock = toRenderBlock(next);
RenderBlock* prevBlock = toRenderBlock(prev);
- while (o) {
- RenderObject* no = o;
- o = no->nextSibling();
- nextBlock->moveChildTo(prevBlock, prevBlock->children(), no);
- }
-
+ nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children());
+ // Delete the now-empty block's lines and nuke it.
nextBlock->deleteLineBoxTree();
-
- // Nuke the now-empty block.
- next->destroy();
+ nextBlock->destroy();
}
RenderBox::removeChild(oldChild);
@@ -547,17 +564,15 @@ void RenderBlock::removeChild(RenderObject* oldChild)
setNeedsLayoutAndPrefWidthsRecalc();
RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false));
setChildrenInline(true);
- RenderObject* o = anonBlock->firstChild();
- while (o) {
- RenderObject* no = o;
- o = no->nextSibling();
- anonBlock->moveChildTo(this, children(), no);
- }
-
+ anonBlock->moveAllChildrenTo(this, children());
// Delete the now-empty block's lines and nuke it.
anonBlock->deleteLineBoxTree();
anonBlock->destroy();
}
+
+ // If this was our last child be sure to clear out our line boxes.
+ if (childrenInline() && !firstChild())
+ lineBoxes()->deleteLineBoxes(renderArena());
}
bool RenderBlock::isSelfCollapsingBlock() const
@@ -1698,7 +1713,7 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ
offsetForContents(tx, ty);
if (type == CursorCaret)
- document()->frame()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
+ document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
else
document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
}
@@ -1965,8 +1980,11 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo);
if (!gapRectsBounds.isEmpty()) {
if (RenderLayer* layer = enclosingLayer()) {
- IntSize offset = hasLayer() ? IntSize() : offsetFromAncestorContainer(layer->renderer());
- gapRectsBounds.move(offset - IntSize(tx, ty));
+ gapRectsBounds.move(IntSize(-tx, -ty));
+ if (!hasLayer()) {
+ FloatRect localBounds(gapRectsBounds);
+ gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox();
+ }
layer->addBlockSelectionGapsBounds(gapRectsBounds);
}
}
@@ -2655,6 +2673,9 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
return bottom;
+
+ if (!firstChild() && (!width() || !height()))
+ return bottom;
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
@@ -2747,6 +2768,9 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
return right;
+ if (!firstChild() && (!width() || !height()))
+ return right;
+
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
// For now, we have to descend into all the children, since we may have a huge abs div inside
@@ -2841,6 +2865,9 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
return left;
+ if (!firstChild() && (!width() || !height()))
+ return left;
+
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
// For now, we have to descend into all the children, since we may have a huge abs div inside
@@ -2938,7 +2965,7 @@ RenderBlock::rightBottom()
return bottom;
}
-void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom)
+void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest)
{
if (top >= bottom)
return;
@@ -2950,7 +2977,7 @@ void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom)
lowestDirtyLine = lowestDirtyLine->prevRootBox();
}
- while (afterLowest && afterLowest->blockHeight() >= top) {
+ while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) {
afterLowest->markDirty();
afterLowest = afterLowest->prevRootBox();
}
@@ -3214,18 +3241,35 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos)
}
// We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
- // FIXME: Note that the remaining space checks aren't quite accurate, since you should be able to clear only some floats (the minimum # needed
- // to fit) and not all (we should be using nextFloatBottomBelow and looping).
int result = clearSet ? max(0, bottom - yPos) : 0;
if (!result && child->avoidsFloats()) {
- int oldYPos = child->y();
- int oldWidth = child->width();
- child->setY(yPos);
- child->calcWidth();
- if (child->width() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth())
- result = max(0, floatBottom() - yPos);
- child->setY(oldYPos);
- child->setWidth(oldWidth);
+ int availableWidth = this->availableWidth();
+ if (child->minPrefWidth() > availableWidth)
+ return 0;
+
+ int y = yPos;
+ while (true) {
+ int widthAtY = lineWidth(y, false);
+ if (widthAtY == availableWidth)
+ return y - yPos;
+
+ int oldChildY = child->y();
+ int oldChildWidth = child->width();
+ child->setY(y);
+ child->calcWidth();
+ int childWidthAtY = child->width();
+ child->setY(oldChildY);
+ child->setWidth(oldChildWidth);
+
+ if (childWidthAtY <= widthAtY)
+ return y - yPos;
+
+ y = nextFloatBottomBelow(y);
+ ASSERT(y >= yPos);
+ if (y < yPos)
+ break;
+ }
+ ASSERT_NOT_REACHED();
}
return result;
}
@@ -5018,7 +5062,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int*
return IntRect(x, y, caretWidth, height);
}
-void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
// inline boxes above and below us (thus getting merged with them to form a single irregular
@@ -5030,16 +5074,19 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in
bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox();
int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0;
int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0;
- graphicsContext->addFocusRingRect(IntRect(tx, ty - topMargin,
- width(), height() + topMargin + bottomMargin));
- } else
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin);
+ if (!rect.isEmpty())
+ rects.append(rect);
+ } else if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
if (!hasOverflowClip() && !hasControlClip()) {
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
int top = max(curr->lineTop(), curr->y());
int bottom = min(curr->lineBottom(), curr->y() + curr->height());
- graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + top, curr->width(), bottom - top));
+ IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
+ if (!rect.isEmpty())
+ rects.append(rect);
}
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
@@ -5051,13 +5098,13 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in
pos = curr->localToAbsolute();
else
pos = FloatPoint(tx + box->x(), ty + box->y());
- box->addFocusRingRects(graphicsContext, pos.x(), pos.y());
+ box->addFocusRingRects(rects, pos.x(), pos.y());
}
}
}
if (inlineContinuation())
- inlineContinuation()->addFocusRingRects(graphicsContext,
+ inlineContinuation()->addFocusRingRects(rects,
tx - x() + inlineContinuation()->containingBlock()->x(),
ty - y() + inlineContinuation()->containingBlock()->y());
}
diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h
index 985074d..884695a 100644
--- a/WebCore/rendering/RenderBlock.h
+++ b/WebCore/rendering/RenderBlock.h
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -34,7 +34,6 @@ namespace WebCore {
class InlineIterator;
class RenderInline;
-class RootInlineBox;
struct BidiRun;
@@ -142,6 +141,8 @@ public:
protected:
void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child);
void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child);
+ void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList);
+ void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild);
int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); }
int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); }
@@ -363,12 +364,12 @@ private:
virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
void adjustPointToColumnContents(IntPoint&) const;
void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust
- void markLinesDirtyInVerticalRange(int top, int bottom);
+ void markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest = 0);
void newLine(EClear);
@@ -528,6 +529,10 @@ private:
RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>.
mutable int m_lineHeight;
+
+ // RenderRubyBase objects need to be able to split and merge, moving their children around
+ // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline).
+ friend class RenderRubyBase;
};
inline RenderBlock* toRenderBlock(RenderObject* object)
diff --git a/WebCore/rendering/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp
index e0d712c..c76d963 100644
--- a/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 Apple Inc. All right reserved.
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,6 +30,7 @@
#include "RenderInline.h"
#include "RenderListMarker.h"
#include "RenderView.h"
+#include "TrailingFloatsRootInlineBox.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>
#include <wtf/RefCountedLeakCounter.h>
@@ -830,7 +832,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// Figure out if we should clear out our line boxes.
// FIXME: Handle resize eventually!
- bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren;
+ bool fullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren;
if (fullLayout)
lineBoxes()->deleteLineBoxes(renderArena());
@@ -882,6 +884,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool endOfInline = false;
RenderObject* o = bidiFirst(this, 0, false);
Vector<FloatWithRect> floats;
+ bool hasInlineChild = false;
while (o) {
if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
RenderBox* box = toRenderBox(o);
@@ -909,6 +912,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
o->layoutIfNeeded();
}
} else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
+ hasInlineChild = true;
if (fullLayout || o->selfNeedsLayout())
dirtyLineBoxesForRenderer(o, fullLayout);
o->setNeedsLayout(false);
@@ -988,7 +992,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool previousLineBrokeCleanly = true;
RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex);
- if (fullLayout && !selfNeedsLayout()) {
+ if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
// we're supposed to.
RenderView* v = view();
@@ -1229,6 +1233,16 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// In case we have a float on the last line, it might not be positioned up to now.
// This has to be done before adding in the bottom border/padding, or the float will
// include the padding incorrectly. -dwh
+ if (checkForFloatsFromLastLine) {
+ int bottomVisualOverflow = lastRootBox()->bottomVisualOverflow();
+ int bottomLayoutOverflow = lastRootBox()->bottomLayoutOverflow();
+ TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
+ m_lineBoxes.appendLineBox(trailingFloatsLineBox);
+ trailingFloatsLineBox->setConstructed();
+ trailingFloatsLineBox->verticallyAlignBoxes(height());
+ trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0);
+ trailingFloatsLineBox->setBlockHeight(height());
+ }
if (lastFloat) {
for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
}
@@ -1291,7 +1305,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
if (floats[floatIndex].rect.size() != newSize) {
int floatTop = floats[floatIndex].rect.y();
curr->markDirty();
- markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()));
+ markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()), curr);
floats[floatIndex].rect.setSize(newSize);
dirtiedByFloat = true;
}
@@ -1908,6 +1922,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
int wordSpacing = o->style()->wordSpacing();
int lastSpaceWordSpacing = 0;
+ // Non-zero only when kerning is enabled, in which case we measure words with their trailing
+ // space, then subtract its width.
+ int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.spaceWidth() + wordSpacing : 0;
+
int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
int charWidth = 0;
bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
@@ -2002,7 +2020,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
}
- int additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
+ int additionalTmpW;
+ if (wordTrailingSpaceWidth && currentCharacterIsSpace)
+ additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
+ else
+ additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
tmpW += additionalTmpW;
if (!appliedStartWidth) {
tmpW += inlineWidth(o, true, false);
@@ -2034,7 +2056,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
}
if (lineWasTooWide || w + tmpW > width) {
- if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
+ if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
if (!stoppedIgnoringSpaces && pos > 0) {
// We need to stop right before the newline and then start up again.
addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index a7c2e63..60230d4 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -26,6 +26,7 @@
#include "RenderBox.h"
#include "CachedImage.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "FrameView.h"
@@ -335,12 +336,12 @@ IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContaine
return box;
}
-void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
}
-
IntRect RenderBox::reflectionBox() const
{
IntRect result;
@@ -568,13 +569,14 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
const FillLayer* bgLayer = style()->backgroundLayers();
Color bgColor = style()->backgroundColor();
+ RenderObject* bodyObject = 0;
if (!style()->hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) {
// Locate the <body> element using the DOM. This is easier than trying
// to crawl around a render tree with potential :before/:after content and
// anonymous blocks created by inline <body> tags etc. We can locate the <body>
// render object very easily via the DOM.
HTMLElement* body = document()->body();
- RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
+ bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
if (bodyObject) {
bgLayer = bodyObject->style()->backgroundLayers();
bgColor = bodyObject->style()->backgroundColor();
@@ -602,7 +604,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
- paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh);
+ paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh, CompositeSourceOver, bodyObject);
if (style()->hasBorder() && style()->display() != INLINE)
paintBorder(paintInfo.context, tx, ty, w, h, style());
@@ -670,9 +672,25 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int
bool compositedMask = hasLayer() && layer()->hasCompositedMask();
CompositeOperator compositeOp = CompositeSourceOver;
+ bool allMaskImagesLoaded = true;
+
if (!compositedMask) {
StyleImage* maskBoxImage = style()->maskBoxImage().image();
- if (maskBoxImage && style()->maskLayers()->hasImage()) {
+ const FillLayer* maskLayers = style()->maskLayers();
+
+ // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
+ if (maskBoxImage)
+ allMaskImagesLoaded &= maskBoxImage->isLoaded();
+
+ if (maskLayers)
+ allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
+
+ // Before all images have loaded, just use an empty transparency layer as the mask.
+ if (!allMaskImagesLoaded)
+ pushTransparencyLayer = true;
+
+ if (maskBoxImage && maskLayers->hasImage()) {
+ // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask.
pushTransparencyLayer = true;
} else {
// We have to use an extra image buffer to hold the mask. Multiple mask images need
@@ -682,7 +700,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int
// and composite that buffer as the mask.
// We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
// before pushing the transparency layer.
- for (const FillLayer* fillLayer = style()->maskLayers()->next(); fillLayer; fillLayer = fillLayer->next()) {
+ for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) {
if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
pushTransparencyLayer = true;
// We found one image that can be used in rendering, exit the loop
@@ -699,8 +717,10 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int
}
}
- paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
- paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
+ if (allMaskImagesLoaded) {
+ paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
+ paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
+ }
if (pushTransparencyLayer)
paintInfo.context->endTransparencyLayer();
@@ -725,18 +745,18 @@ IntRect RenderBox::maskClipRect()
return result;
}
-void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
+void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
{
if (!fillLayer)
return;
- paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op);
- paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op);
+ paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject);
+ paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject);
}
-void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
+void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
{
- paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op);
+ paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op, backgroundObject);
}
void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
@@ -946,18 +966,20 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool
}
}
- if (style()->position() == FixedPosition)
- fixed = true;
-
bool containerSkipped;
RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
+ bool isFixedPos = style()->position() == FixedPosition;
bool hasTransform = hasLayer() && layer()->transform();
- if (hasTransform)
- fixed = false; // Elements with transforms act as a containing block for fixed position descendants
-
+ if (hasTransform) {
+ // If this box has a transform, it acts as a fixed position container for fixed descendants,
+ // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
+ fixed &= isFixedPos;
+ } else
+ fixed |= isFixedPos;
+
IntSize containerOffset = offsetFromContainer(o);
bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
@@ -984,12 +1006,14 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor
// We don't expect absoluteToLocal() to be called during layout (yet)
ASSERT(!view() || !view()->layoutStateEnabled());
- if (style()->position() == FixedPosition)
- fixed = true;
-
+ bool isFixedPos = style()->position() == FixedPosition;
bool hasTransform = hasLayer() && layer()->transform();
- if (hasTransform)
- fixed = false; // Elements with transforms act as a containing block for fixed position descendants
+ if (hasTransform) {
+ // If this box has a transform, it acts as a fixed position container for fixed descendants,
+ // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
+ fixed &= isFixedPos;
+ } else
+ fixed |= isFixedPos;
RenderObject* o = container();
if (!o)
@@ -1968,7 +1992,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO
int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
{
// 'left' and 'right' cannot both be 'auto' because one would of been
- // converted to the static postion already
+ // converted to the static position already
ASSERT(!(left.isAuto() && right.isAuto()));
int leftValue = 0;
@@ -2002,7 +2026,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO
if (marginLeft.isAuto() && marginRight.isAuto()) {
// Both margins auto, solve for equality
if (availableSpace >= 0) {
- marginLeftValue = availableSpace / 2; // split the diference
+ marginLeftValue = availableSpace / 2; // split the difference
marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences
} else {
// see FIXME 1
@@ -2287,7 +2311,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject*
if (marginTop.isAuto() && marginBottom.isAuto()) {
// Both margins auto, solve for equality
// NOTE: This may result in negative values.
- marginTopValue = availableSpace / 2; // split the diference
+ marginTopValue = availableSpace / 2; // split the difference
marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
} else if (marginTop.isAuto()) {
// Solve for top margin
@@ -2365,7 +2389,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject*
void RenderBox::calcAbsoluteHorizontalReplaced()
{
// The following is based off of the W3C Working Draft from April 11, 2006 of
- // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
+ // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
// <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
// (block-style-comments in this function correspond to text from the spec and
// the numbers correspond to numbers in spec)
@@ -2456,7 +2480,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
int difference = availableSpace - (leftValue + rightValue);
if (difference > 0) {
- m_marginLeft = difference / 2; // split the diference
+ m_marginLeft = difference / 2; // split the difference
m_marginRight = difference - m_marginLeft; // account for odd valued differences
} else {
// see FIXME 1
@@ -2543,7 +2567,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
void RenderBox::calcAbsoluteVerticalReplaced()
{
// The following is based off of the W3C Working Draft from April 11, 2006 of
- // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
+ // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
// <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
// (block-style-comments in this function correspond to text from the spec and
// the numbers correspond to numbers in spec)
@@ -2607,7 +2631,7 @@ void RenderBox::calcAbsoluteVerticalReplaced()
int bottomValue = 0;
if (marginTop.isAuto() && marginBottom.isAuto()) {
- // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
+ // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
ASSERT(!(top.isAuto() || bottom.isAuto()));
topValue = top.calcValue(containerHeight);
diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h
index c579123..11c65e8 100644
--- a/WebCore/rendering/RenderBox.h
+++ b/WebCore/rendering/RenderBox.h
@@ -74,7 +74,7 @@ public:
// Bounds of the outline box in absolute coords. Respects transforms
virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const;
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
// Use this with caution! No type checking is done!
RenderBox* previousSiblingBox() const;
@@ -305,8 +305,8 @@ protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual void updateBoxModelInfoFromStyle();
- void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
- void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
+ void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject);
+ void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height);
diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
index 98960e0..f2cd9bd 100644
--- a/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -33,6 +33,7 @@
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderView.h"
+#include <wtf/CurrentTime.h>
using namespace std;
@@ -44,6 +45,140 @@ bool RenderBoxModelObject::s_wasFloating = false;
bool RenderBoxModelObject::s_hadLayer = false;
bool RenderBoxModelObject::s_layerWasSelfPainting = false;
+static const double cInterpolationCutoff = 800. * 800.;
+static const double cLowQualityTimeThreshold = 0.500; // 500 ms
+
+class RenderBoxModelScaleData : public Noncopyable {
+public:
+ RenderBoxModelScaleData(RenderBoxModelObject* object, const IntSize& size, const TransformationMatrix& transform, double time, bool lowQualityScale)
+ : m_size(size)
+ , m_transform(transform)
+ , m_lastPaintTime(time)
+ , m_lowQualityScale(lowQualityScale)
+ , m_highQualityRepaintTimer(object, &RenderBoxModelObject::highQualityRepaintTimerFired)
+ {
+ }
+
+ ~RenderBoxModelScaleData()
+ {
+ m_highQualityRepaintTimer.stop();
+ }
+
+ Timer<RenderBoxModelObject>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; }
+
+ const IntSize& size() const { return m_size; }
+ void setSize(const IntSize& s) { m_size = s; }
+ double lastPaintTime() const { return m_lastPaintTime; }
+ void setLastPaintTime(double t) { m_lastPaintTime = t; }
+ bool useLowQualityScale() const { return m_lowQualityScale; }
+ const TransformationMatrix& transform() const { return m_transform; }
+ void setTransform(const TransformationMatrix& transform) { m_transform = transform; }
+ void setUseLowQualityScale(bool b)
+ {
+ m_highQualityRepaintTimer.stop();
+ m_lowQualityScale = b;
+ if (b)
+ m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold);
+ }
+
+private:
+ IntSize m_size;
+ TransformationMatrix m_transform;
+ double m_lastPaintTime;
+ bool m_lowQualityScale;
+ Timer<RenderBoxModelObject> m_highQualityRepaintTimer;
+};
+
+class RenderBoxModelScaleObserver {
+public:
+ static bool shouldPaintBackgroundAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const IntSize&);
+
+ static void boxModelObjectDestroyed(RenderBoxModelObject* object)
+ {
+ if (gBoxModelObjects) {
+ RenderBoxModelScaleData* data = gBoxModelObjects->take(object);
+ delete data;
+ if (!gBoxModelObjects->size()) {
+ delete gBoxModelObjects;
+ gBoxModelObjects = 0;
+ }
+ }
+ }
+
+ static void highQualityRepaintTimerFired(RenderBoxModelObject* object)
+ {
+ RenderBoxModelScaleObserver::boxModelObjectDestroyed(object);
+ object->repaint();
+ }
+
+ static HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* gBoxModelObjects;
+};
+
+bool RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const IntSize& size)
+{
+ // If the image is not a bitmap image, then none of this is relevant and we just paint at high
+ // quality.
+ if (!image->isBitmapImage())
+ return false;
+
+ // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
+ // is actually being scaled.
+ IntSize imageSize(image->width(), image->height());
+
+ // Look ourselves up in the hashtable.
+ RenderBoxModelScaleData* data = 0;
+ if (gBoxModelObjects)
+ data = gBoxModelObjects->get(object);
+
+ const TransformationMatrix& currentTransform = context->getCTM();
+ bool contextIsScaled = !currentTransform.isIdentityOrTranslation();
+ if (!contextIsScaled && imageSize == size) {
+ // There is no scale in effect. If we had a scale in effect before, we can just delete this data.
+ if (data) {
+ gBoxModelObjects->remove(object);
+ delete data;
+ }
+ return false;
+ }
+
+ // There is no need to hash scaled images that always use low quality mode when the page demands it. This is the iChat case.
+ if (object->document()->page()->inLowQualityImageInterpolationMode()) {
+ double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
+ if (totalPixels > cInterpolationCutoff)
+ return true;
+ }
+
+ // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens
+ // very soon.
+ if (!data) {
+ data = new RenderBoxModelScaleData(object, size, currentTransform, currentTime(), false);
+ if (!gBoxModelObjects)
+ gBoxModelObjects = new HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>;
+ gBoxModelObjects->set(object, data);
+ return false;
+ }
+
+ // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with.
+ if ((!contextIsScaled || data->transform() == currentTransform) && data->size() == size)
+ return data->useLowQualityScale();
+
+ // We have data and our size just changed. If this change happened quickly, go into low quality mode and then set a repaint
+ // timer to paint in high quality mode. Otherwise it is ok to just paint in high quality mode.
+ double newTime = currentTime();
+ data->setUseLowQualityScale(newTime - data->lastPaintTime() < cLowQualityTimeThreshold);
+ data->setLastPaintTime(newTime);
+ data->setTransform(currentTransform);
+ data->setSize(size);
+ return data->useLowQualityScale();
+}
+
+HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* RenderBoxModelScaleObserver::gBoxModelObjects = 0;
+
+void RenderBoxModelObject::highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*)
+{
+ RenderBoxModelScaleObserver::highQualityRepaintTimerFired(this);
+}
+
RenderBoxModelObject::RenderBoxModelObject(Node* node)
: RenderObject(node)
, m_layer(0)
@@ -55,6 +190,7 @@ RenderBoxModelObject::~RenderBoxModelObject()
// Our layer should have been destroyed and cleared by now
ASSERT(!hasLayer());
ASSERT(!m_layer);
+ RenderBoxModelScaleObserver::boxModelObjectDestroyed(this);
}
void RenderBoxModelObject::destroyLayer()
@@ -304,9 +440,12 @@ int RenderBoxModelObject::paddingRight(bool) const
}
-void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op)
+void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op, RenderObject* backgroundObject)
{
GraphicsContext* context = paintInfo.context;
+ if (context->paintingDisabled())
+ return;
+
bool includeLeftEdge = box ? box->includeLeftEdge() : true;
bool includeRightEdge = box ? box->includeRightEdge() : true;
int bLeft = includeLeftEdge ? borderLeft() : 0;
@@ -463,21 +602,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
if (!destRect.isEmpty()) {
phase += destRect.location() - destOrigin;
CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
- RenderObject* clientForBackgroundImage = this;
- // Check if this is the root element painting a background layer propagated from <body>,
- // and pass the body's renderer as the client in that case.
- if (isRoot && !style()->hasBackground()) {
- ASSERT(node()->hasTagName(htmlTag));
- HTMLElement* body = document()->body();
- ASSERT(body);
- ASSERT(body->hasLocalName(bodyTag));
- ASSERT(body->renderer());
- if (body) {
- if (RenderObject* bodyRenderer = body->renderer())
- clientForBackgroundImage = bodyRenderer;
- }
- }
- context->drawTiledImage(bg->image(clientForBackgroundImage, tileSize), style()->colorSpace(), destRect, phase, tileSize, compositeOp);
+ RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
+ Image* image = bg->image(clientForBackgroundImage, tileSize);
+ bool useLowQualityScaling = RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(context, this, image, destRect.size());
+ context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling);
}
}
@@ -557,6 +685,17 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil
// Determine the background positioning area and set destRect to the background painting area.
// destRect will be adjusted later if the background is non-repeating.
bool fixedAttachment = fillLayer->attachment() == FixedBackgroundAttachment;
+
+#if ENABLE(FAST_MOBILE_SCROLLING)
+ if (view()->frameView() && view()->frameView()->canBlitOnScroll()) {
+ // As a side effect of an optimization to blit on scroll, we do not honor the CSS
+ // property "background-attachment: fixed" because it may result in rendering
+ // artifacts. Note, these artifacts only appear if we are blitting on scroll of
+ // a page that has fixed background images.
+ fixedAttachment = false;
+ }
+#endif
+
if (!fixedAttachment) {
destRect = IntRect(tx, ty, w, h);
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
index c9a4a0a..db7538d 100644
--- a/WebCore/rendering/RenderBoxModelObject.h
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -90,7 +90,7 @@ public:
void paintBorder(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true);
bool paintNinePieceImage(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver);
void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, ShadowStyle, bool begin = true, bool end = true);
- void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver);
+ void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
// The difference between this inline's baseline position and the line's baseline position.
int verticalPosition(bool firstLine) const;
@@ -98,6 +98,8 @@ public:
// Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed
void destroyLayer();
+ void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*);
+
protected:
void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize);
diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp
index b0aefc5..46bf9f4 100644
--- a/WebCore/rendering/RenderCounter.cpp
+++ b/WebCore/rendering/RenderCounter.cpp
@@ -38,7 +38,7 @@ using namespace HTMLNames;
typedef HashMap<RefPtr<AtomicStringImpl>, CounterNode*> CounterMap;
typedef HashMap<const RenderObject*, CounterMap*> CounterMaps;
-static CounterNode* makeCounterNode(RenderObject*, const AtomicString& counterName, bool alwaysCreateCounter);
+static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter);
static CounterMaps& counterMaps()
{
@@ -53,7 +53,7 @@ static inline RenderObject* previousSiblingOrParent(RenderObject* object)
return object->parent();
}
-static bool planCounter(RenderObject* object, const AtomicString& counterName, bool& isReset, int& value)
+static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value)
{
ASSERT(object);
@@ -66,7 +66,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b
ASSERT(style);
if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) {
- CounterDirectives directives = directivesMap->get(counterName.impl());
+ CounterDirectives directives = directivesMap->get(identifier.impl());
if (directives.m_reset) {
value = directives.m_resetValue;
if (directives.m_increment)
@@ -81,7 +81,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b
}
}
- if (counterName == "list-item") {
+ if (identifier == "list-item") {
if (object->isListItem()) {
if (toRenderListItem(object)->hasExplicitValue()) {
value = toRenderListItem(object)->explicitValue();
@@ -142,7 +142,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
if (currentCounter) {
// We have a suitable counter on the EndSearchRenderer.
if (previousSibling) { // But we already found another counter that we come after.
- if (currentCounter->isReset()) {
+ if (currentCounter->actsAsReset()) {
// We found a reset counter that is on a renderer that is a sibling of ours or a parent.
if (isReset && currentRenderer->parent() == counterOwner->parent()) {
// We are also a reset counter and the previous reset was on a sibling renderer
@@ -171,7 +171,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
// In this case we follow pretty much the same logic as above but no ASSERTs about
// previousSibling, and when we are a sibling of the end counter we must set previousSibling
// to currentCounter.
- if (currentCounter->isReset()) {
+ if (currentCounter->actsAsReset()) {
if (isReset && currentRenderer->parent() == counterOwner->parent()) {
parent = currentCounter->parent();
previousSibling = currentCounter;
@@ -201,7 +201,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
if (previousSibling) {
// Since we had a suitable previous counter before, we should only consider this one as our
// previousSibling if it is a reset counter and hence the current previousSibling is its child.
- if (currentCounter->isReset()) {
+ if (currentCounter->actsAsReset()) {
previousSibling = currentCounter;
// We are no longer interested in previous siblings of the currentRenderer or their children
// as counters they may have attached cannot be the previous sibling of the counter we are placing.
@@ -226,31 +226,25 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
return false;
}
-static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& counterName, bool alwaysCreateCounter)
+static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter)
{
ASSERT(object);
if (object->m_hasCounterNodeMap)
if (CounterMap* nodeMap = counterMaps().get(object))
- if (CounterNode* node = nodeMap->get(counterName.impl()))
+ if (CounterNode* node = nodeMap->get(identifier.impl()))
return node;
bool isReset = false;
int value = 0;
- if (!planCounter(object, counterName, isReset, value) && !alwaysCreateCounter)
+ if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter)
return 0;
CounterNode* newParent = 0;
CounterNode* newPreviousSibling = 0;
- CounterNode* newNode;
- if (findPlaceForCounter(object, counterName, isReset, newParent, newPreviousSibling)) {
- newNode = new CounterNode(object, isReset, value);
- newParent->insertAfter(newNode, newPreviousSibling, counterName);
- } else {
- // Make a reset node for counters that aren't inside an existing reset node.
- newNode = new CounterNode(object, true, value);
- }
-
+ CounterNode* newNode = new CounterNode(object, isReset, value);
+ if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling))
+ newParent->insertAfter(newNode, newPreviousSibling, identifier);
CounterMap* nodeMap;
if (object->m_hasCounterNodeMap)
nodeMap = counterMaps().get(object);
@@ -259,8 +253,30 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& co
counterMaps().set(object, nodeMap);
object->m_hasCounterNodeMap = true;
}
- nodeMap->set(counterName.impl(), newNode);
-
+ nodeMap->set(identifier.impl(), newNode);
+ if (newNode->parent() || !object->nextInPreOrder(object->parent()))
+ return newNode;
+ // Checking if some nodes that were previously counter tree root nodes
+ // should become children of this node now.
+ CounterMaps& maps = counterMaps();
+ RenderObject* stayWithin = object->parent();
+ for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) {
+ if (!currentRenderer->m_hasCounterNodeMap)
+ continue;
+ CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl());
+ if (!currentCounter)
+ continue;
+ if (currentCounter->parent()) {
+ ASSERT(newNode->firstChild());
+ if (currentRenderer->lastChild())
+ currentRenderer = currentRenderer->lastChild();
+ continue;
+ }
+ if (stayWithin != currentRenderer->parent() || !currentCounter->hasResetType())
+ newNode->insertAfter(currentCounter, newNode->lastChild(), identifier);
+ if (currentRenderer->lastChild())
+ currentRenderer = currentRenderer->lastChild();
+ }
return newNode;
}
@@ -290,12 +306,12 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const
m_counterNode = makeCounterNode(parent(), m_counter.identifier(), true);
CounterNode* child = m_counterNode;
- int value = child->isReset() ? child->value() : child->countInParent();
+ int value = child->actsAsReset() ? child->value() : child->countInParent();
String text = listMarkerText(m_counter.listStyle(), value);
if (!m_counter.separator().isNull()) {
- if (!child->isReset())
+ if (!child->actsAsReset())
child = child->parent();
while (CounterNode* parent = child->parent()) {
text = listMarkerText(m_counter.listStyle(), child->countInParent())
@@ -321,7 +337,7 @@ void RenderCounter::invalidate(const AtomicString& identifier)
setNeedsLayoutAndPrefWidthsRecalc();
}
-static void destroyCounterNodeChildren(const AtomicString& identifier, CounterNode* node)
+static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node)
{
CounterNode* previous;
for (CounterNode* child = node->lastDescendant(); child && child != node; child = previous) {
@@ -336,27 +352,132 @@ static void destroyCounterNodeChildren(const AtomicString& identifier, CounterNo
}
delete child;
}
+ RenderObject* renderer = node->renderer();
+ if (!renderer->documentBeingDestroyed()) {
+ if (RenderObjectChildList* children = renderer->virtualChildren())
+ children->invalidateCounters(renderer, identifier);
+ }
+ if (CounterNode* parent = node->parent())
+ parent->removeChild(node, identifier);
+ delete node;
}
-void RenderCounter::destroyCounterNodes(RenderObject* object)
+void RenderCounter::destroyCounterNodes(RenderObject* renderer)
{
CounterMaps& maps = counterMaps();
- CounterMap* map = maps.get(object);
- if (!map)
+ CounterMaps::iterator mapsIterator = maps.find(renderer);
+ if (mapsIterator == maps.end())
return;
- maps.remove(object);
-
+ CounterMap* map = mapsIterator->second;
CounterMap::const_iterator end = map->end();
for (CounterMap::const_iterator it = map->begin(); it != end; ++it) {
- CounterNode* node = it->second;
AtomicString identifier(it->first.get());
- destroyCounterNodeChildren(identifier, node);
- if (CounterNode* parent = node->parent())
- parent->removeChild(node, identifier);
- delete node;
+ destroyCounterNodeWithoutMapRemoval(identifier, it->second);
}
-
+ maps.remove(mapsIterator);
delete map;
+ renderer->m_hasCounterNodeMap = false;
+}
+
+void RenderCounter::destroyCounterNode(RenderObject* renderer, const AtomicString& identifier)
+{
+ CounterMap* map = counterMaps().get(renderer);
+ if (!map)
+ return;
+ CounterMap::iterator mapIterator = map->find(identifier.impl());
+ if (mapIterator == map->end())
+ return;
+ destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second);
+ map->remove(mapIterator);
+ // We do not delete "map" here even if empty because we expect to reuse
+ // it soon. In order for a renderer to lose all its counters permanently,
+ // a style change for the renderer involving removal of all counter
+ // directives must occur, in which case, RenderCounter::destroyCounterNodes()
+ // must be called.
+ // The destruction of the Renderer (possibly caused by the removal of its
+ // associated DOM node) is the other case that leads to the permanent
+ // destruction of all counters attached to a Renderer. In this case
+ // RenderCounter::destroyCounterNodes() must be and is now called, too.
+ // RenderCounter::destroyCounterNodes() handles destruction of the counter
+ // map associated with a renderer, so there is no risk in leaking the map.
+}
+
+static void updateCounters(RenderObject* renderer)
+{
+ ASSERT(renderer->style());
+ const CounterDirectiveMap* directiveMap = renderer->style()->counterDirectives();
+ if (!directiveMap)
+ return;
+ CounterDirectiveMap::const_iterator end = directiveMap->end();
+ if (!renderer->m_hasCounterNodeMap) {
+ for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it)
+ makeCounterNode(renderer, AtomicString(it->first.get()), false);
+ return;
+ }
+ CounterMap* counterMap = counterMaps().get(renderer);
+ ASSERT(counterMap);
+ for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) {
+ CounterNode* node = counterMap->get(it->first.get());
+ if (!node) {
+ makeCounterNode(renderer, AtomicString(it->first.get()), false);
+ continue;
+ }
+ CounterNode* newParent = 0;
+ CounterNode* newPreviousSibling;
+ findPlaceForCounter(renderer, AtomicString(it->first.get()), node->hasResetType(), newParent, newPreviousSibling);
+ CounterNode* parent = node->parent();
+ if (newParent == parent && newPreviousSibling == node->previousSibling())
+ continue;
+ if (parent)
+ parent->removeChild(node, it->first.get());
+ newParent->insertAfter(node, newPreviousSibling, it->first.get());
+ }
+}
+
+void RenderCounter::rendererSubtreeAttached(RenderObject* renderer)
+{
+ for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
+ updateCounters(descendant);
+}
+
+void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle)
+{
+ const CounterDirectiveMap* newCounterDirectives;
+ const CounterDirectiveMap* oldCounterDirectives;
+ if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) {
+ if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
+ CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
+ CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives->end();
+ for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
+ CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirectives->find(it->first);
+ if (oldMapIt != oldMapEnd) {
+ if (oldMapIt->second == it->second)
+ continue;
+ RenderCounter::destroyCounterNode(renderer, it->first.get());
+ }
+ // We must create this node here, because the changed node may be a node with no display such as
+ // as those created by the increment or reset directives and the re-layout that will happen will
+ // not catch the change if the node had no children.
+ makeCounterNode(renderer, it->first.get(), false);
+ }
+ // Destroying old counters that do not exist in the new counterDirective map.
+ for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) {
+ if (!newCounterDirectives->contains(it->first))
+ RenderCounter::destroyCounterNode(renderer, it->first.get());
+ }
+ } else {
+ if (renderer->m_hasCounterNodeMap)
+ RenderCounter::destroyCounterNodes(renderer);
+ }
+ } else if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
+ CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
+ for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
+ // We must create this node here, because the added node may be a node with no display such as
+ // as those created by the increment or reset directives and the re-layout that will happen will
+ // not catch the change if the node had no children.
+ makeCounterNode(renderer, it->first.get(), false);
+ }
+ }
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h
index 356f1bd..10ba1dc 100644
--- a/WebCore/rendering/RenderCounter.h
+++ b/WebCore/rendering/RenderCounter.h
@@ -40,6 +40,9 @@ public:
void invalidate(const AtomicString& identifier);
static void destroyCounterNodes(RenderObject*);
+ static void destroyCounterNode(RenderObject*, const AtomicString& identifier);
+ static void rendererSubtreeAttached(RenderObject*);
+ static void rendererStyleChanged(RenderObject*, const RenderStyle* oldStyle, const RenderStyle* newStyle);
private:
virtual const char* renderName() const;
diff --git a/WebCore/rendering/RenderEmbeddedObject.cpp b/WebCore/rendering/RenderEmbeddedObject.cpp
new file mode 100644
index 0000000..db32808
--- /dev/null
+++ b/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderEmbeddedObject.h"
+
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "HTMLEmbedElement.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
+#include "HTMLParamElement.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "PluginWidget.h"
+#include "RenderView.h"
+#include "RenderWidgetProtector.h"
+#include "Text.h"
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLVideoElement.h"
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PluginWidget.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
+ : RenderPartObject(element)
+{
+ view()->frameView()->setIsVisuallyNonEmpty();
+}
+
+RenderEmbeddedObject::~RenderEmbeddedObject()
+{
+ if (frameView())
+ frameView()->removeWidgetToUpdate(this);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool RenderEmbeddedObject::requiresLayer() const
+{
+ if (RenderPartObject::requiresLayer())
+ return true;
+
+ return allowsAcceleratedCompositing();
+}
+
+bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
+{
+ return widget() && widget()->isPluginWidget() && static_cast<PluginWidget*>(widget())->platformLayer();
+}
+#endif
+
+static bool isURLAllowed(Document* doc, const String& url)
+{
+ if (doc->frame()->page()->frameCount() >= 200)
+ return false;
+
+ // We allow one level of self-reference because some sites depend on that.
+ // But we don't allow more than one.
+ KURL completeURL = doc->completeURL(url);
+ bool foundSelfReference = false;
+ for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
+ if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
+ if (foundSelfReference)
+ return false;
+ foundSelfReference = true;
+ }
+ }
+ return true;
+}
+
+typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
+
+static ClassIdToTypeMap* createClassIdToTypeMap()
+{
+ ClassIdToTypeMap* map = new ClassIdToTypeMap;
+ map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
+ map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
+ map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
+ map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
+ map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
+ map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
+ return map;
+}
+
+static String serviceTypeForClassId(const String& classId)
+{
+ // Return early if classId is empty (since we won't do anything below).
+ // Furthermore, if classId is null, calling get() below will crash.
+ if (classId.isEmpty())
+ return String();
+
+ static ClassIdToTypeMap* map = createClassIdToTypeMap();
+ return map->get(classId);
+}
+
+static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
+{
+ // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
+ // require "src" attribute).
+ int srcIndex = -1, dataIndex = -1;
+ for (unsigned int i = 0; i < paramNames->size(); ++i) {
+ if (equalIgnoringCase((*paramNames)[i], "src"))
+ srcIndex = i;
+ else if (equalIgnoringCase((*paramNames)[i], "data"))
+ dataIndex = i;
+ }
+
+ if (srcIndex == -1 && dataIndex != -1) {
+ paramNames->append("src");
+ paramValues->append((*paramValues)[dataIndex]);
+ }
+}
+
+void RenderEmbeddedObject::updateWidget(bool onlyCreateNonNetscapePlugins)
+{
+ String url;
+ String serviceType;
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ Frame* frame = frameView()->frame();
+
+ // The calls to FrameLoader::requestObject within this function can result in a plug-in being initialized.
+ // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from
+ // the render tree and destroyed, causing a crash like <rdar://problem/6954546>. By extending our lifetime
+ // artifically to ensure that we remain alive for the duration of plug-in initialization.
+ RenderWidgetProtector protector(this);
+
+ if (node()->hasTagName(objectTag)) {
+ HTMLObjectElement* objectElement = static_cast<HTMLObjectElement*>(node());
+
+ objectElement->setNeedWidgetUpdate(false);
+ if (!objectElement->isFinishedParsingChildren())
+ return;
+
+ // Check for a child EMBED tag.
+ HTMLEmbedElement* embed = 0;
+ for (Node* child = objectElement->firstChild(); child; ) {
+ if (child->hasTagName(embedTag)) {
+ embed = static_cast<HTMLEmbedElement*>(child);
+ break;
+ }
+
+ if (child->hasTagName(objectTag))
+ child = child->nextSibling(); // Don't descend into nested OBJECT tags
+ else
+ child = child->traverseNextNode(objectElement); // Otherwise descend (EMBEDs may be inside COMMENT tags)
+ }
+
+ // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
+ HTMLElement* embedOrObject;
+ if (embed) {
+ embedOrObject = embed;
+ url = embed->url();
+ serviceType = embed->serviceType();
+ } else
+ embedOrObject = objectElement;
+
+ // If there was no URL or type defined in EMBED, try the OBJECT tag.
+ if (url.isEmpty())
+ url = objectElement->url();
+ if (serviceType.isEmpty())
+ serviceType = objectElement->serviceType();
+
+ HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
+
+ // Scan the PARAM children.
+ // Get the URL and type from the params if we don't already have them.
+ // Get the attributes from the params if there is no EMBED tag.
+ Node* child = objectElement->firstChild();
+ while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
+ if (child->hasTagName(paramTag)) {
+ HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
+ String name = p->name();
+ if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
+ url = p->value();
+ if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
+ serviceType = p->value();
+ int pos = serviceType.find(";");
+ if (pos != -1)
+ serviceType = serviceType.left(pos);
+ }
+ if (!embed && !name.isEmpty()) {
+ uniqueParamNames.add(name.impl());
+ paramNames.append(p->name());
+ paramValues.append(p->value());
+ }
+ }
+ child = child->nextSibling();
+ }
+
+ // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
+ // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
+ // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
+ // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
+ // else our Java plugin will misinterpret it. [4004531]
+ String codebase;
+ if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
+ codebase = "codebase";
+ uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
+ }
+
+ // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
+ NamedNodeMap* attributes = embedOrObject->attributes();
+ if (attributes) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ const AtomicString& name = it->name().localName();
+ if (embed || !uniqueParamNames.contains(name.impl())) {
+ paramNames.append(name.string());
+ paramValues.append(it->value().string());
+ }
+ }
+ }
+
+ mapDataParamToSrc(&paramNames, &paramValues);
+
+ // If we still don't have a type, try to map from a specific CLASSID to a type.
+ if (serviceType.isEmpty())
+ serviceType = serviceTypeForClassId(objectElement->classId());
+
+ if (!isURLAllowed(document(), url))
+ return;
+
+ // Find out if we support fallback content.
+ m_hasFallbackContent = false;
+ for (Node* child = objectElement->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
+ if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) // Discount <embed> and <param>
+ || (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
+ m_hasFallbackContent = true;
+ }
+
+ if (onlyCreateNonNetscapePlugins) {
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = frame->loader()->completeURL(url);
+
+ if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
+ return;
+ }
+
+ bool success = objectElement->dispatchBeforeLoadEvent(url) && frame->loader()->requestObject(this, url, objectElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
+ if (!success && m_hasFallbackContent)
+ objectElement->renderFallbackContent();
+
+ } else if (node()->hasTagName(embedTag)) {
+ HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(node());
+ embedElement->setNeedWidgetUpdate(false);
+ url = embedElement->url();
+ serviceType = embedElement->serviceType();
+
+ if (url.isEmpty() && serviceType.isEmpty())
+ return;
+ if (!isURLAllowed(document(), url))
+ return;
+
+ // add all attributes set on the embed object
+ NamedNodeMap* attributes = embedElement->attributes();
+ if (attributes) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ paramNames.append(it->name().localName().string());
+ paramValues.append(it->value().string());
+ }
+ }
+
+ if (onlyCreateNonNetscapePlugins) {
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = frame->loader()->completeURL(url);
+
+ if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
+ return;
+ }
+
+ if (embedElement->dispatchBeforeLoadEvent(url))
+ frame->loader()->requestObject(this, url, embedElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
+ }
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) {
+ HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node());
+
+ mediaElement->setNeedWidgetUpdate(false);
+ if (node()->hasTagName(videoTag)) {
+ HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node());
+ String poster = vid->poster();
+ if (!poster.isEmpty()) {
+ paramNames.append("_media_element_poster_");
+ paramValues.append(poster);
+ }
+ }
+
+ url = mediaElement->initialURL();
+ if (!url.isEmpty()) {
+ paramNames.append("_media_element_src_");
+ paramValues.append(url);
+ }
+
+ serviceType = "application/x-media-element-proxy-plugin";
+
+ if (mediaElement->dispatchBeforeLoadEvent(url))
+ frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues);
+ }
+#endif
+}
+
+void RenderEmbeddedObject::layout()
+{
+ ASSERT(needsLayout());
+
+ calcWidth();
+ calcHeight();
+
+ RenderPart::layout();
+
+ m_overflow.clear();
+ addShadowOverflow();
+
+ if (!widget() && frameView())
+ frameView()->addWidgetToUpdate(this);
+
+ setNeedsLayout(false);
+}
+
+}
diff --git a/WebCore/rendering/RenderEmbeddedObject.h b/WebCore/rendering/RenderEmbeddedObject.h
new file mode 100644
index 0000000..bdaea92
--- /dev/null
+++ b/WebCore/rendering/RenderEmbeddedObject.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderEmbeddedObject_h
+#define RenderEmbeddedObject_h
+
+#include "RenderPartObject.h"
+
+namespace WebCore {
+
+// Renderer for embeds and objects.
+class RenderEmbeddedObject : public RenderPartObject {
+public:
+ RenderEmbeddedObject(Element*);
+ virtual ~RenderEmbeddedObject();
+
+ void updateWidget(bool onlyCreateNonNetscapePlugins);
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool allowsAcceleratedCompositing() const;
+#endif
+
+private:
+ virtual const char* renderName() const { return "RenderEmbeddedObject"; }
+ virtual bool isEmbeddedObject() const { return true; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool requiresLayer() const;
+#endif
+
+ virtual void layout();
+};
+
+inline RenderEmbeddedObject* toRenderEmbeddedObject(RenderObject* object)
+{
+ ASSERT(!object || !strcmp(object->renderName(), "RenderEmbeddedObject"));
+ return static_cast<RenderEmbeddedObject*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderEmbeddedObject(const RenderEmbeddedObject*);
+
+} // namespace WebCore
+
+#endif // RenderEmbeddedObject_h
diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp
index 37ee8fb..59cbacf 100644
--- a/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/WebCore/rendering/RenderFileUploadControl.cpp
@@ -21,6 +21,7 @@
#include "config.h"
#include "RenderFileUploadControl.h"
+#include "Chrome.h"
#include "FileList.h"
#include "Frame.h"
#include "FrameView.h"
@@ -108,6 +109,11 @@ bool RenderFileUploadControl::allowsMultipleFiles()
return !input->getAttribute(multipleAttr).isNull();
}
+String RenderFileUploadControl::acceptTypes()
+{
+ return static_cast<HTMLInputElement*>(node())->accept();
+}
+
void RenderFileUploadControl::click()
{
Frame* frame = node()->document()->frame();
diff --git a/WebCore/rendering/RenderFileUploadControl.h b/WebCore/rendering/RenderFileUploadControl.h
index 72ba308..dcdce4d 100644
--- a/WebCore/rendering/RenderFileUploadControl.h
+++ b/WebCore/rendering/RenderFileUploadControl.h
@@ -49,6 +49,7 @@ public:
String fileTextValue() const;
bool allowsMultipleFiles();
+ String acceptTypes();
private:
virtual const char* renderName() const { return "RenderFileUploadControl"; }
diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp
index b15d55c..6597554 100644
--- a/WebCore/rendering/RenderForeignObject.cpp
+++ b/WebCore/rendering/RenderForeignObject.cpp
@@ -84,12 +84,14 @@ FloatRect RenderForeignObject::repaintRectInLocalCoordinates() const
void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
{
rect = localToParentTransform().mapRect(rect);
+ style()->svgStyle()->inflateForShadow(rect);
RenderBlock::computeRectForRepaint(repaintContainer, rect, fixed);
}
-TransformationMatrix RenderForeignObject::localToParentTransform() const
+const TransformationMatrix& RenderForeignObject::localToParentTransform() const
{
- return localTransform() * translationForAttributes();
+ m_localToParentTransform = localTransform() * translationForAttributes();
+ return m_localToParentTransform;
}
void RenderForeignObject::layout()
@@ -118,6 +120,11 @@ bool RenderForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int
return false;
}
+void RenderForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
+{
+ SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
+}
+
} // namespace WebCore
#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
diff --git a/WebCore/rendering/RenderForeignObject.h b/WebCore/rendering/RenderForeignObject.h
index e014f22..8cb9a55 100644
--- a/WebCore/rendering/RenderForeignObject.h
+++ b/WebCore/rendering/RenderForeignObject.h
@@ -38,25 +38,29 @@ public:
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
virtual bool requiresLayer() const { return false; }
virtual void layout();
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return borderBoxRect(); }
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool isSVGForeignObject() const { return true; }
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const;
+
private:
TransformationMatrix translationForAttributes() const;
virtual TransformationMatrix localTransform() const { return m_localTransform; }
TransformationMatrix m_localTransform;
+ mutable TransformationMatrix m_localToParentTransform;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index d06ca1f..881d0b4 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -4,7 +4,7 @@
* (C) 2000 Dirk Mueller (mueller@kde.org)
* (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,14 +26,19 @@
#include "config.h"
#include "RenderImage.h"
+#include "Frame.h"
#include "GraphicsContext.h"
+#include "HTMLAreaElement.h"
+#include "HTMLCollection.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
#include "HTMLMapElement.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
#include "Page.h"
+#include "RenderTheme.h"
#include "RenderView.h"
+#include "SelectionController.h"
#include <wtf/CurrentTime.h>
#include <wtf/UnusedParam.h>
@@ -430,20 +435,77 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
#endif
IntSize contentSize(cWidth, cHeight);
- bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, contentSize);
IntRect rect(IntPoint(tx + leftBorder + leftPad, ty + topBorder + topPad), contentSize);
- HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
- CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
- context->drawImage(image(cWidth, cHeight), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
+ paintIntoRect(context, rect);
}
}
+void RenderImage::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ RenderReplaced::paint(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseOutline)
+ paintFocusRings(paintInfo, style());
+}
+
+void RenderImage::paintFocusRings(PaintInfo& paintInfo, const RenderStyle* style)
+{
+ // Don't draw focus rings if printing.
+ if (document()->printing() || !document()->frame()->selection()->isFocusedAndActive())
+ return;
+
+ if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints())
+ return;
+
+ HTMLMapElement* mapElement = imageMap();
+ if (!mapElement)
+ return;
+
+ Document* document = mapElement->document();
+ if (!document)
+ return;
+
+ Node* focusedNode = document->focusedNode();
+ if (!focusedNode)
+ return;
+
+ RefPtr<HTMLCollection> areas = mapElement->areas();
+ unsigned numAreas = areas->length();
+
+ // FIXME: Clip the paths to the image bounding box.
+ for (unsigned k = 0; k < numAreas; ++k) {
+ HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(areas->item(k));
+ if (focusedNode != areaElement)
+ continue;
+
+ Vector<Path> focusRingPaths;
+ focusRingPaths.append(areaElement->getPath(this));
+ paintInfo.context->drawFocusRing(focusRingPaths, style->outlineWidth(), style->outlineOffset(), style->outlineColor());
+ break;
+ }
+}
+
+void RenderImage::paintIntoRect(GraphicsContext* context, const IntRect& rect)
+{
+ if (!hasImage() || errorOccurred() || rect.width() <= 0 || rect.height() <= 0)
+ return;
+
+ Image* img = image(rect.width(), rect.height());
+ if (!img || img->isNull())
+ return;
+
+ HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
+ CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
+ bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, rect.size());
+ context->drawImage(image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
+}
+
int RenderImage::minimumReplacedHeight() const
{
return errorOccurred() ? intrinsicSize().height() : 0;
}
-HTMLMapElement* RenderImage::imageMap()
+HTMLMapElement* RenderImage::imageMap() const
{
HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0;
return i ? i->document()->getImageMap(i->getAttribute(usemapAttr)) : 0;
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 2224412..bc5e2d8 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/WebCore/rendering/RenderImage.h
@@ -3,7 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -43,7 +43,7 @@ public:
void setCachedImage(CachedImage*);
CachedImage* cachedImage() const { return m_cachedImage.get(); }
- HTMLMapElement* imageMap();
+ HTMLMapElement* imageMap() const;
void resetAnimation();
@@ -57,6 +57,13 @@ protected:
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+ virtual void paintIntoRect(GraphicsContext*, const IntRect&);
+ void paintFocusRings(PaintInfo&, const RenderStyle*);
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ bool isWidthSpecified() const;
+ bool isHeightSpecified() const;
+
private:
virtual const char* renderName() const { return "RenderImage"; }
@@ -87,9 +94,6 @@ private:
int calcAspectRatioWidth() const;
int calcAspectRatioHeight() const;
- bool isWidthSpecified() const;
- bool isHeightSpecified() const;
-
protected:
// The image we are rendering.
CachedResourceHandle<CachedImage> m_cachedImage;
diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp
index 2f9a247..9571751 100644
--- a/WebCore/rendering/RenderInline.cpp
+++ b/WebCore/rendering/RenderInline.cpp
@@ -23,6 +23,7 @@
#include "config.h"
#include "RenderInline.h"
+#include "Chrome.h"
#include "FloatQuad.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
@@ -931,13 +932,15 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
repaint();
}
-void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
RootInlineBox* root = curr->root();
int top = max(root->lineTop(), curr->y());
int bottom = min(root->lineBottom(), curr->y() + curr->height());
- graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + top, curr->width(), bottom - top));
+ IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
+ if (!rect.isEmpty())
+ rects.append(rect);
}
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
@@ -948,17 +951,17 @@ void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, i
pos = curr->localToAbsolute();
else if (curr->isBox())
pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
- curr->addFocusRingRects(graphicsContext, pos.x(), pos.y());
+ curr->addFocusRingRects(rects, pos.x(), pos.y());
}
}
if (continuation()) {
if (continuation()->isInline())
- continuation()->addFocusRingRects(graphicsContext,
+ continuation()->addFocusRingRects(rects,
tx - containingBlock()->x() + continuation()->containingBlock()->x(),
ty - containingBlock()->y() + continuation()->containingBlock()->y());
else
- continuation()->addFocusRingRects(graphicsContext,
+ continuation()->addFocusRingRects(rects,
tx - containingBlock()->x() + toRenderBox(continuation())->x(),
ty - containingBlock()->y() + toRenderBox(continuation())->y());
}
@@ -975,13 +978,12 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (!oc.isValid())
oc = style()->color();
- graphicsContext->initFocusRing(ow, style()->outlineOffset());
- addFocusRingRects(graphicsContext, tx, ty);
+ Vector<IntRect> focusRingRects;
+ addFocusRingRects(focusRingRects, tx, ty);
if (style()->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(oc);
+ graphicsContext->drawFocusRing(focusRingRects, ow, style()->outlineOffset(), oc);
else
- addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
- graphicsContext->clearFocusRing();
+ addPDFURLRect(graphicsContext, unionRect(focusRingRects));
}
if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE)
diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h
index 8e9715c..d35aa85 100644
--- a/WebCore/rendering/RenderInline.h
+++ b/WebCore/rendering/RenderInline.h
@@ -65,7 +65,7 @@ public:
IntSize relativePositionedInlineOffset(const RenderBox* child) const;
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
void paintOutline(GraphicsContext*, int tx, int ty);
int verticalPositionFromCache(bool firstLine) const;
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 7e0fee9..38e5f44 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -73,11 +73,13 @@
#include "RenderScrollbar.h"
#include "RenderScrollbarPart.h"
#include "RenderTheme.h"
+#include "RenderTreeAsText.h"
#include "RenderView.h"
#include "ScaleTransformOperation.h"
#include "Scrollbar.h"
#include "ScrollbarTheme.h"
#include "SelectionController.h"
+#include "TextStream.h"
#include "TransformationMatrix.h"
#include "TransformState.h"
#include "TranslateTransformOperation.h"
@@ -657,6 +659,12 @@ static inline bool isPositionedContainer(RenderLayer* layer)
return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
}
+static inline bool isFixedPositionedContainer(RenderLayer* layer)
+{
+ RenderObject* o = layer->renderer();
+ return o->isRenderView() || layer->hasTransform();
+}
+
RenderLayer* RenderLayer::enclosingPositionedAncestor() const
{
RenderLayer* curr = parent();
@@ -826,7 +834,7 @@ void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer*
p->clip(clipRect);
p->beginTransparencyLayer(renderer()->opacity());
#ifdef REVEAL_TRANSPARENCY_LAYERS
- p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
+ p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), DeviceColorSpace);
p->fillRect(clipRect);
#endif
}
@@ -986,9 +994,10 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i
{
if (ancestorLayer == this)
return;
-
- if (renderer()->style()->position() == FixedPosition) {
- // Add in the offset of the view. We can obtain this by calling
+
+ EPosition position = renderer()->style()->position();
+ if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) {
+ // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
// localToAbsolute() on the RenderView.
FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
xPos += absPos.x();
@@ -996,9 +1005,43 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i
return;
}
+ if (position == FixedPosition) {
+ // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
+ // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
+ // so we should always find the ancestor at or before we find the fixed position container.
+ RenderLayer* fixedPositionContainerLayer = 0;
+ bool foundAncestor = false;
+ for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) {
+ if (currLayer == ancestorLayer)
+ foundAncestor = true;
+
+ if (isFixedPositionedContainer(currLayer)) {
+ fixedPositionContainerLayer = currLayer;
+ ASSERT(foundAncestor);
+ break;
+ }
+ }
+
+ ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
+
+ if (fixedPositionContainerLayer != ancestorLayer) {
+ int fixedContainerX = 0;
+ int fixedContainerY = 0;
+ convertToLayerCoords(fixedPositionContainerLayer, fixedContainerX, fixedContainerY);
+
+ int ancestorX = 0;
+ int ancestorY = 0;
+ ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorX, ancestorY);
+
+ xPos += (fixedContainerX - ancestorX);
+ yPos += (fixedContainerY - ancestorY);
+ return;
+ }
+ }
+
RenderLayer* parentLayer;
- if (renderer()->style()->position() == AbsolutePosition) {
- // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way
+ if (position == AbsolutePosition || position == FixedPosition) {
+ // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
parentLayer = parent();
bool foundAncestorFirst = false;
while (parentLayer) {
@@ -1114,7 +1157,7 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta)
frame->eventHandler()->updateAutoscrollRenderer();
}
} else if (renderer()->view()->frameView()) {
- // If we are here, we were called on a renderer that can be programatically scrolled, but doesn't
+ // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
// have an overflow clip. Which means that it is a document node that can be scrolled.
renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
// FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
@@ -1198,7 +1241,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai
// The caret rect needs to be invalidated after scrolling
Frame* frame = renderer()->document()->frame();
if (frame)
- frame->invalidateSelection();
+ frame->selection()->setNeedsLayout();
// Just schedule a full repaint of our object.
if (repaint)
@@ -1701,6 +1744,11 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
return localPoint - bottomRight;
}
+bool RenderLayer::hasOverflowControls() const
+{
+ return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
+}
+
void RenderLayer::positionOverflowControls(int tx, int ty)
{
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
@@ -1886,16 +1934,22 @@ RenderLayer::updateScrollInfoAfterLayout()
// Set up the range (and page step/line step).
if (m_hBar) {
int clientWidth = box->clientWidth();
- int pageStep = (clientWidth - cAmountToKeepWhenPaging);
- if (pageStep < 0) pageStep = clientWidth;
+ int pageStep = max(clientWidth * cFractionToStepWhenPaging, 1.f);
m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
m_hBar->setProportion(clientWidth, m_scrollWidth);
+ // Explicitly set the horizontal scroll value. This ensures that when a
+ // right-to-left scrollable area's width (or content width) changes, the
+ // top right corner of the content doesn't shift with respect to the top
+ // right corner of the area. Conceptually, right-to-left areas have
+ // their origin at the top-right, but RenderLayer is top-left oriented,
+ // so this is needed to keep everything working (see how scrollXOffset()
+ // differs from scrollYOffset() to get an idea of why the horizontal and
+ // vertical scrollbars need to be treated differently).
m_hBar->setValue(scrollXOffset());
}
if (m_vBar) {
int clientHeight = box->clientHeight();
- int pageStep = (clientHeight - cAmountToKeepWhenPaging);
- if (pageStep < 0) pageStep = clientHeight;
+ int pageStep = max(clientHeight * cFractionToStepWhenPaging, 1.f);
m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
m_vBar->setProportion(clientHeight, m_scrollHeight);
}
@@ -2228,7 +2282,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
// is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
// Else, our renderer tree may or may not contain the painting root, so we pass that root along
- // so it will be tested against as we decend through the renderers.
+ // so it will be tested against as we descend through the renderers.
RenderObject* paintingRootForRenderer = 0;
if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
paintingRootForRenderer = paintingRoot;
@@ -2351,15 +2405,10 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
}
}
- // Now determine if the result is inside an anchor; make sure an image map wins if
- // it already set URLElement and only use the innermost.
+ // Now determine if the result is inside an anchor - if the urlElement isn't already set.
Node* node = result.innerNode();
- while (node) {
- // for imagemaps, URLElement is the associated area element not the image itself
- if (node->isLink() && !result.URLElement() && !node->hasTagName(imgTag))
- result.setURLElement(static_cast<Element*>(node));
- node = node->eventParentNode();
- }
+ if (node && !result.URLElement())
+ result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
// Next set up the correct :hover/:active state along the new chain.
updateHoverActiveState(request, result);
@@ -2603,7 +2652,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
if (fgRect.contains(hitTestPoint) && isSelfPaintingLayer()) {
- // Hit test with a temporary HitTestResult, because we onlyl want to commit to 'result' if we know we're frontmost.
+ // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
HitTestResult tempResult(result.point());
if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
@@ -3238,7 +3287,7 @@ void RenderLayer::updateCompositingAndLayerListsIfNeeded()
#if USE(ACCELERATED_COMPOSITING)
if (compositor()->inCompositingMode()) {
if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty)
- compositor()->updateCompositingLayers(this);
+ compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this);
return;
}
#endif
@@ -3299,7 +3348,7 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject
bool RenderLayer::shouldBeNormalFlowOnly() const
{
- return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo()) &&
+ return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject()) &&
!renderer()->isPositioned() &&
!renderer()->isRelPositioned() &&
!renderer()->hasTransform() &&
@@ -3308,7 +3357,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const
bool RenderLayer::isSelfPaintingLayer() const
{
- return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo();
+ return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject();
}
void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
@@ -3322,7 +3371,7 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
dirtyStackingContextZOrderLists();
}
- if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) {
+ if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) {
if (!m_marquee)
m_marquee = new RenderMarquee(this);
m_marquee->updateMarqueeStyle();
@@ -3456,3 +3505,16 @@ void RenderLayer::updateReflectionStyle()
}
} // namespace WebCore
+
+#ifndef NDEBUG
+void showLayerTree(const WebCore::RenderLayer* layer)
+{
+ if (!layer)
+ return;
+
+ if (WebCore::Frame* frame = layer->renderer()->document()->frame()) {
+ WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers);
+ fprintf(stderr, "%s\n", output.utf8().data());
+ }
+}
+#endif
diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h
index af64fc4..3cdad3a 100644
--- a/WebCore/rendering/RenderLayer.h
+++ b/WebCore/rendering/RenderLayer.h
@@ -205,6 +205,7 @@ public:
void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, PaintBehavior);
bool hasReflection() const { return renderer()->hasReflection(); }
+ bool isReflection() const { return renderer()->isReplica(); }
RenderReplica* reflection() const { return m_reflection; }
RenderLayer* reflectionLayer() const;
@@ -262,6 +263,7 @@ public:
int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
+ bool hasOverflowControls() const;
void positionOverflowControls(int tx, int ty);
bool isPointInResizeControl(const IntPoint& absolutePoint) const;
bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint);
@@ -662,4 +664,9 @@ private:
} // namespace WebCore
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showLayerTree(const WebCore::RenderLayer* layer);
+#endif
+
#endif // RenderLayer_h
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index 35aa7e1..3f60557 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -41,9 +41,11 @@
#include "HTMLNames.h"
#include "InspectorTimelineAgent.h"
#include "KeyframeList.h"
+#include "PluginWidget.h"
#include "RenderBox.h"
#include "RenderImage.h"
#include "RenderLayerCompositor.h"
+#include "RenderEmbeddedObject.h"
#include "RenderVideo.h"
#include "RenderView.h"
#include "Settings.h"
@@ -57,12 +59,22 @@ namespace WebCore {
using namespace HTMLNames;
static bool hasBorderOutlineOrShadow(const RenderStyle*);
-static bool hasBoxDecorations(const RenderStyle*);
-static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle*);
+static bool hasBoxDecorationsOrBackground(const RenderStyle*);
+static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*);
+
+static inline bool is3DCanvas(RenderObject* renderer)
+{
+#if ENABLE(3D_CANVAS)
+ if (renderer->isCanvas())
+ return static_cast<HTMLCanvasElement*>(renderer->node())->is3D();
+#else
+ UNUSED_PARAM(renderer);
+#endif
+ return false;
+}
RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
: m_owningLayer(layer)
- , m_hasDirectlyCompositedContent(false)
, m_artificiallyInflatedBounds(false)
{
createGraphicsLayer();
@@ -86,11 +98,13 @@ void RenderLayerBacking::createGraphicsLayer()
m_graphicsLayer->setName("Document Node");
else {
if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID())
- m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->getAttribute(idAttr));
+ m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->getIDAttribute());
else
m_graphicsLayer->setName(renderer()->renderName());
}
- } else
+ } else if (m_owningLayer->isReflection())
+ m_graphicsLayer->setName("Reflection");
+ else
m_graphicsLayer->setName("Anonymous Node");
#endif // NDEBUG
@@ -186,30 +200,31 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
if (updateMaskLayer(m_owningLayer->renderer()->hasMask()))
m_graphicsLayer->setMaskLayer(m_maskLayer.get());
- m_hasDirectlyCompositedContent = false;
- if (canUseDirectCompositing()) {
- if (renderer()->isImage()) {
- updateImageContents();
- m_hasDirectlyCompositedContent = true;
- m_graphicsLayer->setDrawsContent(false);
- }
-#if ENABLE(3D_CANVAS)
- else if (renderer()->isCanvas()) {
- HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node());
- if (canvas->is3D()) {
- WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(canvas->renderingContext());
- if (context->graphicsContext3D()->platformGraphicsContext3D())
- m_graphicsLayer->setContentsToGraphicsContext3D(context->graphicsContext3D());
- }
+ if (m_owningLayer->hasReflection()) {
+ if (m_owningLayer->reflectionLayer()->backing()) {
+ GraphicsLayer* reflectionLayer = m_owningLayer->reflectionLayer()->backing()->graphicsLayer();
+ m_graphicsLayer->setReplicatedByLayer(reflectionLayer);
}
-#endif
+ } else
+ m_graphicsLayer->setReplicatedByLayer(0);
+
+ if (isDirectlyCompositedImage())
+ updateImageContents();
- if (rendererHasBackground())
- m_graphicsLayer->setBackgroundColor(rendererBackgroundColor());
- else
- m_graphicsLayer->clearBackgroundColor();
+ if (renderer()->isEmbeddedObject() && toRenderEmbeddedObject(renderer())->allowsAcceleratedCompositing()) {
+ PluginWidget* pluginWidget = static_cast<PluginWidget*>(toRenderEmbeddedObject(renderer())->widget());
+ m_graphicsLayer->setContentsToMedia(pluginWidget->platformLayer());
}
+#if ENABLE(3D_CANVAS)
+ if (is3DCanvas(renderer())) {
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node());
+ WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(canvas->renderingContext());
+ if (context->graphicsContext3D()->platformGraphicsContext3D())
+ m_graphicsLayer->setContentsToGraphicsContext3D(context->graphicsContext3D());
+ }
+#endif
+
return layerConfigChanged;
}
@@ -229,7 +244,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
updateLayerOpacity(renderer()->style());
RenderStyle* style = renderer()->style();
- m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D);
+ m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection());
m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible);
RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
@@ -350,9 +365,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
m_foregroundLayer->setOffsetFromRenderer(foregroundOffset);
}
+ if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) {
+ RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing();
+ reflectionBacking->updateGraphicsLayerGeometry();
+
+ // The reflection layer has the bounds of m_owningLayer->reflectionLayer(),
+ // but the reflected layer is the bounds of this layer, so we need to position it appropriately.
+ FloatRect layerBounds = compositedBounds();
+ FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds();
+ reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location()));
+ }
+
m_graphicsLayer->setContentsRect(contentsBox());
- if (!m_hasDirectlyCompositedContent)
- m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow() && !m_artificiallyInflatedBounds);
+ m_graphicsLayer->setDrawsContent(containsPaintedContent());
}
void RenderLayerBacking::updateInternalHierarchy()
@@ -498,12 +523,12 @@ static bool hasBorderOutlineOrShadow(const RenderStyle* style)
return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow();
}
-static bool hasBoxDecorations(const RenderStyle* style)
+static bool hasBoxDecorationsOrBackground(const RenderStyle* style)
{
return hasBorderOutlineOrShadow(style) || style->hasBackground();
}
-static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style)
+static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style)
{
return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage();
}
@@ -563,7 +588,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
// Reject anything that has a border, a border-radius or outline,
// or any background (color or image).
// FIXME: we could optimize layers for simple backgrounds.
- if (hasBoxDecorations(style))
+ if (hasBoxDecorationsOrBackground(style))
return false;
// If we have got this far and the renderer has no children, then we're ok.
@@ -580,7 +605,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
// Reject anything that has a border, a border-radius or outline,
// or is not a simple background (no background, or solid color).
- if (hasBoxDecorationsWithBackgroundImage(style))
+ if (hasBoxDecorationsOrBackgroundImage(style))
return false;
// Now look at the body's renderer.
@@ -591,7 +616,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
style = bodyObject->style();
- if (hasBoxDecorationsWithBackgroundImage(style))
+ if (hasBoxDecorationsOrBackgroundImage(style))
return false;
// Ceck to see if all the body's children are compositing layers.
@@ -608,9 +633,11 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
return true;
}
+// Conservative test for having no rendered children.
bool RenderLayerBacking::hasNonCompositingContent() const
{
- // Conservative test for having no rendered children.
+ if (m_owningLayer->hasOverflowControls())
+ return true;
// Some HTML can cause whitespace text nodes to have renderers, like:
// <div>
@@ -627,7 +654,6 @@ bool RenderLayerBacking::hasNonCompositingContent() const
}
}
- // FIXME: test for overflow controls.
if (m_owningLayer->isStackingContext()) {
// Use the m_hasCompositingDescendant bit to optimize?
if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) {
@@ -661,51 +687,43 @@ bool RenderLayerBacking::hasNonCompositingContent() const
return false;
}
-// A layer can use direct compositing if the render layer's object is a replaced object and has no children.
-// This allows the GraphicsLayer to display the RenderLayer contents directly; it's used for images.
-bool RenderLayerBacking::canUseDirectCompositing() const
+bool RenderLayerBacking::containsPaintedContent() const
{
- RenderObject* renderObject = renderer();
-
- // Canvas3D is always direct composited
-#if ENABLE(3D_CANVAS)
- if (renderer()->isCanvas()) {
- HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node());
- return canvas->is3D();
- }
-#endif
-
- // Reject anything that isn't an image
- if (!renderObject->isImage() && !renderObject->isVideo())
+ if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
return false;
-
- if (renderObject->hasMask() || renderObject->hasReflection())
+
+ if (isDirectlyCompositedImage())
return false;
- // Video can use an inner layer even if it has box decorations; we draw those into another layer.
- if (renderObject->isVideo())
- return true;
-
- // Reject anything that would require the image to be drawn via the GraphicsContext,
- // like border, shadows etc. Solid background color is OK.
- return !hasBoxDecorationsWithBackgroundImage(renderObject->style());
+ // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely,
+ // and set background color on the layer in that case, instead of allocating backing store and painting.
+ if (renderer()->isVideo() || is3DCanvas(renderer()))
+ return hasBoxDecorationsOrBackground(renderer()->style());
+
+ return true;
}
-
+
+// An image can be directly compositing if it's the sole content of the layer, and has no box decorations
+// that require painting. Direct compositing saves backing store.
+bool RenderLayerBacking::isDirectlyCompositedImage() const
+{
+ RenderObject* renderObject = renderer();
+ return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject->style());
+}
+
void RenderLayerBacking::rendererContentChanged()
{
- if (canUseDirectCompositing()) {
- if (renderer()->isImage())
- updateImageContents();
- else {
+ if (isDirectlyCompositedImage()) {
+ updateImageContents();
+ return;
+ }
+
#if ENABLE(3D_CANVAS)
- if (renderer()->isCanvas()) {
- HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node());
- if (canvas->is3D())
- m_graphicsLayer->setGraphicsContext3DNeedsDisplay();
- }
-#endif
- }
+ if (is3DCanvas(renderer())) {
+ m_graphicsLayer->setGraphicsContext3DNeedsDisplay();
+ return;
}
+#endif
}
void RenderLayerBacking::updateImageContents()
@@ -864,14 +882,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
m_owningLayer->updateLayerListsIfNeeded();
- // Paint the reflection first if we have one.
- if (m_owningLayer->hasReflection()) {
- // Mark that we are now inside replica painting.
- m_owningLayer->setPaintingInsideReflection(true);
- m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection);
- m_owningLayer->setPaintingInsideReflection(false);
- }
-
// Calculate the clip rects we should use.
IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
@@ -1062,7 +1072,7 @@ bool RenderLayerBacking::showRepaintCounter() const
return compositor() ? compositor()->showRepaintCounter() : false;
}
-bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes)
+bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes)
{
bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform);
@@ -1093,10 +1103,10 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim,
bool didAnimateTransform = !hasTransform;
bool didAnimateOpacity = !hasOpacity;
- if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), beginTime))
+ if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), timeOffset))
didAnimateTransform = true;
- if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime))
+ if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset))
didAnimateOpacity = true;
bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity;
@@ -1106,7 +1116,7 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim,
return runningAcceleratedAnimation;
}
-bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
+bool RenderLayerBacking::startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
{
bool didAnimate = false;
ASSERT(property != cAnimateAll);
@@ -1118,7 +1128,7 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R
opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity())));
opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity())));
// The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here.
- if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), beginTime)) {
+ if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), timeOffset)) {
// To ensure that the correct opacity is visible when the animation ends, also set the final opacity.
updateLayerOpacity(toStyle);
didAnimate = true;
@@ -1132,7 +1142,7 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R
KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform()));
transformVector.insert(new TransformAnimationValue(1, &toStyle->transform()));
- if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), beginTime)) {
+ if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), timeOffset)) {
// To ensure that the correct transform is visible when the animation ends, also set the final opacity.
updateLayerTransform(toStyle);
didAnimate = true;
@@ -1162,9 +1172,9 @@ void RenderLayerBacking::animationFinished(const String& animationName)
m_graphicsLayer->removeAnimationsForKeyframes(animationName);
}
-void RenderLayerBacking::animationPaused(const String& animationName)
+void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName)
{
- m_graphicsLayer->pauseAnimation(animationName);
+ m_graphicsLayer->pauseAnimation(animationName, timeOffset);
}
void RenderLayerBacking::transitionFinished(int property)
diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h
index 2bbb37f..7aea926 100644
--- a/WebCore/rendering/RenderLayerBacking.h
+++ b/WebCore/rendering/RenderLayerBacking.h
@@ -97,10 +97,10 @@ public:
void rendererContentChanged();
// Interface to start, finish, suspend and resume animations and transitions
- bool startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes);
- bool startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle);
+ bool startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes);
+ bool startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle);
void animationFinished(const String& name);
- void animationPaused(const String& name);
+ void animationPaused(double timeOffset, const String& name);
void transitionFinished(int property);
void suspendAnimations(double time = 0);
@@ -149,12 +149,12 @@ private:
// Return the opacity value that this layer should use for compositing.
float compositingOpacity(float rendererOpacity) const;
- // Returns true if this RenderLayer only has content that can be rendered directly
- // by the compositing layer, without drawing (e.g. solid background color).
+ // Returns true if this compositing layer has no visible content.
bool isSimpleContainerCompositingLayer() const;
- // Returns true if we can optimize the RenderLayer to draw the replaced content
- // directly into a compositing buffer
- bool canUseDirectCompositing() const;
+ // Returns true if this layer has content that needs to be rendered by painting into the backing store.
+ bool containsPaintedContent() const;
+ // Returns true if the RenderLayer just contains an image that we can composite directly.
+ bool isDirectlyCompositedImage() const;
void updateImageContents();
bool rendererHasBackground() const;
@@ -179,7 +179,6 @@ private:
IntRect m_compositedBounds;
- bool m_hasDirectlyCompositedContent;
bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
};
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index 8ce59cb..2730114 100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -29,6 +29,7 @@
#include "RenderLayerCompositor.h"
#include "AnimationController.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "CSSPropertyNames.h"
#include "Frame.h"
@@ -37,7 +38,9 @@
#include "HitTestResult.h"
#include "HTMLCanvasElement.h"
#include "Page.h"
+#include "RenderEmbeddedObject.h"
#include "RenderLayerBacking.h"
+#include "RenderReplica.h"
#include "RenderVideo.h"
#include "RenderView.h"
#include "Settings.h"
@@ -58,6 +61,8 @@ bool WebCoreHas3DRendering = true;
namespace WebCore {
+using namespace HTMLNames;
+
struct CompositingState {
CompositingState(RenderLayer* compAncestor)
: m_compositingAncestor(compAncestor)
@@ -147,16 +152,30 @@ void RenderLayerCompositor::scheduleSync()
page->chrome()->client()->scheduleCompositingLayerSync();
}
-void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
+void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType updateType, RenderLayer* updateRoot)
{
- // When m_compositingConsultsOverlap is true, then layer positions affect compositing,
- // so we can only bail here when we're not looking at overlap.
- if (!m_compositingLayersNeedRebuild && !m_compositingConsultsOverlap)
+ bool checkForHierarchyUpdate = false;
+ bool needGeometryUpdate = false;
+
+ switch (updateType) {
+ case CompositingUpdateAfterLayoutOrStyleChange:
+ case CompositingUpdateOnPaitingOrHitTest:
+ checkForHierarchyUpdate = true;
+ break;
+ case CompositingUpdateOnScroll:
+ if (m_compositingConsultsOverlap)
+ checkForHierarchyUpdate = true; // Overlap can change with scrolling, so need to check for hierarchy updates.
+
+ needGeometryUpdate = true;
+ break;
+ }
+
+ if (!checkForHierarchyUpdate && !needGeometryUpdate)
return;
ASSERT(inCompositingMode());
- bool needLayerRebuild = m_compositingLayersNeedRebuild;
+ bool needHierarchyUpdate = m_compositingLayersNeedRebuild;
if (!updateRoot) {
// Only clear the flag if we're updating the entire hierarchy.
m_compositingLayersNeedRebuild = false;
@@ -169,24 +188,22 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
double startTime = WTF::currentTime();
#endif
- // Go through the layers in presentation order, so that we can compute which
- // RLs need compositing layers.
- // FIXME: we could maybe do this in one pass, but the parenting logic would be more
- // complex.
- {
+ if (checkForHierarchyUpdate) {
+ // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
+ // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
CompositingState compState(updateRoot);
- bool layersChanged;
+ bool layersChanged = false;
if (m_compositingConsultsOverlap) {
OverlapMap overlapTestRequestMap;
computeCompositingRequirements(updateRoot, &overlapTestRequestMap, compState, layersChanged);
} else
computeCompositingRequirements(updateRoot, 0, compState, layersChanged);
- needLayerRebuild |= layersChanged;
+ needHierarchyUpdate |= layersChanged;
}
- if (needLayerRebuild) {
- // Now updated and parent the compositing layers.
+ if (needHierarchyUpdate) {
+ // Update the hierarchy of the compositing layers.
CompositingState compState(updateRoot);
Vector<GraphicsLayer*> childList;
rebuildCompositingLayerTree(updateRoot, compState, childList);
@@ -194,8 +211,9 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
// Host the document layer in the RenderView's root layer.
if (updateRoot == rootRenderLayer() && !childList.isEmpty())
m_rootPlatformLayer->setChildren(childList);
- } else {
- // We just need to do a geometry update.
+ } else if (needGeometryUpdate) {
+ // We just need to do a geometry update. This is only used for position:fixed scrolling;
+ // most of the time, geometry is updated via RenderLayer::styleChanged().
updateLayerTreeGeometry(updateRoot);
}
@@ -233,6 +251,17 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
}
} else {
if (layer->backing()) {
+ // If we're removing backing on a reflection, clear the source GraphicsLayer's pointer to
+ // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection
+ // are both either composited, or not composited.
+ if (layer->isReflection()) {
+ RenderLayer* sourceLayer = toRenderBoxModelObject(layer->renderer()->parent())->layer();
+ if (RenderLayerBacking* backing = sourceLayer->backing()) {
+ ASSERT(backing->graphicsLayer()->replicaLayer() == layer->backing()->graphicsLayer());
+ backing->graphicsLayer()->setReplicatedByLayer(0);
+ }
+ }
+
layer->clearBacking();
layerChanged = true;
@@ -533,6 +562,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
}
+ if (layer->reflectionLayer())
+ layer->reflectionLayer()->setMustOverlapCompositedLayers(needsToBeComposited(layer));
+
// Subsequent layers in the parent stacking context also need to composite.
if (childState.m_subtreeIsCompositing)
compositingState.m_subtreeIsCompositing = true;
@@ -549,6 +581,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
// Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree().
if (updateBacking(layer, CompositingChangeRepaintNow))
layersChanged = true;
+
+ if (layer->reflectionLayer() && updateLayerCompositingState(layer->reflectionLayer(), CompositingChangeRepaintNow))
+ layersChanged = true;
}
void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer)
@@ -595,9 +630,7 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer)
#if ENABLE(VIDEO)
bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const
{
- // FIXME: ideally we need to look at all ancestors for mask or video. But for now,
- // just bail on the obvious cases.
- if (o->hasReflection() || !m_hasAcceleratedCompositing)
+ if (!m_hasAcceleratedCompositing)
return false;
return o->supportsAcceleratedRendering();
@@ -615,6 +648,12 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons
// The compositing state of all our children has been updated already, so now
// we can compute and cache the composited bounds for this layer.
layerBacking->updateCompositedBounds();
+
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
+
layerBacking->updateGraphicsLayerConfiguration();
layerBacking->updateGraphicsLayerGeometry();
@@ -688,8 +727,10 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer)
// we can compute and cache the composited bounds for this layer.
layerBacking->updateCompositedBounds();
- if (layer->reflectionLayer())
- layer->reflectionLayer()->backing()->updateCompositedBounds();
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
layerBacking->updateGraphicsLayerConfiguration();
layerBacking->updateGraphicsLayerGeometry();
@@ -730,12 +771,21 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com
if (layer != compositingAncestor) {
if (RenderLayerBacking* layerBacking = layer->backing()) {
layerBacking->updateCompositedBounds();
+
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
+
layerBacking->updateGraphicsLayerGeometry();
if (updateDepth == RenderLayerBacking::CompositingChildren)
return;
}
}
+ if (layer->reflectionLayer())
+ updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), updateDepth);
+
if (!layer->hasCompositingDescendant())
return;
@@ -884,9 +934,16 @@ bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
// Use needsToBeComposited() to determine if a RL actually needs a compositing layer.
// static
bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const
-{
+{
+ RenderObject* renderer = layer->renderer();
+ // The compositing state of a reflection should match that of its reflected layer.
+ if (layer->isReflection()) {
+ renderer = renderer->parent(); // The RenderReplica's parent is the object being reflected.
+ layer = toRenderBoxModelObject(renderer)->layer();
+ }
// The root layer always has a compositing layer, but it may not have backing.
return (inCompositingMode() && layer->isRootLayer()) ||
+<<<<<<< HEAD
requiresCompositingForTransform(layer->renderer()) ||
requiresCompositingForVideo(layer->renderer()) ||
requiresCompositingForCanvas(layer->renderer()) ||
@@ -895,8 +952,15 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c
(layer->renderer()->isPositioned() &&
layer->renderer()->style()->position() == FixedPosition) ||
#endif
+=======
+ requiresCompositingForTransform(renderer) ||
+ requiresCompositingForVideo(renderer) ||
+ requiresCompositingForCanvas(renderer) ||
+ requiresCompositingForPlugin(renderer) ||
+ renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden ||
+>>>>>>> webkit.org at r54127
clipsCompositingDescendants(layer) ||
- requiresCompositingForAnimation(layer->renderer());
+ requiresCompositingForAnimation(renderer);
}
// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips,
@@ -959,6 +1023,8 @@ bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer)
RenderVideo* video = toRenderVideo(renderer);
return canAccelerateVideoRendering(video);
}
+#else
+ UNUSED_PARAM(renderer);
#endif
return false;
}
@@ -976,6 +1042,11 @@ bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer)
return false;
}
+bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) const
+{
+ return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing();
+}
+
bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const
{
if (AnimationController* animController = renderer->animation()) {
@@ -987,7 +1058,7 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render
bool RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing(RenderObject* renderer) const
{
- return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask();
+ return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection();
}
// If an element has negative z-index children, those children render in front of the
diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h
index 73683f3..5f1a178 100644
--- a/WebCore/rendering/RenderLayerCompositor.h
+++ b/WebCore/rendering/RenderLayerCompositor.h
@@ -38,6 +38,12 @@ class GraphicsLayer;
class RenderVideo;
#endif
+enum CompositingUpdateType {
+ CompositingUpdateAfterLayoutOrStyleChange,
+ CompositingUpdateOnPaitingOrHitTest,
+ CompositingUpdateOnScroll
+};
+
// RenderLayerCompositor manages the hierarchy of
// composited RenderLayers. It determines which RenderLayers
// become compositing, and creates and maintains a hierarchy of
@@ -47,7 +53,6 @@ class RenderVideo;
class RenderLayerCompositor {
public:
-
RenderLayerCompositor(RenderView*);
~RenderLayerCompositor();
@@ -80,7 +85,7 @@ public:
void scheduleSync();
// Rebuild the tree of compositing layers
- void updateCompositingLayers(RenderLayer* updateRoot = 0);
+ void updateCompositingLayers(CompositingUpdateType = CompositingUpdateAfterLayoutOrStyleChange, RenderLayer* updateRoot = 0);
// Update the compositing state of the given layer. Returns true if that state changed.
enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater };
@@ -173,6 +178,7 @@ private:
bool requiresCompositingForTransform(RenderObject*) const;
bool requiresCompositingForVideo(RenderObject*) const;
bool requiresCompositingForCanvas(RenderObject*) const;
+ bool requiresCompositingForPlugin(RenderObject*) const;
bool requiresCompositingWhenDescendantsAreCompositing(RenderObject*) const;
private:
diff --git a/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp
index 539b8c7..54a7dd2 100644
--- a/WebCore/rendering/RenderListItem.cpp
+++ b/WebCore/rendering/RenderListItem.cpp
@@ -1,7 +1,7 @@
/**
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
*
* This library is free software; you can redistribute it and/or
@@ -51,8 +51,8 @@ void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* old
{
RenderBlock::styleDidChange(diff, oldStyle);
- if (style()->listStyleType() != LNONE ||
- (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) {
+ if (style()->listStyleType() != NoneListStyle
+ || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) {
RefPtr<RenderStyle> newStyle = RenderStyle::create();
// The marker always inherits from the list item, regardless of where it might end
// up (e.g., in some deeply nested line box). See CSS3 spec.
@@ -75,11 +75,16 @@ void RenderListItem::destroy()
RenderBlock::destroy();
}
+static bool isList(Node* node)
+{
+ return (node->hasTagName(ulTag) || node->hasTagName(olTag));
+}
+
static Node* enclosingList(Node* node)
{
Node* parent = node->parentNode();
for (Node* n = parent; n; n = n->parentNode())
- if (n->hasTagName(ulTag) || n->hasTagName(olTag))
+ if (isList(n))
return n;
// If there's no actual <ul> or <ol> list element, then our parent acts as
// our list for purposes of determining what other list items should be
@@ -87,22 +92,38 @@ static Node* enclosingList(Node* node)
return parent;
}
+static Node* enclosingList(const RenderObject* renderer)
+{
+ Node* node = renderer->node();
+ if (node)
+ return enclosingList(node);
+
+ renderer = renderer->parent();
+ while (renderer && !renderer->node())
+ renderer = renderer->parent();
+
+ node = renderer->node();
+ if (isList(node))
+ return node;
+
+ return enclosingList(node);
+}
+
static RenderListItem* previousListItem(Node* list, const RenderListItem* item)
{
- for (Node* node = item->node()->traversePreviousNode(); node != list; node = node->traversePreviousNode()) {
- RenderObject* renderer = node->renderer();
- if (!renderer || !renderer->isListItem())
+ for (RenderObject* renderer = item->previousInPreOrder(); renderer != list->renderer(); renderer = renderer->previousInPreOrder()) {
+ if (!renderer->isListItem())
continue;
- Node* otherList = enclosingList(node);
+ Node* otherList = enclosingList(renderer);
// This item is part of our current list, so it's what we're looking for.
if (list == otherList)
return toRenderListItem(renderer);
// We found ourself inside another list; lets skip the rest of it.
- // Use traverseNextNode() here because the other list itself may actually
+ // Use nextInPreOrder() here because the other list itself may actually
// be a list item itself. We need to examine it, so we do this to counteract
- // the traversePreviousNode() that will be done by the loop.
+ // the previousInPreOrder() that will be done by the loop.
if (otherList)
- node = otherList->traverseNextNode();
+ renderer = otherList->renderer()->nextInPreOrder();
}
return 0;
}
@@ -111,7 +132,7 @@ inline int RenderListItem::calcValue() const
{
if (m_hasExplicitValue)
return m_explicitValue;
- Node* list = enclosingList(node());
+ Node* list = enclosingList(this);
// FIXME: This recurses to a possible depth of the length of the list.
// That's not good -- we need to change this to an iterative algorithm.
if (RenderListItem* previousItem = previousListItem(list, this))
@@ -322,6 +343,8 @@ void RenderListItem::explicitValueChanged()
void RenderListItem::setExplicitValue(int value)
{
+ ASSERT(node());
+
if (m_hasExplicitValue && m_explicitValue == value)
return;
m_explicitValue = value;
@@ -332,6 +355,8 @@ void RenderListItem::setExplicitValue(int value)
void RenderListItem::clearExplicitValue()
{
+ ASSERT(node());
+
if (!m_hasExplicitValue)
return;
m_hasExplicitValue = false;
diff --git a/WebCore/rendering/RenderListMarker.cpp b/WebCore/rendering/RenderListMarker.cpp
index eab4404..f67bc0f 100644
--- a/WebCore/rendering/RenderListMarker.cpp
+++ b/WebCore/rendering/RenderListMarker.cpp
@@ -3,6 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ * Copyright (C) 2010 Daniel Bates (dbates@intudata.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -97,6 +98,11 @@ static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize)
return String(&letters[lettersSize - length], length);
}
+template <size_t size> static inline String toAlphabetic(int number, const UChar(&alphabet)[size])
+{
+ return toAlphabetic(number, alphabet, size);
+}
+
static int toHebrewUnder1000(int number, UChar letters[5])
{
// FIXME: CSS3 mentions various refinements not implemented here.
@@ -337,58 +343,128 @@ static String toCJKIdeographic(int number, const UChar table[16])
return String(characters, length);
}
+static UChar listMarkerSuffix(EListStyleType type)
+{
+ // Note, the following switch statement has been explicitly
+ // grouped by list-style-type suffix.
+ switch (type) {
+ case NoneListStyle:
+ case Disc:
+ case Circle:
+ case Square:
+ ASSERT_NOT_REACHED();
+ return ' ';
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Oromo:
+ case Sidama:
+ case Somali:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ return ethiopicPrefaceColon;
+ case Armenian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Georgian:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Katakana:
+ case KatakanaIroha:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ return '.';
+ }
+
+ ASSERT_NOT_REACHED();
+ return '.';
+}
+
String listMarkerText(EListStyleType type, int value)
{
switch (type) {
- case LNONE:
+ case NoneListStyle:
return "";
// We use the same characters for text security.
// See RenderText::setInternalString.
- case CIRCLE:
+ case Circle:
return String(&whiteBullet, 1);
- case DISC:
+ case Disc:
return String(&bullet, 1);
- case SQUARE:
+ case Square:
// The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE
// instead, but I think this looks better.
return String(&blackSquare, 1);
- case LDECIMAL:
+ case DecimalListStyle:
return String::number(value);
- case DECIMAL_LEADING_ZERO:
+ case DecimalLeadingZero:
if (value < -9 || value > 9)
return String::number(value);
if (value < 0)
return "-0" + String::number(-value); // -01 to -09
return "0" + String::number(value); // 00 to 09
- case LOWER_ALPHA:
- case LOWER_LATIN: {
+ case LowerAlpha:
+ case LowerLatin: {
static const UChar lowerLatinAlphabet[26] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
- return toAlphabetic(value, lowerLatinAlphabet, 26);
+ return toAlphabetic(value, lowerLatinAlphabet);
}
- case UPPER_ALPHA:
- case UPPER_LATIN: {
+ case UpperAlpha:
+ case UpperLatin: {
static const UChar upperLatinAlphabet[26] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
- return toAlphabetic(value, upperLatinAlphabet, 26);
+ return toAlphabetic(value, upperLatinAlphabet);
}
- case LOWER_GREEK: {
+ case LowerGreek: {
static const UChar lowerGreekAlphabet[24] = {
0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9
};
- return toAlphabetic(value, lowerGreekAlphabet, 24);
+ return toAlphabetic(value, lowerGreekAlphabet);
}
- case HIRAGANA: {
+ case Hiragana: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar hiraganaAlphabet[48] = {
@@ -399,9 +475,9 @@ String listMarkerText(EListStyleType type, int value)
0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A,
0x308B, 0x308C, 0x308D, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093
};
- return toAlphabetic(value, hiraganaAlphabet, 48);
+ return toAlphabetic(value, hiraganaAlphabet);
}
- case HIRAGANA_IROHA: {
+ case HiraganaIroha: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar hiraganaIrohaAlphabet[47] = {
@@ -412,9 +488,9 @@ String listMarkerText(EListStyleType type, int value)
0x3053, 0x3048, 0x3066, 0x3042, 0x3055, 0x304D, 0x3086, 0x3081,
0x307F, 0x3057, 0x3091, 0x3072, 0x3082, 0x305B, 0x3059
};
- return toAlphabetic(value, hiraganaIrohaAlphabet, 47);
+ return toAlphabetic(value, hiraganaIrohaAlphabet);
}
- case KATAKANA: {
+ case Katakana: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar katakanaAlphabet[48] = {
@@ -425,9 +501,9 @@ String listMarkerText(EListStyleType type, int value)
0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA,
0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3
};
- return toAlphabetic(value, katakanaAlphabet, 48);
+ return toAlphabetic(value, katakanaAlphabet);
}
- case KATAKANA_IROHA: {
+ case KatakanaIroha: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar katakanaIrohaAlphabet[47] = {
@@ -438,10 +514,187 @@ String listMarkerText(EListStyleType type, int value)
0x30B3, 0x30A8, 0x30C6, 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1,
0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x30B9
};
- return toAlphabetic(value, katakanaIrohaAlphabet, 47);
+ return toAlphabetic(value, katakanaIrohaAlphabet);
}
- case CJK_IDEOGRAPHIC: {
+ case Afar:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAaEr: {
+ static const UChar ethiopicHalehameAaErAlphabet[18] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1260, 0x1270, 0x1290,
+ 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12E8, 0x12F0, 0x1308, 0x1338, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameAaErAlphabet);
+ }
+ case Amharic:
+ case EthiopicHalehameAmEt: {
+ static const UChar ethiopicHalehameAmEtAlphabet[33] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
+ 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8,
+ 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320,
+ 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameAmEtAlphabet);
+ }
+ case AmharicAbegede:
+ case EthiopicAbegedeAmEt: {
+ static const UChar ethiopicAbegedeAmEtAlphabet[33] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1228, 0x1230, 0x1238,
+ 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeAmEtAlphabet);
+ }
+ case CjkEarthlyBranch: {
+ static const UChar cjkEarthlyBranchAlphabet[12] = {
+ 0x5B50, 0x4E11, 0x5BC5, 0x536F, 0x8FB0, 0x5DF3, 0x5348, 0x672A, 0x7533,
+ 0x9149, 0x620C, 0x4EA5
+ };
+ return toAlphabetic(value, cjkEarthlyBranchAlphabet);
+ }
+ case CjkHeavenlyStem: {
+ static const UChar cjkHeavenlyStemAlphabet[10] = {
+ 0x7532, 0x4E59, 0x4E19, 0x4E01, 0x620A, 0x5DF1, 0x5E9A, 0x8F9B, 0x58EC,
+ 0x7678
+ };
+ return toAlphabetic(value, cjkHeavenlyStemAlphabet);
+ }
+ case Ethiopic:
+ case EthiopicHalehameGez: {
+ static const UChar ethiopicHalehameGezAlphabet[26] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1240, 0x1260,
+ 0x1270, 0x1280, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
+ 0x12F0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameGezAlphabet);
+ }
+ case EthiopicAbegede:
+ case EthiopicAbegedeGez: {
+ static const UChar ethiopicAbegedeGezAlphabet[26] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1200, 0x12C8, 0x12D8, 0x1210, 0x1320,
+ 0x12E8, 0x12A8, 0x1208, 0x1218, 0x1290, 0x1220, 0x12D0, 0x1348, 0x1338,
+ 0x1240, 0x1228, 0x1230, 0x1270, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeGezAlphabet);
+ }
+ case HangulConsonant: {
+ static const UChar hangulConsonantAlphabet[14] = {
+ 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142, 0x3145, 0x3147, 0x3148,
+ 0x314A, 0x314B, 0x314C, 0x314D, 0x314E
+ };
+ return toAlphabetic(value, hangulConsonantAlphabet);
+ }
+ case Hangul: {
+ static const UChar hangulAlphabet[14] = {
+ 0xAC00, 0xB098, 0xB2E4, 0xB77C, 0xB9C8, 0xBC14, 0xC0AC, 0xC544, 0xC790,
+ 0xCC28, 0xCE74, 0xD0C0, 0xD30C, 0xD558
+ };
+ return toAlphabetic(value, hangulAlphabet);
+ }
+ case Oromo:
+ case EthiopicHalehameOmEt: {
+ static const UChar ethiopicHalehameOmEtAlphabet[25] = {
+ 0x1200, 0x1208, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, 0x1270,
+ 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0, 0x12F8,
+ 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameOmEtAlphabet);
+ }
+ case Sidama:
+ case EthiopicHalehameSidEt: {
+ static const UChar ethiopicHalehameSidEtAlphabet[26] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0,
+ 0x12F8, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameSidEtAlphabet);
+ }
+ case Somali:
+ case EthiopicHalehameSoEt: {
+ static const UChar ethiopicHalehameSoEtAlphabet[22] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1290, 0x12A0, 0x12A8, 0x12B8, 0x12C8, 0x12D0, 0x12E8, 0x12F0,
+ 0x1300, 0x1308, 0x1338, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameSoEtAlphabet);
+ }
+ case Tigre:
+ case EthiopicHalehameTig: {
+ static const UChar ethiopicHalehameTigAlphabet[27] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1278, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
+ 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTigAlphabet);
+ }
+ case TigrinyaEr:
+ case EthiopicHalehameTiEr: {
+ static const UChar ethiopicHalehameTiErAlphabet[31] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1250,
+ 0x1260, 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8, 0x12C8,
+ 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328,
+ 0x1330, 0x1338, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTiErAlphabet);
+ }
+ case TigrinyaErAbegede:
+ case EthiopicAbegedeTiEr: {
+ static const UChar ethiopicAbegedeTiErAlphabet[31] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230, 0x1238,
+ 0x1270, 0x1278, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeTiErAlphabet);
+ }
+ case TigrinyaEt:
+ case EthiopicHalehameTiEt: {
+ static const UChar ethiopicHalehameTiEtAlphabet[34] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
+ 0x1250, 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8,
+ 0x12B8, 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308,
+ 0x1320, 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTiEtAlphabet);
+ }
+ case TigrinyaEtAbegede:
+ case EthiopicAbegedeTiEt: {
+ static const UChar ethiopicAbegedeTiEtAlphabet[34] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230,
+ 0x1238, 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeTiEtAlphabet);
+ }
+ case UpperGreek: {
+ static const UChar upperGreekAlphabet[24] = {
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399,
+ 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3,
+ 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9
+ };
+ return toAlphabetic(value, upperGreekAlphabet);
+ }
+ case LowerNorwegian: {
+ static const UChar lowerNorwegianAlphabet[29] = {
+ 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069,
+ 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072,
+ 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E6,
+ 0x00F8, 0x00E5
+ };
+ return toAlphabetic(value, lowerNorwegianAlphabet);
+ }
+ case UpperNorwegian: {
+ static const UChar upperNorwegianAlphabet[29] = {
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049,
+ 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
+ 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00C6,
+ 0x00D8, 0x00C5
+ };
+ return toAlphabetic(value, upperNorwegianAlphabet);
+ }
+ case CJKIdeographic: {
static const UChar traditionalChineseInformalTable[16] = {
0x842C, 0x5104, 0x5146,
0x5341, 0x767E, 0x5343,
@@ -451,19 +704,19 @@ String listMarkerText(EListStyleType type, int value)
return toCJKIdeographic(value, traditionalChineseInformalTable);
}
- case LOWER_ROMAN:
+ case LowerRoman:
return toRoman(value, false);
- case UPPER_ROMAN:
+ case UpperRoman:
return toRoman(value, true);
- case ARMENIAN:
+ case Armenian:
// CSS3 says "armenian" means "lower-armenian".
// But the CSS2.1 test suite contains uppercase test results for "armenian",
// so we'll match the test suite.
return toArmenian(value, true);
- case GEORGIAN:
+ case Georgian:
return toGeorgian(value);
- case HEBREW:
+ case Hebrew:
return toHebrew(value);
}
@@ -519,6 +772,15 @@ bool RenderListMarker::isImage() const
return m_image && !m_image->errorOccurred();
}
+IntRect RenderListMarker::localSelectionRect()
+{
+ InlineBox* box = inlineBoxWrapper();
+ if (!box)
+ return IntRect();
+ RootInlineBox* root = box->root();
+ return IntRect(x(), root->selectionTop() - y(), width(), root->selectionHeight());
+}
+
void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
{
if (paintInfo.phase != PaintPhaseForeground)
@@ -547,8 +809,9 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
#endif
context->drawImage(m_image->image(this, marker.size()), style()->colorSpace(), marker.location());
if (selectionState() != SelectionNone) {
- // FIXME: selectionRect() is in absolute, not painting coordinates.
- context->fillRect(selectionRect(), selectionBackgroundColor(), style()->colorSpace());
+ IntRect selRect = localSelectionRect();
+ selRect.move(tx, ty);
+ context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace());
}
return;
}
@@ -560,8 +823,9 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
#endif
if (selectionState() != SelectionNone) {
- // FIXME: selectionRect() is in absolute, not painting coordinates.
- context->fillRect(selectionRect(), selectionBackgroundColor(), style()->colorSpace());
+ IntRect selRect = localSelectionRect();
+ selRect.move(tx, ty);
+ context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace());
}
const Color color(style()->color());
@@ -570,36 +834,71 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
context->setStrokeThickness(1.0f);
context->setFillColor(color, style()->colorSpace());
- switch (style()->listStyleType()) {
- case DISC:
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case Disc:
context->drawEllipse(marker);
return;
- case CIRCLE:
+ case Circle:
context->setFillColor(Color::transparent, DeviceColorSpace);
context->drawEllipse(marker);
return;
- case SQUARE:
+ case Square:
context->drawRect(marker);
return;
- case LNONE:
+ case NoneListStyle:
return;
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case Armenian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Katakana:
+ case KatakanaIroha:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Oromo:
+ case Sidama:
+ case Somali:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
break;
}
if (m_text.isEmpty())
@@ -620,16 +919,17 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
}
const Font& font = style()->font();
+ const UChar suffix = listMarkerSuffix(type);
if (style()->direction() == LTR) {
int width = font.width(textRun);
context->drawText(style()->font(), textRun, marker.location());
- const UChar periodSpace[2] = { '.', ' ' };
- context->drawText(style()->font(), TextRun(periodSpace, 2), marker.location() + IntSize(width, 0));
+ UChar suffixSpace[2] = { suffix, ' ' };
+ context->drawText(style()->font(), TextRun(suffixSpace, 2), marker.location() + IntSize(width, 0));
} else {
- const UChar spacePeriod[2] = { ' ', '.' };
- TextRun spacePeriodRun(spacePeriod, 2);
- int width = font.width(spacePeriodRun);
- context->drawText(style()->font(), spacePeriodRun, marker.location());
+ UChar spaceSuffix[2] = { ' ', suffix };
+ TextRun spaceSuffixRun(spaceSuffix, 2);
+ int width = font.width(spaceSuffixRun);
+ context->drawText(style()->font(), spaceSuffixRun, marker.location());
context->drawText(style()->font(), textRun, marker.location() + IntSize(width, 0));
}
}
@@ -693,39 +993,73 @@ void RenderListMarker::calcPrefWidths()
int width = 0;
EListStyleType type = style()->listStyleType();
switch (type) {
- case LNONE:
+ case NoneListStyle:
break;
- case CIRCLE:
- case DISC:
- case SQUARE:
+ case Circle:
+ case Disc:
+ case Square:
m_text = listMarkerText(type, 0); // value is ignored for these types
width = (font.ascent() * 2 / 3 + 1) / 2 + 2;
break;
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case Armenian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Katakana:
+ case KatakanaIroha:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Oromo:
+ case Sidama:
+ case Somali:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
m_text = listMarkerText(type, m_listItem->value());
if (m_text.isEmpty())
width = 0;
else {
int itemWidth = font.width(m_text);
- const UChar periodSpace[2] = { '.', ' ' };
- int periodSpaceWidth = font.width(TextRun(periodSpace, 2));
- width = itemWidth + periodSpaceWidth;
+ UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' };
+ int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2));
+ width = itemWidth + suffixSpaceWidth;
}
break;
}
@@ -752,9 +1086,9 @@ void RenderListMarker::updateMargins()
else
marginLeft = cMarkerPadding;
} else switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
if (style()->direction() == LTR) {
marginLeft = -1;
marginRight = font.ascent() - minPrefWidth() + 1;
@@ -773,12 +1107,12 @@ void RenderListMarker::updateMargins()
else {
int offset = font.ascent() * 2 / 3;
switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
marginLeft = -offset - cMarkerPadding - 1;
break;
- case LNONE:
+ case NoneListStyle:
break;
default:
marginLeft = m_text.isEmpty() ? 0 : -minPrefWidth() - offset / 2;
@@ -790,12 +1124,12 @@ void RenderListMarker::updateMargins()
else {
int offset = font.ascent() * 2 / 3;
switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
marginLeft = offset + cMarkerPadding + 1 - minPrefWidth();
break;
- case LNONE:
+ case NoneListStyle:
break;
default:
marginLeft = m_text.isEmpty() ? 0 : offset / 2;
@@ -835,42 +1169,77 @@ IntRect RenderListMarker::getRelativeMarkerRect()
if (isImage())
return IntRect(x(), y(), m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height());
- switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE: {
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case Disc:
+ case Circle:
+ case Square: {
// FIXME: Are these particular rounding rules necessary?
const Font& font = style()->font();
int ascent = font.ascent();
int bulletWidth = (ascent * 2 / 3 + 1) / 2;
return IntRect(x() + 1, y() + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth);
}
- case LNONE:
+ case NoneListStyle:
return IntRect();
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case Armenian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Katakana:
+ case KatakanaIroha:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Oromo:
+ case Sidama:
+ case Somali:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
if (m_text.isEmpty())
return IntRect();
const Font& font = style()->font();
int itemWidth = font.width(m_text);
- const UChar periodSpace[2] = { '.', ' ' };
- int periodSpaceWidth = font.width(TextRun(periodSpace, 2));
- return IntRect(x(), y() + font.ascent(), itemWidth + periodSpaceWidth, font.height());
+ UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' };
+ int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2));
+ return IntRect(x(), y() + font.ascent(), itemWidth + suffixSpaceWidth, font.height());
}
return IntRect();
diff --git a/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h
index 5b46278..971877b 100644
--- a/WebCore/rendering/RenderListMarker.h
+++ b/WebCore/rendering/RenderListMarker.h
@@ -73,6 +73,7 @@ private:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
IntRect getRelativeMarkerRect();
+ IntRect localSelectionRect();
String m_text;
RefPtr<StyleImage> m_image;
diff --git a/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp
index 2ff50df..8acebfb 100644
--- a/WebCore/rendering/RenderMedia.cpp
+++ b/WebCore/rendering/RenderMedia.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,32 +45,30 @@ using namespace HTMLNames;
static const double cTimeUpdateRepeatDelay = 0.2;
static const double cOpacityAnimationRepeatDelay = 0.05;
-// FIXME get this from style
-static const double cOpacityAnimationDurationFadeIn = 0.1;
-static const double cOpacityAnimationDurationFadeOut = 0.3;
RenderMedia::RenderMedia(HTMLMediaElement* video)
- : RenderReplaced(video)
+ : RenderImage(video)
, m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
, m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
, m_mouseOver(false)
, m_opacityAnimationStartTime(0)
- , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn)
+ , m_opacityAnimationDuration(0)
, m_opacityAnimationFrom(0)
, m_opacityAnimationTo(1.0f)
{
}
RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
- : RenderReplaced(video, intrinsicSize)
+ : RenderImage(video)
, m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
, m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
, m_mouseOver(false)
, m_opacityAnimationStartTime(0)
- , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn)
+ , m_opacityAnimationDuration(0)
, m_opacityAnimationFrom(0)
, m_opacityAnimationTo(1.0f)
{
+ setIntrinsicSize(intrinsicSize);
}
RenderMedia::~RenderMedia()
@@ -89,7 +87,7 @@ void RenderMedia::destroy()
m_controlsShadowRoot->detach();
m_controlsShadowRoot = 0;
}
- RenderReplaced::destroy();
+ RenderImage::destroy();
}
HTMLMediaElement* RenderMedia::mediaElement() const
@@ -104,7 +102,7 @@ MediaPlayer* RenderMedia::player() const
void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
- RenderReplaced::styleDidChange(diff, oldStyle);
+ RenderImage::styleDidChange(diff, oldStyle);
if (m_controlsShadowRoot) {
if (m_panel)
@@ -146,7 +144,7 @@ void RenderMedia::layout()
{
IntSize oldSize = contentBoxRect().size();
- RenderReplaced::layout();
+ RenderImage::layout();
RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
if (!controlsRenderer)
@@ -452,9 +450,9 @@ void RenderMedia::updateControlVisibility()
}
if (animateFrom < animateTo)
- m_opacityAnimationDuration = cOpacityAnimationDurationFadeIn;
+ m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
else
- m_opacityAnimationDuration = cOpacityAnimationDurationFadeOut;
+ m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
m_opacityAnimationFrom = animateFrom;
m_opacityAnimationTo = animateTo;
@@ -573,7 +571,7 @@ void RenderMedia::forwardEvent(Event* event)
int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int bottom = RenderReplaced::lowestPosition(includeOverflowInterior, includeSelf);
+ int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return bottom;
@@ -582,7 +580,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf)
int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int right = RenderReplaced::rightmostPosition(includeOverflowInterior, includeSelf);
+ int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return right;
@@ -591,7 +589,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel
int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int left = RenderReplaced::leftmostPosition(includeOverflowInterior, includeSelf);
+ int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return left;
diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h
index 066b83d..0d24c4c 100644
--- a/WebCore/rendering/RenderMedia.h
+++ b/WebCore/rendering/RenderMedia.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "RenderReplaced.h"
+#include "RenderImage.h"
#include "Timer.h"
namespace WebCore {
@@ -51,12 +51,12 @@ class MediaControlVolumeSliderContainerElement;
class MediaControlElement;
class MediaPlayer;
-class RenderMedia : public RenderReplaced {
+class RenderMedia : public RenderImage {
public:
RenderMedia(HTMLMediaElement*);
RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize);
virtual ~RenderMedia();
-
+
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
@@ -83,6 +83,7 @@ private:
virtual const char* renderName() const { return "RenderMedia"; }
virtual bool isMedia() const { return true; }
+ virtual bool isImage() const { return false; }
virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp
index cbbc7cb..05a9873 100644
--- a/WebCore/rendering/RenderMenuList.cpp
+++ b/WebCore/rendering/RenderMenuList.cpp
@@ -1,7 +1,7 @@
/*
* This file is part of the select element renderer in WebCore.
*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
#include "config.h"
#include "RenderMenuList.h"
+#include "AXObjectCache.h"
#include "CSSStyleSelector.h"
#include "Frame.h"
#include "FrameView.h"
@@ -50,6 +51,7 @@ RenderMenuList::RenderMenuList(Element* element)
, m_innerBlock(0)
, m_optionsChanged(true)
, m_optionsWidth(0)
+ , m_lastSelectedIndex(-1)
, m_popup(0)
, m_popupIsVisible(false)
{
@@ -306,10 +308,25 @@ void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange);
}
+void RenderMenuList::didSetSelectedIndex()
+{
+ int index = selectedIndex();
+ if (m_lastSelectedIndex == index)
+ return;
+
+ m_lastSelectedIndex = index;
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->postNotification(this, AXObjectCache::AXMenuListValueChanged, true, PostSynchronously);
+}
+
String RenderMenuList::itemText(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return String();
+ Element* element = listItems[listIndex];
if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element))
return optionGroupElement->groupLabelText();
else if (OptionElement* optionElement = toOptionElement(element))
@@ -320,14 +337,20 @@ String RenderMenuList::itemText(unsigned listIndex) const
String RenderMenuList::itemToolTip(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return String();
+ Element* element = listItems[listIndex];
return element->title();
}
bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
if (!isOptionElement(element))
return false;
@@ -345,7 +368,18 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size()) {
+ // If we are making an out of bounds access, then we want to use the style
+ // of a different option element (index 0). However, if there isn't an option element
+ // before at index 0, we fall back to the menu's style.
+ if (!listIndex)
+ return menuStyle();
+
+ // Try to retrieve the style of an option element we know exists (index 0).
+ listIndex = 0;
+ }
+ Element* element = listItems[listIndex];
RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->textIndent(), style->direction()) : menuStyle();
@@ -354,7 +388,10 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return style()->backgroundColor();
+ Element* element = listItems[listIndex];
Color backgroundColor;
if (element->renderStyle())
@@ -374,7 +411,6 @@ Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
PopupMenuStyle RenderMenuList::menuStyle() const
{
-
RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style();
return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE, s->textIndent(), s->direction());
}
@@ -410,8 +446,19 @@ int RenderMenuList::clientPaddingLeft() const
return paddingLeft();
}
+const int endOfLinePadding = 2;
int RenderMenuList::clientPaddingRight() const
{
+ if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) {
+ // For these appearance values, the theme applies padding to leave room for the
+ // drop-down button. But leaving room for the button inside the popup menu itself
+ // looks strange, so we return a small default padding to avoid having a large empty
+ // space appear on the side of the popup menu.
+ return endOfLinePadding;
+ }
+
+ // If the appearance isn't MenulistPart, then the select is styled (non-native), so
+ // we want to return the user specified padding.
return paddingRight();
}
@@ -435,21 +482,30 @@ void RenderMenuList::popupDidHide()
bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
return element->hasTagName(hrTag);
}
bool RenderMenuList::itemIsLabel(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
return isOptionGroupElement(element);
}
bool RenderMenuList::itemIsSelected(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
if (OptionElement* optionElement = toOptionElement(element))
return optionElement->selected();
return false;
diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h
index 2d617c1..a5aa041 100644
--- a/WebCore/rendering/RenderMenuList.h
+++ b/WebCore/rendering/RenderMenuList.h
@@ -1,7 +1,7 @@
/*
* This file is part of the select element renderer in WebCore.
*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -49,6 +49,8 @@ public:
void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
+ void didSetSelectedIndex();
+
String text() const;
private:
@@ -110,6 +112,8 @@ private:
bool m_optionsChanged;
int m_optionsWidth;
+ int m_lastSelectedIndex;
+
RefPtr<PopupMenu> m_popup;
bool m_popupIsVisible;
};
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index 712519b..0368490 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -28,6 +28,7 @@
#include "RenderObject.h"
#include "AXObjectCache.h"
+#include "Chrome.h"
#include "CSSStyleSelector.h"
#include "FloatQuad.h"
#include "Frame.h"
@@ -67,6 +68,10 @@
#include "WMLNames.h"
#endif
+#if ENABLE(SVG)
+#include "SVGRenderSupport.h"
+#endif
+
using namespace std;
namespace WebCore {
@@ -307,7 +312,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
// Just add it...
children->insertChildNode(this, newChild, beforeChild);
}
-
+ RenderCounter::rendererSubtreeAttached(newChild);
if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText();
if (textToTransform)
@@ -366,19 +371,14 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin
if (this == stayWithin)
return 0;
- RenderObject* o;
- if (!(o = nextSibling())) {
- o = parent();
- while (o && !o->nextSibling()) {
- if (o == stayWithin)
- return 0;
- o = o->parent();
- }
- if (o)
- o = o->nextSibling();
+ const RenderObject* current = this;
+ RenderObject* next;
+ while (!(next = current->nextSibling())) {
+ current = current->parent();
+ if (!current || current == stayWithin)
+ return 0;
}
-
- return o;
+ return next;
}
RenderObject* RenderObject::previousInPreOrder() const
@@ -1011,13 +1011,12 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(style)) {
// Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- graphicsContext->initFocusRing(ow, offset);
- addFocusRingRects(graphicsContext, tx, ty);
+ Vector<IntRect> focusRingRects;
+ addFocusRingRects(focusRingRects, tx, ty);
if (style->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(oc);
+ graphicsContext->drawFocusRing(focusRingRects, ow, offset, oc);
else
- addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
- graphicsContext->clearFocusRing();
+ addPDFURLRect(graphicsContext, unionRect(focusRingRects));
}
}
@@ -1075,6 +1074,23 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
return result;
}
+void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
+{
+ Vector<IntRect> rects;
+ // FIXME: addFocusRingRects() needs to be passed this transform-unaware
+ // localToAbsolute() offset here because RenderInline::addFocusRingRects()
+ // implicitly assumes that. This doesn't work correctly with transformed
+ // descendants.
+ FloatPoint absolutePoint = localToAbsolute();
+ addFocusRingRects(rects, absolutePoint.x(), absolutePoint.y());
+ size_t count = rects.size();
+ for (size_t i = 0; i < count; ++i) {
+ IntRect rect = rects[i];
+ rect.move(-absolutePoint.x(), -absolutePoint.y());
+ quads.append(localToAbsoluteQuad(FloatQuad(rect)));
+ }
+}
+
void RenderObject::addAbsoluteRectForLayer(IntRect& result)
{
if (hasLayer())
@@ -1637,8 +1653,20 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
if (view()->frameView()) {
// FIXME: A better solution would be to only invalidate the fixed regions when scrolling. It's overkill to
// prevent the entire view from blitting on a scroll.
- bool newStyleSlowScroll = newStyle && (newStyle->position() == FixedPosition || newStyle->hasFixedBackgroundImage());
- bool oldStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
+
+ bool shouldBlitOnFixedBackgroundImage = false;
+#if ENABLE(FAST_MOBILE_SCROLLING)
+ // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
+ // when scrolling a page with a fixed background image. As an optimization, assuming there are
+ // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
+ // ignore the CSS property "background-attachment: fixed".
+ shouldBlitOnFixedBackgroundImage = true;
+#endif
+
+ bool newStyleSlowScroll = newStyle && (newStyle->position() == FixedPosition
+ || (!shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage()));
+ bool oldStyleSlowScroll = m_style && (m_style->position() == FixedPosition
+ || (!shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage()));
if (oldStyleSlowScroll != newStyleSlowScroll) {
if (oldStyleSlowScroll)
view()->frameView()->removeSlowRepaintObject();
@@ -1648,7 +1676,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
}
}
-void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*)
+void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
if (s_affectsParentBlock)
handleDynamicFloatPositionChange();
@@ -1656,9 +1684,10 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*)
if (!m_parent)
return;
- if (diff == StyleDifferenceLayout)
+ if (diff == StyleDifferenceLayout) {
+ RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get());
setNeedsLayoutAndPrefWidthsRecalc();
- else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
+ } else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout();
// Don't check for repaint here; we need to wait until the layer has been
@@ -1912,7 +1941,7 @@ void RenderObject::destroy()
// If this renderer is being autoscrolled, stop the autoscroll timer
- // FIXME: RenderObject::destroy should not get called with a renderar whose document
+ // FIXME: RenderObject::destroy should not get called with a renderer whose document
// has a null frame, so we assert this. However, we don't want release builds to crash which is why we
// check that the frame is not null.
ASSERT(document()->frame());
@@ -2474,6 +2503,11 @@ VisiblePosition RenderObject::createVisiblePosition(const Position& position)
}
#if ENABLE(SVG)
+const SVGRenderBase* RenderObject::toSVGRenderBase() const
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
FloatRect RenderObject::objectBoundingBox() const
{
@@ -2491,14 +2525,14 @@ FloatRect RenderObject::repaintRectInLocalCoordinates() const
TransformationMatrix RenderObject::localTransform() const
{
- return TransformationMatrix();
+ static const TransformationMatrix identity;
+ return identity;
}
-TransformationMatrix RenderObject::localToParentTransform() const
+const TransformationMatrix& RenderObject::localToParentTransform() const
{
- // FIXME: This double virtual call indirection is temporary until I can land the
- // rest of the of the localToParentTransform() support for SVG.
- return localTransform();
+ static const TransformationMatrix identity;
+ return identity;
}
TransformationMatrix RenderObject::absoluteTransform() const
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index d40ae6d..03ba1e6 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -52,6 +52,9 @@ class RenderLayer;
class RenderTheme;
class TransformState;
class VisiblePosition;
+#if ENABLE(SVG)
+class SVGRenderBase;
+#endif
/*
* The painting of a layer occurs in three distinct phases. Each phase involves
@@ -260,6 +263,7 @@ public:
virtual bool isBlockFlow() const { return false; }
virtual bool isBoxModelObject() const { return false; }
virtual bool isCounter() const { return false; }
+ virtual bool isEmbeddedObject() const { return false; }
virtual bool isFieldset() const { return false; }
virtual bool isFileUploadControl() const { return false; }
virtual bool isFrame() const { return false; }
@@ -277,6 +281,7 @@ public:
virtual bool isRenderInline() const { return false; }
virtual bool isRenderPart() const { return false; }
virtual bool isRenderView() const { return false; }
+ virtual bool isReplica() const { return false; }
virtual bool isRuby() const { return false; }
virtual bool isRubyBase() const { return false; }
virtual bool isRubyRun() const { return false; }
@@ -310,6 +315,10 @@ public:
bool cellWidthChanged() const { return m_cellWidthChanged; }
void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
+#if ENABLE(MATHML)
+ virtual bool isRenderMathMLBlock() const { return false; }
+#endif // ENABLE(MATHML)
+
#if ENABLE(SVG)
// FIXME: Until all SVG renders can be subclasses of RenderSVGModelObject we have
// to add SVG renderer methods to RenderObject with an ASSERT_NOT_REACHED() default implementation.
@@ -321,6 +330,8 @@ public:
virtual bool isSVGImage() const { return false; }
virtual bool isSVGForeignObject() const { return false; }
+ virtual const SVGRenderBase* toSVGRenderBase() const;
+
// Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width.
// This is used for all computation of objectBoundingBox relative units and by SVGLocateable::getBBox().
// NOTE: Markers are not specifically ignored here by SVG 1.1 spec, but we ignore them
@@ -340,7 +351,7 @@ public:
// Returns the full transform mapping from local coordinates to local coords for the parent SVG renderer
// This includes any viewport transforms and x/y offsets as well as the transform="" value off the element.
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
// Walks up the parent chain to create a transform which maps from local to document coords
// NOTE: This method is deprecated! It doesn't respect scroll offsets or repaint containers.
@@ -565,6 +576,8 @@ public:
// Build an array of quads in absolute coords for line boxes
virtual void absoluteQuads(Vector<FloatQuad>&) { }
+ void absoluteFocusRingQuads(Vector<FloatQuad>&);
+
// the rect that will be painted if this object is passed as the paintingRoot
IntRect paintingRootRect(IntRect& topLevelRect);
@@ -750,7 +763,7 @@ public:
bool shouldUseTransformFromContainer(const RenderObject* container) const;
void getTransformFromContainer(const RenderObject* container, const IntSize& offsetInContainer, TransformationMatrix&) const;
- virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { };
+ virtual void addFocusRingRects(Vector<IntRect>&, int /*tx*/, int /*ty*/) { };
IntRect absoluteOutlineBounds() const
{
diff --git a/WebCore/rendering/RenderPart.cpp b/WebCore/rendering/RenderPart.cpp
index cb56c0c..5c4a6ec 100644
--- a/WebCore/rendering/RenderPart.cpp
+++ b/WebCore/rendering/RenderPart.cpp
@@ -31,6 +31,7 @@ namespace WebCore {
RenderPart::RenderPart(Element* node)
: RenderWidget(node)
+ , m_hasFallbackContent(false)
{
// init RenderObject attributes
setInline(false);
diff --git a/WebCore/rendering/RenderPart.h b/WebCore/rendering/RenderPart.h
index 08abf99..8303543 100644
--- a/WebCore/rendering/RenderPart.h
+++ b/WebCore/rendering/RenderPart.h
@@ -27,6 +27,10 @@
namespace WebCore {
+// Renderer for frames via RenderPartObject, and plug-ins via RenderEmbeddedObject.
+
+// FIXME: This class is subclassed in RenderPartObject for iframes, which is in turn
+// subclassed in RenderEmbeddedObject for object and embed. This class itself could be removed.
class RenderPart : public RenderWidget {
public:
RenderPart(Element*);
diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp
index 8e9118e..09573c8 100644
--- a/WebCore/rendering/RenderPartObject.cpp
+++ b/WebCore/rendering/RenderPartObject.cpp
@@ -48,271 +48,6 @@ using namespace HTMLNames;
RenderPartObject::RenderPartObject(Element* element)
: RenderPart(element)
{
- // init RenderObject attributes
- setInline(true);
- m_hasFallbackContent = false;
-
- if (element->hasTagName(embedTag) || element->hasTagName(objectTag))
- view()->frameView()->setIsVisuallyNonEmpty();
-}
-
-RenderPartObject::~RenderPartObject()
-{
- if (frameView())
- frameView()->removeWidgetToUpdate(this);
-}
-
-static bool isURLAllowed(Document* doc, const String& url)
-{
- if (doc->frame()->page()->frameCount() >= 200)
- return false;
-
- // We allow one level of self-reference because some sites depend on that.
- // But we don't allow more than one.
- KURL completeURL = doc->completeURL(url);
- bool foundSelfReference = false;
- for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
- if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
- if (foundSelfReference)
- return false;
- foundSelfReference = true;
- }
- }
- return true;
-}
-
-typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
-
-static ClassIdToTypeMap* createClassIdToTypeMap()
-{
- ClassIdToTypeMap* map = new ClassIdToTypeMap;
- map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
- map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
- map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
- map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
- map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
- map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
- return map;
-}
-
-static String serviceTypeForClassId(const String& classId)
-{
- // Return early if classId is empty (since we won't do anything below).
- // Furthermore, if classId is null, calling get() below will crash.
- if (classId.isEmpty())
- return String();
-
- static ClassIdToTypeMap* map = createClassIdToTypeMap();
- return map->get(classId);
-}
-
-static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
-{
- // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
- // require "src" attribute).
- int srcIndex = -1, dataIndex = -1;
- for (unsigned int i = 0; i < paramNames->size(); ++i) {
- if (equalIgnoringCase((*paramNames)[i], "src"))
- srcIndex = i;
- else if (equalIgnoringCase((*paramNames)[i], "data"))
- dataIndex = i;
- }
-
- if (srcIndex == -1 && dataIndex != -1) {
- paramNames->append("src");
- paramValues->append((*paramValues)[dataIndex]);
- }
-}
-
-void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
-{
- String url;
- String serviceType;
- Vector<String> paramNames;
- Vector<String> paramValues;
- Frame* frame = frameView()->frame();
-
- // The calls to FrameLoader::requestObject within this function can result in a plug-in being initialized.
- // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from
- // the render tree and destroyed, causing a crash like <rdar://problem/6954546>. By extending our lifetime
- // artifically to ensure that we remain alive for the duration of plug-in initialization.
- RenderWidgetProtector protector(this);
-
- if (node()->hasTagName(objectTag)) {
- HTMLObjectElement* o = static_cast<HTMLObjectElement*>(node());
-
- o->setNeedWidgetUpdate(false);
- if (!o->isFinishedParsingChildren())
- return;
-
- // Check for a child EMBED tag.
- HTMLEmbedElement* embed = 0;
- for (Node* child = o->firstChild(); child; ) {
- if (child->hasTagName(embedTag)) {
- embed = static_cast<HTMLEmbedElement*>(child);
- break;
- } else if (child->hasTagName(objectTag))
- child = child->nextSibling(); // Don't descend into nested OBJECT tags
- else
- child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags)
- }
-
- // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
- HTMLElement *embedOrObject;
- if (embed) {
- embedOrObject = (HTMLElement *)embed;
- url = embed->url();
- serviceType = embed->serviceType();
- } else
- embedOrObject = (HTMLElement *)o;
-
- // If there was no URL or type defined in EMBED, try the OBJECT tag.
- if (url.isEmpty())
- url = o->url();
- if (serviceType.isEmpty())
- serviceType = o->serviceType();
-
- HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
-
- // Scan the PARAM children.
- // Get the URL and type from the params if we don't already have them.
- // Get the attributes from the params if there is no EMBED tag.
- Node *child = o->firstChild();
- while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
- if (child->hasTagName(paramTag)) {
- HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
- String name = p->name();
- if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
- url = p->value();
- if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
- serviceType = p->value();
- int pos = serviceType.find(";");
- if (pos != -1)
- serviceType = serviceType.left(pos);
- }
- if (!embed && !name.isEmpty()) {
- uniqueParamNames.add(name.impl());
- paramNames.append(p->name());
- paramValues.append(p->value());
- }
- }
- child = child->nextSibling();
- }
-
- // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
- // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
- // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
- // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
- // else our Java plugin will misinterpret it. [4004531]
- String codebase;
- if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
- codebase = "codebase";
- uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
- }
-
- // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
- NamedNodeMap* attributes = embedOrObject->attributes();
- if (attributes) {
- for (unsigned i = 0; i < attributes->length(); ++i) {
- Attribute* it = attributes->attributeItem(i);
- const AtomicString& name = it->name().localName();
- if (embed || !uniqueParamNames.contains(name.impl())) {
- paramNames.append(name.string());
- paramValues.append(it->value().string());
- }
- }
- }
-
- mapDataParamToSrc(&paramNames, &paramValues);
-
- // If we still don't have a type, try to map from a specific CLASSID to a type.
- if (serviceType.isEmpty())
- serviceType = serviceTypeForClassId(o->classId());
-
- if (!isURLAllowed(document(), url))
- return;
-
- // Find out if we support fallback content.
- m_hasFallbackContent = false;
- for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
- if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param>
- (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
- m_hasFallbackContent = true;
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
- }
-
- bool success = o->dispatchBeforeLoadEvent(url) &&
- frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues);
- if (!success && m_hasFallbackContent)
- o->renderFallbackContent();
- } else if (node()->hasTagName(embedTag)) {
- HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(node());
- o->setNeedWidgetUpdate(false);
- url = o->url();
- serviceType = o->serviceType();
-
- if (url.isEmpty() && serviceType.isEmpty())
- return;
- if (!isURLAllowed(document(), url))
- return;
-
- // add all attributes set on the embed object
- NamedNodeMap* a = o->attributes();
- if (a) {
- for (unsigned i = 0; i < a->length(); ++i) {
- Attribute* it = a->attributeItem(i);
- paramNames.append(it->name().localName().string());
- paramValues.append(it->value().string());
- }
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
-
- }
-
- if (o->dispatchBeforeLoadEvent(url))
- frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues);
- }
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) {
- HTMLMediaElement* o = static_cast<HTMLMediaElement*>(node());
-
- o->setNeedWidgetUpdate(false);
- if (node()->hasTagName(videoTag)) {
- HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node());
- String poster = vid->poster();
- if (!poster.isEmpty()) {
- paramNames.append("_media_element_poster_");
- paramValues.append(poster);
- }
- }
-
- url = o->initialURL();
- if (!url.isEmpty()) {
- paramNames.append("_media_element_src_");
- paramValues.append(url);
- }
-
- serviceType = "application/x-media-element-proxy-plugin";
-
- if (o->dispatchBeforeLoadEvent(url))
- frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues);
- }
-#endif
}
void RenderPartObject::layout()
@@ -401,9 +136,6 @@ void RenderPartObject::layout()
m_overflow.clear();
addShadowOverflow();
- if (!widget() && frameView())
- frameView()->addWidgetToUpdate(this);
-
setNeedsLayout(false);
}
diff --git a/WebCore/rendering/RenderPartObject.h b/WebCore/rendering/RenderPartObject.h
index 092395d..7160ea3 100644
--- a/WebCore/rendering/RenderPartObject.h
+++ b/WebCore/rendering/RenderPartObject.h
@@ -27,12 +27,10 @@
namespace WebCore {
+// Renderer for iframes. Is subclassed in RenderEmbeddedObject for object and embed.
class RenderPartObject : public RenderPart {
public:
RenderPartObject(Element*);
- virtual ~RenderPartObject();
-
- void updateWidget(bool onlyCreateNonNetscapePlugins);
private:
virtual const char* renderName() const { return "RenderPartObject"; }
diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp
index 4a7662f..f497dcf 100644
--- a/WebCore/rendering/RenderPath.cpp
+++ b/WebCore/rendering/RenderPath.cpp
@@ -3,6 +3,7 @@
2004, 2005, 2008 Rob Buis <buis@kde.org>
2005, 2007 Eric Seidel <eric@webkit.org>
2009 Google, Inc.
+ 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -68,7 +69,7 @@ RenderPath::RenderPath(SVGStyledTransformableElement* node)
{
}
-TransformationMatrix RenderPath::localToParentTransform() const
+const TransformationMatrix& RenderPath::localToParentTransform() const
{
return m_localTransform;
}
@@ -112,6 +113,34 @@ FloatRect RenderPath::objectBoundingBox() const
return m_cachedLocalFillBBox;
}
+FloatRect RenderPath::strokeBoundingBox() const
+{
+ if (m_path.isEmpty())
+ return FloatRect();
+
+ if (!m_cachedLocalStrokeBBox.isEmpty())
+ return m_cachedLocalStrokeBBox;
+
+ m_cachedLocalStrokeBBox = objectBoundingBox();
+ if (style()->svgStyle()->hasStroke()) {
+ BoundingRectStrokeStyleApplier strokeStyle(this, style());
+ m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle));
+ }
+
+ return m_cachedLocalStrokeBBox;
+}
+
+FloatRect RenderPath::markerBoundingBox() const
+{
+ if (m_path.isEmpty())
+ return FloatRect();
+
+ if (m_cachedLocalMarkerBBox.isEmpty())
+ calculateMarkerBoundsIfNeeded();
+
+ return m_cachedLocalMarkerBBox;
+}
+
FloatRect RenderPath::repaintRectInLocalCoordinates() const
{
if (m_path.isEmpty())
@@ -121,16 +150,25 @@ FloatRect RenderPath::repaintRectInLocalCoordinates() const
if (!m_cachedLocalRepaintRect.isEmpty())
return m_cachedLocalRepaintRect;
- if (!style()->svgStyle()->hasStroke())
- m_cachedLocalRepaintRect = objectBoundingBox();
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper, marker or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect = rect;
else {
- BoundingRectStrokeStyleApplier strokeStyle(this, style());
- m_cachedLocalRepaintRect = m_path.strokeBoundingRect(&strokeStyle);
+ m_cachedLocalRepaintRect = strokeBoundingBox();
+ m_cachedLocalRepaintRect.unite(markerBoundingBox());
}
- // Markers and filters can paint outside of the stroke path
- m_cachedLocalRepaintRect.unite(m_markerBounds);
- m_cachedLocalRepaintRect.unite(filterBoundingBoxForRenderer(this));
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);
return m_cachedLocalRepaintRect;
}
@@ -139,12 +177,9 @@ void RenderPath::setPath(const Path& newPath)
{
m_path = newPath;
m_cachedLocalRepaintRect = FloatRect();
+ m_cachedLocalStrokeBBox = FloatRect();
m_cachedLocalFillBBox = FloatRect();
-}
-
-const Path& RenderPath::path() const
-{
- return m_path;
+ m_cachedLocalMarkerBBox = FloatRect();
}
void RenderPath::layout()
@@ -180,39 +215,48 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
{
if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty())
return;
-
- paintInfo.context->save();
- paintInfo.context->concatCTM(localToParentTransform());
-
- SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
- if (paintInfo.phase == PaintPhaseForeground) {
- PaintInfo savedInfo(paintInfo);
+ FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox);
+ // FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage
+ // unfortunately fixing that problem is fairly complex unless we were willing to just futz the
+ // rect to something "close enough"
+ if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty())
+ return;
+
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+ applyTransformToPaintInfo(childPaintInfo, m_localTransform);
+ SVGResourceFilter* filter = 0;
- prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
- if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
- paintInfo.context->setShouldAntialias(false);
- fillAndStrokePath(m_path, paintInfo.context, style(), this);
+ if (childPaintInfo.phase == PaintPhaseForeground) {
+ PaintInfo savedInfo(childPaintInfo);
- if (static_cast<SVGStyledElement*>(node())->supportsMarkers())
- m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path);
+ if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) {
+ if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
+ childPaintInfo.context->setShouldAntialias(false);
+ fillAndStrokePath(m_path, childPaintInfo.context, style(), this);
- finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
+ if (static_cast<SVGStyledElement*>(node())->supportsMarkers())
+ m_markerLayoutInfo.drawMarkers(childPaintInfo);
+ }
+ finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context);
}
- if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
- paintOutline(paintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
+ if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
+ paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style());
- paintInfo.context->restore();
+ childPaintInfo.context->restore();
}
// This method is called from inside paintOutline() since we call paintOutline()
// while transformed to our coord system, return local coords
-void RenderPath::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderPath::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
- graphicsContext->addFocusRingRect(enclosingIntRect(repaintRectInLocalCoordinates()));
+ IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates());
+ if (!rect.isEmpty())
+ rects.append(rect);
}
bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
@@ -221,7 +265,7 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result,
if (hitTestAction != HitTestForeground)
return false;
- FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
+ FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent);
PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents());
@@ -237,143 +281,27 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result,
return false;
}
-enum MarkerType {
- Start,
- Mid,
- End
-};
-
-struct MarkerData {
- FloatPoint origin;
- FloatPoint subpathStart;
- double strokeWidth;
- FloatPoint inslopePoints[2];
- FloatPoint outslopePoints[2];
- MarkerType type;
- SVGResourceMarker* marker;
-};
-
-struct DrawMarkersData {
- DrawMarkersData(GraphicsContext*, SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, double strokeWidth);
- GraphicsContext* context;
- int elementIndex;
- MarkerData previousMarkerData;
- SVGResourceMarker* midMarker;
-};
-
-DrawMarkersData::DrawMarkersData(GraphicsContext* c, SVGResourceMarker *start, SVGResourceMarker *mid, double strokeWidth)
- : context(c)
- , elementIndex(0)
- , midMarker(mid)
-{
- previousMarkerData.origin = FloatPoint();
- previousMarkerData.subpathStart = FloatPoint();
- previousMarkerData.strokeWidth = strokeWidth;
- previousMarkerData.marker = start;
- previousMarkerData.type = Start;
-}
-
-static void drawMarkerWithData(GraphicsContext* context, MarkerData &data)
-{
- if (!data.marker)
- return;
-
- FloatPoint inslopeChange = data.inslopePoints[1] - FloatSize(data.inslopePoints[0].x(), data.inslopePoints[0].y());
- FloatPoint outslopeChange = data.outslopePoints[1] - FloatSize(data.outslopePoints[0].x(), data.outslopePoints[0].y());
-
- double inslope = rad2deg(atan2(inslopeChange.y(), inslopeChange.x()));
- double outslope = rad2deg(atan2(outslopeChange.y(), outslopeChange.x()));
-
- double angle = 0.0;
- switch (data.type) {
- case Start:
- angle = outslope;
- break;
- case Mid:
- angle = (inslope + outslope) / 2;
- break;
- case End:
- angle = inslope;
- }
-
- data.marker->draw(context, FloatRect(), data.origin.x(), data.origin.y(), data.strokeWidth, angle);
-}
-
-static inline void updateMarkerDataForElement(MarkerData& previousMarkerData, const PathElement* element)
-{
- FloatPoint* points = element->points;
-
- switch (element->type) {
- case PathElementAddQuadCurveToPoint:
- // TODO
- previousMarkerData.origin = points[1];
- break;
- case PathElementAddCurveToPoint:
- previousMarkerData.inslopePoints[0] = points[1];
- previousMarkerData.inslopePoints[1] = points[2];
- previousMarkerData.origin = points[2];
- break;
- case PathElementMoveToPoint:
- previousMarkerData.subpathStart = points[0];
- case PathElementAddLineToPoint:
- previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.inslopePoints[1] = points[0];
- previousMarkerData.origin = points[0];
- break;
- case PathElementCloseSubpath:
- previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.inslopePoints[1] = points[0];
- previousMarkerData.origin = previousMarkerData.subpathStart;
- previousMarkerData.subpathStart = FloatPoint();
- }
-}
-
-static void drawStartAndMidMarkers(void* info, const PathElement* element)
-{
- DrawMarkersData& data = *reinterpret_cast<DrawMarkersData*>(info);
-
- int elementIndex = data.elementIndex;
- MarkerData& previousMarkerData = data.previousMarkerData;
-
- FloatPoint* points = element->points;
-
- // First update the outslope for the previous element
- previousMarkerData.outslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.outslopePoints[1] = points[0];
-
- // Draw the marker for the previous element
- if (elementIndex != 0)
- drawMarkerWithData(data.context, previousMarkerData);
-
- // Update our marker data for this element
- updateMarkerDataForElement(previousMarkerData, element);
-
- if (elementIndex == 1) {
- // After drawing the start marker, switch to drawing mid markers
- previousMarkerData.marker = data.midMarker;
- previousMarkerData.type = Mid;
- }
-
- data.elementIndex++;
-}
-
-FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect&, const Path& path) const
+void RenderPath::calculateMarkerBoundsIfNeeded() const
{
Document* doc = document();
SVGElement* svgElement = static_cast<SVGElement*>(node());
- ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
+ ASSERT(svgElement && svgElement->document());
+ if (!svgElement->isStyled())
+ return;
SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
- const SVGRenderStyle* svgStyle = style()->svgStyle();
+ if (!styledElement->supportsMarkers())
+ return;
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
AtomicString startMarkerId(svgStyle->startMarker());
AtomicString midMarkerId(svgStyle->midMarker());
AtomicString endMarkerId(svgStyle->endMarker());
- SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId);
- SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId);
- SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId);
+ SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId, this);
+ SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId, this);
+ SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId, this);
if (!startMarker && !startMarkerId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement);
@@ -391,32 +319,10 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR
endMarker->addClient(styledElement);
if (!startMarker && !midMarker && !endMarker)
- return FloatRect();
-
- double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
- DrawMarkersData data(context, startMarker, midMarker, strokeWidth);
-
- path.apply(&data, drawStartAndMidMarkers);
-
- data.previousMarkerData.marker = endMarker;
- data.previousMarkerData.type = End;
- drawMarkerWithData(context, data.previousMarkerData);
-
- // We know the marker boundaries, only after they're drawn!
- // Otherwhise we'd need to do all the marker calculation twice
- // once here (through paint()) and once in absoluteClippedOverflowRect().
- FloatRect bounds;
-
- if (startMarker)
- bounds.unite(startMarker->cachedBounds());
-
- if (midMarker)
- bounds.unite(midMarker->cachedBounds());
-
- if (endMarker)
- bounds.unite(endMarker->cachedBounds());
+ return;
- return bounds;
+ float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
+ m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path);
}
}
diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h
index 2ff179e..be4c2dc 100644
--- a/WebCore/rendering/RenderPath.h
+++ b/WebCore/rendering/RenderPath.h
@@ -25,9 +25,9 @@
#define RenderPath_h
#if ENABLE(SVG)
-
#include "FloatRect.h"
#include "RenderSVGModelObject.h"
+#include "SVGMarkerLayoutInfo.h"
#include "TransformationMatrix.h"
namespace WebCore {
@@ -40,7 +40,7 @@ class RenderPath : public RenderSVGModelObject {
public:
RenderPath(SVGStyledTransformableElement*);
- const Path& path() const;
+ const Path& path() const { return m_path; }
private:
// Hit-detection seperated for the fill and the stroke
@@ -48,9 +48,11 @@ private:
bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
+ virtual FloatRect markerBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
void setPath(const Path&);
@@ -59,19 +61,21 @@ private:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
- FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const;
+ void calculateMarkerBoundsIfNeeded() const;
private:
virtual TransformationMatrix localTransform() const;
mutable Path m_path;
mutable FloatRect m_cachedLocalFillBBox;
+ mutable FloatRect m_cachedLocalStrokeBBox;
mutable FloatRect m_cachedLocalRepaintRect;
- FloatRect m_markerBounds;
+ mutable FloatRect m_cachedLocalMarkerBBox;
+ mutable SVGMarkerLayoutInfo m_markerLayoutInfo;
TransformationMatrix m_localTransform;
};
@@ -94,5 +98,3 @@ void toRenderPath(const RenderPath*);
#endif // ENABLE(SVG)
#endif
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h
index 0ba6b8a..bcf565d 100644
--- a/WebCore/rendering/RenderReplaced.h
+++ b/WebCore/rendering/RenderReplaced.h
@@ -46,6 +46,7 @@ protected:
void setIntrinsicSize(const IntSize&);
virtual void intrinsicSizeChanged();
+ virtual void paint(PaintInfo&, int tx, int ty);
bool shouldPaint(PaintInfo&, int& tx, int& ty);
void adjustOverflowForBoxShadowAndReflect();
IntRect localSelectionRect(bool checkWhetherSelected = true) const;
@@ -62,7 +63,6 @@ private:
virtual int minimumReplacedHeight() const { return 0; }
- virtual void paint(PaintInfo&, int tx, int ty);
virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { }
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
diff --git a/WebCore/rendering/RenderReplica.h b/WebCore/rendering/RenderReplica.h
index d5db3b7..48c64e4 100644
--- a/WebCore/rendering/RenderReplica.h
+++ b/WebCore/rendering/RenderReplica.h
@@ -46,6 +46,10 @@ public:
virtual void calcPrefWidths();
virtual void paint(PaintInfo&, int tx, int ty);
+
+private:
+ virtual bool isReplica() const { return true; }
+
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderRuby.h b/WebCore/rendering/RenderRuby.h
index a74150c..49a84d8 100644
--- a/WebCore/rendering/RenderRuby.h
+++ b/WebCore/rendering/RenderRuby.h
@@ -54,13 +54,15 @@ public:
RenderRubyAsInline(Node*);
virtual ~RenderRubyAsInline();
- virtual const char* renderName() const { return "RenderRuby (inline)"; }
-
- virtual bool isRuby() const { return true; }
-
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
virtual void removeChild(RenderObject* child);
+
+private:
+ virtual bool isRuby() const { return true; }
+ virtual const char* renderName() const { return "RenderRuby (inline)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); }
};
// <ruby> when used as 'display:block' or 'display:inline-block'
@@ -69,13 +71,15 @@ public:
RenderRubyAsBlock(Node*);
virtual ~RenderRubyAsBlock();
- virtual const char* renderName() const { return "RenderRuby (block)"; }
-
- virtual bool isRuby() const { return true; }
-
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
virtual void removeChild(RenderObject* child);
+
+private:
+ virtual bool isRuby() const { return true; }
+ virtual const char* renderName() const { return "RenderRuby (block)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); }
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderRubyBase.cpp b/WebCore/rendering/RenderRubyBase.cpp
index 5cb25f4..41ac4e3 100644
--- a/WebCore/rendering/RenderRubyBase.cpp
+++ b/WebCore/rendering/RenderRubyBase.cpp
@@ -48,39 +48,139 @@ bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const
return child->isInline();
}
-void RenderRubyBase::splitToLeft(RenderBlock* leftBase, RenderObject* beforeChild)
+bool RenderRubyBase::hasOnlyWrappedInlineChildren(RenderObject* beforeChild) const
{
- // This function removes all children that are before (!) beforeChild
- // and appends them to leftBase.
- ASSERT(leftBase);
+ // Tests whether all children in the base before beforeChild are either floated/positioned,
+ // or inline objects wrapped in anonymous blocks.
+ // Note that beforeChild may be 0, in which case all children are looked at.
+ for (RenderObject* child = firstChild(); child != beforeChild; child = child->nextSibling()) {
+ if (!child->isFloatingOrPositioned() && !(child->isAnonymousBlock() && child->childrenInline()))
+ return false;
+ }
+ return true;
+}
+void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ // This function removes all children that are before (!) beforeChild
+ // and appends them to toBase.
+ ASSERT(toBase);
+
// First make sure that beforeChild (if set) is indeed a direct child of this.
- // Fallback: climb up the tree to make sure. This may result in somewhat incorrect rendering.
- // FIXME: Can this happen? Is there a better/more correct way to solve this?
- ASSERT(!beforeChild || beforeChild->parent() == this);
- while (beforeChild && beforeChild->parent() != this)
- beforeChild = beforeChild->parent();
-
- RenderObject* child = firstChild();
- while (child != beforeChild) {
- RenderObject* nextChild = child->nextSibling();
- moveChildTo(leftBase, leftBase->children(), child);
- child = nextChild;
+ // Inline children might be wrapped in an anonymous block if there's a continuation.
+ // Theoretically, in ruby bases, this can happen with only the first such a child,
+ // so it should be OK to just climb the tree.
+ while (fromBeforeChild && fromBeforeChild->parent() != this)
+ fromBeforeChild = fromBeforeChild->parent();
+
+ if (childrenInline())
+ moveInlineChildren(toBase, fromBeforeChild);
+ else
+ moveBlockChildren(toBase, fromBeforeChild);
+
+ setNeedsLayoutAndPrefWidthsRecalc();
+ toBase->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ RenderBlock* toBlock;
+
+ if (toBase->childrenInline()) {
+ // The standard and easy case: move the children into the target base
+ toBlock = toBase;
+ } else {
+ // We need to wrap the inline objects into an anonymous block.
+ // If toBase has a suitable block, we re-use it, otherwise create a new one.
+ RenderObject* lastChild = toBase->lastChild();
+ if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline())
+ toBlock = toRenderBlock(lastChild);
+ else {
+ toBlock = toBase->createAnonymousBlock();
+ toBase->children()->appendChildNode(toBase, toBlock);
+ }
}
+ // Move our inline children into the target block we determined above.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
+ moveChildTo(toBlock, toBlock->children(), child);
}
-void RenderRubyBase::mergeWithRight(RenderBlock* rightBase)
+void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
{
- // This function removes all children and prepends (!) them to rightBase.
- ASSERT(rightBase);
-
- RenderObject* firstPos = rightBase->firstChild();
- RenderObject* child = lastChild();
- while (child) {
- moveChildTo(rightBase, rightBase->children(), firstPos, child);
- firstPos = child;
- child = lastChild();
+ if (toBase->childrenInline()) {
+ // First check whether we move only wrapped inline objects.
+ if (hasOnlyWrappedInlineChildren(fromBeforeChild)) {
+ // The reason why the base is in block flow must be after beforeChild.
+ // We therefore can extract the inline objects and move them to toBase.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) {
+ if (child->isAnonymousBlock()) {
+ RenderBlock* anonBlock = toRenderBlock(child);
+ ASSERT(anonBlock->childrenInline());
+ ASSERT(!anonBlock->inlineContinuation());
+ anonBlock->moveAllChildrenTo(toBase, toBase->children());
+ anonBlock->deleteLineBoxTree();
+ anonBlock->destroy();
+ } else {
+ ASSERT(child->isFloatingOrPositioned());
+ moveChildTo(toBase, toBase->children(), child);
+ }
+ }
+ } else {
+ // Moving block children -> have to set toBase as block flow
+ toBase->makeChildrenNonInline();
+ // Move children, potentially collapsing anonymous block wrappers.
+ mergeBlockChildren(toBase, fromBeforeChild);
+
+ // Now we need to check if the leftover children are all inline.
+ // If so, make this base inline again.
+ if (hasOnlyWrappedInlineChildren()) {
+ RenderObject* next = 0;
+ for (RenderObject* child = firstChild(); child; child = next) {
+ next = child->nextSibling();
+ if (child->isFloatingOrPositioned())
+ continue;
+ ASSERT(child->isAnonymousBlock());
+
+ RenderBlock* anonBlock = toRenderBlock(child);
+ ASSERT(anonBlock->childrenInline());
+ ASSERT(!anonBlock->inlineContinuation());
+ // Move inline children out of anonymous block.
+ anonBlock->moveAllChildrenTo(this, children(), anonBlock);
+ anonBlock->deleteLineBoxTree();
+ anonBlock->destroy();
+ }
+ setChildrenInline(true);
+ }
+ }
+ } else
+ mergeBlockChildren(toBase, fromBeforeChild);
+}
+
+void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ // This function removes all children that are before fromBeforeChild and appends them to toBase.
+ ASSERT(!childrenInline());
+ ASSERT(toBase);
+ ASSERT(!toBase->childrenInline());
+
+ // Quick check whether we have anything to do, to simplify the following code.
+ if (fromBeforeChild != firstChild())
+ return;
+
+ // If an anonymous block would be put next to another such block, then merge those.
+ RenderObject* firstChildHere = firstChild();
+ RenderObject* lastChildThere = toBase->lastChild();
+ if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline()
+ && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) {
+ RenderBlock* anonBlockHere = toRenderBlock(firstChildHere);
+ RenderBlock* anonBlockThere = toRenderBlock(lastChildThere);
+ anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children());
+ anonBlockHere->deleteLineBoxTree();
+ anonBlockHere->destroy();
}
+ // Move all remaining children normally.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
+ moveChildTo(toBase, toBase->children(), child);
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderRubyBase.h b/WebCore/rendering/RenderRubyBase.h
index 57baf99..c029bd5 100644
--- a/WebCore/rendering/RenderRubyBase.h
+++ b/WebCore/rendering/RenderRubyBase.h
@@ -46,8 +46,16 @@ public:
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
- void splitToLeft(RenderBlock* leftBase, RenderObject* beforeChild);
- void mergeWithRight(RenderBlock* rightBase);
+private:
+ bool hasOnlyWrappedInlineChildren(RenderObject* beforeChild = 0) const;
+
+ void moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+
+ // Allow RenderRubyRun to manipulate the children within ruby bases.
+ friend class RenderRubyRun;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderRubyRun.cpp b/WebCore/rendering/RenderRubyRun.cpp
index 8578c55..a3e6281 100644
--- a/WebCore/rendering/RenderRubyRun.cpp
+++ b/WebCore/rendering/RenderRubyRun.cpp
@@ -148,7 +148,7 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
RenderRubyRun* newRun = staticCreateRubyRun(ruby);
ruby->addChild(newRun, this);
newRun->addChild(child);
- rubyBaseSafe()->splitToLeft(newRun->rubyBaseSafe(), beforeChild);
+ rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
}
} else {
// child is not a text -> insert it into the base
@@ -170,7 +170,11 @@ void RenderRubyRun::removeChild(RenderObject* child)
// Ruby run without a base can happen only at the first run.
RenderRubyRun* rightRun = static_cast<RenderRubyRun*>(rightNeighbour);
ASSERT(rightRun->hasRubyBase());
- base->mergeWithRight(rightRun->rubyBaseSafe());
+ RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
+ // Collect all children in a single base, then swap the bases.
+ rightBase->moveChildren(base);
+ moveChildTo(rightRun, rightRun->children(), base);
+ rightRun->moveChildTo(this, children(), rightBase);
// The now empty ruby base will be removed below.
}
}
diff --git a/WebCore/rendering/RenderRubyRun.h b/WebCore/rendering/RenderRubyRun.h
index 361dfe5..222ddb6 100644
--- a/WebCore/rendering/RenderRubyRun.h
+++ b/WebCore/rendering/RenderRubyRun.h
@@ -48,10 +48,6 @@ public:
virtual void destroy();
- virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; }
-
- virtual bool isRubyRun() const { return true; }
-
bool hasRubyText() const;
bool hasRubyBase() const;
bool isEmpty() const;
@@ -70,8 +66,13 @@ public:
protected:
RenderRubyBase* createRubyBase() const;
-
+
private:
+ virtual bool isRubyRun() const { return true; }
+ virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
+
bool m_beingDestroyed;
};
diff --git a/WebCore/rendering/RenderSVGBlock.h b/WebCore/rendering/RenderSVGBlock.h
index a4ececb..0b0d107 100644
--- a/WebCore/rendering/RenderSVGBlock.h
+++ b/WebCore/rendering/RenderSVGBlock.h
@@ -35,6 +35,8 @@ class RenderSVGBlock : public RenderBlock, protected SVGRenderBase {
public:
RenderSVGBlock(SVGElement*);
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
private:
virtual void setStyle(PassRefPtr<RenderStyle>);
};
diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp
index d7aec99..6d1b965 100644
--- a/WebCore/rendering/RenderSVGContainer.cpp
+++ b/WebCore/rendering/RenderSVGContainer.cpp
@@ -3,6 +3,7 @@
2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
2007 Eric Seidel <eric@webkit.org>
Copyright (C) 2009 Google, Inc. All rights reserved.
+ 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -25,14 +26,11 @@
#if ENABLE(SVG)
#include "RenderSVGContainer.h"
-#include "AXObjectCache.h"
-#include "FloatQuad.h"
#include "GraphicsContext.h"
#include "RenderView.h"
#include "SVGRenderSupport.h"
#include "SVGResourceFilter.h"
#include "SVGStyledElement.h"
-#include "SVGURIReference.h"
namespace WebCore {
@@ -62,17 +60,7 @@ void RenderSVGContainer::layout()
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
- // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
- // that's a possible future optimization using LayoutState
- // http://bugs.webkit.org/show_bug.cgi?id=15391
- if (selfNeedsLayout())
- child->setNeedsLayout(true);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
+ layoutChildren(this, selfNeedsLayout());
repainter.repaintAfterLayout();
setNeedsLayout(false);
@@ -82,7 +70,7 @@ bool RenderSVGContainer::selfWillPaint() const
{
#if ENABLE(FILTERS)
const SVGRenderStyle* svgStyle = style()->svgStyle();
- SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this);
if (filter)
return true;
#endif
@@ -94,7 +82,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
if (paintInfo.context->paintingDisabled() || !drawsContents())
return;
- // Spec: groups w/o children still may render filter content.
+ // Spec: groups w/o children still may render filter content.
if (!firstChild() && !selfWillPaint())
return;
@@ -109,12 +97,16 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
+
+ bool continueRendering = true;
if (childPaintInfo.phase == PaintPhaseForeground)
- prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
- childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
- for (RenderObject* child = firstChild(); child; child = child->nextSibling())
- child->paint(childPaintInfo, 0, 0);
+ if (continueRendering) {
+ childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->paint(childPaintInfo, 0, 0);
+ }
if (paintInfo.phase == PaintPhaseForeground)
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
@@ -132,10 +124,11 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
}
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
-void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
- graphicsContext->addFocusRingRect(paintRectInParent);
+ if (!paintRectInParent.isEmpty())
+ rects.append(paintRectInParent);
}
FloatRect RenderSVGContainer::objectBoundingBox() const
@@ -143,14 +136,30 @@ FloatRect RenderSVGContainer::objectBoundingBox() const
return computeContainerBoundingBox(this, false);
}
+FloatRect RenderSVGContainer::strokeBoundingBox() const
+{
+ return computeContainerBoundingBox(this, true);
+}
+
// RenderSVGContainer is used for <g> elements which do not themselves have a
// width or height, so we union all of our child rects as our repaint rect.
FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
{
FloatRect repaintRect = computeContainerBoundingBox(this, true);
- // A filter on this container can paint outside of the union of the child repaint rects
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(repaintRect);
return repaintRect;
}
@@ -178,5 +187,3 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h
index f2195e3..f681e50 100644
--- a/WebCore/rendering/RenderSVGContainer.h
+++ b/WebCore/rendering/RenderSVGContainer.h
@@ -42,10 +42,9 @@ public:
void setDrawsContents(bool);
bool drawsContents() const;
-protected:
virtual void paint(PaintInfo&, int parentX, int parentY);
-private:
+protected:
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -54,9 +53,10 @@ private:
virtual void layout();
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
@@ -71,6 +71,7 @@ private:
bool selfWillPaint() const;
+private:
RenderObjectChildList m_children;
bool m_drawsContents : 1;
};
@@ -78,14 +79,14 @@ private:
inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object)
{
// Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
- ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
return static_cast<RenderSVGContainer*>(object);
}
inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object)
{
// Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
- ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
return static_cast<const RenderSVGContainer*>(object);
}
diff --git a/WebCore/rendering/RenderSVGGradientStop.cpp b/WebCore/rendering/RenderSVGGradientStop.cpp
index b81e7f4..66391c8 100644
--- a/WebCore/rendering/RenderSVGGradientStop.cpp
+++ b/WebCore/rendering/RenderSVGGradientStop.cpp
@@ -49,7 +49,7 @@ void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderSty
// <stop> elements should only be allowed to make renderers under gradient elements
// but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient.
if (SVGGradientElement* gradient = gradientElement()) {
- if (SVGResource* resource = gradient->canvasResource())
+ if (SVGResource* resource = gradient->canvasResource(this))
resource->invalidate();
}
}
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp
index d4b39d3..bb0a15d 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.cpp
+++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp
@@ -38,17 +38,7 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element)
void RenderSVGHiddenContainer::layout()
{
ASSERT(needsLayout());
-
- // Layout our kids to prevent a kid from being marked as needing layout
- // then never being asked to layout.
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (selfNeedsLayout())
- child->setNeedsLayout(true);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
-
+ layoutChildren(this, selfNeedsLayout());
setNeedsLayout(false);
}
diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp
index 41a1a10..c8fb132 100644
--- a/WebCore/rendering/RenderSVGImage.cpp
+++ b/WebCore/rendering/RenderSVGImage.cpp
@@ -4,6 +4,7 @@
Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org>
Copyright (C) 2009, Google, Inc.
+ Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -47,81 +48,6 @@ RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
{
}
-void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio* aspectRatio)
-{
- float origDestWidth = destRect.width();
- float origDestHeight = destRect.height();
- if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET) {
- float widthToHeightMultiplier = srcRect.height() / srcRect.width();
- if (origDestHeight > (origDestWidth * widthToHeightMultiplier)) {
- destRect.setHeight(origDestWidth * widthToHeightMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- destRect.setY(destRect.y() + origDestHeight / 2.0f - destRect.height() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- destRect.setY(destRect.y() + origDestHeight - destRect.height());
- break;
- }
- }
- if (origDestWidth > (origDestHeight / widthToHeightMultiplier)) {
- destRect.setWidth(origDestHeight / widthToHeightMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- destRect.setX(destRect.x() + origDestWidth / 2.0f - destRect.width() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- destRect.setX(destRect.x() + origDestWidth - destRect.width());
- break;
- }
- }
- } else if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE) {
- float widthToHeightMultiplier = srcRect.height() / srcRect.width();
- // if the destination height is less than the height of the image we'll be drawing
- if (origDestHeight < (origDestWidth * widthToHeightMultiplier)) {
- float destToSrcMultiplier = srcRect.width() / destRect.width();
- srcRect.setHeight(destRect.height() * destToSrcMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- srcRect.setY(destRect.y() + image()->height() / 2.0f - srcRect.height() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- srcRect.setY(destRect.y() + image()->height() - srcRect.height());
- break;
- }
- }
- // if the destination width is less than the width of the image we'll be drawing
- if (origDestWidth < (origDestHeight / widthToHeightMultiplier)) {
- float destToSrcMultiplier = srcRect.height() / destRect.height();
- srcRect.setWidth(destRect.width() * destToSrcMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- srcRect.setX(destRect.x() + image()->width() / 2.0f - srcRect.width() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- srcRect.setX(destRect.x() + image()->width() - srcRect.width());
- break;
- }
- }
- }
-}
-
void RenderSVGImage::layout()
{
ASSERT(needsLayout());
@@ -138,6 +64,7 @@ void RenderSVGImage::layout()
calcHeight();
m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
+ m_cachedLocalRepaintRect = FloatRect();
repainter.repaintAfterLayout();
@@ -157,16 +84,16 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
PaintInfo savedInfo(paintInfo);
- prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter);
+ if (prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) {
+ FloatRect destRect = m_localBounds;
+ FloatRect srcRect(0, 0, image()->width(), image()->height());
- FloatRect destRect = m_localBounds;
- FloatRect srcRect(0, 0, image()->width(), image()->height());
+ SVGImageElement* imageElt = static_cast<SVGImageElement*>(node());
+ if (imageElt->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
+ imageElt->preserveAspectRatio().transformRect(destRect, srcRect);
- SVGImageElement* imageElt = static_cast<SVGImageElement*>(node());
- if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
- adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio());
-
- paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect);
+ paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect);
+ }
finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
}
@@ -212,12 +139,29 @@ FloatRect RenderSVGImage::objectBoundingBox() const
FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const
{
- FloatRect repaintRect = m_localBounds;
+ // If we already have a cached repaint rect, return that
+ if (!m_cachedLocalRepaintRect.isEmpty())
+ return m_cachedLocalRepaintRect;
+
+ m_cachedLocalRepaintRect = m_localBounds;
+
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
- // Filters can paint outside the image content
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);
- return repaintRect;
+ return m_cachedLocalRepaintRect;
}
void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect)
@@ -233,6 +177,7 @@ IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* repa
void RenderSVGImage::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
+ style()->svgStyle()->inflateForShadow(repaintRect);
SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
@@ -241,11 +186,12 @@ void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
}
-void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
// this is called from paint() after the localTransform has already been applied
IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates());
- graphicsContext->addFocusRingRect(contentRect);
+ if (!contentRect.isEmpty())
+ rects.append(contentRect);
}
void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int)
diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h
index ef11719..0558aed 100644
--- a/WebCore/rendering/RenderSVGImage.h
+++ b/WebCore/rendering/RenderSVGImage.h
@@ -24,28 +24,29 @@
#define RenderSVGImage_h
#if ENABLE(SVG)
-
-#include "TransformationMatrix.h"
#include "FloatRect.h"
#include "RenderImage.h"
+#include "SVGPreserveAspectRatio.h"
#include "SVGRenderSupport.h"
+#include "TransformationMatrix.h"
namespace WebCore {
class SVGImageElement;
- class SVGPreserveAspectRatio;
class RenderSVGImage : public RenderImage, SVGRenderBase {
public:
RenderSVGImage(SVGImageElement*);
private:
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual const char* renderName() const { return "RenderSVGImage"; }
virtual bool isSVGImage() const { return true; }
- virtual TransformationMatrix localToParentTransform() const { return m_localTransform; }
+ virtual const TransformationMatrix& localToParentTransform() const { return m_localTransform; }
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return m_localBounds; }
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
@@ -55,10 +56,9 @@ namespace WebCore {
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
- void adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio*);
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
@@ -72,6 +72,7 @@ namespace WebCore {
TransformationMatrix m_localTransform;
FloatRect m_localBounds;
+ mutable FloatRect m_cachedLocalRepaintRect;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h
index 9f9f3f5..53fd4b7 100644
--- a/WebCore/rendering/RenderSVGInline.h
+++ b/WebCore/rendering/RenderSVGInline.h
@@ -27,6 +27,8 @@
#if ENABLE(SVG)
#include "RenderInline.h"
+#include "SVGRenderSupport.h"
+
namespace WebCore {
class RenderSVGInline : public RenderInline {
@@ -38,6 +40,9 @@ public:
// These are shared between RenderSVGTSpan and RenderSVGTextPath
virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
+
+ virtual FloatRect objectBoundingBox() const { return FloatRect(); }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
private:
virtual InlineFlowBox* createInlineFlowBox();
diff --git a/WebCore/rendering/RenderSVGModelObject.cpp b/WebCore/rendering/RenderSVGModelObject.cpp
index 3fab5a6..7a76fbd 100644
--- a/WebCore/rendering/RenderSVGModelObject.cpp
+++ b/WebCore/rendering/RenderSVGModelObject.cpp
@@ -56,6 +56,7 @@ IntRect RenderSVGModelObject::clippedOverflowRectForRepaint(RenderBoxModelObject
void RenderSVGModelObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
+ style()->svgStyle()->inflateForShadow(repaintRect);
SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
diff --git a/WebCore/rendering/RenderSVGModelObject.h b/WebCore/rendering/RenderSVGModelObject.h
index 0aa13ad..4c50734 100644
--- a/WebCore/rendering/RenderSVGModelObject.h
+++ b/WebCore/rendering/RenderSVGModelObject.h
@@ -49,6 +49,8 @@ class RenderSVGModelObject : public RenderObject, protected SVGRenderBase {
public:
RenderSVGModelObject(SVGStyledElement*);
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
virtual bool requiresLayer() const { return false; }
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
index 0a39bf4..4a3bbcc 100644
--- a/WebCore/rendering/RenderSVGRoot.cpp
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -86,23 +86,20 @@ void RenderSVGRoot::layout()
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
+ int oldWidth = width();
calcWidth();
+
+ int oldHeight = height();
calcHeight();
SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
setWidth(static_cast<int>(width() * svg->currentScale()));
setHeight(static_cast<int>(height() * svg->currentScale()));
-
calcViewport();
-
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout
- child->setNeedsLayout(true, false);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
+ // RenderSVGRoot needs to take special care to propagate window size changes to the children,
+ // if the outermost <svg> is using relative x/y/width/height values. Hence the additonal parameters.
+ layoutChildren(this, selfNeedsLayout() || (svg->hasRelativeValues() && (width() != oldWidth || height() != oldHeight)));
repainter.repaintAfterLayout();
view()->enableLayoutState();
@@ -113,7 +110,7 @@ bool RenderSVGRoot::selfWillPaint() const
{
#if ENABLE(FILTERS)
const SVGRenderStyle* svgStyle = style()->svgStyle();
- SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this);
if (filter)
return true;
#endif
@@ -153,10 +150,13 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
+
+ bool continueRendering = true;
if (childPaintInfo.phase == PaintPhaseForeground)
- prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
- RenderBox::paint(childPaintInfo, 0, 0);
+ if (continueRendering)
+ RenderBox::paint(childPaintInfo, 0, 0);
if (childPaintInfo.phase == PaintPhaseForeground)
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
@@ -224,14 +224,15 @@ TransformationMatrix RenderSVGRoot::localToRepaintContainerTransform(const IntPo
return localToParentTransform() * parentToContainer;
}
-TransformationMatrix RenderSVGRoot::localToParentTransform() const
+const TransformationMatrix& RenderSVGRoot::localToParentTransform() const
{
IntSize parentToBorderBoxOffset = parentOriginToBorderBox();
TransformationMatrix borderBoxOriginToParentOrigin;
borderBoxOriginToParentOrigin.translate(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height());
- return localToBorderBoxTransform() * borderBoxOriginToParentOrigin;
+ m_localToParentTransform = localToBorderBoxTransform() * borderBoxOriginToParentOrigin;
+ return m_localToParentTransform;
}
// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed.
@@ -249,7 +250,9 @@ FloatRect RenderSVGRoot::objectBoundingBox() const
FloatRect RenderSVGRoot::repaintRectInLocalCoordinates() const
{
// FIXME: This does not include the border but it should!
- return computeContainerBoundingBox(this, true);
+ FloatRect repaintRect = computeContainerBoundingBox(this, true);
+ style()->svgStyle()->inflateForShadow(repaintRect);
+ return repaintRect;
}
TransformationMatrix RenderSVGRoot::localTransform() const
@@ -259,8 +262,10 @@ TransformationMatrix RenderSVGRoot::localTransform() const
void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
- // Apply our local transforms (except for x/y translation) and call RenderBox's method to handle all the normal CSS Box model bits
+ // Apply our local transforms (except for x/y translation), then our shadow,
+ // and then call RenderBox's method to handle all the normal CSS Box model bits
repaintRect = localToBorderBoxTransform().mapRect(repaintRect);
+ style()->svgStyle()->inflateForShadow(repaintRect);
RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed);
}
@@ -310,5 +315,3 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h
index 08c3058..b2f8f7c 100644
--- a/WebCore/rendering/RenderSVGRoot.h
+++ b/WebCore/rendering/RenderSVGRoot.h
@@ -54,12 +54,13 @@ private:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
bool fillContains(const FloatPoint&) const;
bool strokeContains(const FloatPoint&) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return computeContainerBoundingBox(this, true); }
virtual FloatRect repaintRectInLocalCoordinates() const;
// FIXME: Both of these overrides should be removed.
@@ -84,6 +85,7 @@ private:
RenderObjectChildList m_children;
FloatSize m_viewportSize;
+ mutable TransformationMatrix m_localToParentTransform;
};
inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object)
diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp
new file mode 100644
index 0000000..9d3d26f
--- /dev/null
+++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGShadowTreeRootContainer.h"
+
+#include "MouseEvent.h"
+#include "SVGShadowTreeElements.h"
+#include "SVGUseElement.h"
+
+namespace WebCore {
+
+RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer(SVGUseElement* node)
+ : RenderSVGTransformableContainer(node)
+ , m_recreateTree(false)
+{
+}
+
+RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer()
+{
+ if (m_shadowRoot && m_shadowRoot->attached())
+ m_shadowRoot->detach();
+}
+
+void RenderSVGShadowTreeRootContainer::updateStyle(Node::StyleChange change)
+{
+ if (m_shadowRoot && m_shadowRoot->attached())
+ m_shadowRoot->recalcStyle(change);
+}
+
+void RenderSVGShadowTreeRootContainer::updateFromElement()
+{
+ bool hadExistingTree = m_shadowRoot;
+
+ SVGUseElement* useElement = static_cast<SVGUseElement*>(node());
+ if (!m_shadowRoot) {
+ ASSERT(!m_recreateTree);
+ m_shadowRoot = new SVGShadowTreeRootElement(document(), useElement);
+ useElement->buildPendingResource();
+ }
+
+ ASSERT(m_shadowRoot->shadowParentNode() == useElement);
+
+ bool shouldRecreateTree = m_recreateTree;
+ if (m_recreateTree) {
+ ASSERT(hadExistingTree);
+
+ if (m_shadowRoot->attached())
+ m_shadowRoot->detach();
+
+ m_shadowRoot->removeAllChildren();
+ m_recreateTree = false;
+ }
+
+ // Only rebuild the shadow tree, if we a) never had a tree or b) we were specifically asked to do so
+ // If the use element is a pending resource, and a) or b) is true, do nothing, and wait for the use
+ // element to be asked to buildPendingResource(), this will call us again, with m_recreateTrue=true.
+ if ((shouldRecreateTree || !hadExistingTree) && !useElement->isPendingResource()) {
+ useElement->buildShadowAndInstanceTree(m_shadowRoot.get());
+
+ // Attach shadow root element
+ m_shadowRoot->attachElement(style(), renderArena());
+
+ // Attach subtree, as if it was a regular non-shadow tree
+ for (Node* child = m_shadowRoot->firstChild(); child; child = child->nextSibling())
+ child->attach();
+ }
+
+ ASSERT(!m_recreateTree);
+ RenderSVGTransformableContainer::updateFromElement();
+}
+
+void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderSVGTransformableContainer::styleDidChange(diff, oldStyle);
+
+ if (RenderObject* shadowRootRenderer = m_shadowRoot ? m_shadowRoot->renderer() : 0)
+ shadowRootRenderer->setStyle(style());
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.h b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h
new file mode 100644
index 0000000..01cd427
--- /dev/null
+++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef RenderSVGShadowTreeRootContainer_h
+#define RenderSVGShadowTreeRootContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGTransformableContainer.h"
+
+namespace WebCore {
+
+class SVGUseElement;
+class SVGShadowTreeRootElement;
+
+class RenderSVGShadowTreeRootContainer : public RenderSVGTransformableContainer {
+public:
+ RenderSVGShadowTreeRootContainer(SVGUseElement*);
+ virtual ~RenderSVGShadowTreeRootContainer();
+
+ void markShadowTreeForRecreation() { m_recreateTree = true; }
+ void updateStyle(Node::StyleChange);
+ virtual void updateFromElement();
+
+private:
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ bool m_recreateTree;
+ RefPtr<SVGShadowTreeRootElement> m_shadowRoot;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp
index 3919d7f..0cf0332 100644
--- a/WebCore/rendering/RenderSVGText.cpp
+++ b/WebCore/rendering/RenderSVGText.cpp
@@ -6,6 +6,7 @@
* 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
* 2007 Nikolas Zimmermann <zimmermann@kde.org>
* 2008 Rob Buis <buis@kde.org>
+ * 2009 Dirk Schulze <krit@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -58,6 +59,7 @@ IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repai
void RenderSVGText::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
+ style()->svgStyle()->inflateForShadow(repaintRect);
SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
@@ -184,7 +186,7 @@ FloatRect RenderSVGText::objectBoundingBox() const
return boundingBox;
}
-FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
+FloatRect RenderSVGText::strokeBoundingBox() const
{
FloatRect repaintRect = objectBoundingBox();
@@ -205,7 +207,28 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
repaintRect.inflate(strokeWidth);
}
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ return repaintRect;
+}
+
+FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
+{
+ FloatRect repaintRect = strokeBoundingBox();
+
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(repaintRect);
return repaintRect;
}
diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h
index 9a2770b..d001d1c 100644
--- a/WebCore/rendering/RenderSVGText.h
+++ b/WebCore/rendering/RenderSVGText.h
@@ -40,9 +40,11 @@ public:
private:
virtual const char* renderName() const { return "RenderSVGText"; }
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
virtual bool isSVGText() const { return true; }
- virtual TransformationMatrix localToParentTransform() const { return m_localTransform; }
+ virtual const TransformationMatrix& localToParentTransform() const { return m_localTransform; }
virtual void paint(PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
@@ -60,6 +62,7 @@ private:
virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
// FIXME: This can be removed when localTransform() is removed from RenderObject
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.cpp b/WebCore/rendering/RenderSVGTransformableContainer.cpp
index 2324eee..050e1bd 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.cpp
+++ b/WebCore/rendering/RenderSVGTransformableContainer.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
+ Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
2004, 2005, 2006 Rob Buis <buis@kde.org>
2009 Google, Inc.
@@ -20,12 +20,12 @@
*/
#include "config.h"
-#if ENABLE(SVG)
+#if ENABLE(SVG)
#include "RenderSVGTransformableContainer.h"
+#include "SVGShadowTreeElements.h"
#include "SVGStyledTransformableElement.h"
-#include "SVGTransformList.h"
namespace WebCore {
@@ -34,7 +34,7 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf
{
}
-TransformationMatrix RenderSVGTransformableContainer::localToParentTransform() const
+const TransformationMatrix& RenderSVGTransformableContainer::localToParentTransform() const
{
return m_localTransform;
}
@@ -47,6 +47,14 @@ TransformationMatrix RenderSVGTransformableContainer::localTransform() const
void RenderSVGTransformableContainer::calculateLocalTransform()
{
m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
+ if (!node()->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(node())->isShadowTreeContainerElement())
+ return;
+
+ FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(node())->containerTranslation();
+ if (translation.width() == 0 && translation.height() == 0)
+ return;
+
+ m_localTransform.translateRight(translation.width(), translation.height());
}
}
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.h b/WebCore/rendering/RenderSVGTransformableContainer.h
index c929761..43e4001 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.h
+++ b/WebCore/rendering/RenderSVGTransformableContainer.h
@@ -31,7 +31,7 @@ namespace WebCore {
public:
RenderSVGTransformableContainer(SVGStyledTransformableElement*);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
private:
virtual void calculateLocalTransform();
diff --git a/WebCore/rendering/RenderSVGViewportContainer.cpp b/WebCore/rendering/RenderSVGViewportContainer.cpp
index a432ef3..b46e8c2 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.cpp
+++ b/WebCore/rendering/RenderSVGViewportContainer.cpp
@@ -38,17 +38,27 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node)
{
}
-void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY)
+FloatRect RenderSVGViewportContainer::markerBoundaries(const TransformationMatrix& markerTransformation) const
{
- // FIXME: The if statement here evaluates to false. isEmpty() is exactly the same
- // as what is on the right side, so it's basically !isEmpty && isEmpty. So this
- // function does nothing.
+ FloatRect coordinates = repaintRectInLocalCoordinates();
- // A value of zero disables rendering of the element.
- if (!m_viewport.isEmpty() && (m_viewport.width() <= 0. || m_viewport.height() <= 0.))
- return;
+ // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated
+ coordinates = localToParentTransform().mapRect(coordinates);
- RenderSVGContainer::paint(paintInfo, parentX, parentY);
+ return markerTransformation.mapRect(coordinates);
+}
+
+TransformationMatrix RenderSVGViewportContainer::markerContentTransformation(const TransformationMatrix& contentTransformation, const FloatPoint& origin, float strokeWidth) const
+{
+ // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker
+ FloatPoint mappedOrigin = viewportTransform().mapPoint(origin);
+
+ TransformationMatrix transformation = contentTransformation;
+ if (strokeWidth != -1)
+ transformation.scaleNonUniform(strokeWidth, strokeWidth);
+
+ transformation.translate(-mappedOrigin.x(), -mappedOrigin.y());
+ return transformation;
}
void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo)
@@ -95,11 +105,12 @@ TransformationMatrix RenderSVGViewportContainer::viewportTransform() const
return TransformationMatrix();
}
-TransformationMatrix RenderSVGViewportContainer::localToParentTransform() const
+const TransformationMatrix& RenderSVGViewportContainer::localToParentTransform() const
{
TransformationMatrix viewportTranslation;
viewportTranslation.translate(m_viewport.x(), m_viewport.y());
- return viewportTransform() * viewportTranslation;
+ m_localToParentTransform = viewportTransform() * viewportTranslation;
+ return m_localToParentTransform;
// If this class were ever given a localTransform(), then the above would read:
// return viewportTransform() * localTransform() * viewportTranslation;
}
@@ -125,5 +136,3 @@ bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& poi
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGViewportContainer.h b/WebCore/rendering/RenderSVGViewportContainer.h
index b8b30b5..ee08b60 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.h
+++ b/WebCore/rendering/RenderSVGViewportContainer.h
@@ -24,7 +24,6 @@
#define RenderSVGViewportContainer_h
#if ENABLE(SVG)
-
#include "RenderSVGContainer.h"
namespace WebCore {
@@ -35,16 +34,19 @@ class RenderSVGViewportContainer : public RenderSVGContainer {
public:
RenderSVGViewportContainer(SVGStyledElement*);
- // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed.
- TransformationMatrix viewportTransform() const;
+ // Calculates marker boundaries, mapped to the target element's coordinate space
+ FloatRect markerBoundaries(const TransformationMatrix& markerTransformation) const;
- virtual void paint(PaintInfo&, int parentX, int parentY);
+ // Generates a transformation matrix usable to render marker content. Handles scaling the marker content
+ // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in.
+ TransformationMatrix markerContentTransformation(const TransformationMatrix& contentTransformation, const FloatPoint& origin, float strokeWidth = -1) const;
private:
virtual bool isSVGContainer() const { return true; }
virtual const char* renderName() const { return "RenderSVGViewportContainer"; }
- virtual TransformationMatrix localToParentTransform() const;
+ TransformationMatrix viewportTransform() const;
+ virtual const TransformationMatrix& localToParentTransform() const;
// FIXME: This override should be removed once callers of RenderBox::absoluteTransform() can be removed.
virtual TransformationMatrix absoluteTransform() const;
@@ -55,6 +57,7 @@ private:
virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent);
FloatRect m_viewport;
+ mutable TransformationMatrix m_localToParentTransform;
};
inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object)
@@ -70,5 +73,3 @@ void toRenderSVGViewportContainer(const RenderSVGViewportContainer*);
#endif // ENABLE(SVG)
#endif // RenderSVGViewportContainer_h
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp
index 4e7036e..2395527 100644
--- a/WebCore/rendering/RenderTableCell.cpp
+++ b/WebCore/rendering/RenderTableCell.cpp
@@ -237,7 +237,7 @@ void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContain
return;
r.setY(r.y());
RenderView* v = view();
- if ((!v || !v->layoutStateEnabled()) && parent())
+ if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent())
r.move(-parentBox()->x(), -parentBox()->y()); // Rows are in the same coordinate space, so don't add their offset in.
RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
}
@@ -845,7 +845,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i
paintInfo.context->save();
paintInfo.context->clip(clipRect);
}
- paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h);
+ paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h, CompositeSourceOver, backgroundObject);
if (shouldClip)
paintInfo.context->restore();
}
diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h
index f285198..0f8580d 100644
--- a/WebCore/rendering/RenderTableCell.h
+++ b/WebCore/rendering/RenderTableCell.h
@@ -106,6 +106,8 @@ public:
virtual void setOverrideSize(int);
+ bool hasVisibleOverflow() const { return m_overflow; }
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index b627afe..a2457e1 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -733,12 +733,11 @@ int RenderTableSection::layoutRows(int toAdd)
if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
continue;
addOverflowFromChild(cell);
+ m_hasOverflowingCell |= cell->hasVisibleOverflow();
}
}
- m_hasOverflowingCell = m_overflow;
-
- statePusher.pop();
+ statePusher.pop();
return height();
}
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index 95aa277..2e696a9 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -25,7 +25,9 @@
#include "config.h"
#include "RenderText.h"
+#include "AXObjectCache.h"
#include "CharacterNames.h"
+#include "EllipsisBox.h"
#include "FloatQuad.h"
#include "FrameView.h"
#include "InlineTextBox.h"
@@ -286,7 +288,7 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
} else {
unsigned realEnd = min(box->end() + 1, end);
IntRect r = box->selectionRect(0, 0, start, realEnd);
- if (!r.isEmpty()) {
+ if (r.height()) {
if (!useSelectionHeight) {
// change the height and y position because selectionRect uses selection-specific values
r.setHeight(box->height());
@@ -338,7 +340,7 @@ VisiblePosition RenderText::positionForPoint(const IntPoint& point)
// at the y coordinate of the last line or below
// and the x coordinate is to the right of the last text box right edge
offset = lastTextBox()->offsetForPosition(point.x());
- return createVisiblePosition(offset + lastTextBox()->start(), DOWNSTREAM);
+ return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
}
InlineTextBox* lastBoxAbove = 0;
@@ -1014,6 +1016,10 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
setTextInternal(text);
setNeedsLayoutAndPrefWidthsRecalc();
m_knownNotToUseFallbackFonts = false;
+
+ AXObjectCache* axObjectCache = document()->axObjectCache();
+ if (axObjectCache->accessibilityEnabled())
+ axObjectCache->contentChanged(this);
}
int RenderText::lineHeight(bool firstLine, bool) const
@@ -1060,8 +1066,15 @@ void RenderText::positionLineBox(InlineBox* box)
if (!s->len()) {
// We want the box to be destroyed.
s->remove();
+ if (m_firstTextBox == s)
+ m_firstTextBox = s->nextTextBox();
+ else
+ s->prevTextBox()->setNextLineBox(s->nextTextBox());
+ if (m_lastTextBox == s)
+ m_lastTextBox = s->prevTextBox();
+ else
+ s->nextTextBox()->setPreviousLineBox(s->prevTextBox());
s->destroy(renderArena());
- m_firstTextBox = m_lastTextBox = 0;
return;
}
@@ -1164,9 +1177,25 @@ IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContain
return IntRect();
IntRect rect;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
rect.unite(box->selectionRect(0, 0, startPos, endPos));
+ // Check if there are ellipsis which fall within the selection.
+ unsigned short truncation = box->truncation();
+ if (truncation != cNoTruncation) {
+ if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
+ int ePos = min<int>(endPos - box->start(), box->len());
+ int sPos = max<int>(startPos - box->start(), 0);
+ // The ellipsis should be considered to be selected if the end of
+ // the selection is past the beginning of the truncation and the
+ // beginning of the selection is before or at the beginning of the
+ // truncation.
+ if (ePos >= truncation && sPos <= truncation)
+ rect.unite(ellipsis->selectionRect(0, 0));
+ }
+ }
+ }
+
if (clipToVisibleContent)
computeRectForRepaint(repaintContainer, rect);
else {
@@ -1362,7 +1391,7 @@ void RenderText::checkConsistency() const
#ifdef CHECK_CONSISTENCY
const InlineTextBox* prev = 0;
for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
- ASSERT(child->object() == this);
+ ASSERT(child->renderer() == this);
ASSERT(child->prevTextBox() == prev);
prev = child;
}
diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp
index b258597..c0ba070 100644
--- a/WebCore/rendering/RenderTextControl.cpp
+++ b/WebCore/rendering/RenderTextControl.cpp
@@ -195,7 +195,7 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue)
ASSERT(!ec);
}
- // We set m_lastChangeWasUserEdit to false since this change was not explicty made by the user (say, via typing on the keyboard), see <rdar://problem/5359921>.
+ // We set m_lastChangeWasUserEdit to false since this change was not explicitly made by the user (say, via typing on the keyboard), see <rdar://problem/5359921>.
m_lastChangeWasUserEdit = false;
}
@@ -505,9 +505,10 @@ void RenderTextControl::selectionChanged(bool userTriggered)
}
}
-void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
}
HTMLElement* RenderTextControl::innerTextElement() const
diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h
index 394eb9c..d1f3749 100644
--- a/WebCore/rendering/RenderTextControl.h
+++ b/WebCore/rendering/RenderTextControl.h
@@ -99,7 +99,7 @@ private:
virtual bool avoidsFloats() const { return true; }
void setInnerTextStyle(PassRefPtr<RenderStyle>);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual bool canBeProgramaticallyScrolled(bool) const { return true; }
diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp
index 56d4363..b68f004 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -472,8 +472,12 @@ void RenderTextControlSingleLine::updateFromElement()
ExceptionCode ec = 0;
innerTextElement()->setInnerText(static_cast<Element*>(node())->getAttribute(placeholderAttr), ec);
ASSERT(!ec);
- } else
- setInnerTextValue(inputElement()->value());
+ } else {
+ if (!inputElement()->suggestedValue().isNull())
+ setInnerTextValue(inputElement()->suggestedValue());
+ else
+ setInnerTextValue(inputElement()->value());
+ }
if (m_searchPopupIsVisible)
m_searchPopup->updateFromElement();
diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp
index f6afb77..af92465 100644
--- a/WebCore/rendering/RenderTheme.cpp
+++ b/WebCore/rendering/RenderTheme.cpp
@@ -87,6 +87,8 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
switch (part) {
case ListButtonPart:
case CheckboxPart:
+ case InnerSpinButtonPart:
+ case OuterSpinButtonPart:
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
@@ -176,6 +178,10 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
case DefaultButtonPart:
case ButtonPart:
return adjustButtonStyle(selector, style, e);
+ case InnerSpinButtonPart:
+ return adjustInnerSpinButtonStyle(selector, style, e);
+ case OuterSpinButtonPart:
+ return adjustOuterSpinButtonStyle(selector, style, e);
#endif
case TextFieldPart:
return adjustTextFieldStyle(selector, style, e);
@@ -236,6 +242,8 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf
case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
+ case InnerSpinButtonPart:
+ case OuterSpinButtonPart:
m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
return false;
default:
@@ -256,6 +264,10 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf
case DefaultButtonPart:
case ButtonPart:
return paintButton(o, paintInfo, r);
+ case InnerSpinButtonPart:
+ return paintInnerSpinButton(o, paintInfo, r);
+ case OuterSpinButtonPart:
+ return paintOuterSpinButton(o, paintInfo, r);
#endif
case MenulistPart:
return paintMenuList(o, paintInfo, r);
@@ -589,7 +601,7 @@ bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
{
- // Default implementation assumes the controls dont respond to changes in :hover state
+ // Default implementation assumes the controls don't respond to changes in :hover state
if (state == HoverState && !supportsHover(o->style()))
return false;
@@ -766,6 +778,14 @@ void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Eleme
setButtonSize(style);
}
+void RenderTheme::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
#endif
void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h
index ee359d7..a7c6e13 100644
--- a/WebCore/rendering/RenderTheme.h
+++ b/WebCore/rendering/RenderTheme.h
@@ -173,6 +173,8 @@ public:
// Media controls
virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint);
virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
+ virtual double mediaControlsFadeInDuration() { return 0.1; }
+ virtual double mediaControlsFadeOutDuration() { return 0.3; }
#endif
protected:
@@ -203,6 +205,11 @@ protected:
virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual void setButtonSize(RenderStyle*) const { }
+
+ virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintInnerSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual void adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintOuterSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
#endif
virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
diff --git a/WebCore/rendering/RenderThemeChromiumLinux.cpp b/WebCore/rendering/RenderThemeChromiumLinux.cpp
index 4b09174..f972a12 100644
--- a/WebCore/rendering/RenderThemeChromiumLinux.cpp
+++ b/WebCore/rendering/RenderThemeChromiumLinux.cpp
@@ -35,6 +35,14 @@ namespace WebCore {
unsigned RenderThemeChromiumLinux::m_thumbInactiveColor = 0xf0ebe5;
unsigned RenderThemeChromiumLinux::m_thumbActiveColor = 0xfaf8f5;
unsigned RenderThemeChromiumLinux::m_trackColor = 0xe3ddd8;
+unsigned RenderThemeChromiumLinux::m_activeSelectionBackgroundColor =
+ 0xff1e90ff;
+unsigned RenderThemeChromiumLinux::m_activeSelectionForegroundColor =
+ Color::black;
+unsigned RenderThemeChromiumLinux::m_inactiveSelectionBackgroundColor =
+ 0xffc8c8c8;
+unsigned RenderThemeChromiumLinux::m_inactiveSelectionForegroundColor =
+ 0xff323232;
PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create()
{
@@ -96,6 +104,26 @@ Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const
return Color(0x32, 0x32, 0x32);
}
+Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const
+{
+ return m_activeSelectionBackgroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const
+{
+ return m_inactiveSelectionBackgroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const
+{
+ return m_activeSelectionForegroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const
+{
+ return m_inactiveSelectionForegroundColor;
+}
+
void RenderThemeChromiumLinux::adjustSliderThumbSize(RenderObject* o) const
{
// These sizes match the sizes in Chromium Win.
@@ -126,6 +154,18 @@ double RenderThemeChromiumLinux::caretBlinkIntervalInternal() const
return m_caretBlinkInterval;
}
+void RenderThemeChromiumLinux::setSelectionColors(
+ unsigned activeBackgroundColor,
+ unsigned activeForegroundColor,
+ unsigned inactiveBackgroundColor,
+ unsigned inactiveForegroundColor)
+{
+ m_activeSelectionBackgroundColor = activeBackgroundColor;
+ m_activeSelectionForegroundColor = activeForegroundColor;
+ m_inactiveSelectionBackgroundColor = inactiveBackgroundColor;
+ m_inactiveSelectionForegroundColor = inactiveForegroundColor;
+}
+
void RenderThemeChromiumLinux::setScrollbarColors(
SkColor inactiveColor, SkColor activeColor, SkColor trackColor)
{
diff --git a/WebCore/rendering/RenderThemeChromiumLinux.h b/WebCore/rendering/RenderThemeChromiumLinux.h
index 8736b0d..90b043d 100644
--- a/WebCore/rendering/RenderThemeChromiumLinux.h
+++ b/WebCore/rendering/RenderThemeChromiumLinux.h
@@ -49,11 +49,21 @@ namespace WebCore {
virtual Color inactiveListBoxSelectionBackgroundColor() const;
virtual Color inactiveListBoxSelectionForegroundColor() const;
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+
virtual void adjustSliderThumbSize(RenderObject*) const;
void setCaretBlinkInterval(double interval);
virtual double caretBlinkIntervalInternal() const;
+ static void setSelectionColors(unsigned activeBackgroundColor,
+ unsigned activeForegroundColor,
+ unsigned inactiveBackgroundColor,
+ unsigned inactiveForegroundColor);
+
static void setScrollbarColors(unsigned inactive_color,
unsigned active_color,
unsigned track_color);
@@ -70,6 +80,11 @@ namespace WebCore {
double m_caretBlinkInterval;
+ static unsigned m_activeSelectionBackgroundColor;
+ static unsigned m_activeSelectionForegroundColor;
+ static unsigned m_inactiveSelectionBackgroundColor;
+ static unsigned m_inactiveSelectionForegroundColor;
+
static unsigned m_thumbInactiveColor;
static unsigned m_thumbActiveColor;
static unsigned m_trackColor;
diff --git a/WebCore/rendering/RenderThemeChromiumSkia.cpp b/WebCore/rendering/RenderThemeChromiumSkia.cpp
index 016a264..7d3bcec 100644
--- a/WebCore/rendering/RenderThemeChromiumSkia.cpp
+++ b/WebCore/rendering/RenderThemeChromiumSkia.cpp
@@ -217,6 +217,22 @@ int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
return 0;
}
+// These are the default dimensions of radio buttons and checkboxes.
+static const int widgetStandardWidth = 13;
+static const int widgetStandardHeight = 13;
+
+// Return a rectangle that has the same center point as |original|, but with a
+// size capped at |width| by |height|.
+IntRect center(const IntRect& original, int width, int height)
+{
+ width = std::min(original.width(), width);
+ height = std::min(original.height(), height);
+ int x = original.x() + (original.width() - width) / 2;
+ int y = original.y() + (original.height() - height) / 2;
+
+ return IntRect(x, y, width, height);
+}
+
bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef();
@@ -231,7 +247,7 @@ bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject:
else
image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage;
- i.context->drawImage(image, o->style()->colorSpace(), rect);
+ i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
return false;
}
@@ -246,7 +262,7 @@ void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
// querying the theme gives you a larger size that accounts for the higher
// DPI. Until our entire engine honors a DPI setting other than 96, we
// can't rely on the theme's metrics.
- const IntSize size(13, 13);
+ const IntSize size(widgetStandardHeight, widgetStandardWidth);
setSizeIfAuto(style, size);
}
@@ -263,7 +279,7 @@ bool RenderThemeChromiumSkia::paintRadio(RenderObject* o, const RenderObject::Pa
else
image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage;
- i.context->drawImage(image, o->style()->colorSpace(), rect);
+ i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
return false;
}
diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm
index 6304947..ddb538b 100644
--- a/WebCore/rendering/RenderThemeMac.mm
+++ b/WebCore/rendering/RenderThemeMac.mm
@@ -1434,13 +1434,10 @@ static int mediaControllerTheme()
controllerTheme = MediaControllerThemeClassic;
- if (!wkMediaControllerThemeAvailable(MediaControllerThemeQuickTime))
- return controllerTheme;
-
Boolean validKey;
Boolean useQTMediaUIPref = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#if !defined(BUILDING_ON_TIGER)
if (validKey && !useQTMediaUIPref)
return controllerTheme;
#else
diff --git a/WebCore/rendering/RenderThemeWince.cpp b/WebCore/rendering/RenderThemeWince.cpp
index fb89678..c4aaaad 100644
--- a/WebCore/rendering/RenderThemeWince.cpp
+++ b/WebCore/rendering/RenderThemeWince.cpp
@@ -28,6 +28,7 @@
#include "CSSValueKeywords.h"
#include "Document.h"
#include "GraphicsContext.h"
+#include "NotImplemented.h"
#if ENABLE(VIDEO)
#include "HTMLMediaElement.h"
#endif
@@ -377,12 +378,12 @@ bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const Rende
IntRect cancelBounds(IntPoint(x, y), cancelSize);
paintInfo.context->save();
paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius);
- paintInfo.context->fillRect(cancelBounds, buttonColor);
+ paintInfo.context->fillRect(cancelBounds, buttonColor, DeviceColorSpace);
// Draw the 'x'
IntSize xSize(3, 3);
IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize);
- paintInfo.context->setStrokeColor(Color::white);
+ paintInfo.context->setStrokeColor(Color::white, DeviceColorSpace);
paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size());
paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom()));
@@ -489,11 +490,11 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai
bool rc = RenderTheme::paintSliderTrack(o, i, r);
IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2);
i.context->save();
- i.context->setStrokeColor(Color::gray);
- i.context->setFillColor(Color::gray);
+ i.context->setStrokeColor(Color::gray, DeviceColorSpace);
+ i.context->setFillColor(Color::gray, DeviceColorSpace);
i.context->fillRect(r);
#if ENABLE(VIDEO)
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
if (mediaElement) {
i.context->setStrokeColor(Color(0, 0xff, 0));
IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.right() - r.x() - 4), (r.y() + r.bottom()) / 2);
@@ -501,7 +502,7 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai
left = right;
}
#endif
- i.context->setStrokeColor(Color::black);
+ i.context->setStrokeColor(Color::black, DeviceColorSpace);
i.context->drawLine(left, IntPoint(r.right() - 2, left.y()));
i.context->restore();
return rc;
@@ -511,10 +512,10 @@ bool RenderThemeWince::paintSliderThumb(RenderObject* o, const RenderObject::Pai
{
bool rc = RenderTheme::paintSliderThumb(o, i, r);
i.context->save();
- i.context->setStrokeColor(Color::black);
- i.context->setFillColor(Color::black);
+ i.context->setStrokeColor(Color::black, DeviceColorSpace);
+ i.context->setFillColor(Color::black, DeviceColorSpace);
#if ENABLE(VIDEO)
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
if (mediaElement) {
float pt = (mediaElement->currentTime() - mediaElement->startTime()) / mediaElement->duration();
FloatRect intRect = r;
@@ -574,7 +575,7 @@ bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const RenderO
bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
bool muted = !mediaElement || mediaElement->muted();
FloatRect imRect = r;
imRect.inflate(-2);
@@ -604,7 +605,7 @@ bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const RenderObject:
paintInfo.context->save();
paintInfo.context->setStrokeColor(Color::black);
paintInfo.context->setFillColor(Color::black);
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
bool paused = !mediaElement || mediaElement->paused();
if (paused) {
float width = imRect.width();
diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp
index a6f5144..ca4d9d1 100644
--- a/WebCore/rendering/RenderTreeAsText.cpp
+++ b/WebCore/rendering/RenderTreeAsText.cpp
@@ -45,6 +45,7 @@
#include "RenderWidget.h"
#include "SelectionController.h"
#include "TextStream.h"
+#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
#if ENABLE(SVG)
@@ -57,6 +58,10 @@
#include "SVGRenderTreeAsText.h"
#endif
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerBacking.h"
+#endif
+
#if PLATFORM(QT)
#include <QWidget>
#endif
@@ -65,7 +70,7 @@ namespace WebCore {
using namespace HTMLNames;
-static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0);
+static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal);
#if !ENABLE(SVG)
static TextStream &operator<<(TextStream& ts, const IntRect& r)
@@ -444,9 +449,15 @@ void write(TextStream& ts, const RenderObject& o, int indent)
}
}
+enum LayerPaintPhase {
+ LayerPaintPhaseAll = 0,
+ LayerPaintPhaseBackground = -1,
+ LayerPaintPhaseForeground = 1
+};
+
static void write(TextStream& ts, RenderLayer& l,
const IntRect& layerBounds, const IntRect& backgroundClipRect, const IntRect& clipRect, const IntRect& outlineClipRect,
- int layerType = 0, int indent = 0)
+ LayerPaintPhase paintPhase = LayerPaintPhaseAll, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal)
{
writeIndent(ts, indent);
@@ -472,19 +483,28 @@ static void write(TextStream& ts, RenderLayer& l,
ts << " scrollHeight " << l.scrollHeight();
}
- if (layerType == -1)
+ if (paintPhase == LayerPaintPhaseBackground)
ts << " layerType: background only";
- else if (layerType == 1)
+ else if (paintPhase == LayerPaintPhaseForeground)
ts << " layerType: foreground only";
-
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (behavior & RenderAsTextShowCompositedLayers) {
+ if (l.isComposited())
+ ts << " (composited, bounds " << l.backing()->compositedBounds() << ")";
+ }
+#else
+ UNUSED_PARAM(behavior);
+#endif
+
ts << "\n";
- if (layerType != -1)
+ if (paintPhase != LayerPaintPhaseBackground)
write(ts, *l.renderer(), indent + 1);
}
static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l,
- const IntRect& paintDirtyRect, int indent)
+ const IntRect& paintDirtyRect, int indent, RenderAsTextBehavior behavior)
{
// Calculate the clip rects we should use.
IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
@@ -494,29 +514,46 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye
l->updateZOrderLists();
l->updateNormalFlowList();
- bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect, rootLayer);
+ bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : l->intersectsDamageRect(layerBounds, damageRect, rootLayer);
Vector<RenderLayer*>* negList = l->negZOrderList();
- if (shouldPaint && negList && negList->size() > 0)
- write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, -1, indent);
+ bool paintsBackgroundSeparately = negList && negList->size() > 0;
+ if (shouldPaint && paintsBackgroundSeparately)
+ write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, LayerPaintPhaseBackground, indent, behavior);
if (negList) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " negative z-order list(" << negList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != negList->size(); ++i)
- writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, currIndent, behavior);
}
if (shouldPaint)
- write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, negList && negList->size() > 0, indent);
-
- Vector<RenderLayer*>* normalFlowList = l->normalFlowList();
- if (normalFlowList) {
+ write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, paintsBackgroundSeparately ? LayerPaintPhaseForeground : LayerPaintPhaseAll, indent, behavior);
+
+ if (Vector<RenderLayer*>* normalFlowList = l->normalFlowList()) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " normal flow list(" << normalFlowList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != normalFlowList->size(); ++i)
- writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, currIndent, behavior);
}
- Vector<RenderLayer*>* posList = l->posZOrderList();
- if (posList) {
+ if (Vector<RenderLayer*>* posList = l->posZOrderList()) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " positive z-order list(" << posList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != posList->size(); ++i)
- writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, currIndent, behavior);
}
}
@@ -562,7 +599,7 @@ static void writeSelection(TextStream& ts, const RenderObject* o)
<< "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().node()) << "\n";
}
-String externalRepresentation(Frame* frame)
+String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior)
{
frame->document()->updateLayout();
@@ -576,7 +613,7 @@ String externalRepresentation(Frame* frame)
#endif
if (o->hasLayer()) {
RenderLayer* l = toRenderBox(o)->layer();
- writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()));
+ writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), 0, behavior);
writeSelection(ts, o);
}
return ts.release();
diff --git a/WebCore/rendering/RenderTreeAsText.h b/WebCore/rendering/RenderTreeAsText.h
index b00f7c9..13525e7 100644
--- a/WebCore/rendering/RenderTreeAsText.h
+++ b/WebCore/rendering/RenderTreeAsText.h
@@ -34,7 +34,15 @@ class RenderObject;
class String;
class TextStream;
-String externalRepresentation(Frame*);
+enum RenderAsTextBehaviorFlags {
+ RenderAsTextBehaviorNormal = 0,
+ RenderAsTextShowAllLayers = 1 << 0, // Dump all layers, not just those that would paint.
+ RenderAsTextShowLayerNesting = 1 << 1, // Annotate the layer lists.
+ RenderAsTextShowCompositedLayers = 1 << 2 // Show which layers are composited.
+};
+typedef unsigned RenderAsTextBehavior;
+
+String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal);
void write(TextStream&, const RenderObject&, int indent = 0);
// Helper function shared with SVGRenderTreeAsText
diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp
index 246d0c0..d2a9620 100644
--- a/WebCore/rendering/RenderVideo.cpp
+++ b/WebCore/rendering/RenderVideo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,6 +34,7 @@
#include "HTMLNames.h"
#include "HTMLVideoElement.h"
#include "MediaPlayer.h"
+#include "RenderView.h"
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayer.h"
@@ -49,18 +50,25 @@ using namespace HTMLNames;
static const int cDefaultWidth = 300;
static const int cDefaultHeight = 150;
-RenderVideo::RenderVideo(HTMLMediaElement* video)
+RenderVideo::RenderVideo(HTMLVideoElement* video)
: RenderMedia(video)
{
if (video->player())
setIntrinsicSize(video->player()->naturalSize());
else {
- // Video in standalone media documents should not use the default 300x150
- // size since they also have audio thrown at them. By setting the intrinsic
- // size to 300x1 the video will resize itself in these cases, and audio will
- // have the correct height (it needs to be > 0 for controls to render properly).
- if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
+ // When the natural size of the video is unavailable, we use the provided
+ // width and height attributes of the video element as the intrinsic size until
+ // better values become available. If these attributes are not set, we fall back
+ // to a default video size (300x150).
+ if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr))
+ setIntrinsicSize(IntSize(video->width(), video->height()));
+ else if (video->ownerDocument() && video->ownerDocument()->isMediaDocument()) {
+ // Video in standalone media documents should not use the default 300x150
+ // size since they also have audio thrown at them. By setting the intrinsic
+ // size to 300x1 the video will resize itself in these cases, and audio will
+ // have the correct height (it needs to be > 0 for controls to render properly).
setIntrinsicSize(IntSize(cDefaultWidth, 1));
+ }
else
setIntrinsicSize(IntSize(cDefaultWidth, cDefaultHeight));
}
@@ -73,7 +81,15 @@ RenderVideo::~RenderVideo()
p->setFrameView(0);
}
}
-
+
+void RenderVideo::intrinsicSizeChanged()
+{
+ if (videoElement()->shouldDisplayPosterImage())
+ RenderVideo::intrinsicSizeChanged();
+ videoSizeChanged();
+}
+
+
void RenderVideo::videoSizeChanged()
{
if (!player())
@@ -86,41 +102,72 @@ void RenderVideo::videoSizeChanged()
}
}
-IntRect RenderVideo::videoBox() const
+void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
{
+ RenderImage::imageChanged(newImage, rect);
+
+ // Cache the image intrinsic size so we can continue to use it to draw the image correctly
+ // even after we know the video intrisic size but aren't able to draw video frames yet
+ // (we don't want to scale the poster to the video size).
+ if (videoElement()->shouldDisplayPosterImage())
+ m_cachedImageSize = intrinsicSize();
+}
+
+IntRect RenderVideo::videoBox() const
+{
+ if (m_cachedImageSize.isEmpty() && videoElement()->shouldDisplayPosterImage())
+ return IntRect();
+
+ IntSize elementSize;
+ if (videoElement()->shouldDisplayPosterImage())
+ elementSize = m_cachedImageSize;
+ else
+ elementSize = intrinsicSize();
+
IntRect contentRect = contentBoxRect();
-
- if (intrinsicSize().isEmpty() || contentRect.isEmpty())
+ if (elementSize.isEmpty() || contentRect.isEmpty())
return IntRect();
- IntRect resultRect = contentRect;
- int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width();
+ IntRect renderBox = contentRect;
+ int ratio = renderBox.width() * elementSize.height() - renderBox.height() * elementSize.width();
if (ratio > 0) {
- int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().height();
+ int newWidth = renderBox.height() * elementSize.width() / elementSize.height();
// Just fill the whole area if the difference is one pixel or less (in both sides)
- if (resultRect.width() - newWidth > 2)
- resultRect.setWidth(newWidth);
- resultRect.move((contentRect.width() - resultRect.width()) / 2, 0);
+ if (renderBox.width() - newWidth > 2)
+ renderBox.setWidth(newWidth);
+ renderBox.move((contentRect.width() - renderBox.width()) / 2, 0);
} else if (ratio < 0) {
- int newHeight = contentRect.width() * intrinsicSize().height() / intrinsicSize().width();
- if (resultRect.height() - newHeight > 2)
- resultRect.setHeight(newHeight);
- resultRect.move(0, (contentRect.height() - resultRect.height()) / 2);
+ int newHeight = renderBox.width() * elementSize.height() / elementSize.width();
+ if (renderBox.height() - newHeight > 2)
+ renderBox.setHeight(newHeight);
+ renderBox.move(0, (contentRect.height() - renderBox.height()) / 2);
}
- return resultRect;
+
+ return renderBox;
}
void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
{
MediaPlayer* mediaPlayer = player();
- if (!mediaPlayer)
+ bool displayingPoster = videoElement()->shouldDisplayPosterImage();
+
+ if (displayingPoster && document()->printing() && !view()->printImages())
return;
- updatePlayer();
+
+ if (!displayingPoster) {
+ if (!mediaPlayer)
+ return;
+ updatePlayer();
+ }
+
IntRect rect = videoBox();
if (rect.isEmpty())
return;
rect.move(tx, ty);
- mediaPlayer->paint(paintInfo.context, rect);
+ if (displayingPoster)
+ paintIntoRect(paintInfo.context, rect);
+ else
+ mediaPlayer->paint(paintInfo.context, rect);
}
void RenderVideo::layout()
@@ -129,6 +176,12 @@ void RenderVideo::layout()
updatePlayer();
}
+HTMLVideoElement* RenderVideo::videoElement() const
+{
+ ASSERT(node()->hasTagName(videoTag));
+ return static_cast<HTMLVideoElement*>(node());
+}
+
void RenderVideo::updateFromElement()
{
RenderMedia::updateFromElement();
@@ -140,7 +193,7 @@ void RenderVideo::updatePlayer()
MediaPlayer* mediaPlayer = player();
if (!mediaPlayer)
return;
- if (!mediaElement()->inActiveDocument()) {
+ if (!videoElement()->inActiveDocument()) {
mediaPlayer->setVisible(false);
return;
}
@@ -155,40 +208,6 @@ void RenderVideo::updatePlayer()
mediaPlayer->setVisible(true);
}
-bool RenderVideo::isWidthSpecified() const
-{
- switch (style()->width().type()) {
- case Fixed:
- case Percent:
- return true;
- case Auto:
- case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
- case Static:
- case Intrinsic:
- case MinIntrinsic:
- return false;
- }
- ASSERT(false);
- return false;
-}
-
-bool RenderVideo::isHeightSpecified() const
-{
- switch (style()->height().type()) {
- case Fixed:
- case Percent:
- return true;
- case Auto:
- case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
- case Static:
- case Intrinsic:
- case MinIntrinsic:
- return false;
- }
- ASSERT(false);
- return false;
-}
-
int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const
{
int width;
@@ -235,24 +254,9 @@ int RenderVideo::calcAspectRatioHeight() const
return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
}
-void RenderVideo::calcPrefWidths()
+int RenderVideo::minimumReplacedHeight() const
{
- ASSERT(prefWidthsDirty());
-
- int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
- m_maxPrefWidth = calcReplacedWidth(false) + paddingAndBorders;
-
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
- m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
-
- if (style()->width().isPercent() || style()->height().isPercent() ||
- style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
- style()->minWidth().isPercent() || style()->minHeight().isPercent())
- m_minPrefWidth = 0;
- else
- m_minPrefWidth = m_maxPrefWidth;
-
- setPrefWidthsDirty(false);
+ return 0;
}
#if USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/rendering/RenderVideo.h b/WebCore/rendering/RenderVideo.h
index 79e5b4e..3ca5328 100644
--- a/WebCore/rendering/RenderVideo.h
+++ b/WebCore/rendering/RenderVideo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,13 +33,14 @@
namespace WebCore {
class HTMLMediaElement;
+class HTMLVideoElement;
#if USE(ACCELERATED_COMPOSITING)
class GraphicsLayer;
#endif
class RenderVideo : public RenderMedia {
public:
- RenderVideo(HTMLMediaElement*);
+ RenderVideo(HTMLVideoElement*);
virtual ~RenderVideo();
void videoSizeChanged();
@@ -53,8 +54,10 @@ public:
private:
virtual void updateFromElement();
+ inline HTMLVideoElement* videoElement() const;
- virtual void intrinsicSizeChanged() { videoSizeChanged(); }
+ virtual void intrinsicSizeChanged();
+ virtual void imageChanged(WrappedImagePtr, const IntRect*);
virtual const char* renderName() const { return "RenderVideo"; }
@@ -67,16 +70,14 @@ private:
virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
virtual int calcReplacedHeight() const;
-
- virtual void calcPrefWidths();
+ virtual int minimumReplacedHeight() const;
int calcAspectRatioWidth() const;
int calcAspectRatioHeight() const;
- bool isWidthSpecified() const;
- bool isHeightSpecified() const;
-
void updatePlayer();
+
+ IntSize m_cachedImageSize;
};
inline RenderVideo* toRenderVideo(RenderObject* object)
diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp
index 753afe4..502563e 100644
--- a/WebCore/rendering/RenderView.cpp
+++ b/WebCore/rendering/RenderView.cpp
@@ -664,6 +664,17 @@ void RenderView::pushLayoutState(RenderObject* root)
m_layoutState = new (renderArena()) LayoutState(root);
}
+bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const
+{
+ RenderObject* o = renderer;
+ while (o) {
+ if (o->hasColumns() || o->hasTransform() || o->hasReflection())
+ return true;
+ o = o->container();
+ }
+ return false;
+}
+
void RenderView::updateHitTestResult(HitTestResult& result, const IntPoint& point)
{
if (result.innerNode())
diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h
index 37b3f01..c287579 100644
--- a/WebCore/rendering/RenderView.h
+++ b/WebCore/rendering/RenderView.h
@@ -140,6 +140,8 @@ public:
state->destroy(renderArena());
}
+ bool shouldDisableLayoutStateForSubtree(RenderObject*) const;
+
// Returns true if layoutState should be used for its cached offset and clip.
bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; }
LayoutState* layoutState() const { return m_layoutState; }
diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp
index 8b7e899..f6f6da8 100644
--- a/WebCore/rendering/RenderWidget.cpp
+++ b/WebCore/rendering/RenderWidget.cpp
@@ -252,18 +252,27 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
}
if (m_widget) {
- // Move the widget if necessary. We normally move and resize widgets during layout, but sometimes
- // widgets can move without layout occurring (most notably when you scroll a document that
- // contains fixed positioned elements).
- m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
-
// Tell the widget to paint now. This is the only time the widget is allowed
// to paint itself. That way it will composite properly with z-indexed layers.
if (m_substituteImage)
paintInfo.context->drawImage(m_substituteImage.get(), style()->colorSpace(), m_widget->frameRect());
- else
- m_widget->paint(paintInfo.context, paintInfo.rect);
+ else {
+ IntPoint widgetLocation = m_widget->frameRect().location();
+ IntPoint paintLocation(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
+ IntRect paintRect = paintInfo.rect;
+
+ IntSize paintOffset = paintLocation - widgetLocation;
+ // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
+ // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
+ if (!paintOffset.isZero()) {
+ paintInfo.context->translate(paintOffset);
+ paintRect.move(-paintOffset);
+ }
+ m_widget->paint(paintInfo.context, paintRect);
+ if (!paintOffset.isZero())
+ paintInfo.context->translate(-paintOffset);
+ }
if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaintsIfNotOverlapped()) {
ASSERT(!paintInfo.overlapTestRequests->contains(this));
paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp
index c8e072e..23316f7 100644
--- a/WebCore/rendering/RootInlineBox.cpp
+++ b/WebCore/rendering/RootInlineBox.cpp
@@ -21,6 +21,7 @@
#include "RootInlineBox.h"
#include "BidiResolver.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "EllipsisBox.h"
diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h
index b5b4f3e..fb29110 100644
--- a/WebCore/rendering/SVGCharacterLayoutInfo.h
+++ b/WebCore/rendering/SVGCharacterLayoutInfo.h
@@ -298,8 +298,10 @@ struct SVGTextChunkWalkerBase {
virtual void start(InlineBox*) = 0;
virtual void end(InlineBox*) = 0;
+ virtual bool setupBackground(InlineBox*) = 0;
virtual bool setupFill(InlineBox*) = 0;
virtual bool setupStroke(InlineBox*) = 0;
+ virtual bool setupForeground(InlineBox*) = 0;
};
template<typename CallbackClass>
@@ -315,21 +317,27 @@ public:
typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box);
typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box);
+ typedef bool (CallbackClass::*SVGTextChunkSetupBackgroundCallback)(InlineBox* box);
typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box);
typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box);
+ typedef bool (CallbackClass::*SVGTextChunkSetupForegroundCallback)(InlineBox* box);
SVGTextChunkWalker(CallbackClass* object,
SVGTextChunkWalkerCallback walker,
SVGTextChunkStartCallback start = 0,
SVGTextChunkEndCallback end = 0,
+ SVGTextChunkSetupBackgroundCallback background = 0,
SVGTextChunkSetupFillCallback fill = 0,
- SVGTextChunkSetupStrokeCallback stroke = 0)
+ SVGTextChunkSetupStrokeCallback stroke = 0,
+ SVGTextChunkSetupForegroundCallback foreground = 0)
: m_object(object)
, m_walkerCallback(walker)
, m_startCallback(start)
, m_endCallback(end)
+ , m_setupBackgroundCallback(background)
, m_setupFillCallback(fill)
, m_setupStrokeCallback(stroke)
+ , m_setupForegroundCallback(foreground)
{
ASSERT(object);
ASSERT(walker);
@@ -358,6 +366,15 @@ public:
ASSERT_NOT_REACHED();
}
+ virtual bool setupBackground(InlineBox* box)
+ {
+ if (m_setupBackgroundCallback)
+ return (*m_object.*m_setupBackgroundCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
virtual bool setupFill(InlineBox* box)
{
if (m_setupFillCallback)
@@ -376,13 +393,24 @@ public:
return false;
}
+ virtual bool setupForeground(InlineBox* box)
+ {
+ if (m_setupForegroundCallback)
+ return (*m_object.*m_setupForegroundCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
private:
CallbackClass* m_object;
SVGTextChunkWalkerCallback m_walkerCallback;
SVGTextChunkStartCallback m_startCallback;
SVGTextChunkEndCallback m_endCallback;
+ SVGTextChunkSetupBackgroundCallback m_setupBackgroundCallback;
SVGTextChunkSetupFillCallback m_setupFillCallback;
SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
+ SVGTextChunkSetupForegroundCallback m_setupForegroundCallback;
};
struct SVGTextChunkLayoutInfo {
diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp
index cf8464e..2f56e68 100644
--- a/WebCore/rendering/SVGInlineTextBox.cpp
+++ b/WebCore/rendering/SVGInlineTextBox.cpp
@@ -324,7 +324,7 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos)
return enclosingIntRect(walkerCallback.selectionRect());
}
-void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGPaintServer* activePaintServer)
+void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGTextPaintInfo& textPaintInfo)
{
if (renderer()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline)
return;
@@ -356,7 +356,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
// 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
// and marked text.
- if (paintInfo.phase != PaintPhaseSelection && !isPrinting) {
+ if (paintInfo.phase != PaintPhaseSelection && !isPrinting && textPaintInfo.subphase == SVGTextPaintSubphaseBackground) {
#if PLATFORM(MAC)
// Custom highlighters go behind everything else.
if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
@@ -376,29 +376,35 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
}
}
- // Set a text shadow if we have one.
- // FIXME: Support multiple shadow effects. Need more from the CG API before
- // we can do this.
- bool setShadow = false;
- if (styleToUse->textShadow()) {
- paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
- styleToUse->textShadow()->blur, styleToUse->textShadow()->color,
- styleToUse->colorSpace());
- setShadow = true;
- }
+ if (textPaintInfo.subphase == SVGTextPaintSubphaseGlyphFill || textPaintInfo.subphase == SVGTextPaintSubphaseGlyphStroke) {
+ // Set a text shadow if we have one.
+ // FIXME: Support multiple shadow effects. Need more from the CG API before
+ // we can do this.
+ bool setShadow = false;
+ if (styleToUse->textShadow()) {
+ paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
+ styleToUse->textShadow()->blur, styleToUse->textShadow()->color,
+ styleToUse->colorSpace());
+ setShadow = true;
+ }
- IntPoint origin((int) svgChar.x, (int) svgChar.y);
- TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x);
+ IntPoint origin((int) svgChar.x, (int) svgChar.y);
+ TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x);
#if ENABLE(SVG_FONTS)
- // SVG Fonts need access to the paint server used to draw the current text chunk.
- // They need to be able to call renderPath() on a SVGPaintServer object.
- run.setActivePaintServer(activePaintServer);
+ // SVG Fonts need access to the paint server used to draw the current text chunk.
+ // They need to be able to call renderPath() on a SVGPaintServer object.
+ ASSERT(textPaintInfo.activePaintServer);
+ run.setActivePaintServer(textPaintInfo.activePaintServer);
#endif
- paintInfo.context->drawText(font, run, origin);
+ paintInfo.context->drawText(font, run, origin);
- if (paintInfo.phase != PaintPhaseSelection) {
+ if (setShadow)
+ paintInfo.context->clearShadow();
+ }
+
+ if (paintInfo.phase != PaintPhaseSelection && textPaintInfo.subphase == SVGTextPaintSubphaseForeground) {
paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false);
if (useCustomUnderlines) {
@@ -428,9 +434,6 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
}
- if (setShadow)
- paintInfo.context->clearShadow();
-
if (!ctm.isIdentity())
paintInfo.context->concatCTM(ctm.inverse());
}
diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h
index ad39aab..eea6744 100644
--- a/WebCore/rendering/SVGInlineTextBox.h
+++ b/WebCore/rendering/SVGInlineTextBox.h
@@ -32,6 +32,20 @@ namespace WebCore {
struct SVGChar;
struct SVGTextDecorationInfo;
+ enum SVGTextPaintSubphase {
+ SVGTextPaintSubphaseBackground,
+ SVGTextPaintSubphaseGlyphFill,
+ SVGTextPaintSubphaseGlyphStroke,
+ SVGTextPaintSubphaseForeground
+ };
+
+ struct SVGTextPaintInfo {
+ SVGTextPaintInfo() : activePaintServer(0), subphase(SVGTextPaintSubphaseBackground) {}
+
+ SVGPaintServer* activePaintServer;
+ SVGTextPaintSubphase subphase;
+ };
+
class SVGInlineTextBox : public InlineTextBox {
public:
SVGInlineTextBox(RenderObject* obj);
@@ -49,7 +63,7 @@ namespace WebCore {
virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos);
// SVGs custom paint text method
- void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGPaintServer*);
+ void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGTextPaintInfo&);
// SVGs custom paint selection method
void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&);
diff --git a/WebCore/rendering/SVGMarkerData.h b/WebCore/rendering/SVGMarkerData.h
new file mode 100644
index 0000000..5ff2993
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerData.h
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMarkerData_h
+#define SVGMarkerData_h
+
+#if ENABLE(SVG)
+#include "FloatConversion.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+class SVGResourceMarker;
+
+class SVGMarkerData {
+public:
+ enum Type {
+ Unknown = 0,
+ Start,
+ Mid,
+ End
+ };
+
+ SVGMarkerData(const Type& type = Unknown, SVGResourceMarker* marker = 0)
+ : m_type(type)
+ , m_marker(marker)
+ {
+ }
+
+ FloatPoint origin() const { return m_origin; }
+ SVGResourceMarker* marker() const { return m_marker; }
+
+ float currentAngle() const
+ {
+ FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0];
+ FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0];
+
+ double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width()));
+ double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width()));
+
+ double angle = 0;
+ switch (m_type) {
+ case Start:
+ angle = outslope;
+ break;
+ case Mid:
+ angle = (inslope + outslope) / 2;
+ break;
+ case End:
+ angle = inslope;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return narrowPrecisionToFloat(angle);
+ }
+
+ void updateTypeAndMarker(const Type& type, SVGResourceMarker* marker)
+ {
+ m_type = type;
+ m_marker = marker;
+ }
+
+ void updateOutslope(const FloatPoint& point)
+ {
+ m_outslopePoints[0] = m_origin;
+ m_outslopePoints[1] = point;
+ }
+
+ void updateMarkerDataForPathElement(const PathElement* element)
+ {
+ FloatPoint* points = element->points;
+
+ switch (element->type) {
+ case PathElementAddQuadCurveToPoint:
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>)
+ m_origin = points[1];
+ break;
+ case PathElementAddCurveToPoint:
+ m_inslopePoints[0] = points[1];
+ m_inslopePoints[1] = points[2];
+ m_origin = points[2];
+ break;
+ case PathElementMoveToPoint:
+ m_subpathStart = points[0];
+ case PathElementAddLineToPoint:
+ updateInslope(points[0]);
+ m_origin = points[0];
+ break;
+ case PathElementCloseSubpath:
+ updateInslope(points[0]);
+ m_origin = m_subpathStart;
+ m_subpathStart = FloatPoint();
+ }
+ }
+
+private:
+ void updateInslope(const FloatPoint& point)
+ {
+ m_inslopePoints[0] = m_origin;
+ m_inslopePoints[1] = point;
+ }
+
+ Type m_type;
+ SVGResourceMarker* m_marker;
+ FloatPoint m_origin;
+ FloatPoint m_subpathStart;
+ FloatPoint m_inslopePoints[2];
+ FloatPoint m_outslopePoints[2];
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGMarkerData_h
diff --git a/WebCore/rendering/SVGMarkerLayoutInfo.cpp b/WebCore/rendering/SVGMarkerLayoutInfo.cpp
new file mode 100644
index 0000000..3fe513f
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerLayoutInfo.cpp
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2008 Rob Buis <buis@kde.org>
+ 2005, 2007 Eric Seidel <eric@webkit.org>
+ 2009 Google, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGMarkerLayoutInfo.h"
+
+#include "RenderSVGViewportContainer.h"
+#include "SVGResourceMarker.h"
+
+namespace WebCore {
+
+SVGMarkerLayoutInfo::SVGMarkerLayoutInfo()
+ : m_midMarker(0)
+ , m_elementIndex(0)
+ , m_strokeWidth(0)
+{
+}
+
+SVGMarkerLayoutInfo::~SVGMarkerLayoutInfo()
+{
+}
+
+static inline void processStartAndMidMarkers(void* infoPtr, const PathElement* element)
+{
+ SVGMarkerLayoutInfo& info = *reinterpret_cast<SVGMarkerLayoutInfo*>(infoPtr);
+ SVGMarkerData& markerData = info.markerData();
+ int& elementIndex = info.elementIndex();
+
+ // First update the outslope for the previous element
+ markerData.updateOutslope(element->points[0]);
+
+ // Draw the marker for the previous element
+ SVGResourceMarker* marker = markerData.marker();
+ if (elementIndex > 0 && marker)
+ info.addLayoutedMarker(marker, markerData.origin(), markerData.currentAngle());
+
+ // Update our marker data for this element
+ markerData.updateMarkerDataForPathElement(element);
+
+ // After drawing the start marker, switch to drawing mid markers
+ if (elementIndex == 1)
+ markerData.updateTypeAndMarker(SVGMarkerData::Mid, info.midMarker());
+
+ ++elementIndex;
+}
+
+FloatRect SVGMarkerLayoutInfo::calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path& path)
+{
+ m_layout.clear();
+ m_midMarker = midMarker;
+ m_strokeWidth = strokeWidth;
+ m_elementIndex = 0;
+ m_markerData = SVGMarkerData(SVGMarkerData::Start, startMarker);
+ path.apply(this, processStartAndMidMarkers);
+
+ if (endMarker) {
+ m_markerData.updateTypeAndMarker(SVGMarkerData::End, endMarker);
+ addLayoutedMarker(endMarker, m_markerData.origin(), m_markerData.currentAngle());
+ }
+
+ if (m_layout.isEmpty())
+ return FloatRect();
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ FloatRect bounds;
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+
+ RenderSVGViewportContainer* markerContent = layout.marker->renderer();
+ ASSERT(markerContent);
+
+ bounds.unite(markerContent->markerBoundaries(layout.matrix));
+ }
+
+ return bounds;
+}
+
+void SVGMarkerLayoutInfo::drawMarkers(RenderObject::PaintInfo& paintInfo)
+{
+ if (m_layout.isEmpty())
+ return;
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+ layout.marker->draw(paintInfo, layout.matrix);
+ }
+}
+
+void SVGMarkerLayoutInfo::addLayoutedMarker(SVGResourceMarker* marker, const FloatPoint& origin, float angle)
+{
+ ASSERT(marker);
+ m_layout.append(MarkerLayout(marker, marker->markerTransformation(origin, angle, m_strokeWidth)));
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGMarkerLayoutInfo.h b/WebCore/rendering/SVGMarkerLayoutInfo.h
new file mode 100644
index 0000000..1dfeee9
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerLayoutInfo.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMarkerLayoutInfo_h
+#define SVGMarkerLayoutInfo_h
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+#include "SVGMarkerData.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class Path;
+class SVGResourceMarker;
+
+struct MarkerLayout {
+ MarkerLayout(SVGResourceMarker* markerObj = 0, TransformationMatrix matrixObj = TransformationMatrix())
+ : marker(markerObj)
+ , matrix(matrixObj)
+ {
+ ASSERT(marker);
+ }
+
+ SVGResourceMarker* marker;
+ TransformationMatrix matrix;
+};
+
+class SVGMarkerLayoutInfo : public Noncopyable {
+public:
+ SVGMarkerLayoutInfo();
+ ~SVGMarkerLayoutInfo();
+
+ FloatRect calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path&);
+ void drawMarkers(RenderObject::PaintInfo&);
+
+ // Used by static inline helper functions in SVGMarkerLayoutInfo.cpp
+ SVGMarkerData& markerData() { return m_markerData; }
+ SVGResourceMarker* midMarker() const { return m_midMarker; }
+ int& elementIndex() { return m_elementIndex; }
+ void addLayoutedMarker(SVGResourceMarker*, const FloatPoint& origin, float angle);
+
+private:
+ SVGResourceMarker* m_midMarker;
+
+ // Used while layouting markers
+ int m_elementIndex;
+ SVGMarkerData m_markerData;
+ float m_strokeWidth;
+
+ // Holds the final computed result
+ Vector<MarkerLayout> m_layout;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGMarkerLayoutInfo_h
diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp
index a594410..86cbf32 100644
--- a/WebCore/rendering/SVGRenderSupport.cpp
+++ b/WebCore/rendering/SVGRenderSupport.cpp
@@ -2,7 +2,8 @@
* Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
* (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * (C) 2009 Google, Inc. All rights reserved.
+ * (C) 2009 Dirk Schulze <krit@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -41,6 +42,10 @@
namespace WebCore {
+SVGRenderBase::~SVGRenderBase()
+{
+}
+
IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
{
// Return early for any cases where we don't actually paint
@@ -64,12 +69,12 @@ void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelOb
void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
{
ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
- ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless.
+ ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless.
transformState.applyTransform(object->localToParentTransform());
object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}
-void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
+bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
{
#if !ENABLE(FILTERS)
UNUSED_PARAM(filter);
@@ -90,18 +95,12 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
// Setup transparency layers before setting up filters!
float opacity = style->opacity();
if (opacity < 1.0f) {
- paintInfo.context->clip(enclosingIntRect(boundingBox));
+ paintInfo.context->clip(repaintRect);
paintInfo.context->beginTransparencyLayer(opacity);
}
if (ShadowData* shadow = svgStyle->shadow()) {
- int xShift = shadow->x < 0 ? shadow->x : 0;
- int yShift = shadow->y < 0 ? shadow->y :0;
- int widthShift = shadow->x < 0 ? 0 : shadow->x;
- int heightShift = shadow->y < 0 ? 0 : shadow->y;
- FloatRect shadowRect = FloatRect(boundingBox.x() + xShift, boundingBox.y() + yShift,
- boundingBox.width() + widthShift, boundingBox.height() + heightShift);
- paintInfo.context->clip(enclosingIntRect(shadowRect));
+ paintInfo.context->clip(repaintRect);
paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color, style->colorSpace());
paintInfo.context->beginTransparencyLayer(1.0f);
}
@@ -116,7 +115,7 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
Document* document = object->document();
#if ENABLE(FILTERS)
- SVGResourceFilter* newFilter = getFilterById(document, filterId);
+ SVGResourceFilter* newFilter = getFilterById(document, filterId, object);
if (newFilter == rootFilter) {
// Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>.
// The filter is NOT meant to be applied twice in that case!
@@ -126,28 +125,32 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
filter = newFilter;
#endif
- SVGResourceClipper* clipper = getClipperById(document, clipperId);
- SVGResourceMasker* masker = getMaskerById(document, maskerId);
+ SVGResourceClipper* clipper = getClipperById(document, clipperId, object);
+ SVGResourceMasker* masker = getMaskerById(document, maskerId, object);
+
+ if (masker) {
+ masker->addClient(styledElement);
+ if (!masker->applyMask(paintInfo.context, object))
+ return false;
+ } else if (!maskerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+
+ if (clipper) {
+ clipper->addClient(styledElement);
+ clipper->applyClip(paintInfo.context, object->objectBoundingBox());
+ } else if (!clipperId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
#if ENABLE(FILTERS)
if (filter) {
filter->addClient(styledElement);
- filter->prepareFilter(paintInfo.context, object);
+ if (!filter->prepareFilter(paintInfo.context, object))
+ return false;
} else if (!filterId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif
- if (clipper) {
- clipper->addClient(styledElement);
- clipper->applyClip(paintInfo.context, boundingBox);
- } else if (!clipperId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
-
- if (masker) {
- masker->addClient(styledElement);
- masker->applyMask(paintInfo.context, boundingBox);
- } else if (!maskerId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+ return true;
}
void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext)
@@ -232,18 +235,59 @@ FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* contain
return boundingBox;
}
-FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object)
+void SVGRenderBase::layoutChildren(RenderObject* start, bool selfNeedsLayout)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
+ // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
+ // that's a possible future optimization using LayoutState
+ // http://bugs.webkit.org/show_bug.cgi?id=15391
+ bool needsLayout = selfNeedsLayout;
+ if (!needsLayout) {
+ if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
+ if (element->isStyled())
+ needsLayout = static_cast<SVGStyledElement*>(element)->hasRelativeValues();
+ }
+ }
+
+ if (needsLayout)
+ child->setNeedsLayout(true, false);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+}
+
+FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) const
{
#if ENABLE(FILTERS)
- SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter());
+ SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter(), object);
if (filter)
- return filter->filterBoundingBox();
+ return filter->filterBoundingBox(object->objectBoundingBox());
#else
UNUSED_PARAM(object);
#endif
return FloatRect();
}
+FloatRect SVGRenderBase::clipperBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceClipper* clipper = getClipperById(object->document(), object->style()->svgStyle()->clipPath(), object);
+ if (clipper)
+ return clipper->clipperBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceMasker* masker = getMaskerById(object->document(), object->style()->svgStyle()->maskElement(), object);
+ if (masker)
+ return masker->maskerBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform)
{
if (localToAncestorTransform.isIdentity())
diff --git a/WebCore/rendering/SVGRenderSupport.h b/WebCore/rendering/SVGRenderSupport.h
index da2bf59..0804ede 100644
--- a/WebCore/rendering/SVGRenderSupport.h
+++ b/WebCore/rendering/SVGRenderSupport.h
@@ -38,12 +38,27 @@ namespace WebCore {
// all SVG renderers inherit from RenderSVGModelObject.
class SVGRenderBase {
public:
+ virtual ~SVGRenderBase();
+
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
// FIXME: These are only public for SVGRootInlineBox.
// It's unclear if these should be exposed or not. SVGRootInlineBox may
// pass the wrong RenderObject* and boundingBox to these functions.
- static void prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0);
+ static bool prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0);
static void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, SVGResourceFilter*&, GraphicsContext* savedContext);
+ // Layout all children of the passed render object
+ static void layoutChildren(RenderObject*, bool selfNeedsLayout);
+
+ virtual FloatRect strokeBoundingBox() const { return FloatRect(); }
+ virtual FloatRect markerBoundingBox() const { return FloatRect(); }
+
+ // returns the bounding box of filter, clipper, marker and masker (or the empty rect if no filter) in local coordinates
+ FloatRect filterBoundingBoxForRenderer(const RenderObject*) const;
+ FloatRect clipperBoundingBoxForRenderer(const RenderObject*) const;
+ FloatRect maskerBoundingBoxForRenderer(const RenderObject*) const;
+
protected:
static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer);
static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed);
@@ -53,9 +68,6 @@ namespace WebCore {
// Used to share the "walk all the children" logic between objectBoundingBox
// and repaintRectInLocalCoordinates in RenderSVGRoot and RenderSVGContainer
static FloatRect computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent);
-
- // returns the filter bounding box (or the empty rect if no filter) in local coordinates
- static FloatRect filterBoundingBoxForRenderer(const RenderObject*);
};
// FIXME: This should move to RenderObject or PaintInfo
diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp
index 28e506a..bd6a465 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.cpp
+++ b/WebCore/rendering/SVGRenderTreeAsText.cpp
@@ -521,11 +521,11 @@ void writeRenderResources(TextStream& ts, Node* parent)
continue;
SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement);
- RefPtr<SVGResource> resource(styled->canvasResource());
+ RefPtr<SVGResource> resource(styled->canvasResource(node->renderer()));
if (!resource)
continue;
- String elementId = svgElement->getAttribute(HTMLNames::idAttr);
+ String elementId = svgElement->getAttribute(svgElement->idAttributeName());
// FIXME: These names are lies!
if (resource->isPaintServer()) {
RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource);
diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp
index 5829742..92e7654 100644
--- a/WebCore/rendering/SVGRootInlineBox.cpp
+++ b/WebCore/rendering/SVGRootInlineBox.cpp
@@ -429,6 +429,12 @@ struct SVGRootInlineBoxPaintWalker {
m_paintInfo.rect = m_savedInfo.rect;
}
+ bool chunkSetupBackgroundCallback(InlineBox* /*box*/)
+ {
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseBackground;
+ return true;
+ }
+
bool chunkSetupFillCallback(InlineBox* box)
{
InlineFlowBox* flowBox = box->parent();
@@ -440,6 +446,7 @@ struct SVGRootInlineBoxPaintWalker {
ASSERT(!m_strokePaintServer);
teardownFillPaintServer();
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFill;
m_fillPaintServer = SVGPaintServer::fillPaintServer(object->style(), object);
if (m_fillPaintServer) {
m_fillPaintServer->setup(m_paintInfo.context, object, ApplyToFillTargetType, true);
@@ -462,6 +469,7 @@ struct SVGRootInlineBoxPaintWalker {
teardownFillPaintServer();
teardownStrokePaintServer();
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStroke;
m_strokePaintServer = SVGPaintServer::strokePaintServer(object->style(), object);
if (m_strokePaintServer) {
@@ -473,6 +481,32 @@ struct SVGRootInlineBoxPaintWalker {
return false;
}
+ bool chunkSetupForegroundCallback(InlineBox* /*box*/)
+ {
+ teardownFillPaintServer();
+ teardownStrokePaintServer();
+
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseForeground;
+
+ return true;
+ }
+
+ SVGPaintServer* activePaintServer() const
+ {
+ switch (m_textPaintInfo.subphase) {
+ case SVGTextPaintSubphaseGlyphFill:
+ ASSERT(m_fillPaintServer);
+ return m_fillPaintServer;
+ case SVGTextPaintSubphaseGlyphStroke:
+ ASSERT(m_strokePaintServer);
+ return m_strokePaintServer;
+ case SVGTextPaintSubphaseBackground:
+ case SVGTextPaintSubphaseForeground:
+ default:
+ return 0;
+ }
+ }
+
void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
{
@@ -523,12 +557,8 @@ struct SVGRootInlineBoxPaintWalker {
textBox->paintDecoration(OVERLINE, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info);
// Paint text
- SVGPaintServer* activePaintServer = m_fillPaintServer;
- if (!activePaintServer)
- activePaintServer = m_strokePaintServer;
-
- ASSERT(activePaintServer);
- textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, activePaintServer);
+ m_textPaintInfo.activePaintServer = activePaintServer();
+ textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, m_textPaintInfo);
// Paint decorations, that have to be drawn afterwards
if (textDecorations & LINE_THROUGH && textWidth != 0.0f)
@@ -561,6 +591,8 @@ private:
int m_tx;
int m_ty;
+
+ SVGTextPaintInfo m_textPaintInfo;
};
void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
@@ -575,18 +607,20 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
FloatRect boundingBox(tx + x(), ty + y(), width(), height());
// Initialize text rendering
- SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter);
-
- // Render text, chunk-by-chunk
- SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty);
- SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback,
- &SVGRootInlineBoxPaintWalker::chunkPortionCallback,
- &SVGRootInlineBoxPaintWalker::chunkStartCallback,
- &SVGRootInlineBoxPaintWalker::chunkEndCallback,
- &SVGRootInlineBoxPaintWalker::chunkSetupFillCallback,
- &SVGRootInlineBoxPaintWalker::chunkSetupStrokeCallback);
-
- walkTextChunks(&walker);
+ if (SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter)) {
+ // Render text, chunk-by-chunk
+ SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty);
+ SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback,
+ &SVGRootInlineBoxPaintWalker::chunkPortionCallback,
+ &SVGRootInlineBoxPaintWalker::chunkStartCallback,
+ &SVGRootInlineBoxPaintWalker::chunkEndCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupBackgroundCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupFillCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupStrokeCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupForegroundCallback);
+
+ walkTextChunks(&walker);
+ }
// Finalize text rendering
SVGRenderBase::finishRenderSVGContent(renderer(), paintInfo, filter, savedInfo.context);
@@ -1388,7 +1422,7 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox*
} else
ASSERT(!info.chunk.boxes.isEmpty());
- // Walk string to find out new chunk positions, if existant
+ // Walk string to find out new chunk positions, if existent
for (unsigned i = 0; i < length; ++i) {
ASSERT(info.it != svgChars.end());
@@ -1680,11 +1714,18 @@ void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGI
if (textBox)
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
else {
+ if (walker->setupBackground(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
if (walker->setupFill(range.box))
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
if (walker->setupStroke(range.box))
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
+ if (walker->setupForeground(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
}
chunkOffset += length;
diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h
index 65bade0..d2dab98 100644
--- a/WebCore/rendering/SVGRootInlineBox.h
+++ b/WebCore/rendering/SVGRootInlineBox.h
@@ -28,6 +28,7 @@
#if ENABLE(SVG)
#include "RootInlineBox.h"
#include "SVGCharacterLayoutInfo.h"
+#include "SVGRenderSupport.h"
namespace WebCore {
@@ -43,13 +44,14 @@ struct LastGlyphInfo {
bool isValid;
};
-class SVGRootInlineBox : public RootInlineBox {
+class SVGRootInlineBox : public RootInlineBox, SVGRenderBase {
public:
SVGRootInlineBox(RenderObject* obj)
: RootInlineBox(obj)
, m_height(0)
{
}
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual bool isSVGRootInlineBox() { return true; }
@@ -63,6 +65,9 @@ public:
virtual void computePerCharacterLayoutInformation();
+ virtual FloatRect objectBoundingBox() const { return FloatRect(); }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
+
// Used by SVGInlineTextBox
const Vector<SVGTextChunk>& svgTextChunks() const;
diff --git a/WebCore/rendering/SVGShadowTreeElements.cpp b/WebCore/rendering/SVGShadowTreeElements.cpp
new file mode 100644
index 0000000..d9ce640
--- /dev/null
+++ b/WebCore/rendering/SVGShadowTreeElements.cpp
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGShadowTreeElements.h"
+
+#include "Document.h"
+#include "FloatSize.h"
+#include "RenderObject.h"
+#include "SVGNames.h"
+
+namespace WebCore {
+
+// SVGShadowTreeContainerElement
+SVGShadowTreeContainerElement::SVGShadowTreeContainerElement(Document* document)
+ : SVGGElement(SVGNames::gTag, document)
+{
+}
+
+SVGShadowTreeContainerElement::~SVGShadowTreeContainerElement()
+{
+}
+
+FloatSize SVGShadowTreeContainerElement::containerTranslation() const
+{
+ return FloatSize(m_xOffset.value(this), m_yOffset.value(this));
+}
+
+// SVGShadowTreeRootElement
+SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, Node* shadowParent)
+ : SVGShadowTreeContainerElement(document)
+ , m_shadowParent(shadowParent)
+{
+ setInDocument(true);
+}
+
+SVGShadowTreeRootElement::~SVGShadowTreeRootElement()
+{
+}
+
+void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena)
+{
+ ASSERT(m_shadowParent);
+
+ // Create the renderer with the specified style
+ RenderObject* renderer = createRenderer(arena, style.get());
+ if (renderer) {
+ setRenderer(renderer);
+ renderer->setStyle(style);
+ }
+
+ // Set these explicitly since this normally happens during an attach()
+ setAttached();
+
+ // Add the renderer to the render tree
+ if (renderer)
+ m_shadowParent->renderer()->addChild(renderer);
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGShadowTreeElements.h b/WebCore/rendering/SVGShadowTreeElements.h
new file mode 100644
index 0000000..ed42e89
--- /dev/null
+++ b/WebCore/rendering/SVGShadowTreeElements.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGShadowTreeElements_h
+#define SVGShadowTreeElements_h
+
+#if ENABLE(SVG)
+#include "SVGGElement.h"
+#include "SVGLength.h"
+
+namespace WebCore {
+
+class FloatSize;
+
+class SVGShadowTreeContainerElement : public SVGGElement {
+public:
+ SVGShadowTreeContainerElement(Document*);
+ virtual ~SVGShadowTreeContainerElement();
+
+ virtual bool isShadowTreeContainerElement() const { return true; }
+
+ FloatSize containerTranslation() const;
+ void setContainerOffset(const SVGLength& x, const SVGLength& y)
+ {
+ m_xOffset = x;
+ m_yOffset = y;
+ }
+
+private:
+ SVGLength m_xOffset;
+ SVGLength m_yOffset;
+};
+
+class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement {
+public:
+ SVGShadowTreeRootElement(Document*, Node* shadowParent);
+ virtual ~SVGShadowTreeRootElement();
+
+ virtual bool isShadowNode() const { return m_shadowParent; }
+ virtual Node* shadowParentNode() { return m_shadowParent; }
+
+ void attachElement(PassRefPtr<RenderStyle>, RenderArena*);
+
+private:
+ Node* m_shadowParent;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/TrailingFloatsRootInlineBox.h b/WebCore/rendering/TrailingFloatsRootInlineBox.h
new file mode 100644
index 0000000..68bf637
--- /dev/null
+++ b/WebCore/rendering/TrailingFloatsRootInlineBox.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TrailingFloatsRootInlineBox_h
+#define TrailingFloatsRootInlineBox_h
+
+#include "RootInlineBox.h"
+
+namespace WebCore {
+
+class TrailingFloatsRootInlineBox : public RootInlineBox {
+public:
+ TrailingFloatsRootInlineBox(RenderObject* object) : RootInlineBox(object)
+ {
+#if ENABLE(SVG)
+ setHasVirtualHeight();
+#endif
+ }
+
+private:
+ virtual int virtualHeight() const { return 0; }
+};
+
+} // namespace WebCore
+
+#endif // TrailingFloatsRootInlineBox_h
diff --git a/WebCore/rendering/TransformState.cpp b/WebCore/rendering/TransformState.cpp
index a9e68f4..700831b 100644
--- a/WebCore/rendering/TransformState.cpp
+++ b/WebCore/rendering/TransformState.cpp
@@ -115,7 +115,7 @@ void TransformState::flattenWithTransform(const TransformationMatrix& t)
}
// We could throw away m_accumulatedTransform if we wanted to here, but that
- // would cause thrash when traversing hierarachies with alternating
+ // would cause thrash when traversing hierarchies with alternating
// preserve-3d and flat elements.
if (m_accumulatedTransform)
m_accumulatedTransform->makeIdentity();
diff --git a/WebCore/rendering/break_lines.cpp b/WebCore/rendering/break_lines.cpp
index be460c8..bbd86eb 100644
--- a/WebCore/rendering/break_lines.cpp
+++ b/WebCore/rendering/break_lines.cpp
@@ -1,21 +1,26 @@
/*
- * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2007, 2010 Apple Inc. All rights reserved.
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -44,17 +49,37 @@ static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak)
}
}
-static inline bool shouldBreakAfter(UChar ch)
+// This differs from the Unicode algorithm only in that Unicode does not break
+// between a question mark and a vertical line (U+007C).
+static const unsigned char internetExplorerLineBreaksAfterQuestionMarkTable[0x80] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // \t
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, // ! " ' ) , . /
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, // : ; ?
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // ]
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 // }
+};
+
+static const size_t internetExplorerLineBreaksAfterQuestionMarkTableSize = sizeof(internetExplorerLineBreaksAfterQuestionMarkTable) / sizeof(*internetExplorerLineBreaksAfterQuestionMarkTable);
+
+static inline bool shouldBreakAfter(UChar ch, UChar nextCh)
{
- // Match WinIE's breaking strategy, which is to always allow breaks after hyphens and question marks.
- // FIXME: it appears that IE behavior is more complex, see <http://bugs.webkit.org/show_bug.cgi?id=17475>.
switch (ch) {
- case '-':
+ // For a question mark preceding a non-ASCII characters, defer to the Unicode algorithm by returning false.
+ // For ASCII characters, use a lookup table for enhanced speed and for compatibility with Internet Explorer.
case '?':
+<<<<<<< HEAD
#ifdef ANDROID_LAYOUT
// as '/' is used in uri which is always long, we would like to break it
case '/':
#endif
+=======
+ return nextCh < internetExplorerLineBreaksAfterQuestionMarkTableSize && internetExplorerLineBreaksAfterQuestionMarkTable[nextCh];
+ // Internet Explorer always allows breaking after a hyphen.
+ case '-':
+>>>>>>> webkit.org at r54127
case softHyphen:
// FIXME: cases for ideographicComma and ideographicFullStop are a workaround for an issue in Unicode 5.0
// which is likely to be resolved in Unicode 5.1 <http://bugs.webkit.org/show_bug.cgi?id=17411>.
@@ -92,7 +117,7 @@ int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakS
for (int i = pos; i < len; i++) {
UChar ch = str[i];
- if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh))
+ if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh, ch))
return i;
if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) {
diff --git a/WebCore/rendering/style/FillLayer.cpp b/WebCore/rendering/style/FillLayer.cpp
index ec910c9..597e919 100644
--- a/WebCore/rendering/style/FillLayer.cpp
+++ b/WebCore/rendering/style/FillLayer.cpp
@@ -270,4 +270,15 @@ bool FillLayer::containsImage(StyleImage* s) const
return false;
}
+bool FillLayer::imagesAreLoaded() const
+{
+ const FillLayer* curr;
+ for (curr = this; curr; curr = curr->next()) {
+ if (curr->m_image && !curr->m_image->isLoaded())
+ return false;
+ }
+
+ return true;
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/style/FillLayer.h b/WebCore/rendering/style/FillLayer.h
index 9c615b4..cef6b19 100644
--- a/WebCore/rendering/style/FillLayer.h
+++ b/WebCore/rendering/style/FillLayer.h
@@ -126,6 +126,7 @@ public:
}
bool containsImage(StyleImage*) const;
+ bool imagesAreLoaded() const;
bool hasImage() const
{
diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp
index 59d40b4..0952557 100644
--- a/WebCore/rendering/style/RenderStyle.cpp
+++ b/WebCore/rendering/style/RenderStyle.cpp
@@ -702,7 +702,7 @@ void RenderStyle::addBindingURI(StringImpl* uri)
void RenderStyle::setTextShadow(ShadowData* val, bool add)
{
- ASSERT(!val || !val->spread && val->style == Normal);
+ ASSERT(!val || (!val->spread && val->style == Normal));
StyleRareInheritedData* rareData = rareInheritedData.access();
if (!add) {
diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h
index a72b66d..c59d953 100644
--- a/WebCore/rendering/style/RenderStyle.h
+++ b/WebCore/rendering/style/RenderStyle.h
@@ -89,7 +89,11 @@
#include "BindingURI.h"
#endif
+#if COMPILER(WINSCW)
+#define compareEqual(t, u) ((t) == (u))
+#else
template<typename T, typename U> inline bool compareEqual(const T& t, const U& u) { return t == static_cast<T>(u); }
+#endif
#define SET_VAR(group, variable, value) \
if (!compareEqual(group->variable, value)) \
@@ -179,7 +183,7 @@ protected:
unsigned _empty_cells : 1; // EEmptyCell
unsigned _caption_side : 2; // ECaptionSide
- unsigned _list_style_type : 5 ; // EListStyleType
+ unsigned _list_style_type : 6; // EListStyleType
unsigned _list_style_position : 1; // EListStylePosition
unsigned _visibility : 2; // EVisibility
unsigned _text_align : 3; // ETextAlign
@@ -190,37 +194,38 @@ protected:
bool _border_collapse : 1 ;
unsigned _white_space : 3; // EWhiteSpace
unsigned _box_direction : 1; // EBoxDirection (CSS3 box_direction property, flexible box layout module)
- // 32 bits
+ // 33 bits
// non CSS2 inherited
bool _visuallyOrdered : 1;
bool _htmlHacks : 1;
bool _force_backgrounds_to_white : 1;
unsigned _pointerEvents : 4; // EPointerEvents
- // 39 bits
+ // 40 bits
} inherited_flags;
// don't inherit
struct NonInheritedFlags {
bool operator==(const NonInheritedFlags& other) const
{
- return (_effectiveDisplay == other._effectiveDisplay) &&
- (_originalDisplay == other._originalDisplay) &&
- (_overflowX == other._overflowX) &&
- (_overflowY == other._overflowY) &&
- (_vertical_align == other._vertical_align) &&
- (_clear == other._clear) &&
- (_position == other._position) &&
- (_floating == other._floating) &&
- (_table_layout == other._table_layout) &&
- (_page_break_before == other._page_break_before) &&
- (_page_break_after == other._page_break_after) &&
- (_styleType == other._styleType) &&
- (_affectedByHover == other._affectedByHover) &&
- (_affectedByActive == other._affectedByActive) &&
- (_affectedByDrag == other._affectedByDrag) &&
- (_pseudoBits == other._pseudoBits) &&
- (_unicodeBidi == other._unicodeBidi);
+ return _effectiveDisplay == other._effectiveDisplay
+ && _originalDisplay == other._originalDisplay
+ && _overflowX == other._overflowX
+ && _overflowY == other._overflowY
+ && _vertical_align == other._vertical_align
+ && _clear == other._clear
+ && _position == other._position
+ && _floating == other._floating
+ && _table_layout == other._table_layout
+ && _page_break_before == other._page_break_before
+ && _page_break_after == other._page_break_after
+ && _page_break_inside == other._page_break_inside
+ && _styleType == other._styleType
+ && _affectedByHover == other._affectedByHover
+ && _affectedByActive == other._affectedByActive
+ && _affectedByDrag == other._affectedByDrag
+ && _pseudoBits == other._pseudoBits
+ && _unicodeBidi == other._unicodeBidi;
}
bool operator!=(const NonInheritedFlags& other) const { return !(*this == other); }
@@ -237,6 +242,7 @@ protected:
unsigned _page_break_before : 2; // EPageBreak
unsigned _page_break_after : 2; // EPageBreak
+ unsigned _page_break_inside : 2; // EPageBreak
unsigned _styleType : 5; // PseudoId
bool _affectedByHover : 1;
@@ -244,7 +250,7 @@ protected:
bool _affectedByDrag : 1;
unsigned _pseudoBits : 7;
unsigned _unicodeBidi : 2; // EUnicodeBidi
- // 48 bits
+ // 50 bits
} noninherited_flags;
// !END SYNC!
@@ -280,6 +286,7 @@ protected:
noninherited_flags._table_layout = initialTableLayout();
noninherited_flags._page_break_before = initialPageBreak();
noninherited_flags._page_break_after = initialPageBreak();
+ noninherited_flags._page_break_inside = initialPageBreak();
noninherited_flags._styleType = NOPSEUDO;
noninherited_flags._affectedByHover = false;
noninherited_flags._affectedByActive = false;
@@ -460,7 +467,7 @@ public:
return font().lineSpacing();
if (lh.isPercent())
- return lh.calcMinValue(fontSize(), true);
+ return lh.calcMinValue(fontSize());
return lh.value();
}
@@ -581,7 +588,7 @@ public:
short widows() const { return inherited->widows; }
short orphans() const { return inherited->orphans; }
- EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(inherited->page_break_inside); }
+ EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(noninherited_flags._page_break_inside); }
EPageBreak pageBreakBefore() const { return static_cast<EPageBreak>(noninherited_flags._page_break_before); }
EPageBreak pageBreakAfter() const { return static_cast<EPageBreak>(noninherited_flags._page_break_after); }
@@ -921,7 +928,7 @@ public:
void setWidows(short w) { SET_VAR(inherited, widows, w); }
void setOrphans(short o) { SET_VAR(inherited, orphans, o); }
- void setPageBreakInside(EPageBreak b) { SET_VAR(inherited, page_break_inside, b); }
+ void setPageBreakInside(EPageBreak b) { noninherited_flags._page_break_inside = b; }
void setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; }
void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; }
@@ -1114,7 +1121,7 @@ public:
static EEmptyCell initialEmptyCells() { return SHOW; }
static EFloat initialFloating() { return FNONE; }
static EListStylePosition initialListStylePosition() { return OUTSIDE; }
- static EListStyleType initialListStyleType() { return DISC; }
+ static EListStyleType initialListStyleType() { return Disc; }
static EOverflow initialOverflowX() { return OVISIBLE; }
static EOverflow initialOverflowY() { return OVISIBLE; }
static EPageBreak initialPageBreak() { return PBAUTO; }
diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h
index 92cd3d5..d2c80ca 100644
--- a/WebCore/rendering/style/RenderStyleConstants.h
+++ b/WebCore/rendering/style/RenderStyleConstants.h
@@ -73,7 +73,7 @@ enum PseudoId {
MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON,
MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON,
MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER,
- INPUT_LIST_BUTTON,
+ INPUT_LIST_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON,
FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON
};
@@ -203,12 +203,63 @@ enum EResize {
RESIZE_NONE, RESIZE_BOTH, RESIZE_HORIZONTAL, RESIZE_VERTICAL
};
+// The order of this enum must match the order of the list style types in CSSValueKeywords.in.
enum EListStyleType {
- DISC, CIRCLE, SQUARE, LDECIMAL, DECIMAL_LEADING_ZERO,
- LOWER_ROMAN, UPPER_ROMAN, LOWER_GREEK,
- LOWER_ALPHA, LOWER_LATIN, UPPER_ALPHA, UPPER_LATIN,
- HEBREW, ARMENIAN, GEORGIAN, CJK_IDEOGRAPHIC,
- HIRAGANA, KATAKANA, HIRAGANA_IROHA, KATAKANA_IROHA, LNONE
+ Disc,
+ Circle,
+ Square,
+ DecimalListStyle,
+ DecimalLeadingZero,
+ LowerRoman,
+ UpperRoman,
+ LowerGreek,
+ LowerAlpha,
+ LowerLatin,
+ UpperAlpha,
+ UpperLatin,
+ Afar,
+ EthiopicHalehameAaEt,
+ EthiopicHalehameAaEr,
+ Amharic,
+ EthiopicHalehameAmEt,
+ AmharicAbegede,
+ EthiopicAbegedeAmEt,
+ CjkEarthlyBranch,
+ CjkHeavenlyStem,
+ Ethiopic,
+ EthiopicHalehameGez,
+ EthiopicAbegede,
+ EthiopicAbegedeGez,
+ HangulConsonant,
+ Hangul,
+ LowerNorwegian,
+ Oromo,
+ EthiopicHalehameOmEt,
+ Sidama,
+ EthiopicHalehameSidEt,
+ Somali,
+ EthiopicHalehameSoEt,
+ Tigre,
+ EthiopicHalehameTig,
+ TigrinyaEr,
+ EthiopicHalehameTiEr,
+ TigrinyaErAbegede,
+ EthiopicAbegedeTiEr,
+ TigrinyaEt,
+ EthiopicHalehameTiEt,
+ TigrinyaEtAbegede,
+ EthiopicAbegedeTiEt,
+ UpperGreek,
+ UpperNorwegian,
+ Hebrew,
+ Armenian,
+ Georgian,
+ CJKIdeographic,
+ Hiragana,
+ Katakana,
+ HiraganaIroha,
+ KatakanaIroha,
+ NoneListStyle
};
enum StyleContentType {
diff --git a/WebCore/rendering/style/SVGRenderStyle.cpp b/WebCore/rendering/style/SVGRenderStyle.cpp
index 728738b..7958088 100644
--- a/WebCore/rendering/style/SVGRenderStyle.cpp
+++ b/WebCore/rendering/style/SVGRenderStyle.cpp
@@ -30,11 +30,14 @@
#include "CSSPrimitiveValue.h"
#include "CSSValueList.h"
+#include "IntRect.h"
#include "NodeRenderStyle.h"
#include "RenderObject.h"
#include "RenderStyle.h"
#include "SVGStyledElement.h"
+using namespace std;
+
namespace WebCore {
SVGRenderStyle::SVGRenderStyle()
@@ -141,6 +144,56 @@ float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* v
return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style()), item->document()->documentElement()->renderStyle());
}
+
+static void getSVGShadowExtent(ShadowData* shadow, int& top, int& right, int& bottom, int& left)
+{
+ top = 0;
+ right = 0;
+ bottom = 0;
+ left = 0;
+
+ int blurAndSpread = shadow->blur + shadow->spread;
+
+ top = min(top, shadow->y - blurAndSpread);
+ right = max(right, shadow->x + blurAndSpread);
+ bottom = max(bottom, shadow->y + blurAndSpread);
+ left = min(left, shadow->x - blurAndSpread);
+}
+
+void SVGRenderStyle::inflateForShadow(IntRect& repaintRect) const
+{
+ ShadowData* svgShadow = shadow();
+ if (!svgShadow)
+ return;
+
+ FloatRect repaintFloatRect = FloatRect(repaintRect);
+ inflateForShadow(repaintFloatRect);
+ repaintRect = enclosingIntRect(repaintFloatRect);
+}
+
+void SVGRenderStyle::inflateForShadow(FloatRect& repaintRect) const
+{
+ ShadowData* svgShadow = shadow();
+ if (!svgShadow)
+ return;
+
+ int shadowTop;
+ int shadowRight;
+ int shadowBottom;
+ int shadowLeft;
+ getSVGShadowExtent(svgShadow, shadowTop, shadowRight, shadowBottom, shadowLeft);
+
+ int overflowLeft = repaintRect.x() + shadowLeft;
+ int overflowRight = repaintRect.right() + shadowRight;
+ int overflowTop = repaintRect.y() + shadowTop;
+ int overflowBottom = repaintRect.bottom() + shadowBottom;
+
+ repaintRect.setX(overflowLeft);
+ repaintRect.setY(overflowTop);
+ repaintRect.setWidth(overflowRight - overflowLeft);
+ repaintRect.setHeight(overflowBottom - overflowTop);
+}
+
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/style/SVGRenderStyle.h b/WebCore/rendering/style/SVGRenderStyle.h
index c65be97..c7f85db 100644
--- a/WebCore/rendering/style/SVGRenderStyle.h
+++ b/WebCore/rendering/style/SVGRenderStyle.h
@@ -34,176 +34,182 @@
namespace WebCore {
- class RenderObject;
- class RenderStyle;
-
- class SVGRenderStyle : public RefCounted<SVGRenderStyle> {
- public:
- static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); }
- PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));}
- ~SVGRenderStyle();
+class FloatRect;
+class IntRect;
+class RenderObject;
+class RenderStyle;
+
+class SVGRenderStyle : public RefCounted<SVGRenderStyle> {
+public:
+ static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); }
+ PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));}
+ ~SVGRenderStyle();
+
+ bool inheritedNotEqual(const SVGRenderStyle*) const;
+ void inheritFrom(const SVGRenderStyle*);
+
+ // FIXME: These functions should move to ShadowData.
+ void inflateForShadow(IntRect&) const;
+ void inflateForShadow(FloatRect&) const;
+
+ bool operator==(const SVGRenderStyle&) const;
+ bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); }
+
+ // SVG CSS Properties
+ SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE)
+
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO)
+
+ // SVG CSS Properties (using DataRef's)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill())
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0);
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0))
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String())
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0))
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255))
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(ShadowData, shadowSVG, shadow, Shadow, shadow, 0)
+
+ // convenience
+ bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
+ bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
+
+ static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f);
+
+protected:
+ // inherit
+ struct InheritedFlags {
+ bool operator==(const InheritedFlags& other) const
+ {
+ return (_colorRendering == other._colorRendering)
+ && (_imageRendering == other._imageRendering)
+ && (_shapeRendering == other._shapeRendering)
+ && (_clipRule == other._clipRule)
+ && (_fillRule == other._fillRule)
+ && (_capStyle == other._capStyle)
+ && (_joinStyle == other._joinStyle)
+ && (_textAnchor == other._textAnchor)
+ && (_colorInterpolation == other._colorInterpolation)
+ && (_colorInterpolationFilters == other._colorInterpolationFilters)
+ && (_writingMode == other._writingMode)
+ && (_glyphOrientationHorizontal == other._glyphOrientationHorizontal)
+ && (_glyphOrientationVertical == other._glyphOrientationVertical);
+ }
- bool inheritedNotEqual(const SVGRenderStyle*) const;
- void inheritFrom(const SVGRenderStyle*);
-
- bool operator==(const SVGRenderStyle&) const;
- bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); }
-
- // SVG CSS Properties
- SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE)
-
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO)
-
- // SVG CSS Properties (using DataRef's)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill())
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f)
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0);
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0)
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0))
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String())
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0))
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255))
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0)
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(ShadowData, shadowSVG, shadow, Shadow, shadow, 0)
-
- // convenience
- bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
- bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
-
- static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f);
-
- protected:
- // inherit
- struct InheritedFlags {
- bool operator==(const InheritedFlags& other) const
- {
- return (_colorRendering == other._colorRendering) &&
- (_imageRendering == other._imageRendering) &&
- (_shapeRendering == other._shapeRendering) &&
- (_clipRule == other._clipRule) &&
- (_fillRule == other._fillRule) &&
- (_capStyle == other._capStyle) &&
- (_joinStyle == other._joinStyle) &&
- (_textAnchor == other._textAnchor) &&
- (_colorInterpolation == other._colorInterpolation) &&
- (_colorInterpolationFilters == other._colorInterpolationFilters) &&
- (_writingMode == other._writingMode) &&
- (_glyphOrientationHorizontal == other._glyphOrientationHorizontal) &&
- (_glyphOrientationVertical == other._glyphOrientationVertical);
- }
-
- bool operator!=(const InheritedFlags& other) const
- {
- return !(*this == other);
- }
-
- unsigned _colorRendering : 2; // EColorRendering
- unsigned _imageRendering : 2; // EImageRendering
- unsigned _shapeRendering : 2; // EShapeRendering
- unsigned _clipRule : 1; // WindRule
- unsigned _fillRule : 1; // WindRule
- unsigned _capStyle : 2; // LineCap
- unsigned _joinStyle : 2; // LineJoin
- unsigned _textAnchor : 2; // ETextAnchor
- unsigned _colorInterpolation : 2; // EColorInterpolation
- unsigned _colorInterpolationFilters : 2; // EColorInterpolation
- unsigned _writingMode : 3; // EWritingMode
- unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
- unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
- } svg_inherited_flags;
-
- // don't inherit
- struct NonInheritedFlags {
- // 32 bit non-inherited, don't add to the struct, or the operator will break.
- bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; }
- bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; }
-
- union {
- struct {
- unsigned _alignmentBaseline : 4; // EAlignmentBaseline
- unsigned _dominantBaseline : 4; // EDominantBaseline
- unsigned _baselineShift : 2; // EBaselineShift
- // 22 bits unused
- } f;
- uint32_t _niflags;
- };
- } svg_noninherited_flags;
-
- // inherited attributes
- DataRef<StyleFillData> fill;
- DataRef<StyleStrokeData> stroke;
- DataRef<StyleMarkerData> markers;
- DataRef<StyleTextData> text;
-
- // non-inherited attributes
- DataRef<StyleStopData> stops;
- DataRef<StyleClipData> clip;
- DataRef<StyleMaskData> mask;
- DataRef<StyleMiscData> misc;
- DataRef<StyleShadowSVGData> shadowSVG;
-
- private:
- enum CreateDefaultType { CreateDefault };
-
- SVGRenderStyle();
- SVGRenderStyle(const SVGRenderStyle&);
- SVGRenderStyle(CreateDefaultType); // Used to create the default style.
-
- void setBitDefaults()
+ bool operator!=(const InheritedFlags& other) const
{
- svg_inherited_flags._clipRule = initialClipRule();
- svg_inherited_flags._colorRendering = initialColorRendering();
- svg_inherited_flags._fillRule = initialFillRule();
- svg_inherited_flags._imageRendering = initialImageRendering();
- svg_inherited_flags._shapeRendering = initialShapeRendering();
- svg_inherited_flags._textAnchor = initialTextAnchor();
- svg_inherited_flags._capStyle = initialCapStyle();
- svg_inherited_flags._joinStyle = initialJoinStyle();
- svg_inherited_flags._colorInterpolation = initialColorInterpolation();
- svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters();
- svg_inherited_flags._writingMode = initialWritingMode();
- svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal();
- svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical();
-
- svg_noninherited_flags._niflags = 0;
- svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline();
- svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
- svg_noninherited_flags.f._baselineShift = initialBaselineShift();
+ return !(*this == other);
}
- };
+
+ unsigned _colorRendering : 2; // EColorRendering
+ unsigned _imageRendering : 2; // EImageRendering
+ unsigned _shapeRendering : 2; // EShapeRendering
+ unsigned _clipRule : 1; // WindRule
+ unsigned _fillRule : 1; // WindRule
+ unsigned _capStyle : 2; // LineCap
+ unsigned _joinStyle : 2; // LineJoin
+ unsigned _textAnchor : 2; // ETextAnchor
+ unsigned _colorInterpolation : 2; // EColorInterpolation
+ unsigned _colorInterpolationFilters : 2; // EColorInterpolation
+ unsigned _writingMode : 3; // EWritingMode
+ unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
+ unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
+ } svg_inherited_flags;
+
+ // don't inherit
+ struct NonInheritedFlags {
+ // 32 bit non-inherited, don't add to the struct, or the operator will break.
+ bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; }
+ bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; }
+
+ union {
+ struct {
+ unsigned _alignmentBaseline : 4; // EAlignmentBaseline
+ unsigned _dominantBaseline : 4; // EDominantBaseline
+ unsigned _baselineShift : 2; // EBaselineShift
+ // 22 bits unused
+ } f;
+ uint32_t _niflags;
+ };
+ } svg_noninherited_flags;
+
+ // inherited attributes
+ DataRef<StyleFillData> fill;
+ DataRef<StyleStrokeData> stroke;
+ DataRef<StyleMarkerData> markers;
+ DataRef<StyleTextData> text;
+
+ // non-inherited attributes
+ DataRef<StyleStopData> stops;
+ DataRef<StyleClipData> clip;
+ DataRef<StyleMaskData> mask;
+ DataRef<StyleMiscData> misc;
+ DataRef<StyleShadowSVGData> shadowSVG;
+
+private:
+ enum CreateDefaultType { CreateDefault };
+
+ SVGRenderStyle();
+ SVGRenderStyle(const SVGRenderStyle&);
+ SVGRenderStyle(CreateDefaultType); // Used to create the default style.
+
+ void setBitDefaults()
+ {
+ svg_inherited_flags._clipRule = initialClipRule();
+ svg_inherited_flags._colorRendering = initialColorRendering();
+ svg_inherited_flags._fillRule = initialFillRule();
+ svg_inherited_flags._imageRendering = initialImageRendering();
+ svg_inherited_flags._shapeRendering = initialShapeRendering();
+ svg_inherited_flags._textAnchor = initialTextAnchor();
+ svg_inherited_flags._capStyle = initialCapStyle();
+ svg_inherited_flags._joinStyle = initialJoinStyle();
+ svg_inherited_flags._colorInterpolation = initialColorInterpolation();
+ svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters();
+ svg_inherited_flags._writingMode = initialWritingMode();
+ svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal();
+ svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical();
+
+ svg_noninherited_flags._niflags = 0;
+ svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline();
+ svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
+ svg_noninherited_flags.f._baselineShift = initialBaselineShift();
+ }
+};
} // namespace WebCore
diff --git a/WebCore/rendering/style/StyleInheritedData.cpp b/WebCore/rendering/style/StyleInheritedData.cpp
index f59c0c2..c73497f 100644
--- a/WebCore/rendering/style/StyleInheritedData.cpp
+++ b/WebCore/rendering/style/StyleInheritedData.cpp
@@ -37,7 +37,6 @@ StyleInheritedData::StyleInheritedData()
, vertical_border_spacing(RenderStyle::initialVerticalBorderSpacing())
, widows(RenderStyle::initialWidows())
, orphans(RenderStyle::initialOrphans())
- , page_break_inside(RenderStyle::initialPageBreak())
{
}
@@ -58,7 +57,6 @@ StyleInheritedData::StyleInheritedData(const StyleInheritedData& o)
, vertical_border_spacing(o.vertical_border_spacing)
, widows(o.widows)
, orphans(o.orphans)
- , page_break_inside(o.page_break_inside)
{
}
@@ -84,8 +82,7 @@ bool StyleInheritedData::operator==(const StyleInheritedData& o) const
horizontal_border_spacing == o.horizontal_border_spacing &&
vertical_border_spacing == o.vertical_border_spacing &&
widows == o.widows &&
- orphans == o.orphans &&
- page_break_inside == o.page_break_inside;
+ orphans == o.orphans;
}
} // namespace WebCore
diff --git a/WebCore/rendering/style/StyleInheritedData.h b/WebCore/rendering/style/StyleInheritedData.h
index 548ca72..3b30b8f 100644
--- a/WebCore/rendering/style/StyleInheritedData.h
+++ b/WebCore/rendering/style/StyleInheritedData.h
@@ -68,7 +68,6 @@ public:
// Paged media properties.
short widows;
short orphans;
- unsigned page_break_inside : 2; // EPageBreak
private:
StyleInheritedData();