summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/CounterNode.cpp5
-rw-r--r--WebCore/rendering/CounterNode.h6
-rw-r--r--WebCore/rendering/EllipsisBox.cpp2
-rw-r--r--WebCore/rendering/HitTestResult.cpp11
-rw-r--r--WebCore/rendering/HitTestResult.h14
-rw-r--r--WebCore/rendering/InlineBox.cpp4
-rw-r--r--WebCore/rendering/InlineBox.h13
-rw-r--r--WebCore/rendering/InlineFlowBox.cpp237
-rw-r--r--WebCore/rendering/InlineFlowBox.h46
-rw-r--r--WebCore/rendering/InlineIterator.h4
-rw-r--r--WebCore/rendering/InlineTextBox.cpp51
-rw-r--r--WebCore/rendering/InlineTextBox.h6
-rw-r--r--WebCore/rendering/LayoutState.cpp5
-rw-r--r--WebCore/rendering/LayoutState.h7
-rw-r--r--WebCore/rendering/RenderApplet.cpp4
-rw-r--r--WebCore/rendering/RenderApplet.h1
-rw-r--r--WebCore/rendering/RenderBR.cpp33
-rw-r--r--WebCore/rendering/RenderBR.h19
-rw-r--r--WebCore/rendering/RenderBlock.cpp1402
-rw-r--r--WebCore/rendering/RenderBlock.h256
-rw-r--r--WebCore/rendering/RenderBlockLineLayout.cpp342
-rw-r--r--WebCore/rendering/RenderBox.cpp323
-rw-r--r--WebCore/rendering/RenderBox.h103
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp39
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h12
-rw-r--r--WebCore/rendering/RenderButton.cpp4
-rw-r--r--WebCore/rendering/RenderButton.h3
-rw-r--r--WebCore/rendering/RenderCounter.cpp43
-rw-r--r--WebCore/rendering/RenderCounter.h1
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.cpp2
-rw-r--r--WebCore/rendering/RenderFieldset.cpp191
-rw-r--r--WebCore/rendering/RenderFieldset.h4
-rw-r--r--WebCore/rendering/RenderFileUploadControl.cpp13
-rw-r--r--WebCore/rendering/RenderFlexibleBox.cpp236
-rw-r--r--WebCore/rendering/RenderForeignObject.cpp4
-rw-r--r--WebCore/rendering/RenderForeignObject.h3
-rw-r--r--WebCore/rendering/RenderFrame.h2
-rw-r--r--WebCore/rendering/RenderFrameBase.h2
-rw-r--r--WebCore/rendering/RenderHTMLCanvas.h2
-rw-r--r--WebCore/rendering/RenderIFrame.h2
-rw-r--r--WebCore/rendering/RenderImage.cpp93
-rw-r--r--WebCore/rendering/RenderImage.h12
-rw-r--r--WebCore/rendering/RenderInline.cpp30
-rw-r--r--WebCore/rendering/RenderInline.h5
-rw-r--r--WebCore/rendering/RenderLayer.cpp12
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp25
-rw-r--r--[-rwxr-xr-x]WebCore/rendering/RenderLayerCompositor.cpp0
-rw-r--r--[-rwxr-xr-x]WebCore/rendering/RenderLayerCompositor.h0
-rw-r--r--WebCore/rendering/RenderLineBoxList.cpp4
-rw-r--r--WebCore/rendering/RenderListBox.cpp6
-rw-r--r--WebCore/rendering/RenderListBox.h2
-rw-r--r--WebCore/rendering/RenderListItem.cpp8
-rw-r--r--WebCore/rendering/RenderListItem.h2
-rw-r--r--WebCore/rendering/RenderListMarker.cpp29
-rw-r--r--WebCore/rendering/RenderListMarker.h4
-rw-r--r--WebCore/rendering/RenderMarquee.cpp6
-rw-r--r--WebCore/rendering/RenderMarquee.h3
-rw-r--r--WebCore/rendering/RenderMedia.cpp68
-rw-r--r--WebCore/rendering/RenderMedia.h7
-rw-r--r--WebCore/rendering/RenderMediaControls.h4
-rw-r--r--WebCore/rendering/RenderMediaControlsChromium.cpp16
-rw-r--r--WebCore/rendering/RenderMeter.cpp2
-rw-r--r--WebCore/rendering/RenderObject.cpp30
-rw-r--r--WebCore/rendering/RenderObject.h21
-rw-r--r--WebCore/rendering/RenderObjectChildList.cpp5
-rw-r--r--WebCore/rendering/RenderProgress.cpp2
-rw-r--r--WebCore/rendering/RenderReplaced.cpp72
-rw-r--r--WebCore/rendering/RenderReplaced.h13
-rw-r--r--WebCore/rendering/RenderRuby.cpp47
-rw-r--r--WebCore/rendering/RenderSVGAllInOne.cpp32
-rw-r--r--WebCore/rendering/RenderSVGBlock.h2
-rw-r--r--WebCore/rendering/RenderSVGContainer.cpp4
-rw-r--r--WebCore/rendering/RenderSVGContainer.h3
-rw-r--r--WebCore/rendering/RenderSVGGradientStop.cpp2
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.cpp2
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.h2
-rw-r--r--WebCore/rendering/RenderSVGImage.cpp50
-rw-r--r--WebCore/rendering/RenderSVGImage.h12
-rw-r--r--WebCore/rendering/RenderSVGInlineText.cpp111
-rw-r--r--WebCore/rendering/RenderSVGModelObject.h2
-rw-r--r--WebCore/rendering/RenderSVGResource.cpp174
-rw-r--r--WebCore/rendering/RenderSVGResource.h9
-rw-r--r--WebCore/rendering/RenderSVGResourceClipper.cpp10
-rw-r--r--WebCore/rendering/RenderSVGResourceContainer.cpp2
-rw-r--r--WebCore/rendering/RenderSVGResourceFilter.cpp112
-rw-r--r--WebCore/rendering/RenderSVGResourceFilter.h4
-rw-r--r--WebCore/rendering/RenderSVGResourceFilterPrimitive.h2
-rw-r--r--WebCore/rendering/RenderSVGResourceGradient.cpp52
-rw-r--r--WebCore/rendering/RenderSVGResourceGradient.h8
-rw-r--r--WebCore/rendering/RenderSVGResourceLinearGradient.cpp17
-rw-r--r--WebCore/rendering/RenderSVGResourceLinearGradient.h7
-rw-r--r--WebCore/rendering/RenderSVGResourceMasker.cpp4
-rw-r--r--WebCore/rendering/RenderSVGResourcePattern.cpp46
-rw-r--r--WebCore/rendering/RenderSVGResourcePattern.h7
-rw-r--r--WebCore/rendering/RenderSVGResourceRadialGradient.cpp19
-rw-r--r--WebCore/rendering/RenderSVGResourceRadialGradient.h7
-rw-r--r--WebCore/rendering/RenderSVGResourceSolidColor.cpp4
-rw-r--r--WebCore/rendering/RenderSVGRoot.cpp22
-rw-r--r--WebCore/rendering/RenderSVGRoot.h9
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.h2
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.h2
-rw-r--r--WebCore/rendering/RenderScrollbarTheme.cpp2
-rw-r--r--WebCore/rendering/RenderSlider.cpp2
-rw-r--r--WebCore/rendering/RenderSlider.h2
-rw-r--r--WebCore/rendering/RenderTable.cpp12
-rw-r--r--WebCore/rendering/RenderTable.h3
-rw-r--r--WebCore/rendering/RenderTableCell.cpp33
-rw-r--r--WebCore/rendering/RenderTableCell.h4
-rw-r--r--WebCore/rendering/RenderTableCol.h3
-rw-r--r--WebCore/rendering/RenderTableRow.h3
-rw-r--r--WebCore/rendering/RenderTableSection.cpp54
-rw-r--r--WebCore/rendering/RenderTableSection.h9
-rw-r--r--WebCore/rendering/RenderText.cpp39
-rw-r--r--WebCore/rendering/RenderText.h2
-rw-r--r--WebCore/rendering/RenderTextControl.cpp10
-rw-r--r--WebCore/rendering/RenderTextControl.h2
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.cpp4
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.h2
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.cpp21
-rw-r--r--WebCore/rendering/RenderTextFragment.cpp4
-rw-r--r--WebCore/rendering/RenderTextFragment.h1
-rw-r--r--WebCore/rendering/RenderThemeMac.mm10
-rw-r--r--WebCore/rendering/RenderThemeSafari.cpp8
-rw-r--r--WebCore/rendering/RenderThemeWin.cpp93
-rw-r--r--WebCore/rendering/RenderThemeWin.h18
-rw-r--r--WebCore/rendering/RenderThemeWinCE.cpp14
-rw-r--r--WebCore/rendering/RenderTreeAsText.cpp10
-rw-r--r--WebCore/rendering/RenderVideo.cpp8
-rw-r--r--WebCore/rendering/RenderVideo.h4
-rw-r--r--WebCore/rendering/RenderView.cpp3
-rw-r--r--WebCore/rendering/RenderView.h19
-rw-r--r--WebCore/rendering/RenderWordBreak.h2
-rw-r--r--WebCore/rendering/RenderingAllInOne.cpp112
-rw-r--r--WebCore/rendering/RootInlineBox.cpp15
-rw-r--r--WebCore/rendering/RootInlineBox.h11
-rw-r--r--WebCore/rendering/SVGCharacterData.h96
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.cpp519
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.h173
-rw-r--r--WebCore/rendering/SVGImageBufferTools.cpp2
-rw-r--r--WebCore/rendering/SVGImageBufferTools.h2
-rw-r--r--WebCore/rendering/SVGInlineFlowBox.cpp63
-rw-r--r--WebCore/rendering/SVGInlineTextBox.cpp889
-rw-r--r--WebCore/rendering/SVGRenderSupport.cpp18
-rw-r--r--WebCore/rendering/SVGRenderSupport.h1
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.cpp195
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.h4
-rw-r--r--WebCore/rendering/SVGResources.cpp34
-rw-r--r--WebCore/rendering/SVGRootInlineBox.cpp364
-rw-r--r--WebCore/rendering/SVGTextChunkLayoutInfo.cpp493
-rw-r--r--WebCore/rendering/SVGTextChunkLayoutInfo.h198
-rw-r--r--WebCore/rendering/SVGTextLayoutUtilities.cpp375
-rw-r--r--WebCore/rendering/SVGTextLayoutUtilities.h70
-rw-r--r--WebCore/rendering/SVGTextQuery.cpp467
-rw-r--r--WebCore/rendering/TextControlInnerElements.cpp2
-rw-r--r--WebCore/rendering/style/RenderStyle.cpp199
-rw-r--r--WebCore/rendering/style/RenderStyle.h51
-rw-r--r--WebCore/rendering/style/RenderStyleConstants.h6
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.cpp4
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.h9
-rw-r--r--WebCore/rendering/style/SVGRenderStyleDefs.h2
-rw-r--r--WebCore/rendering/style/StyleAllInOne.cpp49
-rw-r--r--WebCore/rendering/style/StyleRareInheritedData.cpp5
-rw-r--r--WebCore/rendering/style/StyleRareInheritedData.h1
-rw-r--r--WebCore/rendering/svg/RenderSVGInline.cpp (renamed from WebCore/rendering/RenderSVGInline.cpp)12
-rw-r--r--WebCore/rendering/svg/RenderSVGInline.h (renamed from WebCore/rendering/RenderSVGInline.h)2
-rw-r--r--WebCore/rendering/svg/RenderSVGInlineText.cpp196
-rw-r--r--WebCore/rendering/svg/RenderSVGInlineText.h (renamed from WebCore/rendering/RenderSVGInlineText.h)24
-rw-r--r--WebCore/rendering/svg/RenderSVGPath.cpp (renamed from WebCore/rendering/RenderPath.cpp)54
-rw-r--r--WebCore/rendering/svg/RenderSVGPath.h (renamed from WebCore/rendering/RenderPath.h)27
-rw-r--r--WebCore/rendering/svg/RenderSVGTSpan.cpp (renamed from WebCore/rendering/RenderSVGTSpan.cpp)0
-rw-r--r--WebCore/rendering/svg/RenderSVGTSpan.h (renamed from WebCore/rendering/RenderSVGTSpan.h)2
-rw-r--r--WebCore/rendering/svg/RenderSVGText.cpp (renamed from WebCore/rendering/RenderSVGText.cpp)63
-rw-r--r--WebCore/rendering/svg/RenderSVGText.h (renamed from WebCore/rendering/RenderSVGText.h)26
-rw-r--r--WebCore/rendering/svg/RenderSVGTextPath.cpp (renamed from WebCore/rendering/RenderSVGTextPath.cpp)3
-rw-r--r--WebCore/rendering/svg/RenderSVGTextPath.h (renamed from WebCore/rendering/RenderSVGTextPath.h)44
-rw-r--r--WebCore/rendering/svg/SVGInlineFlowBox.cpp143
-rw-r--r--WebCore/rendering/svg/SVGInlineFlowBox.h (renamed from WebCore/rendering/SVGInlineFlowBox.h)7
-rw-r--r--WebCore/rendering/svg/SVGInlineTextBox.cpp610
-rw-r--r--WebCore/rendering/svg/SVGInlineTextBox.h (renamed from WebCore/rendering/SVGInlineTextBox.h)53
-rw-r--r--WebCore/rendering/svg/SVGRootInlineBox.cpp221
-rw-r--r--WebCore/rendering/svg/SVGRootInlineBox.h (renamed from WebCore/rendering/SVGRootInlineBox.h)15
-rw-r--r--WebCore/rendering/svg/SVGTextChunk.cpp93
-rw-r--r--WebCore/rendering/svg/SVGTextChunk.h68
-rw-r--r--WebCore/rendering/svg/SVGTextChunkBuilder.cpp232
-rw-r--r--WebCore/rendering/svg/SVGTextChunkBuilder.h64
-rw-r--r--WebCore/rendering/svg/SVGTextFragment.h57
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributes.cpp26
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributes.h36
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp317
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h (renamed from WebCore/rendering/svg/SVGTextLayoutBuilder.h)44
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutBuilder.cpp304
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngine.cpp579
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngine.h94
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp234
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h54
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp96
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h (renamed from WebCore/rendering/SVGCharacterData.cpp)43
-rw-r--r--WebCore/rendering/svg/SVGTextMetrics.cpp115
-rw-r--r--WebCore/rendering/svg/SVGTextMetrics.h78
-rw-r--r--WebCore/rendering/svg/SVGTextQuery.cpp562
-rw-r--r--WebCore/rendering/svg/SVGTextQuery.h (renamed from WebCore/rendering/SVGTextQuery.h)27
201 files changed, 7492 insertions, 6689 deletions
diff --git a/WebCore/rendering/CounterNode.cpp b/WebCore/rendering/CounterNode.cpp
index c164c81..ac83d5a 100644
--- a/WebCore/rendering/CounterNode.cpp
+++ b/WebCore/rendering/CounterNode.cpp
@@ -41,6 +41,11 @@ CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value)
{
}
+PassRefPtr<CounterNode> CounterNode::create(RenderObject* renderer, bool hasResetType, int value)
+{
+ return adoptRef(new CounterNode(renderer, hasResetType, value));
+}
+
CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const
{
if (this == stayWithin)
diff --git a/WebCore/rendering/CounterNode.h b/WebCore/rendering/CounterNode.h
index e35fb61..529d409 100644
--- a/WebCore/rendering/CounterNode.h
+++ b/WebCore/rendering/CounterNode.h
@@ -24,6 +24,7 @@
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
// This implements a counter tree that is used for finding parents in counters() lookup,
// and for propagating count changes when nodes are added or removed.
@@ -38,9 +39,9 @@ namespace WebCore {
class RenderObject;
-class CounterNode : public Noncopyable {
+class CounterNode : public RefCounted<CounterNode> {
public:
- CounterNode(RenderObject*, bool isReset, int value);
+ static PassRefPtr<CounterNode> create(RenderObject*, bool isReset, int value);
bool actsAsReset() const { return m_hasResetType || !m_parent; }
bool hasResetType() const { return m_hasResetType; }
@@ -64,6 +65,7 @@ public:
void removeChild(CounterNode*, const AtomicString& identifier);
private:
+ CounterNode(RenderObject*, bool isReset, int value);
int computeCountInParent() const;
void recount(const AtomicString& identifier);
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp
index 1d71d35..f9c4f03 100644
--- a/WebCore/rendering/EllipsisBox.cpp
+++ b/WebCore/rendering/EllipsisBox.cpp
@@ -114,7 +114,7 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
}
IntRect boundsRect = IntRect(tx, ty, m_logicalWidth, m_height);
- if (visibleToHitTesting() && boundsRect.intersects(result.rectFromPoint(x, y))) {
+ if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(x, y))) {
renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, boundsRect))
return true;
diff --git a/WebCore/rendering/HitTestResult.cpp b/WebCore/rendering/HitTestResult.cpp
index 35a6d23..1bc238f 100644
--- a/WebCore/rendering/HitTestResult.cpp
+++ b/WebCore/rendering/HitTestResult.cpp
@@ -29,6 +29,7 @@
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "RenderImage.h"
#include "Scrollbar.h"
#include "SelectionController.h"
@@ -305,14 +306,14 @@ KURL HitTestResult::absoluteImageURL() const
} else
return KURL();
- return m_innerNonSharedNode->document()->completeURL(deprecatedParseURL(urlString));
+ return m_innerNonSharedNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
}
KURL HitTestResult::absoluteMediaURL() const
{
#if ENABLE(VIDEO)
if (HTMLMediaElement* mediaElt = mediaElement())
- return m_innerNonSharedNode->document()->completeURL(deprecatedParseURL(mediaElt->currentSrc()));
+ return m_innerNonSharedNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(mediaElt->currentSrc()));
return KURL();
#else
return KURL();
@@ -461,7 +462,7 @@ KURL HitTestResult::absoluteLinkURL() const
else
return KURL();
- return m_innerURLElement->document()->completeURL(deprecatedParseURL(urlString));
+ return m_innerURLElement->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
}
bool HitTestResult::isLiveLink() const
@@ -530,7 +531,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const
node = node->shadowAncestorNode();
m_rectBasedTestResult.add(node);
- return !rect.contains(rectFromPoint(x, y));
+ return !rect.contains(rectForPoint(x, y));
}
void HitTestResult::append(const HitTestResult& other)
@@ -552,7 +553,7 @@ void HitTestResult::append(const HitTestResult& other)
m_rectBasedTestResult.add(it->get());
}
-IntRect HitTestResult::rectFromPoint(const IntPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
+IntRect HitTestResult::rectForPoint(const IntPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
{
IntPoint actualPoint(point);
actualPoint -= IntSize(leftPadding, topPadding);
diff --git a/WebCore/rendering/HitTestResult.h b/WebCore/rendering/HitTestResult.h
index 1304e22..8d9b18d 100644
--- a/WebCore/rendering/HitTestResult.h
+++ b/WebCore/rendering/HitTestResult.h
@@ -98,9 +98,9 @@ public:
// Rect-based hit test related methods.
bool isRectBasedTest() const { return m_isRectBased; }
- IntRect rectFromPoint(int x, int y) const;
- IntRect rectFromPoint(const IntPoint&) const;
- static IntRect rectFromPoint(const IntPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
+ IntRect rectForPoint(int x, int y) const;
+ IntRect rectForPoint(const IntPoint&) const;
+ static IntRect rectForPoint(const IntPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
int topPadding() const { return m_topPadding; }
int rightPadding() const { return m_rightPadding; }
int bottomPadding() const { return m_bottomPadding; }
@@ -134,9 +134,9 @@ private:
ListHashSet<RefPtr<Node> > m_rectBasedTestResult;
};
-inline IntRect HitTestResult::rectFromPoint(int x, int y) const
+inline IntRect HitTestResult::rectForPoint(int x, int y) const
{
- return rectFromPoint(IntPoint(x, y), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
+ return rectForPoint(IntPoint(x, y), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
}
// Formula:
@@ -144,9 +144,9 @@ inline IntRect HitTestResult::rectFromPoint(int x, int y) const
// y = p.y() - topPadding
// width = leftPadding + rightPadding + 1
// height = topPadding + bottomPadding + 1
-inline IntRect HitTestResult::rectFromPoint(const IntPoint& point) const
+inline IntRect HitTestResult::rectForPoint(const IntPoint& point) const
{
- return rectFromPoint(point, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
+ return rectForPoint(point, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
}
String displayString(const String&, const Node*);
diff --git a/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp
index 91cbaff..2028d4e 100644
--- a/WebCore/rendering/InlineBox.cpp
+++ b/WebCore/rendering/InlineBox.cpp
@@ -95,14 +95,14 @@ int InlineBox::logicalHeight() const
if (renderer()->isText())
return m_isText ? renderer()->style(m_firstLine)->font().height() : 0;
if (renderer()->isBox() && parent())
- return toRenderBox(m_renderer)->height();
+ return m_isVertical ? toRenderBox(m_renderer)->width() : toRenderBox(m_renderer)->height();
ASSERT(isInlineFlowBox());
RenderBoxModelObject* flowObject = boxModelObject();
const Font& font = renderer()->style(m_firstLine)->font();
int result = font.height();
if (parent())
- result += flowObject->borderAndPaddingHeight();
+ result += flowObject->borderAndPaddingLogicalHeight();
return result;
}
diff --git a/WebCore/rendering/InlineBox.h b/WebCore/rendering/InlineBox.h
index 1cd88ff..38a7805 100644
--- a/WebCore/rendering/InlineBox.h
+++ b/WebCore/rendering/InlineBox.h
@@ -21,6 +21,7 @@
#ifndef InlineBox_h
#define InlineBox_h
+#include "RenderBR.h"
#include "RenderBoxModelObject.h"
#include "TextDirection.h"
@@ -139,6 +140,7 @@ public:
virtual bool isRootInlineBox() const { return false; }
#if ENABLE(SVG)
virtual bool isSVGInlineTextBox() const { return false; }
+ virtual bool isSVGInlineFlowBox() const { return false; }
virtual bool isSVGRootInlineBox() const { return false; }
#endif
@@ -216,6 +218,7 @@ public:
// The logicalLeft position is the left edge of the line box in a horizontal line and the top edge in a vertical line.
int logicalLeft() const { return !m_isVertical ? m_x : m_y; }
+ int logicalRight() const { return logicalLeft() + logicalWidth(); }
void setLogicalLeft(int left)
{
if (!m_isVertical)
@@ -241,8 +244,9 @@ public:
// The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text.
int logicalHeight() const;
- inline int baselinePosition(bool isRootLineBox) const { return renderer()->baselinePosition(m_firstLine, isRootLineBox); }
- inline int lineHeight(bool isRootLineBox) const { return renderer()->lineHeight(m_firstLine, isRootLineBox); }
+ virtual int baselinePosition() const { return boxModelObject()->baselinePosition(m_firstLine, m_isVertical ? VerticalLine : HorizontalLine, PositionOnContainingLine); }
+ virtual int lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, m_isVertical ? VerticalLine : HorizontalLine, PositionOnContainingLine); }
+
virtual int caretMinOffset() const;
virtual int caretMaxOffset() const;
@@ -251,8 +255,9 @@ public:
unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; }
void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; }
TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; }
- int caretLeftmostOffset() const { return direction() == LTR ? caretMinOffset() : caretMaxOffset(); }
- int caretRightmostOffset() const { return direction() == LTR ? caretMaxOffset() : caretMinOffset(); }
+ bool isLeftToRightDirection() const { return direction() == LTR; }
+ int caretLeftmostOffset() const { return isLeftToRightDirection() ? caretMinOffset() : caretMaxOffset(); }
+ int caretRightmostOffset() const { return isLeftToRightDirection() ? caretMaxOffset() : caretMinOffset(); }
virtual void clearTruncation() { }
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index 588d054..79c571d 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/WebCore/rendering/InlineFlowBox.cpp
@@ -83,8 +83,6 @@ void InlineFlowBox::addToLine(InlineBox* child)
child->setIsVertical(m_isVertical);
if (child->isText())
m_hasTextChildren = true;
- if (child->renderer()->selectionState() != RenderObject::SelectionNone)
- root()->setHasSelectedChildren(true);
checkConsistency();
}
@@ -209,7 +207,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
// The root inline box never has borders/margins/padding.
if (parent()) {
- bool ltr = renderer()->style()->direction() == LTR;
+ bool ltr = renderer()->style()->isLeftToRightDirection();
// Check to see if all initial lines are unconstructed. If so, then
// we know the inline began on this line (unless we are a continuation).
@@ -253,24 +251,24 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
}
}
-int InlineFlowBox::placeBoxesInInlineDirection(int xPos, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
+int InlineFlowBox::placeBoxesInInlineDirection(int logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
{
// Set our x position.
- setX(xPos);
+ setLogicalLeft(logicalLeft);
- int leftLayoutOverflow = xPos;
- int rightLayoutOverflow = xPos;
- int leftVisualOverflow = xPos;
- int rightVisualOverflow = xPos;
+ int logicalLeftLayoutOverflow = logicalLeft;
+ int logicalRightLayoutOverflow = logicalLeft;
+ int logicalLeftVisualOverflow = logicalLeft;
+ int logicalRightVisualOverflow = logicalLeft;
- int boxShadowLeft;
- int boxShadowRight;
- renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(boxShadowLeft, boxShadowRight);
+ int boxShadowLogicalLeft;
+ int boxShadowLogicalRight;
+ renderer()->style(m_firstLine)->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight);
- leftVisualOverflow = min(xPos + boxShadowLeft, leftVisualOverflow);
+ logicalLeftVisualOverflow = min(logicalLeft + boxShadowLogicalLeft, logicalLeftVisualOverflow);
- int startX = xPos;
- xPos += borderLogicalLeft() + paddingLogicalLeft();
+ int startLogicalLeft = logicalLeft;
+ logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isText()) {
@@ -278,81 +276,87 @@ int InlineFlowBox::placeBoxesInInlineDirection(int xPos, bool& needsWordSpacing,
RenderText* rt = toRenderText(text->renderer());
if (rt->textLength()) {
if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()]))
- xPos += rt->style(m_firstLine)->font().wordSpacing();
+ logicalLeft += rt->style(m_firstLine)->font().wordSpacing();
needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]);
}
- text->setX(xPos);
+ text->setLogicalLeft(logicalLeft);
int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
// If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
// applied to the right, so this is not an issue with left overflow.
int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing());
- rightLayoutOverflow = max(xPos + text->logicalWidth() - letterSpacing, rightLayoutOverflow);
+ logicalRightLayoutOverflow = max(logicalLeft + text->logicalWidth() - letterSpacing, logicalRightLayoutOverflow);
GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr));
GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second;
- int leftGlyphOverflow = -strokeOverflow - (glyphOverflow ? glyphOverflow->left : 0);
- int rightGlyphOverflow = strokeOverflow - letterSpacing + (glyphOverflow ? glyphOverflow->right : 0);
+ int logicalLeftGlyphOverflow = -strokeOverflow - (glyphOverflow ? glyphOverflow->left : 0);
+ int logicalRightGlyphOverflow = strokeOverflow - letterSpacing + (glyphOverflow ? glyphOverflow->right : 0);
- int childOverflowLeft = leftGlyphOverflow;
- int childOverflowRight = rightGlyphOverflow;
- for (const ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next()) {
- childOverflowLeft = min(childOverflowLeft, shadow->x() - shadow->blur() + leftGlyphOverflow);
- childOverflowRight = max(childOverflowRight, shadow->x() + shadow->blur() + rightGlyphOverflow);
- }
-
- leftVisualOverflow = min(xPos + childOverflowLeft, leftVisualOverflow);
- rightVisualOverflow = max(xPos + text->logicalWidth() + childOverflowRight, rightVisualOverflow);
+ int childOverflowLogicalLeft = logicalLeftGlyphOverflow;
+ int childOverflowLogicalRight = logicalRightGlyphOverflow;
+ int textShadowLogicalLeft;
+ int textShadowLogicalRight;
+ rt->style(m_firstLine)->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
+ childOverflowLogicalLeft = min(childOverflowLogicalLeft, textShadowLogicalLeft);
+ childOverflowLogicalRight = max(childOverflowLogicalRight, textShadowLogicalRight);
+ logicalLeftVisualOverflow = min(logicalLeft + childOverflowLogicalLeft, logicalLeftVisualOverflow);
+ logicalRightVisualOverflow = max(logicalLeft + text->logicalWidth() + childOverflowLogicalRight, logicalRightVisualOverflow);
- xPos += text->logicalWidth();
+ logicalLeft += text->logicalWidth();
} else {
if (curr->renderer()->isPositioned()) {
- if (curr->renderer()->parent()->style()->direction() == LTR)
- curr->setX(xPos);
+ if (curr->renderer()->parent()->style()->isLeftToRightDirection())
+ curr->setLogicalLeft(logicalLeft);
else
// Our offset that we cache needs to be from the edge of the right border box and
// not the left border box. We have to subtract |x| from the width of the block
// (which can be obtained from the root line box).
- curr->setX(root()->block()->width() - xPos);
+ curr->setLogicalLeft(root()->block()->logicalWidth() - logicalLeft);
continue; // The positioned object has no effect on the width.
}
if (curr->renderer()->isRenderInline()) {
InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
- xPos += flow->marginLogicalLeft();
- xPos = flow->placeBoxesInInlineDirection(xPos, needsWordSpacing, textBoxDataMap);
- xPos += flow->marginLogicalRight();
- leftLayoutOverflow = min(leftLayoutOverflow, flow->leftLayoutOverflow());
- rightLayoutOverflow = max(rightLayoutOverflow, flow->rightLayoutOverflow());
- leftVisualOverflow = min(leftVisualOverflow, flow->leftVisualOverflow());
- rightVisualOverflow = max(rightVisualOverflow, flow->rightVisualOverflow());
+ logicalLeft += flow->marginLogicalLeft();
+ logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
+ logicalLeft += flow->marginLogicalRight();
+ logicalLeftLayoutOverflow = min(logicalLeftLayoutOverflow, flow->logicalLeftLayoutOverflow());
+ logicalRightLayoutOverflow = max(logicalRightLayoutOverflow, flow->logicalRightLayoutOverflow());
+ logicalLeftVisualOverflow = min(logicalLeftVisualOverflow, flow->logicalLeftVisualOverflow());
+ logicalRightVisualOverflow = max(logicalRightVisualOverflow, flow->logicalRightVisualOverflow());
} else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
- xPos += curr->boxModelObject()->marginLeft();
- curr->setX(xPos);
-
+ // The box can have a different writing-mode than the overall line, so this is a bit complicated.
+ // Just get all the physical margin and overflow values by hand based off |isVertical|.
+ int logicalLeftMargin = !isVertical() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop();
+ int logicalRightMargin = !isVertical() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom();
+
+ logicalLeft += logicalLeftMargin;
+ curr->setLogicalLeft(logicalLeft);
+
RenderBox* box = toRenderBox(curr->renderer());
- int childLeftOverflow = box->hasOverflowClip() ? 0 : box->leftLayoutOverflow();
- int childRightOverflow = box->hasOverflowClip() ? curr->logicalWidth() : box->rightLayoutOverflow();
+
+ int childOverflowLogicalLeft = box->hasOverflowClip() ? 0 : (!isVertical() ? box->leftLayoutOverflow() : box->topLayoutOverflow());
+ int childOverflowLogicalRight = box->hasOverflowClip() ? curr->logicalWidth() : (!isVertical() ? box->rightLayoutOverflow() : box->bottomLayoutOverflow());
- leftLayoutOverflow = min(xPos + childLeftOverflow, leftLayoutOverflow);
- rightLayoutOverflow = max(xPos + childRightOverflow, rightLayoutOverflow);
+ logicalLeftLayoutOverflow = min(logicalLeft + childOverflowLogicalLeft, logicalLeftLayoutOverflow);
+ logicalRightLayoutOverflow = max(logicalLeft + childOverflowLogicalRight, logicalRightLayoutOverflow);
- leftVisualOverflow = min(xPos + box->leftVisualOverflow(), leftVisualOverflow);
- rightVisualOverflow = max(xPos + box->rightVisualOverflow(), rightVisualOverflow);
+ logicalLeftVisualOverflow = min(logicalLeft + (!isVertical() ? box->leftVisualOverflow() : box->topVisualOverflow()), logicalLeftVisualOverflow);
+ logicalRightVisualOverflow = max(logicalLeft + (!isVertical() ? box->rightVisualOverflow() : box->bottomVisualOverflow()), logicalRightVisualOverflow);
- xPos += curr->logicalWidth() + curr->boxModelObject()->marginRight();
+ logicalLeft += curr->logicalWidth() + logicalRightMargin;
}
}
}
- xPos += borderLogicalRight() + paddingLogicalRight();
- setLogicalWidth(xPos - startX);
- rightVisualOverflow = max(x() + logicalWidth() + boxShadowRight, rightVisualOverflow);
- rightLayoutOverflow = max(x() + logicalWidth(), rightLayoutOverflow);
+ logicalLeft += borderLogicalRight() + paddingLogicalRight();
+ setLogicalWidth(logicalLeft - startLogicalLeft);
+ logicalRightVisualOverflow = max(logicalLeft + boxShadowLogicalRight, logicalRightVisualOverflow);
+ logicalRightLayoutOverflow = max(logicalLeft, logicalRightLayoutOverflow);
- setInlineDirectionOverflowPositions(leftLayoutOverflow, rightLayoutOverflow, leftVisualOverflow, rightVisualOverflow);
- return xPos;
+ setInlineDirectionOverflowPositions(logicalLeftLayoutOverflow, logicalRightLayoutOverflow, logicalLeftVisualOverflow, logicalRightVisualOverflow);
+ return logicalLeft;
}
void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
@@ -363,9 +367,9 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
// positioned elements
if (curr->renderer()->isPositioned())
continue; // Positioned placeholders don't affect calculations.
- if (curr->y() == PositionTop || curr->y() == PositionBottom) {
- int lineHeight = curr->lineHeight(false);
- if (curr->y() == PositionTop) {
+ if (curr->logicalTop() == PositionTop || curr->logicalTop() == PositionBottom) {
+ int lineHeight = curr->lineHeight();
+ if (curr->logicalTop() == PositionTop) {
if (maxAscent + maxDescent < lineHeight)
maxDescent = lineHeight - maxAscent;
}
@@ -386,7 +390,7 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
static int verticalPositionForBox(InlineBox* curr, bool firstLine)
{
if (curr->renderer()->isText())
- return curr->parent()->y();
+ return curr->parent()->logicalTop();
if (curr->renderer()->isBox())
return toRenderBox(curr->renderer())->verticalPosition(firstLine);
return toRenderInline(curr->renderer())->verticalPositionFromCache(firstLine);
@@ -397,8 +401,8 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
{
if (isRootInlineBox()) {
// Examine our root box.
- int height = lineHeight(true);
- int baseline = baselinePosition(true);
+ int height = lineHeight();
+ int baseline = baselinePosition();
if (hasTextChildren() || strictMode) {
int ascent = baseline;
int descent = height - ascent;
@@ -451,19 +455,19 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
}
} else {
- lineHeight = curr->lineHeight(false);
- baseline = curr->baselinePosition(false);
+ lineHeight = curr->lineHeight();
+ baseline = curr->baselinePosition();
}
- curr->setY(verticalPositionForBox(curr, m_firstLine));
- if (curr->y() == PositionTop) {
+ curr->setLogicalTop(verticalPositionForBox(curr, m_firstLine));
+ if (curr->logicalTop() == PositionTop) {
if (maxPositionTop < lineHeight)
maxPositionTop = lineHeight;
- } else if (curr->y() == PositionBottom) {
+ } else if (curr->logicalTop() == PositionBottom) {
if (maxPositionBottom < lineHeight)
maxPositionBottom = lineHeight;
- } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasHorizontalBordersOrPadding() || strictMode) {
- int ascent = baseline - curr->y();
+ } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasInlineDirectionBordersOrPadding() || strictMode) {
+ int ascent = baseline - curr->logicalTop();
int descent = lineHeight - ascent;
if (maxAscent < ascent)
maxAscent = ascent;
@@ -476,10 +480,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
}
-void InlineFlowBox::placeBoxesInBlockDirection(int yPos, int maxHeight, int maxAscent, bool strictMode, int& selectionTop, int& selectionBottom)
+void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom)
{
if (isRootInlineBox())
- setY(yPos + maxAscent - baselinePosition(true)); // Place our root box.
+ setLogicalTop(top + maxAscent - baselinePosition()); // Place our root box.
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isPositioned())
@@ -489,47 +493,70 @@ void InlineFlowBox::placeBoxesInBlockDirection(int yPos, int maxHeight, int maxA
// line-height).
bool isInlineFlow = curr->isInlineFlowBox();
if (isInlineFlow)
- static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(yPos, maxHeight, maxAscent, strictMode, selectionTop, selectionBottom);
+ static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom);
bool childAffectsTopBottomPos = true;
- if (curr->y() == PositionTop)
- curr->setY(yPos);
- else if (curr->y() == PositionBottom)
- curr->setY(yPos + maxHeight - curr->lineHeight(false));
+ if (curr->logicalTop() == PositionTop)
+ curr->setLogicalTop(top);
+ else if (curr->logicalTop() == PositionBottom)
+ curr->setLogicalTop(top + maxHeight - curr->lineHeight());
else {
- if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode)
+ if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() && !strictMode)
childAffectsTopBottomPos = false;
- int posAdjust = maxAscent - curr->baselinePosition(false);
- curr->setY(curr->y() + yPos + posAdjust);
+ int posAdjust = maxAscent - curr->baselinePosition();
+ curr->setLogicalTop(curr->logicalTop() + top + posAdjust);
}
- int newY = curr->y();
+ int newLogicalTop = curr->logicalTop();
if (curr->isText() || curr->isInlineFlowBox()) {
const Font& font = curr->renderer()->style(m_firstLine)->font();
- newY += curr->baselinePosition(false) - font.ascent();
- if (curr->isInlineFlowBox())
- newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop();
+ newLogicalTop += curr->baselinePosition() - font.ascent();
+ if (curr->isInlineFlowBox()) {
+ RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer());
+ newLogicalTop -= boxObject->style(m_firstLine)->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() :
+ boxObject->borderRight() + boxObject->paddingRight();
+ }
} else if (!curr->renderer()->isBR()) {
RenderBox* box = toRenderBox(curr->renderer());
- newY += box->marginTop();
+ newLogicalTop += box->style(m_firstLine)->isHorizontalWritingMode() ? box->marginTop() : box->marginRight();
}
- curr->setY(newY);
+ curr->setLogicalTop(newLogicalTop);
if (childAffectsTopBottomPos) {
int boxHeight = curr->logicalHeight();
- selectionTop = min(selectionTop, newY);
- selectionBottom = max(selectionBottom, newY + boxHeight);
+ lineTop = min(lineTop, newLogicalTop);
+ lineBottom = max(lineBottom, newLogicalTop + boxHeight);
}
}
if (isRootInlineBox()) {
const Font& font = renderer()->style(m_firstLine)->font();
- setY(y() + baselinePosition(true) - font.ascent());
+ setLogicalTop(logicalTop() + baselinePosition() - font.ascent());
+
if (hasTextChildren() || strictMode) {
- selectionTop = min(selectionTop, y());
- selectionBottom = max(selectionBottom, y() + logicalHeight());
+ lineTop = min(lineTop, logicalTop());
+ lineBottom = max(lineBottom, logicalTop() + logicalHeight());
}
+
+ if (renderer()->style()->isFlippedLinesWritingMode())
+ flipLinesInBlockDirection(lineTop, lineBottom);
+ }
+}
+
+void InlineFlowBox::flipLinesInBlockDirection(int lineTop, int lineBottom)
+{
+ // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop.
+ setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight());
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->renderer()->isPositioned())
+ continue; // Positioned placeholders aren't affected here.
+
+ if (curr->isInlineFlowBox())
+ static_cast<InlineFlowBox*>(curr)->flipLinesInBlockDirection(lineTop, lineBottom);
+ else
+ curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight());
}
}
@@ -612,7 +639,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
{
IntRect overflowRect(visibleOverflowRect());
overflowRect.move(tx, ty);
- if (!overflowRect.intersects(result.rectFromPoint(x, y)))
+ if (!overflowRect.intersects(result.rectForPoint(x, y)))
return false;
// Check children first.
@@ -625,7 +652,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
// Now check ourselves.
IntRect rect(tx + m_x, ty + m_y, m_logicalWidth, logicalHeight());
- if (visibleToHitTesting() && rect.intersects(result.rectFromPoint(x, y))) {
+ if (visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space.
if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
return true;
@@ -758,16 +785,18 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
int x = m_x;
int y = m_y;
- int w = logicalWidth();
- int h = logicalHeight();
+ int w = m_isVertical ? logicalHeight() : logicalWidth();
+ int h = m_isVertical ? logicalWidth() : logicalHeight();
// Constrain our background/border painting to the line top and bottom if necessary.
bool noQuirksMode = renderer()->document()->inNoQuirksMode();
if (!hasTextChildren() && !noQuirksMode) {
RootInlineBox* rootBox = root();
- int bottom = min(rootBox->lineBottom(), y + h);
- y = max(rootBox->lineTop(), y);
- h = bottom - y;
+ int& top = m_isVertical ? x : y;
+ int& logicalHeight = m_isVertical ? w : h;
+ int bottom = min(rootBox->lineBottom(), top + logicalHeight);
+ top = max(rootBox->lineTop(), top);
+ logicalHeight = bottom - top;
}
// Move x/y to our coordinates.
@@ -834,16 +863,18 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
int x = m_x;
int y = m_y;
- int w = logicalWidth();
- int h = logicalHeight();
+ int w = m_isVertical ? logicalHeight() : logicalWidth();
+ int h = m_isVertical ? logicalWidth() : logicalHeight();
// Constrain our background/border painting to the line top and bottom if necessary.
bool noQuirksMode = renderer()->document()->inNoQuirksMode();
if (!hasTextChildren() && !noQuirksMode) {
RootInlineBox* rootBox = root();
- int bottom = min(rootBox->lineBottom(), y + h);
- y = max(rootBox->lineTop(), y);
- h = bottom - y;
+ int& top = m_isVertical ? x : y;
+ int& logicalHeight = m_isVertical ? w : h;
+ int bottom = min(rootBox->lineBottom(), top + logicalHeight);
+ top = max(rootBox->lineTop(), top);
+ logicalHeight = bottom - top;
}
// Move x/y to our coordinates.
@@ -945,7 +976,7 @@ void InlineFlowBox::paintTextDecorations(PaintInfo& paintInfo, int tx, int ty, b
if (rootLine->ellipsisBox()) {
int ellipsisX = m_x + rootLine->ellipsisBox()->x();
int ellipsisWidth = rootLine->ellipsisBox()->logicalWidth();
- bool ltr = renderer()->style()->direction() == LTR;
+ bool ltr = renderer()->style()->isLeftToRightDirection();
if (rootLine == this) {
// Trim w and x so that the underline isn't drawn underneath the ellipsis.
// ltr: is our right edge farther right than the right edge of the ellipsis.
diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h
index 2d57cca..ee16a0f 100644
--- a/WebCore/rendering/InlineFlowBox.h
+++ b/WebCore/rendering/InlineFlowBox.h
@@ -154,12 +154,13 @@ public:
void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject);
int getFlowSpacingLogicalWidth();
bool onEndChain(RenderObject* endObject);
- int placeBoxesInInlineDirection(int x, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
+ int placeBoxesInInlineDirection(int logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
int& maxAscent, int& maxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap&);
void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
int maxPositionTop, int maxPositionBottom);
- void placeBoxesInBlockDirection(int y, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom);
+ void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom);
+ void flipLinesInBlockDirection(int lineTop, int lineBottom);
void computeBlockDirectionOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap&);
void removeChild(InlineBox* child);
@@ -185,15 +186,21 @@ public:
int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : m_x; }
int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : m_x + m_logicalWidth; }
IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : IntRect(m_x, m_y, m_logicalWidth, logicalHeight()); }
-
+ int logicalLeftLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? leftLayoutOverflow() : topLayoutOverflow(); }
+ int logicalRightLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? rightLayoutOverflow() : bottomLayoutOverflow(); }
+
int topVisualOverflow() const { return m_overflow ? m_overflow->topVisualOverflow() : m_y; }
int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : m_y + logicalHeight(); }
int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : m_x; }
int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : m_x + m_logicalWidth; }
IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : IntRect(m_x, m_y, m_logicalWidth, logicalHeight()); }
-
- void setInlineDirectionOverflowPositions(int leftLayoutOverflow, int rightLayoutOverflow, int leftVisualOverflow, int rightVisualOverflow);
- void setBlockDirectionOverflowPositions(int topLayoutOverflow, int bottomLayoutOverflow, int topVisualOverflow, int bottomVisualOverflow, int boxHeight);
+ int logicalLeftVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? leftVisualOverflow() : topVisualOverflow(); }
+ int logicalRightVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? rightVisualOverflow() : bottomVisualOverflow(); }
+
+ void setInlineDirectionOverflowPositions(int logicalLeftLayoutOverflow, int logicalRightLayoutOverflow,
+ int logicalLeftVisualOverflow, int logicalRightVisualOverflow);
+ void setBlockDirectionOverflowPositions(int logicalTopLayoutOverflow, int logicalBottomLayoutOverflow,
+ int logicalTopVisualOverflow, int logicalBottomVisualOverflow, int boxLogicalHeight);
protected:
OwnPtr<RenderOverflow> m_overflow;
@@ -215,18 +222,31 @@ protected:
#endif
};
-inline void InlineFlowBox::setInlineDirectionOverflowPositions(int leftLayoutOverflow, int rightLayoutOverflow, int leftVisualOverflow, int rightVisualOverflow)
+inline void InlineFlowBox::setInlineDirectionOverflowPositions(int logicalLeftLayoutOverflow, int logicalRightLayoutOverflow,
+ int logicalLeftVisualOverflow, int logicalRightVisualOverflow)
{
if (!m_overflow) {
- if (leftLayoutOverflow == m_x && rightLayoutOverflow == m_x + m_logicalWidth && leftVisualOverflow == m_x && rightVisualOverflow == m_x + m_logicalWidth)
+ if (logicalLeftLayoutOverflow == logicalLeft() && logicalRightLayoutOverflow == logicalRight()
+ && logicalLeftVisualOverflow == logicalLeft() && logicalRightVisualOverflow == logicalRight())
return;
- m_overflow = adoptPtr(new RenderOverflow(IntRect(m_x, m_y, m_logicalWidth, m_renderer->style(m_firstLine)->font().height())));
+
+ int width = isVertical() ? m_renderer->style(m_firstLine)->font().height() : logicalWidth();
+ int height = isVertical() ? logicalWidth() : m_renderer->style(m_firstLine)->font().height();
+
+ m_overflow = adoptPtr(new RenderOverflow(IntRect(m_x, m_y, width, height)));
}
- m_overflow->setLeftLayoutOverflow(leftLayoutOverflow);
- m_overflow->setRightLayoutOverflow(rightLayoutOverflow);
- m_overflow->setLeftVisualOverflow(leftVisualOverflow);
- m_overflow->setRightVisualOverflow(rightVisualOverflow);
+ if (isVertical()) {
+ m_overflow->setTopLayoutOverflow(logicalLeftLayoutOverflow);
+ m_overflow->setBottomLayoutOverflow(logicalRightLayoutOverflow);
+ m_overflow->setTopVisualOverflow(logicalLeftVisualOverflow);
+ m_overflow->setBottomVisualOverflow(logicalRightVisualOverflow);
+ } else {
+ m_overflow->setLeftLayoutOverflow(logicalLeftLayoutOverflow);
+ m_overflow->setRightLayoutOverflow(logicalRightLayoutOverflow);
+ m_overflow->setLeftVisualOverflow(logicalLeftVisualOverflow);
+ m_overflow->setRightVisualOverflow(logicalRightVisualOverflow);
+ }
}
inline void InlineFlowBox::setBlockDirectionOverflowPositions(int topLayoutOverflow, int bottomLayoutOverflow, int topVisualOverflow, int bottomVisualOverflow, int boxHeight)
diff --git a/WebCore/rendering/InlineIterator.h b/WebCore/rendering/InlineIterator.h
index 9310ea8..270364f 100644
--- a/WebCore/rendering/InlineIterator.h
+++ b/WebCore/rendering/InlineIterator.h
@@ -53,7 +53,7 @@ public:
bool atEnd() const;
UChar current() const;
- WTF::Unicode::Direction direction() const;
+ ALWAYS_INLINE WTF::Unicode::Direction direction() const;
RenderBlock* block;
RenderObject* obj;
@@ -220,7 +220,7 @@ ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
return WTF::Unicode::direction(c);
if (obj && obj->isListMarker())
- return obj->style()->direction() == LTR ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+ return obj->style()->isLeftToRightDirection() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
return WTF::Unicode::OtherNeutral;
}
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index 68bff3c..cf100e0 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -43,6 +43,22 @@ using namespace std;
namespace WebCore {
+int InlineTextBox::baselinePosition() const
+{
+ if (!isText() || !parent())
+ return 0;
+ return parent()->baselinePosition();
+}
+
+int InlineTextBox::lineHeight() const
+{
+ if (!isText() || !parent())
+ return 0;
+ if (m_renderer->isBR())
+ return toRenderBR(m_renderer)->lineHeight(m_firstLine);
+ return parent()->lineHeight();
+}
+
int InlineTextBox::selectionTop()
{
return root()->selectionTop();
@@ -137,7 +153,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
ePos = len;
}
- IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
+ IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride),
IntPoint(tx + m_x, ty + selTop), selHeight, sPos, ePos));
if (r.x() > tx + m_x + m_logicalWidth)
r.setWidth(0);
@@ -198,7 +214,7 @@ int InlineTextBox::placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int vis
// The inline box may have different directionality than it's parent. Since truncation
// behavior depends both on both the parent and the inline block's directionality, we
// must keep track of these separately.
- bool ltr = direction() == LTR;
+ bool ltr = isLeftToRightDirection();
if (ltr != flowIsLTR) {
// Width in pixels of the visible portion of the box, excluding the ellipsis.
int visibleBoxWidth = visibleRightEdge - visibleLeftEdge - ellipsisWidth;
@@ -287,7 +303,7 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in
return false;
IntRect rect(tx + m_x, ty + m_y, m_logicalWidth, logicalHeight());
- if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.intersects(result.rectFromPoint(x, y))) {
+ if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
return true;
@@ -382,8 +398,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
return;
if (m_truncation != cNoTruncation) {
- TextDirection flowDirection = renderer()->containingBlock()->style()->direction();
- if (flowDirection != direction()) {
+ if (renderer()->containingBlock()->style()->isLeftToRightDirection() != isLeftToRightDirection()) {
// Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin
// at which we start drawing text.
// e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is:
@@ -395,7 +410,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
int widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine);
int widthOfHiddenText = m_logicalWidth - widthOfVisibleText;
// FIXME: The hit testing logic also needs to take this translation int account.
- tx += direction() == LTR ? widthOfHiddenText : -widthOfHiddenText;
+ tx += isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText;
}
}
@@ -504,7 +519,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
int baseline = renderer()->style(m_firstLine)->font().ascent();
IntPoint textOrigin(m_x + tx, m_y + ty + baseline);
- TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered());
+ TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered());
int sPos = 0;
int ePos = 0;
@@ -635,7 +650,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren
context->clip(IntRect(m_x + tx, y + ty, m_logicalWidth, h));
context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd,
- direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos);
context->restore();
}
@@ -658,7 +673,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx,
int y = selectionTop();
int h = selectionHeight();
context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd,
- direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos);
context->restore();
}
@@ -694,7 +709,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
int width = m_logicalWidth;
if (m_truncation != cNoTruncation) {
width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine);
- if (direction() == RTL)
+ if (!isLeftToRightDirection())
tx += (m_logicalWidth - width);
}
@@ -813,7 +828,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
// Calculate start & width
IntPoint startPoint(tx + m_x, ty + selectionTop());
- TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
int h = selectionHeight();
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, startPosition, endPosition));
@@ -858,7 +873,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, co
int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
- TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
// Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(m_x, y), h, sPos, ePos));
@@ -886,7 +901,7 @@ void InlineTextBox::computeRectForReplacementMarker(int /*tx*/, int /*ty*/, cons
int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
- TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
IntPoint startPoint = IntPoint(m_x, y);
// Compute and store the rect associated with this marker.
@@ -1031,7 +1046,7 @@ int InlineTextBox::textPos() const
return 0;
RenderBlock* blockElement = renderer()->containingBlock();
- return direction() == RTL ? x() - blockElement->borderRight() - blockElement->paddingRight()
+ return !isLeftToRightDirection() ? x() - blockElement->borderRight() - blockElement->paddingRight()
: x() - blockElement->borderLeft() - blockElement->paddingLeft();
}
@@ -1043,7 +1058,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
RenderText* text = toRenderText(renderer());
RenderStyle* style = text->style(m_firstLine);
const Font* f = &style->font();
- return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
_x - m_x, includePartialGlyphs);
}
@@ -1057,10 +1072,10 @@ int InlineTextBox::positionForOffset(int offset) const
RenderText* text = toRenderText(renderer());
const Font& f = text->style(m_firstLine)->font();
- int from = direction() == RTL ? offset - m_start : 0;
- int to = direction() == RTL ? m_len : offset - m_start;
+ int from = !isLeftToRightDirection() ? offset - m_start : 0;
+ int to = !isLeftToRightDirection() ? m_len : offset - m_start;
// FIXME: Do we need to add rightBearing here?
- return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
+ return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride),
IntPoint(m_x, 0), 0, from, to)).right();
}
diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h
index 2bf099b..f010c39 100644
--- a/WebCore/rendering/InlineTextBox.h
+++ b/WebCore/rendering/InlineTextBox.h
@@ -69,6 +69,10 @@ public:
void setHasHyphen(bool hasHyphen) { m_hasEllipsisBoxOrHyphen = hasHyphen; }
static inline bool compareByStart(const InlineTextBox* first, const InlineTextBox* second) { return first->start() < second->start(); }
+
+ virtual int baselinePosition() const;
+ virtual int lineHeight() const;
+
private:
virtual int selectionTop();
virtual int selectionHeight();
@@ -78,7 +82,7 @@ public:
virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos);
bool isSelected(int startPos, int endPos) const;
- virtual void selectionStartEnd(int& sPos, int& ePos);
+ void selectionStartEnd(int& sPos, int& ePos);
protected:
virtual void paint(PaintInfo&, int tx, int ty);
diff --git a/WebCore/rendering/LayoutState.cpp b/WebCore/rendering/LayoutState.cpp
index 0d81b15..3eea51f 100644
--- a/WebCore/rendering/LayoutState.cpp
+++ b/WebCore/rendering/LayoutState.cpp
@@ -34,7 +34,7 @@
namespace WebCore {
-LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset, int pageHeight, ColumnInfo* columnInfo)
+LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset, int pageHeight, bool pageHeightChanged, ColumnInfo* columnInfo)
: m_columnInfo(columnInfo)
, m_next(prev)
#ifndef NDEBUG
@@ -86,9 +86,11 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize&
m_pageHeight = pageHeight;
m_pageOffset = IntSize(m_layoutOffset.width() + renderer->borderLeft() + renderer->paddingLeft(),
m_layoutOffset.height() + renderer->borderTop() + renderer->paddingTop());
+ m_pageHeightChanged = pageHeightChanged;
} else {
// If we don't establish a new page height, then propagate the old page height and offset down.
m_pageHeight = m_next->m_pageHeight;
+ m_pageHeightChanged = m_next->m_pageHeightChanged;
m_pageOffset = m_next->m_pageOffset;
// Disable pagination for objects we don't support. For now this includes overflow:scroll/auto and inline blocks.
@@ -107,6 +109,7 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize&
LayoutState::LayoutState(RenderObject* root)
: m_clipped(false)
, m_pageHeight(0)
+ , m_pageHeightChanged(false)
, m_columnInfo(0)
, m_next(0)
#ifndef NDEBUG
diff --git a/WebCore/rendering/LayoutState.h b/WebCore/rendering/LayoutState.h
index ca4cbfb..cca3e42 100644
--- a/WebCore/rendering/LayoutState.h
+++ b/WebCore/rendering/LayoutState.h
@@ -42,6 +42,7 @@ public:
LayoutState()
: m_clipped(false)
, m_pageHeight(0)
+ , m_pageHeightChanged(false)
, m_columnInfo(0)
, m_next(0)
#ifndef NDEBUG
@@ -50,7 +51,7 @@ public:
{
}
- LayoutState(LayoutState*, RenderBox*, const IntSize& offset, int pageHeight, ColumnInfo*);
+ LayoutState(LayoutState*, RenderBox*, const IntSize& offset, int pageHeight, bool pageHeightChanged, ColumnInfo*);
LayoutState(RenderObject*);
void destroy(RenderArena*);
@@ -67,6 +68,9 @@ public:
int pageY(int childY) const;
void addForcedColumnBreak(int childY);
+ bool pageHeight() const { return m_pageHeight; }
+ bool pageHeightChanged() const { return m_pageHeightChanged; }
+
private:
// The normal operator new is disallowed.
void* operator new(size_t) throw();
@@ -81,6 +85,7 @@ public:
// This is a total delta accumulated from the root.
int m_pageHeight; // The current page height for the pagination model that encloses us.
+ bool m_pageHeightChanged; // If our page height has changed, this will force all blocks to relayout.
IntSize m_pageOffset; // The offset of the start of the first page in the nearest enclosing pagination model.
ColumnInfo* m_columnInfo; // If the enclosing pagination model is a column model, then this will store column information for easy retrieval/manipulation.
diff --git a/WebCore/rendering/RenderApplet.cpp b/WebCore/rendering/RenderApplet.cpp
index 63a18a0..f9eb56e 100644
--- a/WebCore/rendering/RenderApplet.cpp
+++ b/WebCore/rendering/RenderApplet.cpp
@@ -39,6 +39,10 @@ RenderApplet::RenderApplet(HTMLAppletElement* applet, const HashMap<String, Stri
setInline(true);
}
+RenderApplet::~RenderApplet()
+{
+}
+
IntSize RenderApplet::intrinsicSize() const
{
// FIXME: This doesn't make sense. We can't just start returning
diff --git a/WebCore/rendering/RenderApplet.h b/WebCore/rendering/RenderApplet.h
index 62f46cd..641568d 100644
--- a/WebCore/rendering/RenderApplet.h
+++ b/WebCore/rendering/RenderApplet.h
@@ -32,6 +32,7 @@ namespace WebCore {
class RenderApplet : public RenderWidget {
public:
RenderApplet(HTMLAppletElement*, const HashMap<String, String>& args);
+ virtual ~RenderApplet();
void createWidgetIfNecessary();
diff --git a/WebCore/rendering/RenderBR.cpp b/WebCore/rendering/RenderBR.cpp
index 340d6b7..fb136a4 100644
--- a/WebCore/rendering/RenderBR.cpp
+++ b/WebCore/rendering/RenderBR.cpp
@@ -38,36 +38,17 @@ RenderBR::~RenderBR()
{
}
-int RenderBR::baselinePosition(bool firstLine, bool isRootLineBox) const
+int RenderBR::lineHeight(bool firstLine) const
{
- if (firstTextBox() && !firstTextBox()->isText())
- return 0;
- return RenderText::baselinePosition(firstLine, isRootLineBox);
-}
-
-int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
-{
- if (firstTextBox() && !firstTextBox()->isText())
- return 0;
-
- if (firstLine) {
+ if (firstLine && document()->usesFirstLineRules()) {
RenderStyle* s = style(firstLine);
- Length lh = s->lineHeight();
- if (lh.isNegative()) {
- if (s == style()) {
- if (m_lineHeight == -1)
- m_lineHeight = RenderObject::lineHeight(false);
- return m_lineHeight;
- }
- return s->font().lineSpacing();
- }
- if (lh.isPercent())
- return lh.calcMinValue(s->fontSize());
- return lh.value();
+ if (s != style())
+ return s->computedLineHeight();
}
-
+
if (m_lineHeight == -1)
- m_lineHeight = RenderObject::lineHeight(false);
+ m_lineHeight = style()->computedLineHeight();
+
return m_lineHeight;
}
diff --git a/WebCore/rendering/RenderBR.h b/WebCore/rendering/RenderBR.h
index 8850d46..7216b5a 100644
--- a/WebCore/rendering/RenderBR.h
+++ b/WebCore/rendering/RenderBR.h
@@ -43,8 +43,7 @@ public:
virtual unsigned width(unsigned /*from*/, unsigned /*len*/, const Font&, int /*xpos*/) const { return 0; }
virtual unsigned width(unsigned /*from*/, unsigned /*len*/, int /*xpos*/, bool /*firstLine = false*/) const { return 0; }
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
- virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+ int lineHeight(bool firstLine) const;
// overrides
virtual bool isBR() const { return true; }
@@ -62,6 +61,22 @@ private:
mutable int m_lineHeight;
};
+
+inline RenderBR* toRenderBR(RenderObject* object)
+{
+ ASSERT(!object || object->isBR());
+ return static_cast<RenderBR*>(object);
+}
+
+inline const RenderBR* toRenderBR(const RenderObject* object)
+{
+ ASSERT(!object || object->isBR());
+ return static_cast<const RenderBR*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderBR(const RenderBR*);
+
} // namespace WebCore
#endif // RenderBR_h
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 1e378d8..d951277 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -94,7 +94,7 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding,
// we're positioned, floating, a table cell.
m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
&& !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
- && !block->isBlockFlowRoot();
+ && !block->isWritingModeRoot();
m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE;
@@ -108,8 +108,8 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding,
m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD ||
block->style()->marginAfterCollapse() == MDISCARD;
- m_posMargin = m_canCollapseMarginBeforeWithChildren ? block->maxMarginBefore(RenderBox::PositiveMargin) : 0;
- m_negMargin = m_canCollapseMarginBeforeWithChildren ? block->maxMarginBefore(RenderBox::NegativeMargin) : 0;
+ m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
+ m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
}
// -------------------------------------------------------------------------------------------------------
@@ -1023,24 +1023,25 @@ bool RenderBlock::isSelfCollapsingBlock() const
// (c) have border/padding,
// (d) have a min-height
// (e) have specified that one of our margins can't collapse using a CSS extension
- if (height() > 0
- || isTable() || borderAndPaddingHeight()
- || style()->minHeight().isPositive()
+ if (logicalHeight() > 0
+ || isTable() || borderAndPaddingLogicalHeight()
+ || style()->logicalMinHeight().isPositive()
|| style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
return false;
- bool hasAutoHeight = style()->height().isAuto();
- if (style()->height().isPercent() && !document()->inQuirksMode()) {
+ Length logicalHeightLength = style()->logicalHeight();
+ bool hasAutoHeight = logicalHeightLength.isAuto();
+ if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
hasAutoHeight = true;
for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
- if (cb->style()->height().isFixed() || cb->isTableCell())
+ if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
hasAutoHeight = false;
}
}
// If the height is 0 or auto, then whether or not we are a self-collapsing block depends
// on whether we have content that is all self-collapsing or not.
- if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
+ if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
// If the block has inline children, see if we generated any line boxes. If we have any
// line boxes, then we can't be self-collapsing, since we have content.
if (childrenInline())
@@ -1125,7 +1126,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
- int oldWidth = width();
+ int oldWidth = logicalWidth();
int oldColumnWidth = desiredColumnWidth();
computeLogicalWidth();
@@ -1145,6 +1146,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
int previousHeight = logicalHeight();
setLogicalHeight(0);
bool hasSpecifiedPageHeight = false;
+ bool pageHeightChanged = false;
ColumnInfo* colInfo = columnInfo();
if (hasColumns()) {
if (!pageHeight) {
@@ -1160,14 +1162,14 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
}
if (colInfo->columnHeight() != pageHeight && m_everHadLayout) {
colInfo->setColumnHeight(pageHeight);
- markDescendantBlocksAndLinesForLayout(); // We need to dirty all descendant blocks and lines, since the column height is different now.
+ pageHeightChanged = true;
}
if (!hasSpecifiedPageHeight && !pageHeight)
colInfo->clearForcedBreaks();
}
- LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection(), pageHeight, colInfo);
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection(), pageHeight, pageHeightChanged, colInfo);
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
// our current maximal positive and negative margins. These values are used when we
@@ -1204,20 +1206,20 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
layer()->setHasVerticalScrollbar(true);
}
- int repaintTop = 0;
- int repaintBottom = 0;
- int maxFloatBottom = 0;
+ int repaintLogicalTop = 0;
+ int repaintLogicalBottom = 0;
+ int maxFloatLogicalBottom = 0;
if (!firstChild() && !isAnonymousBlock())
setChildrenInline(true);
if (childrenInline())
- layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
+ layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
else
- layoutBlockChildren(relayoutChildren, maxFloatBottom);
+ layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
// Expand our intrinsic height to encompass floats.
- int toAdd = borderAfter() + paddingAfter() + horizontalScrollbarHeight(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=46645, overflow and block-flow.
- if (floatBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
- setLogicalHeight(floatBottom() + toAdd);
+ int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
+ setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
if (layoutColumns(hasSpecifiedPageHeight, pageHeight, statePusher))
return;
@@ -1227,13 +1229,13 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
computeLogicalHeight();
int newHeight = logicalHeight();
if (oldHeight != newHeight) {
- if (oldHeight > newHeight && maxFloatBottom > newHeight && !childrenInline()) {
+ if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
// One of our children's floats may have become an overhanging float for us. We need to look for it.
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
RenderBlock* block = toRenderBlock(child);
- if (block->floatBottom() + block->logicalTop() > newHeight)
- addOverhangingFloats(block, -block->x(), -block->y(), false);
+ if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
+ addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false);
}
}
}
@@ -1273,10 +1275,15 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
// Repaint with our new bounds if they are different from our old bounds.
bool didFullRepaint = repainter.repaintAfterLayout();
- if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
- int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow());
- int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow());
- IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop);
+ if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
+ int repaintLogicalLeft = min(logicalLeftVisualOverflow(), logicalLeftLayoutOverflow());
+ int repaintLogicalRight = max(logicalRightVisualOverflow(), logicalRightLayoutOverflow());
+
+ IntRect repaintRect;
+ if (style()->isHorizontalWritingMode())
+ repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
+ else
+ repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
// The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
adjustRectForColumns(repaintRect);
@@ -1318,7 +1325,7 @@ void RenderBlock::addOverflowFromFloats()
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for (; (r = it.current()); ++it) {
if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
- addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
+ addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop()));
}
return;
}
@@ -1326,13 +1333,13 @@ void RenderBlock::addOverflowFromFloats()
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox())
- || hasColumns() || isTableCell() || isFieldset() || isBlockFlowRoot();
+ || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot();
}
void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
{
if (child->style()->hasStaticX()) {
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
child->layer()->setStaticX(borderLeft() + paddingLeft());
else
child->layer()->setStaticX(borderRight() + paddingRight());
@@ -1343,8 +1350,8 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
if (!marginInfo.canCollapseWithMarginBefore()) {
child->computeBlockDirectionMargins(this);
int marginTop = child->marginTop();
- int collapsedTopPos = marginInfo.posMargin();
- int collapsedTopNeg = marginInfo.negMargin();
+ int collapsedTopPos = marginInfo.positiveMargin();
+ int collapsedTopNeg = marginInfo.negativeMargin();
if (marginTop > 0) {
if (marginTop > collapsedTopPos)
collapsedTopPos = marginTop;
@@ -1378,9 +1385,9 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
// http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
// an example of this scenario.
int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
- setLogicalHeight(height() + marginOffset);
+ setLogicalHeight(logicalHeight() + marginOffset);
positionNewFloats();
- setLogicalHeight(height() - marginOffset);
+ setLogicalHeight(logicalHeight() - marginOffset);
}
bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
@@ -1474,15 +1481,18 @@ bool RenderBlock::handleRunInChild(RenderBox* child)
int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
{
+ // Get the four margin values for the child and cache them.
+ const MarginValues childMargins = marginValuesForChild(child);
+
// Get our max pos and neg top margins.
- int posTop = child->maxMarginBefore(PositiveMargin);
- int negTop = child->maxMarginBefore(NegativeMargin);
+ int posTop = childMargins.positiveMarginBefore();
+ int negTop = childMargins.negativeMarginBefore();
// For self-collapsing blocks, collapse our bottom margins into our
// top to get new posTop and negTop values.
if (child->isSelfCollapsingBlock()) {
- posTop = max(posTop, child->maxMarginAfter(PositiveMargin));
- negTop = max(negTop, child->maxMarginAfter(NegativeMargin));
+ posTop = max(posTop, childMargins.positiveMarginAfter());
+ negTop = max(negTop, childMargins.negativeMarginAfter());
}
// See if the top margin is quirky. We only care if this child has
@@ -1494,18 +1504,18 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
// block. If it has larger margin values, then we need to update
// our own maximal values.
if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
- setMaxMarginBeforeValues(max(posTop, maxPosMarginBefore()), max(negTop, maxNegMarginBefore()));
+ setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
// The minute any of the margins involved isn't a quirk, don't
// collapse it away, even if the margin is smaller (www.webreference.com
// has an example of this, a <dt> with 0.8em author-specified inside
// a <dl> inside a <td>.
- if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop-negTop)) {
+ if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
setMarginBeforeQuirk(false);
marginInfo.setDeterminedMarginBeforeQuirk(true);
}
- if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && marginTop() == 0)
+ if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
// We have no top margin and our top child has a quirky margin.
// We will pick up this quirky margin and pass it through.
// This deals with the <td><div><p> case.
@@ -1517,44 +1527,44 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
marginInfo.setMarginBeforeQuirk(topQuirk);
- int beforeCollapseY = height();
- int ypos = beforeCollapseY;
+ int beforeCollapseLogicalTop = logicalHeight();
+ int logicalTop = beforeCollapseLogicalTop;
if (child->isSelfCollapsingBlock()) {
// This child has no height. We need to compute our
// position before we collapse the child's margins together,
// so that we can get an accurate position for the zero-height block.
- int collapsedTopPos = max(marginInfo.posMargin(), child->maxMarginBefore(PositiveMargin));
- int collapsedTopNeg = max(marginInfo.negMargin(), child->maxMarginBefore(NegativeMargin));
- marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);
+ int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
+ int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
+ marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
// Now collapse the child's margins together, which means examining our
// bottom margin values as well.
- marginInfo.setPosMarginIfLarger(child->maxMarginAfter(PositiveMargin));
- marginInfo.setNegMarginIfLarger(child->maxMarginAfter(NegativeMargin));
+ marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
if (!marginInfo.canCollapseWithMarginBefore())
// We need to make sure that the position of the self-collapsing block
// is correct, since it could have overflowing content
// that needs to be positioned correctly (e.g., a block that
// had a specified height of 0 but that actually had subcontent).
- ypos = height() + collapsedTopPos - collapsedTopNeg;
+ logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
}
else {
if (child->style()->marginBeforeCollapse() == MSEPARATE) {
- setLogicalHeight(height() + marginInfo.margin() + child->marginTop());
- ypos = height();
+ setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
+ logicalTop = logicalHeight();
}
else if (!marginInfo.atBeforeSideOfBlock() ||
(!marginInfo.canCollapseMarginBeforeWithChildren()
&& (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
// We're collapsing with a previous sibling's margins and not
// with the top of the block.
- setLogicalHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop));
- ypos = height();
+ setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
+ logicalTop = logicalHeight();
}
- marginInfo.setPosMargin(child->maxMarginAfter(PositiveMargin));
- marginInfo.setNegMargin(child->maxMarginAfter(NegativeMargin));
+ marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
if (marginInfo.margin())
marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
@@ -1563,12 +1573,12 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
// If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
// collapsed into the page edge.
bool paginated = view()->layoutState()->isPaginated();
- if (paginated && ypos > beforeCollapseY) {
- int oldY = ypos;
- ypos = min(ypos, nextPageTop(beforeCollapseY));
- setLogicalHeight(height() + (ypos - oldY));
+ if (paginated && logicalTop > beforeCollapseLogicalTop) {
+ int oldLogicalTop = logicalTop;
+ logicalTop = min(logicalTop, nextPageTop(beforeCollapseLogicalTop));
+ setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
}
- return ypos;
+ return logicalTop;
}
int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
@@ -1590,12 +1600,14 @@ int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, i
if (!curr->isFloatingOrPositioned())
atBottomOfBlock = false;
}
+
+ MarginValues childMargins = marginValuesForChild(child);
if (atBottomOfBlock) {
- marginInfo.setPosMargin(child->maxMarginAfter(PositiveMargin));
- marginInfo.setNegMargin(child->maxMarginAfter(NegativeMargin));
+ marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
} else {
- marginInfo.setPosMargin(max(child->maxMarginBefore(PositiveMargin), child->maxMarginAfter(PositiveMargin)));
- marginInfo.setNegMargin(max(child->maxMarginBefore(NegativeMargin), child->maxMarginAfter(NegativeMargin)));
+ marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
+ marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
}
// Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
@@ -1618,89 +1630,68 @@ int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, i
return yPos + heightIncrease;
}
-int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo)
+int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo)
{
// FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
// relayout if there are intruding floats.
- int yPosEstimate = height();
+ int logicalTopEstimate = logicalHeight();
if (!marginInfo.canCollapseWithMarginBefore()) {
- int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginBefore();
- yPosEstimate += max(marginInfo.margin(), childMarginTop);
+ int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
+ logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
}
bool paginated = view()->layoutState()->isPaginated();
- // Adjust yPosEstimate down to the next page if the margins are so large that we don't fit on the current
+ // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
// page.
- if (paginated && yPosEstimate > height())
- yPosEstimate = min(yPosEstimate, nextPageTop(height()));
+ if (paginated && logicalTopEstimate > logicalHeight())
+ logicalTopEstimate = min(logicalTopEstimate, nextPageTop(logicalHeight()));
- yPosEstimate += getClearDelta(child, yPosEstimate);
+ logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
if (paginated) {
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
- yPosEstimate = applyBeforeBreak(child, yPosEstimate);
+ logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
- yPosEstimate = adjustForUnsplittableChild(child, yPosEstimate);
+ logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
if (!child->selfNeedsLayout() && child->isRenderBlock())
- yPosEstimate += toRenderBlock(child)->paginationStrut();
+ logicalTopEstimate += toRenderBlock(child)->paginationStrut();
}
- return yPosEstimate;
+ return logicalTopEstimate;
}
-void RenderBlock::determineHorizontalPosition(RenderBox* child)
+void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
{
- int xPos = borderLeft() + paddingLeft();
- if (style()->direction() == LTR) {
- // Add in our left margin.
- int chPos = xPos + child->marginLeft();
+ int startPosition = borderStart() + paddingStart();
+ int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
+
+ // Add in our start margin.
+ int childMarginStart = marginStartForChild(child);
+ int newPosition = startPosition + childMarginStart;
- // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
- // to shift over as necessary to dodge any floats that might get in the way.
- if (child->avoidsFloats()) {
- int leftOff = logicalLeftOffsetForLine(height(), false);
- if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) {
- if (child->marginLeft() < 0)
- leftOff += child->marginLeft();
- chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
- }
- else if (leftOff != xPos) {
- // The object is shifting right. The object might be centered, so we need to
- // recalculate our horizontal margins. Note that the containing block content
- // width computation will take into account the delta between |leftOff| and |xPos|
- // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
- // function.
- child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(child->y(), false), child->width());
- chPos = leftOff + child->marginLeft();
- }
- }
- view()->addLayoutDelta(IntSize(child->x() - chPos, 0));
- child->setLocation(chPos, child->y());
- } else {
- xPos += availableLogicalWidth();
- int chPos = xPos - (child->width() + child->marginRight());
- if (child->avoidsFloats()) {
- int rightOff = logicalRightOffsetForLine(height(), false);
- if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) {
- if (child->marginRight() < 0)
- rightOff -= child->marginRight();
- chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
- } else if (rightOff != xPos) {
- // The object is shifting left. The object might be centered, so we need to
- // recalculate our horizontal margins. Note that the containing block content
- // width computation will take into account the delta between |rightOff| and |xPos|
- // so that we can just pass the content width in directly to the |computeInlineDirectionMargins|
- // function.
- child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(child->y(), false), child->width());
- chPos = rightOff - child->marginRight() - child->width();
- }
+ // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
+ // to shift over as necessary to dodge any floats that might get in the way.
+ if (child->avoidsFloats()) {
+ int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false);
+ if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
+ if (childMarginStart < 0)
+ startOff += childMarginStart;
+ newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
+ } else if (startOff != startPosition) {
+ // The object is shifting to the "end" side of the block. The object might be centered, so we need to
+ // recalculate our inline direction margins. Note that the containing block content
+ // width computation will take into account the delta between |startOff| and |startPosition|
+ // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
+ // function.
+ child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child));
+ newPosition = startOff + marginStartForChild(child);
}
- view()->addLayoutDelta(IntSize(child->x() - chPos, 0));
- child->setLocation(chPos, child->y());
}
+
+ setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
}
void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
@@ -1708,12 +1699,12 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
// Update our max pos/neg bottom margins, since we collapsed our bottom margins
// with our children.
- setMaxMarginAfterValues(max(maxPosMarginAfter(), marginInfo.posMargin()), max(maxNegMarginAfter(), marginInfo.negMargin()));
+ setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
if (!marginInfo.marginAfterQuirk())
setMarginAfterQuirk(false);
- if (marginInfo.marginAfterQuirk() && marginBottom() == 0)
+ if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
// We have no bottom margin and our last child has a quirky margin.
// We will pick up this quirky margin and pass it through.
// This deals with the <td><div><p> case.
@@ -1721,27 +1712,53 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
}
}
-void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo)
+void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo)
{
marginInfo.setAtAfterSideOfBlock(true);
// If we can't collapse with children then go ahead and add in the bottom margin.
if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
&& (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
- setLogicalHeight(height() + marginInfo.margin());
+ setLogicalHeight(logicalHeight() + marginInfo.margin());
// Now add in our bottom border/padding.
- setLogicalHeight(height() + bottom);
+ setLogicalHeight(logicalHeight() + afterSide);
// Negative margins can cause our height to shrink below our minimal height (border/padding).
// If this happens, ensure that the computed height is increased to the minimal height.
- setLogicalHeight(max(height(), top + bottom));
+ setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
// Update our bottom collapsed margin info.
setCollapsedBottomMargin(marginInfo);
}
-void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom)
+void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta)
+{
+ if (style()->isHorizontalWritingMode()) {
+ if (applyDelta == ApplyLayoutDelta)
+ view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0));
+ child->setX(logicalLeft);
+ } else {
+ if (applyDelta == ApplyLayoutDelta)
+ view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft));
+ child->setY(logicalLeft);
+ }
+}
+
+void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta)
+{
+ if (style()->isHorizontalWritingMode()) {
+ if (applyDelta == ApplyLayoutDelta)
+ view()->addLayoutDelta(IntSize(0, child->y() - logicalTop));
+ child->setY(logicalTop);
+ } else {
+ if (applyDelta == ApplyLayoutDelta)
+ view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0));
+ child->setX(logicalTop);
+ }
+}
+
+void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom)
{
if (gPercentHeightDescendantsMap) {
if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
@@ -1761,20 +1778,22 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
}
}
- int top = borderTop() + paddingTop();
- int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+ int beforeEdge = borderBefore() + paddingBefore();
+ int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
- setLogicalHeight(top);
+ setLogicalHeight(beforeEdge);
// The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
- MarginInfo marginInfo(this, top, bottom);
+ MarginInfo marginInfo(this, beforeEdge, afterEdge);
// Fieldsets need to find their legend and position it inside the border of the object.
// The legend then gets skipped during normal layout.
+ // FIXME: Make fieldsets work with block-flow.
+ // https://bugs.webkit.org/show_bug.cgi?id=46785
RenderObject* legend = layoutLegend(relayoutChildren);
- int previousFloatBottom = 0;
- maxFloatBottom = 0;
+ int previousFloatLogicalBottom = 0;
+ maxFloatLogicalBottom = 0;
RenderBox* next = firstChildBox();
@@ -1788,11 +1807,11 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
// Make sure we layout children if they need it.
// FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
// an auto value. Add a method to determine this, so that we can avoid the relayout.
- if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView()))
+ if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView()))
child->setChildNeedsLayout(true, false);
- // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
- if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent()))
+ // If relayoutChildren is set and the child has percentage padding, we also need to invalidate the child's pref widths.
+ if (relayoutChildren && (child->style()->paddingStart().isPercent() || child->style()->paddingEnd().isPercent()))
child->setPreferredLogicalWidthsDirty(true, false);
// Handle the four types of special elements first. These include positioned content, floating content, compacts and
@@ -1801,63 +1820,64 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
continue;
// Lay out the child.
- layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom);
+ layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
}
// Now do the handling of the bottom of the block, adding in our bottom border/padding and
// determining the correct collapsed bottom margin information.
- handleBottomOfBlock(top, bottom, marginInfo);
+ handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
}
-void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom)
+void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom)
{
- int oldTopPosMargin = maxPosMarginBefore();
- int oldTopNegMargin = maxNegMarginBefore();
+ int oldPosMarginBefore = maxPositiveMarginBefore();
+ int oldNegMarginBefore = maxNegativeMarginBefore();
- // The child is a normal flow object. Compute its vertical margins now.
+ // The child is a normal flow object. Compute the margins we will use for collapsing now.
child->computeBlockDirectionMargins(this);
- // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
+ // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
if (child->style()->marginBeforeCollapse() == MSEPARATE) {
marginInfo.setAtBeforeSideOfBlock(false);
marginInfo.clearMargin();
}
- // Try to guess our correct y position. In most cases this guess will
- // be correct. Only if we're wrong (when we compute the real y position)
+ // Try to guess our correct logical top position. In most cases this guess will
+ // be correct. Only if we're wrong (when we compute the real logical top position)
// will we have to potentially relayout.
- int yPosEstimate = estimateVerticalPosition(child, marginInfo);
+ int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo);
// Cache our old rect so that we can dirty the proper repaint rects if the child moves.
IntRect oldRect(child->x(), child->y() , child->width(), child->height());
+ int oldLogicalTop = logicalTopForChild(child);
+
#ifndef NDEBUG
IntSize oldLayoutDelta = view()->layoutDelta();
#endif
// Go ahead and position the child as though it didn't collapse with the top.
- view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate));
- child->setLocation(child->x(), yPosEstimate);
+ setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
bool markDescendantsWithFloats = false;
- if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
+ if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
markDescendantsWithFloats = true;
else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
// layout.
- int fb = max(previousFloatBottom, floatBottom());
- if (fb > yPosEstimate)
+ int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
+ if (fb > logicalTopEstimate)
markDescendantsWithFloats = true;
}
if (childRenderBlock) {
if (markDescendantsWithFloats)
childRenderBlock->markAllDescendantsWithFloatsForLayout();
- previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom());
+ if (!child->isWritingModeRoot())
+ previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
}
- bool paginated = view()->layoutState()->isPaginated();
- if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight && childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
+ if (!child->needsLayout())
+ child->markForPaginationRelayoutIfNeeded();
bool childHadLayout = child->m_everHadLayout;
bool childNeededLayout = child->needsLayout();
@@ -1869,23 +1889,24 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
// Now determine the correct ypos based off examination of collapsing margin
// values.
- int yBeforeClear = collapseMargins(child, marginInfo);
+ int logicalTopBeforeClear = collapseMargins(child, marginInfo);
// Now check for clear.
- int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
+ int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
+ bool paginated = view()->layoutState()->isPaginated();
if (paginated) {
- int oldY = yAfterClear;
+ int oldTop = logicalTopAfterClear;
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
- yAfterClear = applyBeforeBreak(child, yAfterClear);
+ logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear);
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
- int yBeforeUnsplittableAdjustment = yAfterClear;
- int yAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, yAfterClear);
+ int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear;
+ int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear);
int paginationStrut = 0;
- int unsplittableAdjustmentDelta = yAfterUnsplittableAdjustment - yBeforeUnsplittableAdjustment;
+ int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
if (unsplittableAdjustmentDelta)
paginationStrut = unsplittableAdjustmentDelta;
else if (childRenderBlock && childRenderBlock->paginationStrut())
@@ -1894,26 +1915,25 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
if (paginationStrut) {
// We are willing to propagate out to our parent block as long as we were at the top of the block prior
// to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
- if (atBeforeSideOfBlock && oldY == yBeforeClear && !isPositioned() && !isTableCell()) {
+ if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) {
// FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
// have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
// and pushes to the next page anyway, so not too concerned about it.
- setPaginationStrut(yAfterClear + paginationStrut);
+ setPaginationStrut(logicalTopAfterClear + paginationStrut);
if (childRenderBlock)
childRenderBlock->setPaginationStrut(0);
} else
- yAfterClear += paginationStrut;
+ logicalTopAfterClear += paginationStrut;
}
// Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
- setLogicalHeight(height() + (yAfterClear - oldY));
+ setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop));
}
- view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear));
- child->setLocation(child->x(), yAfterClear);
+ setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
- // Now we have a final y position. See if it really does end up being different from our estimate.
- if (yAfterClear != yPosEstimate) {
+ // Now we have a final top position. See if it really does end up being different from our estimate.
+ if (logicalTopAfterClear != logicalTopEstimate) {
if (child->shrinkToAvoidFloats()) {
// The child's width depends on the line width.
// When the child shifts to clear an item, its width can
@@ -1924,8 +1944,8 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
if (childRenderBlock) {
if (!child->avoidsFloats() && childRenderBlock->containsFloats())
childRenderBlock->markAllDescendantsWithFloatsForLayout();
- if (paginated && !child->needsLayout() && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
+ if (!child->needsLayout())
+ child->markForPaginationRelayoutIfNeeded();
}
// Our guess was wrong. Make the child lay itself out again.
@@ -1937,19 +1957,19 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
marginInfo.setAtBeforeSideOfBlock(false);
- // Now place the child in the correct horizontal position
- determineHorizontalPosition(child);
+ // Now place the child in the correct left position
+ determineLogicalLeftPositionForChild(child);
// Update our height now that the child has been placed in the correct position.
- setLogicalHeight(height() + child->height());
+ setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
if (child->style()->marginAfterCollapse() == MSEPARATE) {
- setLogicalHeight(height() + child->marginBottom());
+ setLogicalHeight(logicalHeight() + marginAfterForChild(child));
marginInfo.clearMargin();
}
// If the child has overhanging floats that intrude into following siblings (or possibly out
// of this block), then the parent gets notified of the floats now.
if (childRenderBlock && childRenderBlock->containsFloats())
- maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
+ maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout));
IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
if (childOffset.width() || childOffset.height()) {
@@ -2014,8 +2034,6 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
if (hasColumns())
view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
- bool paginated = view()->layoutState()->isPaginated();
-
RenderBox* r;
Iterator end = m_positionedObjects->end();
for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
@@ -2031,11 +2049,8 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
//if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent()))
r->setPreferredLogicalWidthsDirty(true, false);
- if (!r->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
- RenderBlock* childRenderBlock = r->isRenderBlock() ? toRenderBlock(r) : 0;
- if (childRenderBlock && view()->layoutState()->pageY(childRenderBlock->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
- }
+ if (!r->needsLayout())
+ r->markForPaginationRelayoutIfNeeded();
// We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width
// and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
@@ -2061,6 +2076,16 @@ void RenderBlock::markPositionedObjectsForLayout()
}
}
+void RenderBlock::markForPaginationRelayoutIfNeeded()
+{
+ ASSERT(!needsLayout());
+ if (needsLayout())
+ return;
+
+ if (view()->layoutState()->pageHeightChanged() || (view()->layoutState()->pageHeight() && view()->layoutState()->pageY(y()) != pageY()))
+ setChildNeedsLayout(true, false);
+}
+
void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
{
// Repaint any overhanging floats (if we know we're the one to paint them).
@@ -2081,7 +2106,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
// Only repaint the object if it is overhanging, is not in its own layer, and
// is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
// condition is replaced with being a descendant of us.
- if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
+ if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
r->m_renderer->repaint();
r->m_renderer->repaintOverhangingFloats();
}
@@ -2134,14 +2159,14 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
// We need to do multiple passes, breaking up our child painting into strips.
ColumnInfo* colInfo = columnInfo();
unsigned colCount = columnCount(colInfo);
- int currXOffset = style()->direction() == LTR ? 0 : contentWidth();
+ int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth();
int ruleAdd = borderLeft() + paddingLeft();
- int ruleX = style()->direction() == LTR ? 0 : contentWidth();
+ int ruleX = style()->isLeftToRightDirection() ? 0 : contentWidth();
for (unsigned i = 0; i < colCount; i++) {
IntRect colRect = columnRectAt(colInfo, i);
// Move to the next position.
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
ruleX += colRect.width() + colGap / 2;
currXOffset += colRect.width() + colGap;
} else {
@@ -2156,7 +2181,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
int ruleTop = ty + borderTop() + paddingTop();
int ruleBottom = ruleTop + contentHeight();
drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom,
- style()->direction() == LTR ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0);
+ style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0);
}
ruleX = currXOffset;
@@ -2172,7 +2197,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool
unsigned colCount = columnCount(colInfo);
if (!colCount)
return;
- int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - columnRectAt(colInfo, 0).width();
+ int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth() - columnRectAt(colInfo, 0).width();
int currYOffset = 0;
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
@@ -2200,7 +2225,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool
}
// Move to the next position.
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
currXOffset += colRect.width() + colGap;
else
currXOffset -= (colRect.width() + colGap);
@@ -2393,8 +2418,8 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv
if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
PaintInfo currentPaintInfo(paintInfo);
currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
- int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft();
- int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop();
+ int currentTX = tx + r->left() - r->m_renderer->x() + r->m_renderer->marginLeft();
+ int currentTY = ty + r->top() - r->m_renderer->y() + r->m_renderer->marginTop();
r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
if (!preservePhase) {
currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
@@ -2603,8 +2628,8 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int
if (m_floatingObjects) {
for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) {
FloatingObject* r = it.current();
- paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(),
- ty + r->m_top + r->m_renderer->marginTop(),
+ paintInfo->context->clipOut(IntRect(tx + r->left() + r->m_renderer->marginLeft(),
+ ty + r->top() + r->m_renderer->marginTop(),
r->m_renderer->width(), r->m_renderer->height()));
}
}
@@ -2815,7 +2840,7 @@ IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int y
void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
{
- bool ltr = style()->direction() == LTR;
+ bool ltr = style()->isLeftToRightDirection();
leftGap = (state == RenderObject::SelectionInside) ||
(state == RenderObject::SelectionEnd && ltr) ||
(state == RenderObject::SelectionStart && !ltr);
@@ -2933,20 +2958,21 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
// Create the special object entry & append it to the list
FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
-
- newObj->m_top = -1;
- newObj->m_bottom = -1;
// Our location is irrelevant if we're unsplittable or no pagination is in effect.
// Just go ahead and lay out the float.
- bool affectedByPagination = o->isRenderBlock() && view()->layoutState()->m_pageHeight;
- if (!affectedByPagination)
+ bool isChildRenderBlock = o->isRenderBlock();
+ if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageHeightChanged())
+ o->setChildNeedsLayout(true, false);
+
+ bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageHeight;
+ if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
o->layoutIfNeeded();
else {
o->computeLogicalWidth();
o->computeBlockDirectionMargins(this);
}
- newObj->m_width = o->width() + o->marginLeft() + o->marginRight();
+ setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
newObj->m_isDescendant = true;
@@ -2964,12 +2990,14 @@ void RenderBlock::removeFloatingObject(RenderBox* o)
while (it.current()) {
if (it.current()->m_renderer == o) {
if (childrenInline()) {
- int bottom = it.current()->m_bottom;
+ int logicalTop = logicalTopForFloat(it.current());
+ int logicalBottom = logicalBottomForFloat(it.current());
+
// Special-case zero- and less-than-zero-height floats: those don't touch
// the line that they're on, but it still needs to be dirtied. This is
// accomplished by pretending they have a height of 1.
- bottom = max(bottom, it.current()->m_top + 1);
- markLinesDirtyInVerticalRange(0, bottom);
+ logicalBottom = max(logicalBottom, logicalTop + 1);
+ markLinesDirtyInBlockRange(0, logicalBottom);
}
m_floatingObjects->removeRef(it.current());
}
@@ -2984,7 +3012,7 @@ void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int y)
return;
FloatingObject* curr = m_floatingObjects->last();
- while (curr != lastFloat && (curr->m_top == -1 || curr->m_top >= y)) {
+ while (curr != lastFloat && (!curr->isPlaced() || curr->top() >= y)) {
m_floatingObjects->removeLast();
curr = m_floatingObjects->last();
}
@@ -2995,111 +3023,118 @@ bool RenderBlock::positionNewFloats()
if (!m_floatingObjects)
return false;
- FloatingObject* f = m_floatingObjects->last();
+ FloatingObject* floatingObject = m_floatingObjects->last();
// If all floats have already been positioned, then we have no work to do.
- if (!f || f->m_top != -1)
+ if (!floatingObject || floatingObject->isPlaced())
return false;
// Move backwards through our floating object list until we find a float that has
// already been positioned. Then we'll be able to move forward, positioning all of
// the new floats that need it.
FloatingObject* lastFloat = m_floatingObjects->getPrev();
- while (lastFloat && lastFloat->m_top == -1) {
- f = m_floatingObjects->prev();
+ while (lastFloat && !lastFloat->isPlaced()) {
+ floatingObject = m_floatingObjects->prev();
lastFloat = m_floatingObjects->getPrev();
}
- int y = height();
+ int logicalTop = logicalHeight();
- // The float cannot start above the y position of the last positioned float.
+ // The float cannot start above the top position of the last positioned float.
if (lastFloat)
- y = max(lastFloat->m_top, y);
+ logicalTop = max(logicalTopForFloat(lastFloat), logicalTop);
// Now walk through the set of unpositioned floats and place them.
- while (f) {
+ while (floatingObject) {
// The containing block is responsible for positioning floats, so if we have floats in our
// list that come from somewhere else, do not attempt to position them.
- if (f->m_renderer->containingBlock() != this) {
- f = m_floatingObjects->next();
+ if (floatingObject->renderer()->containingBlock() != this) {
+ floatingObject = m_floatingObjects->next();
continue;
}
- RenderBox* o = f->m_renderer;
+ RenderBox* childBox = floatingObject->renderer();
+ int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
- int ro = logicalRightOffsetForContent(); // Constant part of right offset.
- int lo = logicalLeftOffsetForContent(); // Constant part of left offset.
- int fwidth = f->m_width; // The width we look for.
- if (ro - lo < fwidth)
- fwidth = ro - lo; // Never look for more than what will be available.
+ int rightOffset = logicalRightOffsetForContent(); // Constant part of right offset.
+ int leftOffset = logicalLeftOffsetForContent(); // Constant part of left offset.
+ int floatLogicalWidth = logicalWidthForFloat(floatingObject); // The width we look for.
+ if (rightOffset - leftOffset < floatLogicalWidth)
+ floatLogicalWidth = rightOffset - leftOffset; // Never look for more than what will be available.
- IntRect oldRect(o->x(), o->y() , o->width(), o->height());
+ IntRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height());
- if (o->style()->clear() & CLEFT)
- y = max(leftBottom(), y);
- if (o->style()->clear() & CRIGHT)
- y = max(rightBottom(), y);
+ if (childBox->style()->clear() & CLEFT)
+ logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
+ if (childBox->style()->clear() & CRIGHT)
+ logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
- if (o->style()->floating() == FLEFT) {
+ int floatLogicalLeft;
+ if (childBox->style()->floating() == FLEFT) {
int heightRemainingLeft = 1;
int heightRemainingRight = 1;
- int fx = logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft);
- while (logicalRightOffsetForLine(y, ro, false, &heightRemainingRight)-fx < fwidth) {
- y += min(heightRemainingLeft, heightRemainingRight);
- fx = logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft);
+ floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
+ while (logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
+ logicalTop += min(heightRemainingLeft, heightRemainingRight);
+ floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
}
- fx = max(0, fx);
- f->m_left = fx;
- o->setLocation(fx + o->marginLeft(), y + o->marginTop());
+ floatLogicalLeft = max(0, floatLogicalLeft);
} else {
int heightRemainingLeft = 1;
int heightRemainingRight = 1;
- int fx = logicalRightOffsetForLine(y, ro, false, &heightRemainingRight);
- while (fx - logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft) < fwidth) {
- y += min(heightRemainingLeft, heightRemainingRight);
- fx = logicalRightOffsetForLine(y, ro, false, &heightRemainingRight);
+ floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
+ while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
+ logicalTop += min(heightRemainingLeft, heightRemainingRight);
+ floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
}
- f->m_left = fx - f->m_width;
- o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop());
+ floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
+ // |floatLogicalWidth| was capped to the available line width.
+ // See fast/block/float/clamped-right-float.html.
}
+
+ setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
+ setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
+ setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
if (view()->layoutState()->isPaginated()) {
- RenderBlock* childBlock = o->isRenderBlock() ? toRenderBlock(o) : 0;
+ RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
- if (childBlock && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(o->y()) != childBlock->pageY())
- childBlock->markForPaginationRelayout();
- o->layoutIfNeeded();
+ if (!childBox->needsLayout())
+ childBox->markForPaginationRelayoutIfNeeded();;
+ childBox->layoutIfNeeded();
// If we are unsplittable and don't fit, then we need to move down.
// We include our margins as part of the unsplittable area.
- int newY = adjustForUnsplittableChild(o, y, true);
+ int newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, true);
// See if we have a pagination strut that is making us move down further.
// Note that an unsplittable child can't also have a pagination strut, so this is
// exclusive with the case above.
if (childBlock && childBlock->paginationStrut()) {
- newY += childBlock->paginationStrut();
+ newLogicalTop += childBlock->paginationStrut();
childBlock->setPaginationStrut(0);
}
- if (newY != y) {
- f->m_paginationStrut = newY - y;
- y = newY;
- o->setY(y + o->marginTop());
+ if (newLogicalTop != logicalTop) {
+ floatingObject->m_paginationStrut = newLogicalTop - logicalTop;
+ logicalTop = newLogicalTop;
+ setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
if (childBlock)
childBlock->setChildNeedsLayout(true, false);
- o->layoutIfNeeded();
+ childBox->layoutIfNeeded();
}
}
- f->m_top = y;
- f->m_bottom = f->m_top + o->marginTop() + o->height() + o->marginBottom();
-
+ setLogicalTopForFloat(floatingObject, logicalTop);
+ setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
+
+ floatingObject->setIsPlaced();
+
// If the child moved, we have to repaint it.
- if (o->checkForRepaintDuringLayout())
- o->repaintDuringLayoutIfMoved(oldRect);
+ if (childBox->checkForRepaintDuringLayout())
+ childBox->repaintDuringLayoutIfMoved(oldRect);
- f = m_floatingObjects->next();
+ floatingObject = m_floatingObjects->next();
}
return true;
}
@@ -3110,30 +3145,29 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec
if (!didPosition || !newFloat->m_paginationStrut)
return didPosition;
- int floatTop = newFloat->m_top;
+ int floatLogicalTop = logicalTopForFloat(newFloat);
int paginationStrut = newFloat->m_paginationStrut;
FloatingObject* f = m_floatingObjects->last();
ASSERT(f == newFloat);
- if (floatTop - paginationStrut != height())
+ if (floatLogicalTop - paginationStrut != logicalHeight())
return didPosition;
for (f = m_floatingObjects->prev(); f && f != lastFloatFromPreviousLine; f = m_floatingObjects->prev()) {
- if (f->m_top == height()) {
+ if (logicalTopForFloat(f) == logicalHeight()) {
ASSERT(!f->m_paginationStrut);
f->m_paginationStrut = paginationStrut;
RenderBox* o = f->m_renderer;
- o->setY(o->y() + o->marginTop() + paginationStrut);
+ setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut);
if (o->isRenderBlock())
toRenderBlock(o)->setChildNeedsLayout(true, false);
o->layoutIfNeeded();
- f->m_top += f->m_paginationStrut;
- f->m_bottom += f->m_paginationStrut;
+ setLogicalTopForFloat(f, logicalTopForFloat(f) + f->m_paginationStrut);
}
}
- setLogicalHeight(height() + paginationStrut);
+ setLogicalHeight(logicalHeight() + paginationStrut);
return didPosition;
}
@@ -3146,13 +3180,13 @@ void RenderBlock::newLine(EClear clear)
switch (clear)
{
case CLEFT:
- newY = leftBottom();
+ newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
break;
case CRIGHT:
- newY = rightBottom();
+ newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
break;
case CBOTH:
- newY = floatBottom();
+ newY = lowestFloatLogicalBottom();
default:
break;
}
@@ -3220,30 +3254,26 @@ HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
}
-int RenderBlock::logicalLeftOffsetForContent() const
-{
- return borderLeft() + paddingLeft();
-}
-
-int RenderBlock::logicalLeftOffsetForLine(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
+int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
{
int left = fixedOffset;
if (m_floatingObjects) {
- if ( heightRemaining ) *heightRemaining = 1;
+ if (heightRemaining)
+ *heightRemaining = 1;
FloatingObject* r;
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for ( ; (r = it.current()); ++it )
- {
- if (r->m_top <= y && r->m_bottom > y &&
- r->type() == FloatingObject::FloatLeft &&
- r->m_left + r->m_width > left) {
- left = r->m_left + r->m_width;
- if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
+ for ( ; (r = it.current()); ++it) {
+ if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
+ && r->type() == FloatingObject::FloatLeft
+ && logicalRightForFloat(r) > left) {
+ left = logicalRightForFloat(r);
+ if (heightRemaining)
+ *heightRemaining = logicalBottomForFloat(r) - logicalTop;
}
}
}
- if (applyTextIndent && style()->direction() == LTR) {
+ if (applyTextIndent && style()->isLeftToRightDirection()) {
int cw = 0;
if (style()->textIndent().isPercent())
cw = containingBlock()->availableLogicalWidth();
@@ -3253,31 +3283,27 @@ int RenderBlock::logicalLeftOffsetForLine(int y, int fixedOffset, bool applyText
return left;
}
-int RenderBlock::logicalRightOffsetForContent() const
-{
- return borderLeft() + paddingLeft() + availableLogicalWidth();
-}
-
-int RenderBlock::logicalRightOffsetForLine(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
+int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
{
int right = fixedOffset;
if (m_floatingObjects) {
- if (heightRemaining) *heightRemaining = 1;
+ if (heightRemaining)
+ *heightRemaining = 1;
FloatingObject* r;
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for ( ; (r = it.current()); ++it )
- {
- if (r->m_top <= y && r->m_bottom > y &&
- r->type() == FloatingObject::FloatRight &&
- r->m_left < right) {
- right = r->m_left;
- if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
+ for ( ; (r = it.current()); ++it) {
+ if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
+ && r->type() == FloatingObject::FloatRight
+ && logicalLeftForFloat(r) < right) {
+ right = logicalLeftForFloat(r);
+ if (heightRemaining)
+ *heightRemaining = logicalBottomForFloat(r) - logicalTop;
}
}
}
- if (applyTextIndent && style()->direction() == RTL) {
+ if (applyTextIndent && !style()->isLeftToRightDirection()) {
int cw = 0;
if (style()->textIndent().isPercent())
cw = containingBlock()->availableLogicalWidth();
@@ -3294,7 +3320,7 @@ RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const
return (result < 0) ? 0 : result;
}
-int RenderBlock::nextFloatBottomBelow(int height) const
+int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const
{
if (!m_floatingObjects)
return 0;
@@ -3303,36 +3329,130 @@ int RenderBlock::nextFloatBottomBelow(int height) const
FloatingObject* r;
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it) {
- if (r->m_bottom > height)
- bottom = min(r->m_bottom, bottom);
+ int floatBottom = logicalBottomForFloat(r);
+ if (floatBottom > logicalHeight)
+ bottom = min(floatBottom, bottom);
}
return bottom == INT_MAX ? 0 : bottom;
}
-int
-RenderBlock::floatBottom() const
+int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
{
- if (!m_floatingObjects) return 0;
- int bottom = 0;
+ if (!m_floatingObjects)
+ return 0;
+ int lowestFloatBottom = 0;
FloatingObject* r;
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for ( ; (r = it.current()); ++it )
- if (r->m_bottom>bottom)
- bottom = r->m_bottom;
- return bottom;
+ for ( ; (r = it.current()); ++it) {
+ if (r->isPlaced() && r->type() & floatType)
+ lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
+ }
+ return lowestFloatBottom;
}
-int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderBlock::topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int bottom = includeSelf && width() > 0 ? height() : 0;
-
+ IntRect transformedRect = transformedFrameRect();
+ int transformedTop = includeSelf && transformedRect.width() > 0 ? 0 : transformedRect.height();
+
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return bottom;
+ return transformedTop;
- if (!firstChild() && (!width() || !height()))
- return bottom;
+ if (!firstChild() && (!transformedRect.width() || !transformedRect.height()))
+ return transformedTop;
+
+ int top = includeSelf && width() > 0 ? 0 : height();
+
+ if (!hasColumns()) {
+ // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
+ // For now, we have to descend into all the children, since we may have a huge abs div inside
+ // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
+ // the abs div.
+ for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ top = min(top, childBox->transformedFrameRect().y() + childBox->topmostPosition(false));
+ }
+ }
+ }
+
+ if (includeSelf && isRelPositioned())
+ top += relativePositionOffsetY();
+
+ if (!includeOverflowInterior && hasOverflowClip())
+ return top;
+ int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0;
+
+ if (includeSelf)
+ top = min(top, topLayoutOverflow() + relativeOffset);
+
+ if (m_positionedObjects) {
+ RenderBox* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ // Fixed positioned objects do not scroll and thus should not constitute
+ // part of the topmost position.
+ if (r->style()->position() != FixedPosition) {
+ // FIXME: Should work for overflow sections too.
+ // If a positioned object lies completely to the left of the root it will be unreachable via scrolling.
+ // Therefore we should not allow it to contribute to the topmost position.
+ IntRect transformedR = r->transformedFrameRect();
+ if (!isRenderView() || transformedR.x() + transformedR.width() > 0 || transformedR.x() + r->rightmostPosition(false) > 0) {
+ int tp = transformedR.y() + r->topmostPosition(false);
+ top = min(top, tp + relativeOffset);
+ }
+ }
+ }
+ }
+
+ if (hasColumns()) {
+ ColumnInfo* colInfo = columnInfo();
+ for (unsigned i = 0; i < columnCount(colInfo); i++)
+ top = min(top, columnRectAt(colInfo, i).y() + relativeOffset);
+ return top;
+ }
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it) {
+ if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
+ int tp = r->top() + r->m_renderer->marginTop() + r->m_renderer->topmostPosition(false);
+ top = min(top, tp + relativeOffset);
+ }
+ }
+ }
+
+ if (!includeSelf && firstRootBox())
+ top = min(top, firstRootBox()->selectionTop() + relativeOffset);
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.y();
+ }
+
+ return top;
+}
+
+int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
+{
+ IntRect transformedRect = transformedFrameRect();
+ int transformedBottom = includeSelf && transformedRect.width() > 0 ? transformedRect.height() : 0;
+
+ if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
+ return transformedBottom;
+
+ if (!firstChild() && (!transformedRect.width() || !transformedRect.height()))
+ return transformedBottom;
+
+ int bottom = includeSelf && width() > 0 ? height() : 0;
+
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
// For now, we have to descend into all the children, since we may have a huge abs div inside
@@ -3343,7 +3463,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
if (!c->isFloatingOrPositioned() && c->isBox()) {
RenderBox* childBox = toRenderBox(c);
- bottom = max(bottom, childBox->y() + childBox->lowestPosition(false));
+ bottom = max(bottom, childBox->transformedFrameRect().y() + childBox->lowestPosition(false));
}
}
}
@@ -3369,8 +3489,9 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
// FIXME: Should work for overflow sections too.
// If a positioned object lies completely to the left of the root it will be unreachable via scrolling.
// Therefore we should not allow it to contribute to the lowest position.
- if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) {
- int lp = r->y() + r->lowestPosition(false);
+ IntRect transformedR = r->transformedFrameRect();
+ if (!isRenderView() || transformedR.x() + transformedR.width() > 0 || transformedR.x() + r->rightmostPosition(false) > 0) {
+ int lp = transformedR.y() + r->lowestPosition(false);
bottom = max(bottom, lp + relativeOffset);
}
}
@@ -3389,7 +3510,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it ) {
if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
- int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false);
+ int lp = r->top() + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false);
bottom = max(bottom, lp + relativeOffset);
}
}
@@ -3408,24 +3529,36 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
while (currBox && currBox->isFloatingOrPositioned())
currBox = currBox->previousSiblingBox();
if (currBox) {
- int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginAfter(); // FIXME: "after" is wrong here for lowestPosition.
+ IntRect transformedCurrBox = currBox->transformedFrameRect();
+ int childBottomEdge = transformedCurrBox.y() + transformedCurrBox.height() + currBox->collapsedMarginAfter(); // FIXME: "after" is wrong here for lowestPosition.
bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset);
}
}
}
-
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.height();
+ }
+
return bottom;
}
-int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int right = includeSelf && height() > 0 ? width() : 0;
+ IntRect transformedRect = transformedFrameRect();
+ int transformedRight = includeSelf && transformedRect.height() > 0 ? transformedRect.width() : 0;
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return right;
+ return transformedRight;
- if (!firstChild() && (!width() || !height()))
- return right;
+ if (!firstChild() && (!transformedRect.width() || !transformedRect.height()))
+ return transformedRight;
+
+ int right = includeSelf && height() > 0 ? width() : 0;
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
@@ -3435,7 +3568,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
if (!c->isFloatingOrPositioned() && c->isBox()) {
RenderBox* childBox = toRenderBox(c);
- right = max(right, childBox->x() + childBox->rightmostPosition(false));
+ right = max(right, childBox->transformedFrameRect().x() + childBox->rightmostPosition(false));
}
}
}
@@ -3462,8 +3595,9 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
// FIXME: Should work for overflow sections too.
// If a positioned object lies completely above the root it will be unreachable via scrolling.
// Therefore we should not allow it to contribute to the rightmost position.
- if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) {
- int rp = r->x() + r->rightmostPosition(false);
+ IntRect transformedR = r->transformedFrameRect();
+ if (!isRenderView() || transformedR.y() + transformedR.height() > 0 || transformedR.y() + r->lowestPosition(false) > 0) {
+ int rp = transformedR.x() + r->rightmostPosition(false);
right = max(right, rp + relativeOffset);
}
}
@@ -3472,12 +3606,19 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
if (hasColumns()) {
// This only matters for LTR
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
ColumnInfo* colInfo = columnInfo();
unsigned count = columnCount(colInfo);
if (count)
right = max(columnRectAt(colInfo, count - 1).right() + relativeOffset, right);
}
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.width();
+ }
return right;
}
@@ -3486,7 +3627,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it ) {
if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
- int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false);
+ int rp = r->left() + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false);
right = max(right, rp + relativeOffset);
}
}
@@ -3500,7 +3641,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
// If this node is a root editable element, then the rightmostPosition should account for a caret at the end.
// FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
- if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight())
+ if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection() && !paddingRight())
childRightEdge += 1;
right = max(right, childRightEdge + paddingRight() + relativeOffset);
}
@@ -3509,24 +3650,36 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) {
if (currBox->isFloatingOrPositioned())
continue;
- int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight();
+ IntRect transformedChild = currBox->transformedFrameRect();
+ int childRightEdge = transformedChild.x() + transformedChild.width() + currBox->marginRight();
right = max(right, childRightEdge + paddingRight() + relativeOffset);
}
}
}
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.width();
+ }
return right;
}
-int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int left = includeSelf && height() > 0 ? 0 : width();
+ IntRect transformedRect = transformedFrameRect();
+ int transformedLeft = includeSelf && transformedRect.height() > 0 ? 0 : transformedRect.width();
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return left;
+ return transformedLeft;
- if (!firstChild() && (!width() || !height()))
- return left;
+ if (!firstChild() && (!transformedRect.width() || !transformedRect.height()))
+ return transformedLeft;
+
+ int left = includeSelf && height() > 0 ? 0 : width();
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
@@ -3536,7 +3689,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
if (!c->isFloatingOrPositioned() && c->isBox()) {
RenderBox* childBox = toRenderBox(c);
- left = min(left, childBox->x() + childBox->leftmostPosition(false));
+ left = min(left, childBox->transformedFrameRect().x() + childBox->leftmostPosition(false));
}
}
}
@@ -3563,8 +3716,9 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
// FIXME: Should work for overflow sections too.
// If a positioned object lies completely above the root it will be unreachable via scrolling.
// Therefore we should not allow it to contribute to the leftmost position.
- if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) {
- int lp = r->x() + r->leftmostPosition(false);
+ IntRect transformedR = r->transformedFrameRect();
+ if (!isRenderView() || transformedR.y() + transformedR.height() > 0 || transformedR.y() + r->lowestPosition(false) > 0) {
+ int lp = transformedR.x() + r->leftmostPosition(false);
left = min(left, lp + relativeOffset);
}
}
@@ -3573,7 +3727,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
if (hasColumns()) {
// This only matters for RTL
- if (style()->direction() == RTL) {
+ if (!style()->isLeftToRightDirection()) {
ColumnInfo* colInfo = columnInfo();
unsigned count = columnCount(colInfo);
if (count)
@@ -3587,7 +3741,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for ( ; (r = it.current()); ++it ) {
if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
- int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false);
+ int lp = r->left() + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false);
left = min(left, lp + relativeOffset);
}
}
@@ -3597,51 +3751,31 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
for (InlineFlowBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox())
left = min(left, (int)currBox->x() + relativeOffset);
}
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.x();
+ }
return left;
}
-int
-RenderBlock::leftBottom()
-{
- if (!m_floatingObjects) return 0;
- int bottom = 0;
- FloatingObject* r;
- DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for ( ; (r = it.current()); ++it )
- if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft)
- bottom = r->m_bottom;
-
- return bottom;
-}
-
-int
-RenderBlock::rightBottom()
-{
- if (!m_floatingObjects) return 0;
- int bottom = 0;
- FloatingObject* r;
- DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for ( ; (r = it.current()); ++it )
- if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight)
- bottom = r->m_bottom;
-
- return bottom;
-}
-
-void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest)
+void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest)
{
- if (top >= bottom)
+ if (logicalTop >= logicalBottom)
return;
RootInlineBox* lowestDirtyLine = lastRootBox();
RootInlineBox* afterLowest = lowestDirtyLine;
- while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) {
+ while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom) {
afterLowest = lowestDirtyLine;
lowestDirtyLine = lowestDirtyLine->prevRootBox();
}
- while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) {
+ while (afterLowest && afterLowest != highest && afterLowest->blockLogicalHeight() >= logicalTop) {
afterLowest->markDirty();
afterLowest = afterLowest->prevRootBox();
}
@@ -3678,6 +3812,7 @@ void RenderBlock::clearFloats()
// out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
// to avoid floats.
bool parentHasFloats = false;
+ RenderBlock* parentBlock = toRenderBlock(parent());
RenderObject* prev = previousSibling();
while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
if (prev->isFloating())
@@ -3686,18 +3821,16 @@ void RenderBlock::clearFloats()
}
// First add in floats from the parent.
- int offset = y();
- if (parentHasFloats) {
- RenderBlock* parentBlock = toRenderBlock(parent());
- addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset);
- }
+ int logicalTopOffset = logicalTop();
+ if (parentHasFloats)
+ addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
- int xoffset = 0;
+ int logicalLeftOffset = 0;
if (prev)
- offset -= toRenderBox(prev)->y();
- else if (parent()->isBox()) {
- prev = parent();
- xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft();
+ logicalTopOffset -= toRenderBox(prev)->logicalTop();
+ else {
+ prev = parentBlock;
+ logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
}
// Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
@@ -3705,29 +3838,31 @@ void RenderBlock::clearFloats()
return;
RenderBlock* block = toRenderBlock(prev);
- if (block->m_floatingObjects && block->floatBottom() > offset)
- addIntrudingFloats(block, xoffset, offset);
+ if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
+ addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
if (childrenInline()) {
- int changeTop = numeric_limits<int>::max();
- int changeBottom = numeric_limits<int>::min();
+ int changeLogicalTop = numeric_limits<int>::max();
+ int changeLogicalBottom = numeric_limits<int>::min();
if (m_floatingObjects) {
for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
+ int logicalBottom = logicalBottomForFloat(f);
if (oldFloatingObject) {
- if (f->m_width != oldFloatingObject->m_width || f->m_left != oldFloatingObject->m_left) {
- changeTop = 0;
- changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
- } else if (f->m_bottom != oldFloatingObject->m_bottom) {
- changeTop = min(changeTop, min(f->m_bottom, oldFloatingObject->m_bottom));
- changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
+ int oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
+ if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
+ changeLogicalTop = 0;
+ changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
+ } else if (logicalBottom != oldLogicalBottom) {
+ changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
+ changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
}
floatMap.remove(f->m_renderer);
delete oldFloatingObject;
} else {
- changeTop = 0;
- changeBottom = max(changeBottom, f->m_bottom);
+ changeLogicalTop = 0;
+ changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
}
}
}
@@ -3736,39 +3871,37 @@ void RenderBlock::clearFloats()
for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
FloatingObject* floatingObject = (*it).second;
if (!floatingObject->m_isDescendant) {
- changeTop = 0;
- changeBottom = max(changeBottom, floatingObject->m_bottom);
+ changeLogicalTop = 0;
+ changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
}
}
deleteAllValues(floatMap);
- markLinesDirtyInVerticalRange(changeTop, changeBottom);
+ markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
}
}
-int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bool makeChildPaintOtherFloats)
+int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, int logicalTopOffset, bool makeChildPaintOtherFloats)
{
// Prevent floats from being added to the canvas by the root element, e.g., <html>.
- if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isBlockFlowRoot())
+ if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
return 0;
- int lowestFloatBottom = 0;
+ int lowestFloatLogicalBottom = 0;
// Floats that will remain the child's responsibility to paint should factor into its
// overflow.
DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects);
for (FloatingObject* r; (r = it.current()); ++it) {
- int bottom = child->y() + r->m_bottom;
- lowestFloatBottom = max(lowestFloatBottom, bottom);
+ int logicalBottom = child->logicalTop() + logicalBottomForFloat(r);
+ lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
- if (bottom > height()) {
+ if (logicalBottom > logicalHeight()) {
// If the object is not in the list, we add it now.
if (!containsFloat(r->m_renderer)) {
- FloatingObject *floatingObj = new FloatingObject(r->type());
- floatingObj->m_top = r->m_top - yoff;
- floatingObj->m_bottom = r->m_bottom - yoff;
- floatingObj->m_left = r->m_left - xoff;
- floatingObj->m_width = r->m_width;
+ int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
+ int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
+ FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height()));
floatingObj->m_renderer = r->m_renderer;
// The nearest enclosing layer always paints the float (so that zindex and stacking
@@ -3797,45 +3930,48 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo
r->m_shouldPaint = true;
if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
- child->addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
+ child->addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop()));
}
- return lowestFloatBottom;
+ return lowestFloatLogicalBottom;
}
-void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff)
+void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, int logicalTopOffset)
{
// If the parent or previous sibling doesn't have any floats to add, don't bother.
if (!prev->m_floatingObjects)
return;
+ logicalLeftOffset += (style()->isHorizontalWritingMode() ? marginLeft() : marginTop());
+
DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects);
for (FloatingObject *r; (r = it.current()); ++it) {
- if (r->m_bottom > yoff) {
+ if (logicalBottomForFloat(r) > logicalTopOffset) {
// The object may already be in our list. Check for it up front to avoid
// creating duplicate entries.
FloatingObject* f = 0;
if (m_floatingObjects) {
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
while ((f = it.current())) {
- if (f->m_renderer == r->m_renderer) break;
+ if (f->m_renderer == r->m_renderer)
+ break;
++it;
}
}
if (!f) {
- FloatingObject *floatingObj = new FloatingObject(r->type());
- floatingObj->m_top = r->m_top - yoff;
- floatingObj->m_bottom = r->m_bottom - yoff;
- floatingObj->m_left = r->m_left - xoff;
+ int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
+ int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
+
+ FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height()));
+
// Applying the child's margin makes no sense in the case where the child was passed in.
- // since his own margin was added already through the subtraction of the |xoff| variable
- // above. |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
- // into account. Only apply this code if |child| is false, since otherwise the left margin
+ // since this margin was added already through the modification of the |logicalLeftOffset| variable
+ // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
+ // into account. Only apply this code if prev is the parent, since otherwise the left margin
// will get applied twice.
if (prev != parent())
- floatingObj->m_left += prev->marginLeft();
- floatingObj->m_left -= marginLeft();
+ floatingObj->setLeft(floatingObj->left() + (style()->isHorizontalWritingMode() ? prev->marginLeft() : prev->marginTop()));
+
floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it.
- floatingObj->m_width = r->m_width;
floatingObj->m_renderer = r->m_renderer;
// We create the floating object list lazily.
@@ -3890,41 +4026,6 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove
}
}
-void RenderBlock::markDescendantBlocksAndLinesForLayout(bool inLayout)
-{
- if (!m_everHadLayout)
- return;
-
- setChildNeedsLayout(true, !inLayout);
-
- // Iterate over our children and mark them as needed.
- if (!childrenInline()) {
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- if (child->isFloatingOrPositioned())
- continue;
- child->markDescendantBlocksAndLinesForLayout(inLayout);
- }
- }
-
- // Walk our floating objects and mark them too.
- if (m_floatingObjects) {
- DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
- while (it.current()) {
- if (it.current()->m_renderer->isRenderBlock())
- it.current()->m_renderer->markDescendantBlocksAndLinesForLayout(inLayout);
- ++it;
- }
- }
-
- if (m_positionedObjects) {
- // FIXME: Technically we don't have to mark the positioned objects if we're the block
- // that established the columns, but we don't really have that information here.
- Iterator end = m_positionedObjects->end();
- for (Iterator it = m_positionedObjects->begin(); it != end; ++it)
- (*it)->markDescendantBlocksAndLinesForLayout();
- }
-}
-
int RenderBlock::getClearDelta(RenderBox* child, int yPos)
{
// There is no need to compute clearance if we have no floats.
@@ -3938,13 +4039,13 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos)
case CNONE:
break;
case CLEFT:
- bottom = leftBottom();
+ bottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
break;
case CRIGHT:
- bottom = rightBottom();
+ bottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
break;
case CBOTH:
- bottom = floatBottom();
+ bottom = lowestFloatLogicalBottom();
break;
}
@@ -3972,7 +4073,7 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos)
if (childWidthAtY <= widthAtY)
return y - yPos;
- y = nextFloatBottomBelow(y);
+ y = nextFloatLogicalBottomBelow(y);
ASSERT(y >= yPos);
if (y < yPos)
break;
@@ -3999,7 +4100,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// Check if we need to do anything at all.
IntRect overflowBox = visibleOverflowRect();
overflowBox.move(tx, ty);
- if (!overflowBox.intersects(result.rectFromPoint(_x, _y)))
+ if (!overflowBox.intersects(result.rectForPoint(_x, _y)))
return false;
}
@@ -4013,7 +4114,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// If we have clipping, then we can't have any spillout.
bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
bool useClip = (hasControlClip() || useOverflowClip);
- IntRect hitTestArea(result.rectFromPoint(_x, _y));
+ IntRect hitTestArea(result.rectForPoint(_x, _y));
bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty).intersects(hitTestArea));
if (checkChildren) {
// Hit test descendants first.
@@ -4042,7 +4143,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// Now hit test our background
if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
IntRect boundsRect(tx, ty, width(), height());
- if (visibleToHitTesting() && boundsRect.intersects(result.rectFromPoint(_x, _y))) {
+ if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(_x, _y))) {
updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
if (!result.addNodeToRectBasedTestResult(node(), _x, _y, boundsRect))
return true;
@@ -4066,8 +4167,8 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for (it.toLast(); (floatingObject = it.current()); --it) {
if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
- int xOffset = tx + floatingObject->m_left + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x();
- int yOffset = ty + floatingObject->m_top + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y();
+ int xOffset = tx + floatingObject->left() + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x();
+ int yOffset = ty + floatingObject->top() + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y();
if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), xOffset, yOffset)) {
updateHitTestResult(result, IntPoint(x - xOffset, y - yOffset));
return true;
@@ -4096,13 +4197,13 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
currYOffset += colRect.height();
colRect.move(tx, ty);
- if (colRect.intersects(result.rectFromPoint(x, y))) {
+ if (colRect.intersects(result.rectForPoint(x, y))) {
// The point is inside this column.
// Adjust tx and ty to change where we hit test.
int finalX = tx + currXOffset;
int finalY = ty + currYOffset;
- if (result.isRectBasedTest() && !colRect.contains(result.rectFromPoint(x, y)))
+ if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(x, y)))
hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
else
return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, x, y, finalX, finalY));
@@ -4443,7 +4544,7 @@ IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
int colHeight = colInfo->columnHeight();
int colTop = borderTop() + paddingTop();
int colGap = columnGap();
- int colLeft = style()->direction() == LTR ?
+ int colLeft = style()->isLeftToRightDirection() ?
borderLeft() + paddingLeft() + (index * (colWidth + colGap))
: borderLeft() + paddingLeft() + contentWidth() - colWidth - (index * (colWidth + colGap));
return IntRect(colLeft, colTop, colWidth, colHeight);
@@ -4485,8 +4586,8 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageHeight, int pageHeight, Lay
if (columnCount(colInfo)) {
IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
- int overflowLeft = style()->direction() == RTL ? min(0, lastRect.x()) : 0;
- int overflowRight = style()->direction() == LTR ? max(width(), lastRect.x() + lastRect.width()) : 0;
+ int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0;
+ int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.x() + lastRect.width()) : 0;
int overflowHeight = borderTop() + paddingTop() + colInfo->columnHeight();
setLogicalHeight(overflowHeight + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
@@ -4607,8 +4708,8 @@ void RenderBlock::computePreferredLogicalWidths()
updateFirstLetter();
- if (!isTableCell() && style()->width().isFixed() && style()->width().value() > 0)
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value());
+ if (!isTableCell() && style()->logicalWidth().isFixed() && style()->logicalWidth().value() > 0)
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->logicalWidth().value());
else {
m_minPreferredLogicalWidth = 0;
m_maxPreferredLogicalWidth = 0;
@@ -4635,18 +4736,18 @@ void RenderBlock::computePreferredLogicalWidths()
}
}
- if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
- m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
- m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
+ if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
+ m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
}
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
- m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
- m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
+ if (style()->logicalMaxWidth().isFixed() && style()->logicalMaxWidth().value() != undefinedLength) {
+ m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
+ m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
}
int toAdd = 0;
- toAdd = borderAndPaddingWidth();
+ toAdd = borderAndPaddingLogicalWidth();
if (hasOverflowClip() && style()->overflowY() == OSCROLL)
toAdd += verticalScrollbarWidth();
@@ -4732,7 +4833,7 @@ static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfI
{
RenderStyle* cstyle = child->style();
int result = 0;
- bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
+ bool leftSide = (cstyle->isLeftToRightDirection()) ? !endOfInline : endOfInline;
result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
(leftSide ? cstyle->marginLeft() :
cstyle->marginRight()));
@@ -5135,15 +5236,15 @@ bool RenderBlock::hasLineIfEmpty() const
return false;
}
-int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const
+int RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
// Inline blocks are replaced elements. Otherwise, just pass off to
// the base class. If we're being queried as though we're the root line
// box, then the fact that we're an inline-block is irrelevant, and we behave
// just like a block.
- if (isReplaced() && !isRootLineBox)
- return height() + marginTop() + marginBottom();
-
+ if (isReplaced() && linePositionMode == PositionOnContainingLine)
+ return RenderBox::lineHeight(firstLine, direction, linePositionMode);
+
if (firstLine && document()->usesFirstLineRules()) {
RenderStyle* s = style(firstLine);
if (s != style())
@@ -5156,16 +5257,17 @@ int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const
return m_lineHeight;
}
-int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const
+int RenderBlock::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
// Inline blocks are replaced elements. Otherwise, just pass off to
// the base class. If we're being queried as though we're the root line
// box, then the fact that we're an inline-block is irrelevant, and we behave
// just like a block.
- if (isReplaced() && !isRootLineBox) {
+ if (isReplaced() && linePositionMode == PositionOnContainingLine) {
// For "leaf" theme objects, let the theme decide what the baseline position is.
// FIXME: Might be better to have a custom CSS property instead, so that if the theme
// is turned off, checkboxes/radios will still have decent baselines.
+ // FIXME: Need to patch form controls to deal with vertical lines.
if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
return theme()->baselinePosition(this);
@@ -5175,22 +5277,29 @@ int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const
// We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
// vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
// of our content box.
- int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline();
- if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight())
- return marginTop() + baselinePos;
- return height() + marginTop() + marginBottom();
+ bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)
+ : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || isWritingModeRoot();
+ int baselinePos = ignoreBaseline ? -1 : lastLineBoxBaseline();
+
+ int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
+ if (baselinePos != -1 && baselinePos <= bottomOfContent)
+ return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
+
+ return RenderBox::baselinePosition(firstLine, direction, linePositionMode);
}
- return RenderBox::baselinePosition(b, isRootLineBox);
+
+ const Font& f = style(firstLine)->font();
+ return f.ascent() + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2;
}
int RenderBlock::firstLineBoxBaseline() const
{
- if (!isBlockFlow())
+ if (!isBlockFlow() || isWritingModeRoot())
return -1;
if (childrenInline()) {
if (firstLineBox())
- return firstLineBox()->y() + style(true)->font().ascent();
+ return firstLineBox()->logicalTop() + style(true)->font().ascent();
else
return -1;
}
@@ -5199,7 +5308,7 @@ int RenderBlock::firstLineBoxBaseline() const
if (!curr->isFloatingOrPositioned()) {
int result = curr->firstLineBoxBaseline();
if (result != -1)
- return curr->y() + result; // Translate to our coordinate space.
+ return curr->logicalTop() + result; // Translate to our coordinate space.
}
}
}
@@ -5209,28 +5318,33 @@ int RenderBlock::firstLineBoxBaseline() const
int RenderBlock::lastLineBoxBaseline() const
{
- if (!isBlockFlow())
+ if (!isBlockFlow() || isWritingModeRoot())
return -1;
+ LineDirectionMode lineDirection = style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
+
if (childrenInline()) {
- if (!firstLineBox() && hasLineIfEmpty())
- return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop();
+ if (!firstLineBox() && hasLineIfEmpty()) {
+ const Font& f = firstLineStyle()->font();
+ return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
+ }
if (lastLineBox())
- return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent();
+ return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->font().ascent();
return -1;
- }
- else {
+ } else {
bool haveNormalFlowChild = false;
for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
if (!curr->isFloatingOrPositioned()) {
haveNormalFlowChild = true;
int result = curr->lastLineBoxBaseline();
if (result != -1)
- return curr->y() + result; // Translate to our coordinate space.
+ return curr->logicalTop() + result; // Translate to our coordinate space.
}
}
- if (!haveNormalFlowChild && hasLineIfEmpty())
- return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop();
+ if (!haveNormalFlowChild && hasLineIfEmpty()) {
+ const Font& f = firstLineStyle()->font();
+ return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
+ }
}
return -1;
@@ -5279,6 +5393,24 @@ static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderOb
return pseudoStyle;
}
+// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
+// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
+// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
+static inline bool isPunctuationForFirstLetter(UChar c)
+{
+ CharCategory charCategory = category(c);
+ return charCategory == Punctuation_Open
+ || charCategory == Punctuation_Close
+ || charCategory == Punctuation_InitialQuote
+ || charCategory == Punctuation_FinalQuote
+ || charCategory == Punctuation_Other;
+}
+
+static inline bool shouldSkipForFirstLetter(UChar c)
+{
+ return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
+}
+
void RenderBlock::updateFirstLetter()
{
if (!document()->usesFirstLetterRules())
@@ -5403,15 +5535,27 @@ void RenderBlock::updateFirstLetter()
if (oldText && oldText->length() > 0) {
unsigned length = 0;
- // account for leading spaces and punctuation
- while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length])))
+ // Account for leading spaces and punctuation.
+ while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length]))
length++;
- // account for first letter
+ // Account for first letter.
length++;
+
+ // Keep looking for whitespace and allowed punctuation, but avoid
+ // accumulating just whitespace into the :first-letter.
+ for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) {
+ UChar c = (*oldText)[scanLength];
+
+ if (!shouldSkipForFirstLetter(c))
+ break;
- // construct text fragment for the text after the first letter
- // NOTE: this might empty
+ if (isPunctuationForFirstLetter(c))
+ length = scanLength + 1;
+ }
+
+ // Construct a text fragment for the text after the first letter.
+ // This text fragment might be empty.
RenderTextFragment* remainingText =
new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
remainingText->setStyle(textObj->style());
@@ -5553,7 +5697,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const
for (; (r = it.current()); ++it) {
// Only examine the object if our m_shouldPaint flag is set.
if (r->m_shouldPaint) {
- int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft();
+ int floatLeft = r->left() - r->m_renderer->x() + r->m_renderer->marginLeft();
int floatRight = floatLeft + r->m_renderer->width();
left = min(left, floatLeft);
right = max(right, floatRight);
@@ -5605,23 +5749,23 @@ void RenderBlock::clearTruncation()
void RenderBlock::setMaxMarginBeforeValues(int pos, int neg)
{
if (!m_rareData) {
- if (pos == RenderBlockRareData::beforePosDefault(this) && neg == RenderBlockRareData::beforeNegDefault(this))
+ if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
return;
m_rareData = new RenderBlockRareData(this);
}
- m_rareData->m_beforePos = pos;
- m_rareData->m_beforeNeg = neg;
+ m_rareData->m_margins.setPositiveMarginBefore(pos);
+ m_rareData->m_margins.setNegativeMarginBefore(neg);
}
void RenderBlock::setMaxMarginAfterValues(int pos, int neg)
{
if (!m_rareData) {
- if (pos == RenderBlockRareData::afterPosDefault(this) && neg == RenderBlockRareData::afterNegDefault(this))
+ if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
return;
m_rareData = new RenderBlockRareData(this);
}
- m_rareData->m_afterPos = pos;
- m_rareData->m_afterNeg = neg;
+ m_rareData->m_margins.setPositiveMarginAfter(pos);
+ m_rareData->m_margins.setNegativeMarginAfter(neg);
}
void RenderBlock::setPaginationStrut(int strut)
@@ -5745,7 +5889,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int*
// constructed and this kludge is not called any more. So only the caret size
// of an empty :first-line'd block is wrong. I think we can live with that.
RenderStyle* currentStyle = firstLineStyle();
- int height = lineHeight(true);
+ int height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
enum CaretAlignment { alignLeft, alignRight, alignCenter };
@@ -5754,7 +5898,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int*
switch (currentStyle->textAlign()) {
case TAAUTO:
case JUSTIFY:
- if (currentStyle->direction() == RTL)
+ if (!currentStyle->isLeftToRightDirection())
alignment = alignRight;
break;
case LEFT:
@@ -6020,7 +6164,213 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& d
}
}
}
-
+
+int RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // collapsed margin.
+ if (!child->isWritingModeRoot())
+ return child->collapsedMarginBefore();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the collapsed margin for the opposite edge.
+ if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode())
+ return child->collapsedMarginAfter();
+
+ // The child is perpendicular to us, which means its margins don't collapse but are on the
+ // "logical left/right" sides of the child box. We can just return the raw margin in this case.
+ return marginBeforeForChild(child);
+}
+
+int RenderBlock::collapsedMarginAfterForChild(RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // collapsed margin.
+ if (!child->isWritingModeRoot())
+ return child->collapsedMarginAfter();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the collapsed margin for the opposite edge.
+ if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode())
+ return child->collapsedMarginBefore();
+
+ // The child is perpendicular to us, which means its margins don't collapse but are on the
+ // "logical left/right" side of the child box. We can just return the raw margin in this case.
+ return marginAfterForChild(child);
+}
+
+int RenderBlock::marginBeforeForChild(RenderBoxModelObject* child) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return child->marginTop();
+ case BottomToTopWritingMode:
+ return child->marginBottom();
+ case LeftToRightWritingMode:
+ return child->marginLeft();
+ case RightToLeftWritingMode:
+ return child->marginRight();
+ }
+ ASSERT_NOT_REACHED();
+ return child->marginTop();
+}
+
+int RenderBlock::marginAfterForChild(RenderBoxModelObject* child) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return child->marginBottom();
+ case BottomToTopWritingMode:
+ return child->marginTop();
+ case LeftToRightWritingMode:
+ return child->marginRight();
+ case RightToLeftWritingMode:
+ return child->marginLeft();
+ }
+ ASSERT_NOT_REACHED();
+ return child->marginBottom();
+}
+
+int RenderBlock::marginStartForChild(RenderBoxModelObject* child) const
+{
+ if (style()->isHorizontalWritingMode())
+ return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight();
+ return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom();
+}
+
+int RenderBlock::marginEndForChild(RenderBoxModelObject* child) const
+{
+ if (style()->isHorizontalWritingMode())
+ return style()->isLeftToRightDirection() ? child->marginRight() : child->marginLeft();
+ return style()->isLeftToRightDirection() ? child->marginBottom() : child->marginTop();
+}
+
+void RenderBlock::setMarginStartForChild(RenderBox* child, int margin)
+{
+ if (style()->isHorizontalWritingMode()) {
+ if (style()->isLeftToRightDirection())
+ child->setMarginLeft(margin);
+ else
+ child->setMarginRight(margin);
+ } else {
+ if (style()->isLeftToRightDirection())
+ child->setMarginTop(margin);
+ else
+ child->setMarginBottom(margin);
+ }
+}
+
+void RenderBlock::setMarginEndForChild(RenderBox* child, int margin)
+{
+ if (style()->isHorizontalWritingMode()) {
+ if (style()->isLeftToRightDirection())
+ child->setMarginRight(margin);
+ else
+ child->setMarginLeft(margin);
+ } else {
+ if (style()->isLeftToRightDirection())
+ child->setMarginBottom(margin);
+ else
+ child->setMarginTop(margin);
+ }
+}
+
+void RenderBlock::setMarginBeforeForChild(RenderBox* child, int margin)
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ child->setMarginTop(margin);
+ break;
+ case BottomToTopWritingMode:
+ child->setMarginBottom(margin);
+ break;
+ case LeftToRightWritingMode:
+ child->setMarginLeft(margin);
+ break;
+ case RightToLeftWritingMode:
+ child->setMarginRight(margin);
+ break;
+ }
+}
+
+void RenderBlock::setMarginAfterForChild(RenderBox* child, int margin)
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ child->setMarginBottom(margin);
+ break;
+ case BottomToTopWritingMode:
+ child->setMarginTop(margin);
+ break;
+ case LeftToRightWritingMode:
+ child->setMarginRight(margin);
+ break;
+ case RightToLeftWritingMode:
+ child->setMarginLeft(margin);
+ break;
+ }
+}
+
+RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child)
+{
+ int childBeforePositive = 0;
+ int childBeforeNegative = 0;
+ int childAfterPositive = 0;
+ int childAfterNegative = 0;
+
+ int beforeMargin = 0;
+ int afterMargin = 0;
+
+ RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
+
+ // If the child has the same directionality as we do, then we can just return its
+ // margins in the same direction.
+ if (!child->isWritingModeRoot()) {
+ if (childRenderBlock) {
+ childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
+ childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
+ childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
+ childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
+ } else {
+ beforeMargin = child->marginBefore();
+ afterMargin = child->marginAfter();
+ }
+ } else if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode()) {
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the margins for the opposite edges.
+ if (childRenderBlock) {
+ childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
+ childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
+ childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
+ childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
+ } else {
+ beforeMargin = child->marginAfter();
+ afterMargin = child->marginBefore();
+ }
+ } else {
+ // The child is perpendicular to us, which means its margins don't collapse but are on the
+ // "logical left/right" sides of the child box. We can just return the raw margin in this case.
+ beforeMargin = marginBeforeForChild(child);
+ afterMargin = marginAfterForChild(child);
+ }
+
+ // Resolve uncollapsing margins into their positive/negative buckets.
+ if (beforeMargin) {
+ if (beforeMargin > 0)
+ childBeforePositive = beforeMargin;
+ else
+ childBeforeNegative = -beforeMargin;
+ }
+ if (afterMargin) {
+ if (afterMargin > 0)
+ childAfterPositive = afterMargin;
+ else
+ childAfterNegative = -afterMargin;
+ }
+
+ return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
+}
+
const char* RenderBlock::renderName() const
{
if (isBody())
diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h
index 0682039..66c8659 100644
--- a/WebCore/rendering/RenderBlock.h
+++ b/WebCore/rendering/RenderBlock.h
@@ -57,8 +57,8 @@ public:
virtual void destroy();
// These two functions are overridden for inline-block.
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
- virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
RenderLineBoxList* lineBoxes() { return &m_lineBoxes; }
const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; }
@@ -90,14 +90,7 @@ public:
void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true);
void markPositionedObjectsForLayout();
- void markForPaginationRelayout()
- {
- if (isTable())
- markDescendantBlocksAndLinesForLayout();
- else
- setChildNeedsLayout(true, false);
- }
- virtual void markDescendantBlocksAndLinesForLayout(bool inLayout = true);
+ virtual void markForPaginationRelayoutIfNeeded();
bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); }
bool containsFloat(RenderObject*);
@@ -105,10 +98,11 @@ public:
int availableLogicalWidthForLine(int position, bool firstLine) const;
int logicalRightOffsetForLine(int position, bool firstLine) const { return logicalRightOffsetForLine(position, logicalRightOffsetForContent(), firstLine); }
int logicalLeftOffsetForLine(int position, bool firstLine) const { return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(), firstLine); }
-
- virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
- virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
- virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
+
+ virtual int topmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
virtual VisiblePosition positionForPoint(const IntPoint&);
@@ -169,6 +163,51 @@ public:
void setPaginationStrut(int strut);
void setPageY(int y);
+ // Accessors for logical width/height and margins in the containing block's block-flow direction.
+ enum ApplyLayoutDeltaMode { ApplyLayoutDelta, DoNotApplyLayoutDelta };
+ int logicalWidthForChild(RenderBox* child) { return style()->isHorizontalWritingMode() ? child->width() : child->height(); }
+ int logicalHeightForChild(RenderBox* child) { return style()->isHorizontalWritingMode() ? child->height() : child->width(); }
+ int logicalTopForChild(RenderBox* child) { return style()->isHorizontalWritingMode() ? child->y() : child->x(); }
+ void setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta);
+ void setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta);
+ int marginBeforeForChild(RenderBoxModelObject* child) const;
+ int marginAfterForChild(RenderBoxModelObject* child) const;
+ int marginStartForChild(RenderBoxModelObject* child) const;
+ int marginEndForChild(RenderBoxModelObject* child) const;
+ void setMarginStartForChild(RenderBox* child, int);
+ void setMarginEndForChild(RenderBox* child, int);
+ void setMarginBeforeForChild(RenderBox* child, int);
+ void setMarginAfterForChild(RenderBox* child, int);
+ int collapsedMarginBeforeForChild(RenderBox* child) const;
+ int collapsedMarginAfterForChild(RenderBox* child) const;
+
+ class MarginValues {
+ public:
+ MarginValues(int beforePos, int beforeNeg, int afterPos, int afterNeg)
+ : m_positiveMarginBefore(beforePos)
+ , m_negativeMarginBefore(beforeNeg)
+ , m_positiveMarginAfter(afterPos)
+ , m_negativeMarginAfter(afterNeg)
+ { }
+
+ int positiveMarginBefore() const { return m_positiveMarginBefore; }
+ int negativeMarginBefore() const { return m_negativeMarginBefore; }
+ int positiveMarginAfter() const { return m_positiveMarginAfter; }
+ int negativeMarginAfter() const { return m_negativeMarginAfter; }
+
+ void setPositiveMarginBefore(int pos) { m_positiveMarginBefore = pos; }
+ void setNegativeMarginBefore(int neg) { m_negativeMarginBefore = neg; }
+ void setPositiveMarginAfter(int pos) { m_positiveMarginAfter = pos; }
+ void setNegativeMarginAfter(int neg) { m_negativeMarginAfter = neg; }
+
+ private:
+ int m_positiveMarginBefore;
+ int m_negativeMarginBefore;
+ int m_positiveMarginAfter;
+ int m_negativeMarginAfter;
+ };
+ MarginValues marginValuesForChild(RenderBox* child);
+
protected:
// These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode.
// Since they are typically called only to move objects around within anonymous blocks (which only have layers in
@@ -194,10 +233,10 @@ protected:
}
void moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false);
- int maxPosMarginBefore() const { return m_rareData ? m_rareData->m_beforePos : RenderBlockRareData::beforePosDefault(this); }
- int maxNegMarginBefore() const { return m_rareData ? m_rareData->m_beforeNeg : RenderBlockRareData::beforeNegDefault(this); }
- int maxPosMarginAfter() const { return m_rareData ? m_rareData->m_afterPos : RenderBlockRareData::afterPosDefault(this); }
- int maxNegMarginAfter() const { return m_rareData ? m_rareData->m_afterNeg : RenderBlockRareData::afterNegDefault(this); }
+ int maxPositiveMarginBefore() const { return m_rareData ? m_rareData->m_margins.positiveMarginBefore() : RenderBlockRareData::positiveMarginBeforeDefault(this); }
+ int maxNegativeMarginBefore() const { return m_rareData ? m_rareData->m_margins.negativeMarginBefore() : RenderBlockRareData::negativeMarginBeforeDefault(this); }
+ int maxPositiveMarginAfter() const { return m_rareData ? m_rareData->m_margins.positiveMarginAfter() : RenderBlockRareData::positiveMarginAfterDefault(this); }
+ int maxNegativeMarginAfter() const { return m_rareData ? m_rareData->m_margins.negativeMarginAfter() : RenderBlockRareData::negativeMarginAfterDefault(this); }
void setMaxMarginBeforeValues(int pos, int neg);
void setMaxMarginAfterValues(int pos, int neg);
@@ -205,10 +244,8 @@ protected:
void initMaxMarginValues()
{
if (m_rareData) {
- m_rareData->m_beforePos = RenderBlockRareData::beforePosDefault(this);
- m_rareData->m_beforeNeg = RenderBlockRareData::beforeNegDefault(this);
- m_rareData->m_afterPos = RenderBlockRareData::afterPosDefault(this);
- m_rareData->m_afterNeg = RenderBlockRareData::afterNegDefault(this);
+ m_rareData->m_margins = MarginValues(RenderBlockRareData::positiveMarginBeforeDefault(this) , RenderBlockRareData::negativeMarginBeforeDefault(this),
+ RenderBlockRareData::positiveMarginAfterDefault(this), RenderBlockRareData::negativeMarginAfterDefault(this));
m_rareData->m_paginationStrut = 0;
}
}
@@ -220,8 +257,8 @@ protected:
virtual void paint(PaintInfo&, int tx, int ty);
virtual void paintObject(PaintInfo&, int tx, int ty);
- int logicalRightOffsetForContent() const;
- int logicalLeftOffsetForContent() const;
+ int logicalRightOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() + availableLogicalWidth() : borderTop() + paddingTop() + availableLogicalWidth(); }
+ int logicalLeftOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); }
int logicalRightOffsetForLine(int position, int fixedOffset, bool applyTextIndent = true, int* logicalHeightRemaining = 0) const;
int logicalLeftOffsetForLine(int position, int fixedOffset, bool applyTextIndent = true, int* logicalHeightRemaining = 0) const;
@@ -256,9 +293,9 @@ protected:
// Only used by RenderSVGText, which explicitely overrides RenderBlock::layoutBlock(), do NOT use for anything else.
void forceLayoutInlineChildren()
{
- int repaintTop = 0;
- int repaintBottom = 0;
- layoutInlineChildren(true, repaintTop, repaintBottom);
+ int repaintLogicalTop = 0;
+ int repaintLogicalBottom = 0;
+ layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom);
}
#endif
@@ -284,19 +321,13 @@ private:
virtual bool isSelfCollapsingBlock() const;
- virtual int maxMarginBefore(MarginSign sign) const
- {
- return (sign == PositiveMargin) ? maxPosMarginBefore() : maxNegMarginBefore();
- }
- virtual int maxMarginAfter(MarginSign sign) const
- {
- return (sign == PositiveMargin) ? maxPosMarginAfter() : maxNegMarginAfter();
- }
+ virtual int collapsedMarginBefore() const { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); }
+ virtual int collapsedMarginAfter() const { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); }
virtual void repaintOverhangingFloats(bool paintAllDescendants);
- void layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom);
- void layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom);
+ void layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom);
+ void layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom);
virtual void positionListMarker() { }
@@ -323,37 +354,94 @@ private:
};
struct FloatingObject : Noncopyable {
- enum Type {
- FloatLeft,
- FloatRight
- };
+ // Note that Type uses bits so you can use FloatBoth as a mask to query for both left and right.
+ enum Type { FloatLeft = 1, FloatRight = 2, FloatBoth = 3 };
FloatingObject(Type type)
: m_renderer(0)
- , m_top(0)
- , m_bottom(0)
- , m_left(0)
- , m_width(0)
, m_paginationStrut(0)
, m_type(type)
, m_shouldPaint(true)
, m_isDescendant(false)
+ , m_isPlaced(false)
{
}
- Type type() { return static_cast<Type>(m_type); }
+ FloatingObject(Type type, const IntRect& frameRect)
+ : m_renderer(0)
+ , m_frameRect(frameRect)
+ , m_paginationStrut(0)
+ , m_type(type)
+ , m_shouldPaint(true)
+ , m_isDescendant(false)
+ , m_isPlaced(true)
+ {
+ }
+
+ Type type() const { return static_cast<Type>(m_type); }
+ RenderBox* renderer() const { return m_renderer; }
+
+ bool isPlaced() const { return m_isPlaced; }
+ void setIsPlaced(bool placed = true) { m_isPlaced = placed; }
+
+ int left() const { ASSERT(isPlaced()); return m_frameRect.x(); }
+ int right() const { ASSERT(isPlaced()); return m_frameRect.right(); }
+ int top() const { ASSERT(isPlaced()); return m_frameRect.y(); }
+ int bottom() const { ASSERT(isPlaced()); return m_frameRect.bottom(); }
+ int width() const { return m_frameRect.width(); }
+ int height() const { return m_frameRect.height(); }
+
+ void setLeft(int left) { m_frameRect.setX(left); }
+ void setTop(int top) { m_frameRect.setY(top); }
+ void setWidth(int width) { m_frameRect.setWidth(width); }
+ void setHeight(int height) { m_frameRect.setHeight(height); }
+
+ const IntRect& frameRect() const { ASSERT(isPlaced()); return m_frameRect; }
+ void setFrameRect(const IntRect& frameRect) { m_frameRect = frameRect; }
RenderBox* m_renderer;
- int m_top;
- int m_bottom;
- int m_left;
- int m_width;
+ IntRect m_frameRect;
int m_paginationStrut;
- unsigned m_type : 1; // Type (left or right aligned)
+ unsigned m_type : 2; // Type (left or right aligned)
bool m_shouldPaint : 1;
bool m_isDescendant : 1;
+ bool m_isPlaced : 1;
};
+ int logicalTopForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->top() : child->left(); }
+ int logicalBottomForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->bottom() : child->right(); }
+ int logicalLeftForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->left() : child->top(); }
+ int logicalRightForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->right() : child->bottom(); }
+ int logicalWidthForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->width() : child->height(); }
+ void setLogicalTopForFloat(FloatingObject* child, int logicalTop)
+ {
+ if (style()->isHorizontalWritingMode())
+ child->setTop(logicalTop);
+ else
+ child->setLeft(logicalTop);
+ }
+ void setLogicalLeftForFloat(FloatingObject* child, int logicalLeft)
+ {
+ if (style()->isHorizontalWritingMode())
+ child->setLeft(logicalLeft);
+ else
+ child->setTop(logicalLeft);
+ }
+ void setLogicalHeightForFloat(FloatingObject* child, int logicalHeight)
+ {
+ if (style()->isHorizontalWritingMode())
+ child->setHeight(logicalHeight);
+ else
+ child->setWidth(logicalHeight);
+ }
+ void setLogicalWidthForFloat(FloatingObject* child, int logicalWidth)
+ {
+ if (style()->isHorizontalWritingMode())
+ child->setWidth(logicalWidth);
+ else
+ child->setHeight(logicalWidth);
+ }
+
// The following functions' implementations are in RenderBlockLineLayout.cpp.
RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
@@ -375,6 +463,10 @@ private:
void deleteEllipsisLineBoxes();
void checkLinesForTextOverflow();
void addOverflowFromInlineChildren();
+ int beforeSideVisibleOverflowForLine(RootInlineBox*) const;
+ int afterSideVisibleOverflowForLine(RootInlineBox*) const;
+ int beforeSideLayoutOverflowForLine(RootInlineBox*) const;
+ int afterSideLayoutOverflowForLine(RootInlineBox*) const;
// End of functions defined in RenderBlockLineLayout.cpp.
void addOverflowFromBlockChildren();
@@ -406,15 +498,13 @@ private:
virtual bool avoidsFloats() const;
- bool hasOverhangingFloats() { return parent() && !hasColumns() && floatBottom() > height(); }
+ bool hasOverhangingFloats() { return parent() && !hasColumns() && lowestFloatLogicalBottom() > logicalHeight(); }
void addIntrudingFloats(RenderBlock* prev, int xoffset, int yoffset);
int addOverhangingFloats(RenderBlock* child, int xoffset, int yoffset, bool makeChildPaintOtherFloats);
- int nextFloatBottomBelow(int) const;
- int floatBottom() const;
- inline int leftBottom();
- inline int rightBottom();
-
+ int lowestFloatLogicalBottom(FloatingObject::Type = FloatingObject::FloatBoth) const;
+ int nextFloatLogicalBottomBelow(int) const;
+
virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
bool hitTestFloats(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
@@ -468,7 +558,7 @@ private:
void adjustPointToColumnContents(IntPoint&) const;
void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust
- void markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest = 0);
+ void markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest = 0);
void newLine(EClear);
@@ -524,24 +614,24 @@ private:
bool m_determinedMarginBeforeQuirk : 1;
// These flags track the previous maximal positive and negative margins.
- int m_posMargin;
- int m_negMargin;
+ int m_positiveMargin;
+ int m_negativeMargin;
public:
MarginInfo(RenderBlock* b, int beforeBorderPadding, int afterBorderPadding);
void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; }
void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; }
- void clearMargin() { m_posMargin = m_negMargin = 0; }
+ void clearMargin() { m_positiveMargin = m_negativeMargin = 0; }
void setMarginBeforeQuirk(bool b) { m_marginBeforeQuirk = b; }
void setMarginAfterQuirk(bool b) { m_marginAfterQuirk = b; }
void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
- void setPosMargin(int p) { m_posMargin = p; }
- void setNegMargin(int n) { m_negMargin = n; }
- void setPosMarginIfLarger(int p) { if (p > m_posMargin) m_posMargin = p; }
- void setNegMarginIfLarger(int n) { if (n > m_negMargin) m_negMargin = n; }
+ void setPositiveMargin(int p) { m_positiveMargin = p; }
+ void setNegativeMargin(int n) { m_negativeMargin = n; }
+ void setPositiveMarginIfLarger(int p) { if (p > m_positiveMargin) m_positiveMargin = p; }
+ void setNegativeMarginIfLarger(int n) { if (n > m_negativeMargin) m_negativeMargin = n; }
- void setMargin(int p, int n) { m_posMargin = p; m_negMargin = n; }
+ void setMargin(int p, int n) { m_positiveMargin = p; m_negativeMargin = n; }
bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; }
@@ -552,12 +642,12 @@ private:
bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
bool marginBeforeQuirk() const { return m_marginBeforeQuirk; }
bool marginAfterQuirk() const { return m_marginAfterQuirk; }
- int posMargin() const { return m_posMargin; }
- int negMargin() const { return m_negMargin; }
- int margin() const { return m_posMargin - m_negMargin; }
+ int positiveMargin() const { return m_positiveMargin; }
+ int negativeMargin() const { return m_negativeMargin; }
+ int margin() const { return m_positiveMargin - m_negativeMargin; }
};
- void layoutBlockChild(RenderBox* child, MarginInfo&, int& previousFloatBottom, int& maxFloatBottom);
+ void layoutBlockChild(RenderBox* child, MarginInfo&, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom);
void adjustPositionedBlock(RenderBox* child, const MarginInfo&);
void adjustFloatingBlock(const MarginInfo&);
bool handleSpecialChild(RenderBox* child, const MarginInfo&);
@@ -566,9 +656,9 @@ private:
bool handleRunInChild(RenderBox* child);
int collapseMargins(RenderBox* child, MarginInfo&);
int clearFloatsIfNeeded(RenderBox* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin, int yPos);
- int estimateVerticalPosition(RenderBox* child, const MarginInfo&);
- void determineHorizontalPosition(RenderBox* child);
- void handleBottomOfBlock(int top, int bottom, MarginInfo&);
+ int estimateLogicalTopPosition(RenderBox* child, const MarginInfo&);
+ void determineLogicalLeftPositionForChild(RenderBox* child);
+ void handleAfterSideOfBlock(int top, int bottom, MarginInfo&);
void setCollapsedBottomMargin(const MarginInfo&);
// End helper functions and structs used by layoutBlockChildren.
@@ -589,41 +679,35 @@ private:
// split into a sequence of inlines and blocks. The continuation will either be
// an anonymous block (that houses other blocks) or it will be an inline flow.
RenderBoxModelObject* m_continuation;
-
+
// Allocated only when some of these fields have non-default values
struct RenderBlockRareData : Noncopyable {
RenderBlockRareData(const RenderBlock* block)
- : m_beforePos(beforePosDefault(block))
- , m_beforeNeg(beforeNegDefault(block))
- , m_afterPos(afterPosDefault(block))
- , m_afterNeg(afterNegDefault(block))
+ : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block))
, m_paginationStrut(0)
, m_pageY(0)
{
}
- static int beforePosDefault(const RenderBlock* block)
+ static int positiveMarginBeforeDefault(const RenderBlock* block)
{
return std::max(block->marginBefore(), 0);
}
- static int beforeNegDefault(const RenderBlock* block)
+ static int negativeMarginBeforeDefault(const RenderBlock* block)
{
return std::max(-block->marginBefore(), 0);
}
- static int afterPosDefault(const RenderBlock* block)
+ static int positiveMarginAfterDefault(const RenderBlock* block)
{
return std::max(block->marginAfter(), 0);
}
- static int afterNegDefault(const RenderBlock* block)
+ static int negativeMarginAfterDefault(const RenderBlock* block)
{
return std::max(-block->marginAfter(), 0);
}
- int m_beforePos;
- int m_beforeNeg;
- int m_afterPos;
- int m_afterNeg;
+ MarginValues m_margins;
int m_paginationStrut;
int m_pageY;
};
diff --git a/WebCore/rendering/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp
index 1df4bbc..ce84d31 100644
--- a/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -64,13 +64,12 @@ const unsigned cMaxLineDepth = 200;
static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
{
- bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline;
- if (leftSide)
- return child->marginLeft() + child->paddingLeft() + child->borderLeft();
- return child->marginRight() + child->paddingRight() + child->borderRight();
+ if (endOfInline)
+ return child->marginEnd() + child->paddingEnd() + child->borderEnd();
+ return child->marginStart() + child->paddingStart() + child->borderStart();
}
-static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
+static int inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
{
unsigned lineDepth = 1;
int extraWidth = 0;
@@ -246,12 +245,13 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
{
ASSERT(firstRun);
+ bool rootHasSelectedChildren = false;
InlineFlowBox* parentBox = 0;
for (BidiRun* r = firstRun; r; r = r->next()) {
// Create a box for our object.
bool isOnlyRun = (runCount == 1);
if (runCount == 2 && !r->m_object->isListMarker())
- isOnlyRun = ((style()->direction() == RTL) ? lastRun : firstRun)->m_object->isListMarker();
+ isOnlyRun = (!style()->isLeftToRightDirection() ? lastRun : firstRun)->m_object->isListMarker();
InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
r->m_box = box;
@@ -260,6 +260,9 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
if (!box)
continue;
+ if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone)
+ rootHasSelectedChildren = true;
+
// If we have no parent box yet, or if the run is not simply a sibling,
// then we need to construct inline boxes as necessary to properly enclose the
// run's inline box.
@@ -287,6 +290,11 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
// be the last continuation of our line list.
ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
+ // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
+ // from the bidi runs walk above has a selection state.
+ if (rootHasSelectedChildren)
+ lastLineBox()->root()->setHasSelectedChildren(true);
+
// Set bits on our inline flow boxes that indicate which sides should
// paint borders/margins/padding. This knowledge will ultimately be used when
// we determine the horizontal positions and widths of all the inline boxes on
@@ -302,9 +310,9 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
{
- // First determine our total width.
- int availableWidth = availableLogicalWidthForLine(height(), firstLine);
- int totWidth = lineBox->getFlowSpacingLogicalWidth();
+ // First determine our total logical width.
+ int availableLogicalWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
+ int totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
bool needsWordSpacing = false;
unsigned numSpaces = 0;
ETextAlign textAlign = style()->textAlign();
@@ -328,7 +336,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
if (int length = rt->textLength()) {
if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
- totWidth += rt->style(firstLine)->font().wordSpacing();
+ totalLogicalWidth += rt->style(firstLine)->font().wordSpacing();
needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length;
}
HashSet<const SimpleFontData*> fallbackFonts;
@@ -338,7 +346,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
const AtomicString& hyphenString = rt->style()->hyphenString();
hyphenWidth = rt->style(firstLine)->font().width(TextRun(hyphenString.characters(), hyphenString.length()));
}
- r->m_box->setLogicalWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, firstLine, &fallbackFonts, &glyphOverflow) + hyphenWidth);
+ r->m_box->setLogicalWidth(rt->width(r->m_start, r->m_stop - r->m_start, totalLogicalWidth, firstLine, &fallbackFonts, &glyphOverflow) + hyphenWidth);
if (!fallbackFonts.isEmpty()) {
ASSERT(r->m_box->isText());
GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
@@ -353,37 +361,37 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
} else if (!r->m_object->isRenderInline()) {
RenderBox* renderBox = toRenderBox(r->m_object);
renderBox->computeLogicalWidth();
- r->m_box->setLogicalWidth(renderBox->width());
- totWidth += renderBox->marginLeft() + renderBox->marginRight();
+ r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
+ totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
}
- totWidth += r->m_box->logicalWidth();
+ totalLogicalWidth += r->m_box->logicalWidth();
}
// Armed with the total width of the line (without justification),
// we now examine our text-align property in order to determine where to position the
// objects horizontally. The total width of the line can be increased if we end up
// justifying text.
- int x = logicalLeftOffsetForLine(height(), firstLine);
+ int logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine);
switch (textAlign) {
case LEFT:
case WEBKIT_LEFT:
// The direction of the block should determine what happens with wide lines. In
// particular with RTL blocks, wide lines should still spill out to the left.
- if (style()->direction() == LTR) {
- if (totWidth > availableWidth && trailingSpaceRun)
- trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totWidth + availableWidth));
+ if (style()->isLeftToRightDirection()) {
+ if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
+ trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
} else {
if (trailingSpaceRun)
trailingSpaceRun->m_box->setLogicalWidth(0);
- else if (totWidth > availableWidth)
- x -= (totWidth - availableWidth);
+ else if (totalLogicalWidth > availableLogicalWidth)
+ logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
}
break;
case JUSTIFY:
if (numSpaces && !reachedEnd && !lineBox->endsWithBreak()) {
if (trailingSpaceRun) {
- totWidth -= trailingSpaceRun->m_box->logicalWidth();
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
trailingSpaceRun->m_box->setLogicalWidth(0);
}
break;
@@ -392,9 +400,9 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
case TAAUTO:
numSpaces = 0;
// for right to left fall through to right aligned
- if (style()->direction() == LTR) {
- if (totWidth > availableWidth && trailingSpaceRun)
- trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totWidth + availableWidth));
+ if (style()->isLeftToRightDirection()) {
+ if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
+ trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
break;
}
case RIGHT:
@@ -402,33 +410,33 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
// Wide lines spill out of the block based off direction.
// So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
// side of the block.
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
if (trailingSpaceRun) {
- totWidth -= trailingSpaceRun->m_box->logicalWidth();
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
trailingSpaceRun->m_box->setLogicalWidth(0);
}
- if (totWidth < availableWidth)
- x += availableWidth - totWidth;
+ if (totalLogicalWidth < availableLogicalWidth)
+ logicalLeft += availableLogicalWidth - totalLogicalWidth;
} else {
- if (totWidth > availableWidth && trailingSpaceRun) {
- trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totWidth + availableWidth));
- totWidth -= trailingSpaceRun->m_box->logicalWidth();
+ if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
+ trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
} else
- x += availableWidth - totWidth;
+ logicalLeft += availableLogicalWidth - totalLogicalWidth;
}
break;
case CENTER:
case WEBKIT_CENTER:
int trailingSpaceWidth = 0;
if (trailingSpaceRun) {
- totWidth -= trailingSpaceRun->m_box->logicalWidth();
- trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableWidth - totWidth + 1) / 2);
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
+ trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceWidth));
}
- if (style()->direction() == LTR)
- x += max((availableWidth - totWidth) / 2, 0);
+ if (style()->isLeftToRightDirection())
+ logicalLeft += max((availableLogicalWidth - totalLogicalWidth) / 2, 0);
else
- x += totWidth > availableWidth ? (availableWidth - totWidth) : (availableWidth - totWidth) / 2 - trailingSpaceWidth;
+ logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
break;
}
@@ -451,9 +459,9 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
// Only justify text if whitespace is collapsed.
if (r->m_object->style()->collapseWhiteSpace()) {
- spaceAdd = (availableWidth - totWidth) * spaces / numSpaces;
+ spaceAdd = (availableLogicalWidth - totalLogicalWidth) * spaces / numSpaces;
static_cast<InlineTextBox*>(r->m_box)->setSpaceAdd(spaceAdd);
- totWidth += spaceAdd;
+ totalLogicalWidth += spaceAdd;
}
numSpaces -= spaces;
if (!numSpaces)
@@ -465,13 +473,13 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
// The widths of all runs are now known. We can now place every inline box (and
// compute accurate widths for the inline flow boxes).
needsWordSpacing = false;
- lineBox->placeBoxesInInlineDirection(x, needsWordSpacing, textBoxDataMap);
+ lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
}
void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
{
- setLogicalHeight(lineBox->alignBoxesInBlockDirection(height(), textBoxDataMap));
- lineBox->setBlockHeight(height());
+ setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap));
+ lineBox->setBlockLogicalHeight(logicalHeight());
// Now make sure we place replaced render objects correctly.
for (BidiRun* r = firstRun; r; r = r->next()) {
@@ -482,7 +490,7 @@ void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox,
// Align positioned boxes with the top of the line box. This is
// a reasonable approximation of an appropriate y position.
if (r->m_object->isPositioned())
- r->m_box->setY(height());
+ r->m_box->setLogicalTop(logicalHeight());
// Position is used to properly position both replaced elements and
// to update the static normal flow x/y of positioned elements.
@@ -507,14 +515,13 @@ static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
return false;
}
-void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom)
+void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom)
{
bool useRepaintBounds = false;
m_overflow.clear();
- setLogicalHeight(borderTop() + paddingTop());
- int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+ setLogicalHeight(borderBefore() + paddingBefore());
// Figure out if we should clear out our line boxes.
// FIXME: Handle resize eventually!
@@ -582,7 +589,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
o->setChildNeedsLayout(true, false);
// If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
- if (relayoutChildren && (o->style()->paddingLeft().isPercent() || o->style()->paddingRight().isPercent()))
+ if (relayoutChildren && (o->style()->paddingStart().isPercent() || o->style()->paddingEnd().isPercent()))
o->setPreferredLogicalWidthsDirty(true, false);
if (o->isPositioned())
@@ -706,7 +713,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool firstLine = true;
bool previousLineBrokeCleanly = true;
RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex,
- useRepaintBounds, repaintTop, repaintBottom);
+ useRepaintBounds, repaintLogicalTop, repaintLogicalBottom);
if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
@@ -729,21 +736,21 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// if we determine that we're able to synchronize after handling all our dirty lines.
InlineIterator cleanLineStart;
BidiStatus cleanLineBidiStatus;
- int endLineYPos = 0;
+ int endLineLogicalTop = 0;
RootInlineBox* endLine = (fullLayout || !startLine) ?
- 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
+ 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
if (startLine) {
if (!useRepaintBounds) {
useRepaintBounds = true;
- repaintTop = height();
- repaintBottom = height();
+ repaintLogicalTop = logicalHeight();
+ repaintLogicalBottom = logicalHeight();
}
RenderArena* arena = renderArena();
RootInlineBox* box = startLine;
while (box) {
- repaintTop = min(repaintTop, box->topVisibleOverflow());
- repaintBottom = max(repaintBottom, box->bottomVisibleOverflow());
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(box));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(box));
RootInlineBox* next = box->nextRootBox();
box->deleteLine(arena);
box = next;
@@ -777,7 +784,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
while (!end.atEnd()) {
// FIXME: Is this check necessary before the first iteration or can it be moved to the end?
- if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop)))
+ if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop)))
break;
lineMidpointState.reset();
@@ -854,7 +861,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// inline flow boxes.
RootInlineBox* lineBox = 0;
- int oldHeight = height();
+ int oldLogicalHeight = logicalHeight();
if (resolver.runCount()) {
if (hyphenated)
resolver.logicallyLastRun()->m_hasHyphen = true;
@@ -902,30 +909,30 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
if (lineBox) {
lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
if (useRepaintBounds) {
- repaintTop = min(repaintTop, lineBox->topVisibleOverflow());
- repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(lineBox));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(lineBox));
}
if (paginated) {
int adjustment = 0;
adjustLinePositionForPagination(lineBox, adjustment);
if (adjustment) {
- int oldLineWidth = availableLogicalWidthForLine(oldHeight, firstLine);
+ int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, firstLine);
lineBox->adjustPosition(0, adjustment);
if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop.
- repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(lineBox));
- if (availableLogicalWidthForLine(oldHeight + adjustment, firstLine) != oldLineWidth) {
+ if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, firstLine) != oldLineWidth) {
// We have to delete this line, remove all floats that got added, and let line layout re-run.
lineBox->deleteLine(renderArena());
- removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldHeight);
- setLogicalHeight(oldHeight + adjustment);
+ removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
+ setLogicalHeight(oldLogicalHeight + adjustment);
resolver.setPosition(oldEnd);
end = oldEnd;
continue;
}
- setLogicalHeight(lineBox->blockHeight());
+ setLogicalHeight(lineBox->blockLogicalHeight());
}
}
}
@@ -945,7 +952,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
lastRootBox()->floats().append(f->m_renderer);
ASSERT(f->m_renderer == floats[floatIndex].object);
// If a float's geometry has changed, give up on syncing with clean lines.
- if (floats[floatIndex].rect != IntRect(f->m_left, f->m_top, f->m_width, f->m_bottom - f->m_top))
+ if (floats[floatIndex].rect != f->frameRect())
checkForEndLineMatch = false;
floatIndex++;
}
@@ -959,7 +966,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
if (endLine) {
if (endLineMatched) {
// Attach all the remaining lines, and then adjust their y-positions as needed.
- int delta = height() - endLineYPos;
+ int delta = logicalHeight() - endLineLogicalTop;
for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
line->attachLine();
if (paginated) {
@@ -967,28 +974,27 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
adjustLinePositionForPagination(line, delta);
}
if (delta) {
- repaintTop = min(repaintTop, line->topVisibleOverflow() + min(delta, 0));
- repaintBottom = max(repaintBottom, line->bottomVisibleOverflow() + max(delta, 0));
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(line) + min(delta, 0));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(line) + max(delta, 0));
line->adjustPosition(0, delta);
}
if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
Vector<RenderBox*>::iterator end = cleanLineFloats->end();
for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
- int floatTop = (*f)->y() - (*f)->marginTop();
insertFloatingObject(*f);
- setLogicalHeight(floatTop + delta);
+ setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
positionNewFloats();
}
}
}
- setLogicalHeight(lastRootBox()->blockHeight());
+ setLogicalHeight(lastRootBox()->blockLogicalHeight());
} else {
// Delete all the remaining lines.
RootInlineBox* line = endLine;
RenderArena* arena = renderArena();
while (line) {
- repaintTop = min(repaintTop, line->topVisibleOverflow());
- repaintBottom = max(repaintBottom, line->bottomVisibleOverflow());
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(line));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(line));
RootInlineBox* next = line->nextRootBox();
line->deleteLine(arena);
line = next;
@@ -1000,15 +1006,15 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// 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();
+ int bottomVisualOverflow = afterSideVisibleOverflowForLine(lastRootBox());
+ int bottomLayoutOverflow = afterSideLayoutOverflowForLine(lastRootBox());
TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
m_lineBoxes.appendLineBox(trailingFloatsLineBox);
trailingFloatsLineBox->setConstructed();
GlyphOverflowAndFallbackFontsMap textBoxDataMap;
- trailingFloatsLineBox->alignBoxesInBlockDirection(height(), textBoxDataMap);
- trailingFloatsLineBox->setBlockDirectionOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0);
- trailingFloatsLineBox->setBlockHeight(height());
+ trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap);
+ trailingFloatsLineBox->setBlockDirectionOverflowPositions(logicalHeight(), bottomLayoutOverflow, logicalHeight(), bottomVisualOverflow, 0);
+ trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight());
}
if (lastFloat) {
for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
@@ -1034,10 +1040,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
}
// Now add in the bottom border/padding.
- setLogicalHeight(height() + toAdd);
+ setLogicalHeight(logicalHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
if (!firstLineBox() && hasLineIfEmpty())
- setLogicalHeight(height() + lineHeight(true, true));
+ setLogicalHeight(logicalHeight() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
// See if we have any lines that spill out of our block. If we do, then we will possibly need to
// truncate text.
@@ -1047,7 +1053,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
- bool& useRepaintBounds, int& repaintTop, int& repaintBottom)
+ bool& useRepaintBounds, int& repaintLogicalTop, int& repaintLogicalBottom)
{
RootInlineBox* curr = 0;
RootInlineBox* last = 0;
@@ -1072,8 +1078,8 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
if (!useRepaintBounds)
useRepaintBounds = true;
- repaintTop = min(repaintTop, curr->topVisibleOverflow() + min(paginationDelta, 0));
- repaintBottom = max(repaintBottom, curr->bottomVisibleOverflow() + max(paginationDelta, 0));
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(curr) + min(paginationDelta, 0));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(curr) + max(paginationDelta, 0));
curr->adjustPosition(0, paginationDelta);
}
}
@@ -1092,9 +1098,11 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
break;
}
if (floats[floatIndex].rect.size() != newSize) {
- int floatTop = floats[floatIndex].rect.y();
+ int floatTop = style()->isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
+ int floatHeight = style()->isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height())
+ : max(floats[floatIndex].rect.width(), newSize.width());
curr->markDirty();
- markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()), curr);
+ markLinesDirtyInBlockRange(curr->blockLogicalHeight(), floatTop + floatHeight, curr);
floats[floatIndex].rect.setSize(newSize);
dirtiedByFloat = true;
}
@@ -1144,7 +1152,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
numCleanFloats = 0;
if (!floats.isEmpty()) {
- int savedHeight = height();
+ int savedLogicalHeight = logicalHeight();
// Restore floats from clean lines.
RootInlineBox* line = firstRootBox();
while (line != curr) {
@@ -1152,7 +1160,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
Vector<RenderBox*>::iterator end = cleanLineFloats->end();
for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
insertFloatingObject(*f);
- setLogicalHeight((*f)->y() - (*f)->marginTop());
+ setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
positionNewFloats();
ASSERT(floats[numCleanFloats].object == *f);
numCleanFloats++;
@@ -1160,7 +1168,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
}
line = line->nextRootBox();
}
- setLogicalHeight(savedHeight);
+ setLogicalHeight(savedLogicalHeight);
}
firstLine = !last;
@@ -1169,12 +1177,12 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
RenderObject* startObj;
int pos = 0;
if (last) {
- setLogicalHeight(last->blockHeight());
+ setLogicalHeight(last->blockLogicalHeight());
startObj = last->lineBreakObj();
pos = last->lineBreakPos();
resolver.setStatus(last->lineBreakBidiStatus());
} else {
- bool ltr = style()->direction() == LTR
+ bool ltr = style()->isLeftToRightDirection()
#if ENABLE(SVG)
|| (style()->unicodeBidi() == UBNormal && isSVGText())
#endif
@@ -1194,7 +1202,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
return curr;
}
-RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& yPos)
+RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& logicalTop)
{
RootInlineBox* last = 0;
if (!startLine)
@@ -1214,7 +1222,7 @@ RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, Inlin
RootInlineBox* prev = last->prevRootBox();
cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
cleanLineBidiStatus = prev->lineBreakBidiStatus();
- yPos = prev->blockHeight();
+ logicalTop = prev->blockLogicalHeight();
for (RootInlineBox* line = last; line; line = line->nextRootBox())
line->extractLine(); // Disconnect all line boxes from their render objects while preserving
@@ -1223,27 +1231,28 @@ RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, Inlin
return last;
}
-bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop)
+bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine,
+ int& endLogicalTop, int& repaintLogicalBottom, int& repaintLogicalTop)
{
if (resolver.position() == endLineStart) {
if (resolver.status() != endLineStatus)
return false;
- int delta = height() - endYPos;
+ int delta = logicalHeight() - endLogicalTop;
if (!delta || !m_floatingObjects)
return true;
// See if any floats end in the range along which we want to shift the lines vertically.
- int top = min(height(), endYPos);
+ int logicalTop = min(logicalHeight(), endLogicalTop);
RootInlineBox* lastLine = endLine;
while (RootInlineBox* nextLine = lastLine->nextRootBox())
lastLine = nextLine;
- int bottom = lastLine->blockHeight() + abs(delta);
+ int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
- if (f->m_bottom >= top && f->m_bottom < bottom)
+ if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
return false;
}
@@ -1261,23 +1270,23 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin
return false; // ...but the bidi state doesn't match.
RootInlineBox* result = line->nextRootBox();
- // Set our yPos to be the block height of endLine.
+ // Set our logical top to be the block height of endLine.
if (result)
- endYPos = line->blockHeight();
+ endLogicalTop = line->blockLogicalHeight();
- int delta = height() - endYPos;
+ int delta = logicalHeight() - endLogicalTop;
if (delta && m_floatingObjects) {
// See if any floats end in the range along which we want to shift the lines vertically.
- int top = min(height(), endYPos);
+ int logicalTop = min(logicalHeight(), endLogicalTop);
RootInlineBox* lastLine = endLine;
while (RootInlineBox* nextLine = lastLine->nextRootBox())
lastLine = nextLine;
- int bottom = lastLine->blockHeight() + abs(delta);
+ int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
- if (f->m_bottom >= top && f->m_bottom < bottom)
+ if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
return false;
}
}
@@ -1286,8 +1295,8 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin
RootInlineBox* boxToDelete = endLine;
RenderArena* arena = renderArena();
while (boxToDelete && boxToDelete != result) {
- repaintTop = min(repaintTop, boxToDelete->topVisibleOverflow());
- repaintBottom = max(repaintBottom, boxToDelete->bottomVisibleOverflow());
+ repaintLogicalTop = min(repaintLogicalTop, beforeSideVisibleOverflowForLine(boxToDelete));
+ repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisibleOverflowForLine(boxToDelete));
RootInlineBox* next = boxToDelete->nextRootBox();
boxToDelete->deleteLine(arena);
boxToDelete = next;
@@ -1337,7 +1346,7 @@ static bool inlineFlowRequiresLineBox(RenderInline* flow)
// FIXME: Right now, we only allow line boxes for inlines that are truly empty.
// We need to fix this, though, because at the very least, inlines containing only
// ignorable whitespace should should also have line boxes.
- return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();
+ return !flow->firstChild() && flow->hasInlineDirectionBordersPaddingOrMargin();
}
bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
@@ -1387,16 +1396,16 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm
// A relative positioned inline encloses us. In this case, we also have to determine our
// position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
// inline so that we can obtain the value later.
- toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? logicalLeftOffsetForLine(height(), false) : logicalRightOffsetForLine(height(), false));
+ toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : logicalRightOffsetForLine(height(), false));
toRenderInline(c)->layer()->setStaticY(height());
}
RenderBox* box = toRenderBox(object);
if (box->style()->hasStaticX()) {
if (box->style()->isOriginalDisplayInlineType())
- box->layer()->setStaticX(style()->direction() == LTR ? logicalLeftOffsetForLine(height(), false) : width() - logicalRightOffsetForLine(height(), false));
+ box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : width() - logicalRightOffsetForLine(height(), false));
else
- box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
+ box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
}
if (box->style()->hasStaticY())
@@ -1409,12 +1418,12 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm
int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
FloatingObject* lastFloatFromPreviousLine)
{
- int availableWidth = availableLogicalWidthForLine(height(), firstLine);
+ int availableWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) {
RenderObject* object = resolver.position().obj;
if (object->isFloating()) {
positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine);
- availableWidth = availableLogicalWidthForLine(height(), firstLine);
+ availableWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
} else if (object->isPositioned()) {
// FIXME: The math here is actually not really right. It's a best-guess approximation that
// will work for the common cases
@@ -1423,16 +1432,16 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstL
// A relative positioned inline encloses us. In this case, we also have to determine our
// position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
// inline so that we can obtain the value later.
- toRenderInline(c)->layer()->setStaticX(style()->direction() == LTR ? logicalLeftOffsetForLine(height(), firstLine) : logicalRightOffsetForLine(height(), firstLine));
+ toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : logicalRightOffsetForLine(height(), firstLine));
toRenderInline(c)->layer()->setStaticY(height());
}
RenderBox* box = toRenderBox(object);
if (box->style()->hasStaticX()) {
if (box->style()->isOriginalDisplayInlineType())
- box->layer()->setStaticX(style()->direction() == LTR ? logicalLeftOffsetForLine(height(), firstLine) : width() - logicalRightOffsetForLine(height(), firstLine));
+ box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : width() - logicalRightOffsetForLine(height(), firstLine));
else
- box->layer()->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
+ box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
}
if (box->style()->hasStaticY())
@@ -1465,22 +1474,22 @@ void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableW
{
ASSERT(widthToFit > availableWidth);
- int floatBottom;
- int lastFloatBottom = height();
+ int floatLogicalBottom;
+ int lastFloatLogicalBottom = logicalHeight();
int newLineWidth = availableWidth;
while (true) {
- floatBottom = nextFloatBottomBelow(lastFloatBottom);
- if (!floatBottom)
+ floatLogicalBottom = nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
+ if (!floatLogicalBottom)
break;
- newLineWidth = availableLogicalWidthForLine(floatBottom, firstLine);
- lastFloatBottom = floatBottom;
+ newLineWidth = availableLogicalWidthForLine(floatLogicalBottom, firstLine);
+ lastFloatLogicalBottom = floatLogicalBottom;
if (newLineWidth >= widthToFit)
break;
}
if (newLineWidth > availableWidth) {
- setLogicalHeight(lastFloatBottom);
+ setLogicalHeight(lastFloatLogicalBottom);
availableWidth = newLineWidth;
}
}
@@ -1571,7 +1580,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// Firefox and Opera will allow a table cell to grow to fit an image inside it under
// very specific circumstances (in order to match common WinIE renderings).
// Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
- bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->width().isIntrinsicOrAuto();
+ bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto();
EWhiteSpace currWS = style()->whiteSpace();
EWhiteSpace lastWS = currWS;
@@ -1621,9 +1630,9 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// check if it fits in the current line.
// If it does, position it now, otherwise, position
// it after moving to next line (in newLine() func)
- if (floatsFitOnLine && floatBox->width() + floatBox->marginLeft() + floatBox->marginRight() + w + tmpW <= width) {
+ if (floatsFitOnLine && logicalWidthForFloat(f) + w + tmpW <= width) {
positionNewFloatOnLine(f, lastFloatFromPreviousLine);
- width = availableLogicalWidthForLine(height(), firstLine);
+ width = availableLogicalWidthForLine(logicalHeight(), firstLine);
} else
floatsFitOnLine = false;
} else if (o->isPositioned()) {
@@ -1633,7 +1642,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
bool isInlineType = box->style()->isOriginalDisplayInlineType();
bool needToSetStaticX = box->style()->hasStaticX();
if (box->style()->hasStaticX() && !isInlineType) {
- box->layer()->setStaticX(o->parent()->style()->direction() == LTR ?
+ box->layer()->setStaticX(o->parent()->style()->isLeftToRightDirection() ?
borderLeft() + paddingLeft() :
borderRight() + paddingRight());
needToSetStaticX = false;
@@ -1691,8 +1700,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
}
- tmpW += flowBox->marginLeft() + flowBox->borderLeft() + flowBox->paddingLeft() +
- flowBox->marginRight() + flowBox->borderRight() + flowBox->paddingRight();
+ tmpW += flowBox->marginStart() + flowBox->borderStart() + flowBox->paddingStart() +
+ flowBox->marginEnd() + flowBox->borderEnd() + flowBox->paddingEnd();
} else if (o->isReplaced()) {
RenderBox* replacedBox = toRenderBox(o);
@@ -1715,7 +1724,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
trailingSpaceObject = 0;
// Optimize for a common case. If we can't find whitespace after the list
- // item, then this is all moot. -dwh
+ // item, then this is all moot.
+ int replacedLogicalWidth = logicalWidthForChild(replacedBox) + marginStartForChild(replacedBox) + marginEndForChild(replacedBox) + inlineLogicalWidth(o);
if (o->isListMarker()) {
if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
// Like with inline flows, we start ignoring spaces to make sure that any
@@ -1725,9 +1735,9 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
ignoringSpaces = true;
}
if (toRenderListMarker(o)->isInside())
- tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o);
+ tmpW += replacedLogicalWidth;
} else
- tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o);
+ tmpW += replacedLogicalWidth;
} else if (o->isText()) {
if (!pos)
appliedStartWidth = false;
@@ -1755,7 +1765,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// space, then subtract its width.
int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0;
- int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
+ int wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true);
int charWidth = 0;
bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
// Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
@@ -1839,7 +1849,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
tmpW += additionalTmpW;
if (!appliedStartWidth) {
- tmpW += inlineWidth(o, true, false);
+ tmpW += inlineLogicalWidth(o, true, false);
appliedStartWidth = true;
}
@@ -1984,7 +1994,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// IMPORTANT: pos is > length here!
int additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
tmpW += additionalTmpW;
- tmpW += inlineWidth(o, !appliedStartWidth, true);
+ tmpW += inlineLogicalWidth(o, !appliedStartWidth, true);
if (canHyphenate && w + tmpW > width) {
tryHyphenating(t, f, style->hyphenationLocale(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
@@ -2149,6 +2159,70 @@ void RenderBlock::addOverflowFromInlineChildren()
}
}
+int RenderBlock::beforeSideVisibleOverflowForLine(RootInlineBox* line) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return line->topVisibleOverflow();
+ case LeftToRightWritingMode:
+ return line->leftVisibleOverflow();
+ case RightToLeftWritingMode:
+ return line->rightVisibleOverflow();
+ case BottomToTopWritingMode:
+ return line->bottomVisibleOverflow();
+ }
+ ASSERT_NOT_REACHED();
+ return line->topVisibleOverflow();
+}
+
+int RenderBlock::afterSideVisibleOverflowForLine(RootInlineBox* line) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return line->bottomVisibleOverflow();
+ case LeftToRightWritingMode:
+ return line->rightVisibleOverflow();
+ case RightToLeftWritingMode:
+ return line->leftVisibleOverflow();
+ case BottomToTopWritingMode:
+ return line->topVisibleOverflow();
+ }
+ ASSERT_NOT_REACHED();
+ return line->bottomVisibleOverflow();
+}
+
+int RenderBlock::beforeSideLayoutOverflowForLine(RootInlineBox* line) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return line->topLayoutOverflow();
+ case LeftToRightWritingMode:
+ return line->leftLayoutOverflow();
+ case RightToLeftWritingMode:
+ return line->rightLayoutOverflow();
+ case BottomToTopWritingMode:
+ return line->bottomLayoutOverflow();
+ }
+ ASSERT_NOT_REACHED();
+ return line->topLayoutOverflow();
+}
+
+int RenderBlock::afterSideLayoutOverflowForLine(RootInlineBox* line) const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return line->bottomLayoutOverflow();
+ case LeftToRightWritingMode:
+ return line->rightLayoutOverflow();
+ case RightToLeftWritingMode:
+ return line->leftLayoutOverflow();
+ case BottomToTopWritingMode:
+ return line->topLayoutOverflow();
+ }
+ ASSERT_NOT_REACHED();
+ return line->bottomLayoutOverflow();
+}
+
void RenderBlock::deleteEllipsisLineBoxes()
{
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
@@ -2170,7 +2244,7 @@ void RenderBlock::checkLinesForTextOverflow()
// if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
// check the left edge of the line box to see if it is less
// Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
- bool ltr = style()->direction() == LTR;
+ bool ltr = style()->isLeftToRightDirection();
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
int blockRightEdge = logicalRightOffsetForLine(curr->y(), curr == firstRootBox());
int blockLeftEdge = logicalLeftOffsetForLine(curr->y(), curr == firstRootBox());
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index ecb6ccc..ac40ee9 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -92,19 +92,14 @@ RenderBox::~RenderBox()
int RenderBox::marginBefore() const
{
- return marginBeforeUsing(style());
-}
-
-int RenderBox::marginBeforeUsing(const RenderStyle* s) const
-{
- switch (s->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
return m_marginTop;
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return m_marginBottom;
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return m_marginLeft;
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return m_marginRight;
}
ASSERT_NOT_REACHED();
@@ -113,19 +108,14 @@ int RenderBox::marginBeforeUsing(const RenderStyle* s) const
int RenderBox::marginAfter() const
{
- return marginAfterUsing(style());
-}
-
-int RenderBox::marginAfterUsing(const RenderStyle* s) const
-{
- switch (s->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
return m_marginBottom;
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return m_marginTop;
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return m_marginRight;
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return m_marginLeft;
}
ASSERT_NOT_REACHED();
@@ -134,62 +124,42 @@ int RenderBox::marginAfterUsing(const RenderStyle* s) const
int RenderBox::marginStart() const
{
- return marginStartUsing(style());
-}
-
-int RenderBox::marginStartUsing(const RenderStyle* s) const
-{
- if (s->isVerticalBlockFlow())
- return s->direction() == LTR ? m_marginLeft : m_marginRight;
- return s->direction() == LTR ? m_marginTop : m_marginBottom;
+ if (style()->isHorizontalWritingMode())
+ return style()->isLeftToRightDirection() ? m_marginLeft : m_marginRight;
+ return style()->isLeftToRightDirection() ? m_marginTop : m_marginBottom;
}
int RenderBox::marginEnd() const
{
- return marginEndUsing(style());
-}
-
-int RenderBox::marginEndUsing(const RenderStyle* s) const
-{
- if (s->isVerticalBlockFlow())
- return s->direction() == LTR ? m_marginRight : m_marginLeft;
- return s->direction() == LTR ? m_marginBottom : m_marginTop;
+ if (style()->isHorizontalWritingMode())
+ return style()->isLeftToRightDirection() ? m_marginRight : m_marginLeft;
+ return style()->isLeftToRightDirection() ? m_marginBottom : m_marginTop;
}
void RenderBox::setMarginStart(int margin)
{
- setMarginStartUsing(style(), margin);
-}
-
-void RenderBox::setMarginEnd(int margin)
-{
- setMarginEndUsing(style(), margin);
-}
-
-void RenderBox::setMarginStartUsing(const RenderStyle* s, int margin)
-{
- if (s->isVerticalBlockFlow()) {
- if (s->direction() == LTR)
+ if (style()->isHorizontalWritingMode()) {
+ if (style()->isLeftToRightDirection())
m_marginLeft = margin;
else
m_marginRight = margin;
} else {
- if (s->direction() == LTR)
+ if (style()->isLeftToRightDirection())
m_marginTop = margin;
else
m_marginBottom = margin;
}
}
-void RenderBox::setMarginEndUsing(const RenderStyle* s, int margin)
+void RenderBox::setMarginEnd(int margin)
{
- if (s->isVerticalBlockFlow()) {
- if (s->direction() == LTR)
+ if (style()->isHorizontalWritingMode()) {
+ if (style()->isLeftToRightDirection())
m_marginRight = margin;
else
m_marginLeft = margin;
} else {
- if (s->direction() == LTR)
+ if (style()->isLeftToRightDirection())
m_marginBottom = margin;
else
m_marginTop = margin;
@@ -198,45 +168,35 @@ void RenderBox::setMarginEndUsing(const RenderStyle* s, int margin)
void RenderBox::setMarginBefore(int margin)
{
- setMarginBeforeUsing(style(), margin);
-}
-
-void RenderBox::setMarginAfter(int margin)
-{
- setMarginAfterUsing(style(), margin);
-}
-
-void RenderBox::setMarginBeforeUsing(const RenderStyle* s, int margin)
-{
- switch (s->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
m_marginTop = margin;
break;
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
m_marginBottom = margin;
break;
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
m_marginLeft = margin;
break;
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
m_marginRight = margin;
break;
}
}
-void RenderBox::setMarginAfterUsing(const RenderStyle* s, int margin)
+void RenderBox::setMarginAfter(int margin)
{
- switch (s->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
m_marginBottom = margin;
break;
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
m_marginTop = margin;
break;
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
m_marginRight = margin;
break;
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
m_marginLeft = margin;
break;
}
@@ -270,8 +230,13 @@ void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
outermostBlock = p;
}
- if (outermostBlock)
+ if (outermostBlock) {
+ RenderObject* parent = outermostBlock->parent();
+ if (parent && parent->isFlexibleBox())
+ outermostBlock = toRenderBlock(parent);
+
outermostBlock->markAllDescendantsWithFloatsForLayout(this, false);
+ }
}
if (isPositioned()) {
@@ -347,11 +312,16 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
// Set the text color if we're the body.
if (isBody())
document()->setTextColor(style()->visitedDependentColor(CSSPropertyColor));
- else if (oldStyle && isRoot() && oldStyle->blockFlow() != style()->blockFlow()) {
- // Propagate the new block flow up to the RenderView.
+ else if (isRoot() && (!oldStyle || oldStyle->writingMode() != style()->writingMode() || oldStyle->direction() != style()->direction())) {
+ // Propagate the new block flow and direction up to the RenderView.
+ // FIXME: WinIE seems to propagate from the <body> as well. We may want to consider doing that at some point.
RenderView* viewRenderer = view();
- viewRenderer->style()->setBlockFlow(style()->blockFlow());
- viewRenderer->setNeedsLayoutAndPrefWidthsRecalc();
+ RenderStyle* viewStyle = viewRenderer->style();
+ if (viewStyle->writingMode() != style()->writingMode() || viewStyle->direction() != style()->direction()) {
+ viewStyle->setWritingMode(style()->writingMode());
+ viewStyle->setDirection(style()->direction());
+ viewRenderer->setNeedsLayoutAndPrefWidthsRecalc();
+ }
}
}
@@ -434,7 +404,7 @@ int RenderBox::scrollWidth() const
if (hasOverflowClip())
return layer()->scrollWidth();
// For objects with visible overflow, this matches IE.
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
return max(clientWidth(), rightmostPosition(true, false) - borderLeft());
return clientWidth() - min(0, leftmostPosition(true, false) - borderLeft());
}
@@ -479,6 +449,24 @@ void RenderBox::absoluteQuads(Vector<FloatQuad>& quads)
quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
}
+IntRect RenderBox::applyLayerTransformToRect(const IntRect& rect) const
+{
+ if (layer() && layer()->hasTransform()) {
+ TransformationMatrix transform;
+ transform.makeIdentity();
+ transform.translate(rect.x(), rect.y());
+ layer()->updateTransform();
+ transform.multLeft(layer()->currentTransform());
+ return transform.mapRect(IntRect(0, 0, rect.width(), rect.height()));
+ }
+ return rect;
+}
+
+IntRect RenderBox::transformedFrameRect() const
+{
+ return applyLayerTransformToRect(frameRect());
+}
+
IntRect RenderBox::absoluteContentBox() const
{
IntRect rect = contentBoxRect();
@@ -721,7 +709,7 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
// Check our bounds next. For this purpose always assume that we can only be hit in the
// foreground phase (which is true for replaced elements like images).
IntRect boundsRect = IntRect(tx, ty, width(), height());
- if (visibleToHitTesting() && action == HitTestForeground && boundsRect.intersects(result.rectFromPoint(xPos, yPos))) {
+ if (visibleToHitTesting() && action == HitTestForeground && boundsRect.intersects(result.rectForPoint(xPos, yPos))) {
updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
if (!result.addNodeToRectBasedTestResult(node(), xPos, yPos, boundsRect))
return true;
@@ -833,7 +821,7 @@ void RenderBox::paintBoxDecorationsWithSize(PaintInfo& paintInfo, int tx, int ty
void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
{
- if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
return;
int w = width();
@@ -856,6 +844,11 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int
bool allMaskImagesLoaded = true;
if (!compositedMask) {
+ // If the context has a rotation, scale or skew, then use a transparency layer to avoid
+ // pixel cruft around the edge of the mask.
+ const AffineTransform& currentCTM = paintInfo.context->getCTM();
+ pushTransparencyLayer = !currentCTM.isIdentityOrTranslationOrFlipped();
+
StyleImage* maskBoxImage = style()->maskBoxImage().image();
const FillLayer* maskLayers = style()->maskLayers();
@@ -1141,7 +1134,7 @@ int RenderBox::perpendicularContainingBlockLogicalHeight() const
// Rather than making the child be completely unconstrained, WinIE uses the viewport width and height
// as a constraint. We do that for now as well even though it's likely being unconstrained is what the spec
// will decide.
- return containingBlockStyle->isVerticalBlockFlow() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
+ return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
}
// Use the content box logical height as specified by the style.
@@ -1507,11 +1500,11 @@ void RenderBox::computeLogicalWidth()
bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
- Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedWidth(), Fixed) : style()->logicalWidth();
+ Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : style()->logicalWidth();
RenderBlock* cb = containingBlock();
int containerLogicalWidth = max(0, containingBlockLogicalWidthForContent());
- bool hasPerpendicularContainingBlock = cb->style()->isVerticalBlockFlow() != style()->isVerticalBlockFlow();
+ bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
int containerWidthInInlineDirection = containerLogicalWidth;
if (hasPerpendicularContainingBlock)
containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
@@ -1596,7 +1589,7 @@ void RenderBox::computeLogicalWidth()
if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd())
&& !isFloating() && !isInline() && !cb->isFlexibleBox())
- setMarginEndUsing(cb->style(), containerLogicalWidth - logicalWidth() - marginStartUsing(cb->style()));
+ cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this));
}
int RenderBox::computeLogicalWidthUsing(LogicalWidthType widthType, int availableLogicalWidth)
@@ -1678,31 +1671,31 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, int
// Case One: The object is being centered in the containing block's available logical width.
if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
|| (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
- setMarginStartUsing(containingBlockStyle, max(0, (containerWidth - childWidth) / 2));
- setMarginEndUsing(containingBlockStyle, containerWidth - childWidth - marginStartUsing(containingBlockStyle));
+ containingBlock->setMarginStartForChild(this, max(0, (containerWidth - childWidth) / 2));
+ containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
return;
}
// Case Two: The object is being pushed to the start of the containing block's available logical width.
if (marginEndLength.isAuto() && childWidth < containerWidth) {
- setMarginStartUsing(containingBlockStyle, marginStartLength.calcValue(containerWidth));
- setMarginEndUsing(containingBlockStyle, containerWidth - childWidth - marginStartUsing(containingBlockStyle));
+ containingBlock->setMarginStartForChild(this, marginStartLength.calcValue(containerWidth));
+ containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
return;
}
// Case Three: The object is being pushed to the end of the containing block's available logical width.
- bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((containingBlockStyle->direction() == RTL && containingBlockStyle->textAlign() == WEBKIT_LEFT)
- || (containingBlockStyle->direction() == LTR && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
+ bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
+ || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
- setMarginEndUsing(containingBlockStyle, marginEndLength.calcValue(containerWidth));
- setMarginStartUsing(containingBlockStyle, containerWidth - childWidth - marginEndUsing(containingBlockStyle));
+ containingBlock->setMarginEndForChild(this, marginEndLength.calcValue(containerWidth));
+ containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this));
return;
}
// Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3). In that case
// auto margins will just turn into 0.
- setMarginStartUsing(containingBlockStyle, marginStartLength.calcMinValue(containerWidth));
- setMarginEndUsing(containingBlockStyle, marginEndLength.calcMinValue(containerWidth));
+ containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth));
+ containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth));
}
void RenderBox::computeLogicalHeight()
@@ -1718,7 +1711,7 @@ void RenderBox::computeLogicalHeight()
computePositionedLogicalHeight();
} else {
RenderBlock* cb = containingBlock();
- bool hasPerpendicularContainingBlock = cb->style()->isVerticalBlockFlow() != style()->isVerticalBlockFlow();
+ bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
if (!hasPerpendicularContainingBlock)
computeBlockDirectionMargins(cb);
@@ -1745,7 +1738,7 @@ void RenderBox::computeLogicalHeight()
&& parent()->isFlexingChildren())
h = Length(overrideSize() - borderAndPaddingLogicalHeight(), Fixed);
else if (treatAsReplaced)
- h = Length(computeReplacedHeight(), Fixed);
+ h = Length(computeReplacedLogicalHeight(), Fixed);
else {
h = style()->logicalHeight();
checkMinMaxHeight = true;
@@ -1797,7 +1790,7 @@ void RenderBox::computeLogicalHeight()
// height has nothing to be a percentage of, and it ends up being 0. That is bad.
bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
&& (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
- if (stretchesToViewHeight() || paginatedContentNeedsBaseHeight) {
+ if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
// FIXME: Finish accounting for block flow here.
// https://bugs.webkit.org/show_bug.cgi?id=46603
int margins = collapsedMarginBefore() + collapsedMarginAfter();
@@ -1805,7 +1798,7 @@ void RenderBox::computeLogicalHeight()
if (document()->printing())
visHeight = static_cast<int>(view()->pageHeight());
else {
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
visHeight = view()->viewHeight();
else
visHeight = view()->viewWidth();
@@ -1916,48 +1909,48 @@ int RenderBox::computePercentageLogicalHeight(const Length& height)
return result;
}
-int RenderBox::computeReplacedWidth(bool includeMaxWidth) const
+int RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
{
- int width = computeReplacedWidthUsing(style()->width());
- int minW = computeReplacedWidthUsing(style()->minWidth());
- int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : computeReplacedWidthUsing(style()->maxWidth());
+ int logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
+ int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
+ int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
- return max(minW, min(width, maxW));
+ return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
}
-int RenderBox::computeReplacedWidthUsing(Length width) const
+int RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
{
- switch (width.type()) {
+ switch (logicalWidth.type()) {
case Fixed:
- return computeContentBoxLogicalWidth(width.value());
+ return computeContentBoxLogicalWidth(logicalWidth.value());
case Percent: {
// FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
// containing block's block-flow.
// https://bugs.webkit.org/show_bug.cgi?id=46496
const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
if (cw > 0)
- return computeContentBoxLogicalWidth(width.calcMinValue(cw));
+ return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw));
}
// fall through
default:
- return intrinsicSize().width();
+ return intrinsicLogicalWidth();
}
}
-int RenderBox::computeReplacedHeight() const
+int RenderBox::computeReplacedLogicalHeight() const
{
- int height = computeReplacedHeightUsing(style()->height());
- int minH = computeReplacedHeightUsing(style()->minHeight());
- int maxH = style()->maxHeight().isUndefined() ? height : computeReplacedHeightUsing(style()->maxHeight());
+ int logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
+ int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
+ int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
- return max(minH, min(height, maxH));
+ return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
}
-int RenderBox::computeReplacedHeightUsing(Length height) const
+int RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
{
- switch (height.type()) {
+ switch (logicalHeight.type()) {
case Fixed:
- return computeContentBoxLogicalHeight(height.value());
+ return computeContentBoxLogicalHeight(logicalHeight.value());
case Percent:
{
RenderObject* cb = isPositioned() ? container() : containingBlock();
@@ -1966,6 +1959,8 @@ int RenderBox::computeReplacedHeightUsing(Length height) const
toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
}
+ // FIXME: This calculation is not patched for block-flow yet.
+ // https://bugs.webkit.org/show_bug.cgi?id=46500
if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
ASSERT(cb->isRenderBlock());
RenderBlock* block = toRenderBlock(cb);
@@ -1973,25 +1968,30 @@ int RenderBox::computeReplacedHeightUsing(Length height) const
block->computeLogicalHeight();
int newHeight = block->computeContentBoxLogicalHeight(block->contentHeight());
block->setHeight(oldHeight);
- return computeContentBoxLogicalHeight(height.calcValue(newHeight));
+ return computeContentBoxLogicalHeight(logicalHeight.calcValue(newHeight));
}
+ // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
+ // containing block's block-flow.
+ // https://bugs.webkit.org/show_bug.cgi?id=46496
int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight();
// It is necessary to use the border-box to match WinIE's broken
// box model. This is essential for sizing inside
// table cells using percentage heights.
- if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) {
+ // FIXME: This needs to be made block-flow-aware. If the cell and image are perpendicular block-flows, this isn't right.
+ // https://bugs.webkit.org/show_bug.cgi?id=46997
+ if (cb->isTableCell() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
// Don't let table cells squeeze percent-height replaced elements
// <http://bugs.webkit.org/show_bug.cgi?id=15359>
- availableHeight = max(availableHeight, intrinsicSize().height());
- return height.calcValue(availableHeight - borderAndPaddingHeight());
+ availableHeight = max(availableHeight, intrinsicLogicalHeight());
+ return logicalHeight.calcValue(availableHeight - borderAndPaddingLogicalHeight());
}
- return computeContentBoxLogicalHeight(height.calcValue(availableHeight));
+ return computeContentBoxLogicalHeight(logicalHeight.calcValue(availableHeight));
}
default:
- return intrinsicSize().height();
+ return intrinsicLogicalHeight();
}
}
@@ -2006,7 +2006,7 @@ int RenderBox::availableLogicalHeightUsing(const Length& h) const
return computeContentBoxLogicalHeight(h.value());
if (isRenderView())
- return style()->isVerticalBlockFlow() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
+ return style()->isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
// We need to stop here, since we don't want to increase the height of the table
// artificially. We're going to rely on this cell getting expanded to some new
@@ -2046,8 +2046,8 @@ void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock)
int cw = containingBlockLogicalWidthForContent();
RenderStyle* containingBlockStyle = containingBlock->style();
- setMarginBeforeUsing(containingBlockStyle, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw));
- setMarginAfterUsing(containingBlockStyle, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw));
+ containingBlock->setMarginBeforeForChild(this, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw));
+ containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw));
}
int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const
@@ -2069,7 +2069,7 @@ int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* con
int fromLeft;
int fromRight;
- if (containingBlock->style()->direction() == LTR) {
+ if (containingBlock->style()->isLeftToRightDirection()) {
fromLeft = first->logicalLeft() + first->borderLogicalLeft();
fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
} else {
@@ -2411,7 +2411,7 @@ void RenderBox::computePositionedLogicalWidthUsing(Length width, const RenderBox
// positioned, inline because right now, it is using the xPos
// of the first line box when really it should use the last line box. When
// this is fixed elsewhere, this block should be removed.
- if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
+ if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
const RenderInline* flow = toRenderInline(containerBlock);
InlineFlowBox* firstLine = flow->firstLineBox();
InlineFlowBox* lastLine = flow->lastLineBox();
@@ -2684,7 +2684,7 @@ void RenderBox::computePositionedLogicalWidthReplaced()
// NOTE: This value of width is FINAL in that the min/max width calculations
// are dealt with in computeReplacedWidth(). This means that the steps to produce
// correct max/min in the non-replaced version, are not necessary.
- setWidth(computeReplacedWidth() + borderAndPaddingWidth());
+ setWidth(computeReplacedLogicalWidth() + borderAndPaddingWidth());
const int availableSpace = containerWidth - width();
/*-----------------------------------------------------------------------*\
@@ -2817,7 +2817,7 @@ void RenderBox::computePositionedLogicalWidthReplaced()
// positioned, inline containing block because right now, it is using the xPos
// of the first line box when really it should use the last line box. When
// this is fixed elsewhere, this block should be removed.
- if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
+ if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
const RenderInline* flow = toRenderInline(containerBlock);
InlineFlowBox* firstLine = flow->firstLineBox();
InlineFlowBox* lastLine = flow->lastLineBox();
@@ -2857,7 +2857,7 @@ void RenderBox::computePositionedLogicalHeightReplaced()
// NOTE: This value of height is FINAL in that the min/max height calculations
// are dealt with in computeReplacedHeight(). This means that the steps to produce
// correct max/min in the non-replaced version, are not necessary.
- setHeight(computeReplacedHeight() + borderAndPaddingHeight());
+ setHeight(computeReplacedLogicalHeight() + borderAndPaddingHeight());
const int availableSpace = containerHeight - height();
/*-----------------------------------------------------------------------*\
@@ -2971,9 +2971,9 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid
// FIXME: What about border and padding?
IntRect rect(x(), y(), caretWidth, height());
- TextDirection direction = box ? box->direction() : style()->direction();
+ bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
- if ((!caretOffset) ^ (direction == LTR))
+ if ((!caretOffset) ^ ltr)
rect.move(IntSize(width() - caretWidth, 0));
if (box) {
@@ -3003,30 +3003,44 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid
return rect;
}
-int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+int RenderBox::topmostPosition(bool /*includeOverflowInterior*/, bool includeSelf, ApplyTransform applyTransform) const
+{
+ IntRect transformedRect = applyTransform == IncludeTransform && includeSelf ? transformedFrameRect() : frameRect();
+ if (!includeSelf || !transformedRect.width())
+ return 0;
+ int top = 0;
+ if (isRelPositioned())
+ top += relativePositionOffsetY();
+ return top;
+}
+
+int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf, ApplyTransform applyTransform) const
{
- if (!includeSelf || !width())
+ IntRect transformedRect = applyTransform == IncludeTransform && includeSelf ? transformedFrameRect() : frameRect();
+ if (!includeSelf || !transformedRect.width())
return 0;
- int bottom = height();
+ int bottom = transformedRect.height();
if (isRelPositioned())
bottom += relativePositionOffsetY();
return bottom;
}
-int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf, ApplyTransform applyTransform) const
{
- if (!includeSelf || !height())
+ IntRect transformedRect = applyTransform == IncludeTransform && includeSelf ? transformedFrameRect() : frameRect();
+ if (!includeSelf || !transformedRect.height())
return 0;
- int right = width();
+ int right = transformedRect.width();
if (isRelPositioned())
right += relativePositionOffsetX();
return right;
}
-int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf, ApplyTransform applyTransform) const
{
- if (!includeSelf || !height())
- return width();
+ IntRect transformedRect = applyTransform == IncludeTransform && includeSelf ? transformedFrameRect() : frameRect();
+ if (!includeSelf || !transformedRect.height())
+ return transformedRect.width();
int left = 0;
if (isRelPositioned())
left += relativePositionOffsetX();
@@ -3137,7 +3151,7 @@ bool RenderBox::shrinkToAvoidFloats() const
bool RenderBox::avoidsFloats() const
{
- return isReplaced() || hasOverflowClip() || isHR() || isBlockFlowRoot();
+ return isReplaced() || hasOverflowClip() || isHR() || isWritingModeRoot();
}
void RenderBox::addShadowOverflow()
@@ -3215,19 +3229,18 @@ void RenderBox::clearLayoutOverflow()
m_overflow->resetLayoutOverflow(borderBoxRect());
}
-void RenderBox::markDescendantBlocksAndLinesForLayout(bool inLayout)
+int RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
{
- if (!m_everHadLayout || isReplaced())
- return;
-
- setChildNeedsLayout(true, !inLayout);
+ if (isReplaced())
+ return direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
+ return 0;
+}
- // Iterate over our children and mark them as needed.
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- if (child->isFloatingOrPositioned())
- continue;
- child->markDescendantBlocksAndLinesForLayout(inLayout);
- }
+int RenderBox::baselinePosition(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
+{
+ if (isReplaced())
+ return direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
+ return 0;
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h
index 1b70fad..2e37657 100644
--- a/WebCore/rendering/RenderBox.h
+++ b/WebCore/rendering/RenderBox.h
@@ -50,41 +50,41 @@ public:
void setWidth(int width) { m_frameRect.setWidth(width); }
void setHeight(int height) { m_frameRect.setHeight(height); }
- int logicalLeft() const { return style()->isVerticalBlockFlow() ? x() : y(); }
- int logicalTop() const { return style()->isVerticalBlockFlow() ? y() : x(); }
- int logicalWidth() const { return style()->isVerticalBlockFlow() ? width() : height(); }
- int logicalHeight() const { return style()->isVerticalBlockFlow() ? height() : width(); }
+ int logicalLeft() const { return style()->isHorizontalWritingMode() ? x() : y(); }
+ int logicalTop() const { return style()->isHorizontalWritingMode() ? y() : x(); }
+ int logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); }
+ int logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); }
void setLogicalLeft(int left)
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
setX(left);
else
setY(left);
}
void setLogicalTop(int top)
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
setY(top);
else
setX(top);
}
void setLogicalWidth(int size)
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
setWidth(size);
else
setHeight(size);
}
void setLogicalHeight(int size)
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
setHeight(size);
else
setWidth(size);
}
void setLogicalLocation(int left, int top)
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
setLocation(left, top);
else
setLocation(top, left);
@@ -103,6 +103,9 @@ public:
IntRect frameRect() const { return m_frameRect; }
void setFrameRect(const IntRect& rect) { m_frameRect = rect; }
+ IntRect transformedFrameRect() const;
+ IntRect applyLayerTransformToRect(const IntRect&) const;
+
IntRect borderBoxRect() const { return IntRect(0, 0, width(), height()); }
virtual IntRect borderBoundingBox() const { return borderBoxRect(); }
@@ -127,19 +130,23 @@ public:
int bottomVisibleOverflow() const { return hasOverflowClip() ? bottomVisualOverflow() : std::max(bottomLayoutOverflow(), bottomVisualOverflow()); }
int leftVisibleOverflow() const { return hasOverflowClip() ? leftVisualOverflow() : std::min(leftLayoutOverflow(), leftVisualOverflow()); }
int rightVisibleOverflow() const { return hasOverflowClip() ? rightVisualOverflow() : std::max(rightLayoutOverflow(), rightVisualOverflow()); }
-
+
IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : borderBoxRect(); }
int topLayoutOverflow() const { return m_overflow? m_overflow->topLayoutOverflow() : 0; }
int bottomLayoutOverflow() const { return m_overflow ? m_overflow->bottomLayoutOverflow() : height(); }
int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : 0; }
int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : width(); }
+ int logicalLeftLayoutOverflow() const { return style()->isHorizontalWritingMode() ? leftLayoutOverflow() : topLayoutOverflow(); }
+ int logicalRightLayoutOverflow() const { return style()->isHorizontalWritingMode() ? rightLayoutOverflow() : bottomLayoutOverflow(); }
IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : borderBoxRect(); }
int topVisualOverflow() const { return m_overflow? m_overflow->topVisualOverflow() : 0; }
int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : height(); }
int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : 0; }
int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : width(); }
-
+ int logicalLeftVisualOverflow() const { return style()->isHorizontalWritingMode() ? leftVisualOverflow() : topVisualOverflow(); }
+ int logicalRightVisualOverflow() const { return style()->isHorizontalWritingMode() ? rightVisualOverflow() : bottomVisualOverflow(); }
+
void addLayoutOverflow(const IntRect&);
void addVisualOverflow(const IntRect&);
@@ -150,8 +157,8 @@ public:
int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); }
int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); }
- int contentLogicalWidth() const { return style()->isVerticalBlockFlow() ? contentWidth() : contentHeight(); }
- int contentLogicalHeight() const { return style()->isVerticalBlockFlow() ? contentHeight() : contentWidth(); }
+ int contentLogicalWidth() const { return style()->isHorizontalWritingMode() ? contentWidth() : contentHeight(); }
+ int contentLogicalHeight() const { return style()->isHorizontalWritingMode() ? contentHeight() : contentWidth(); }
// IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow)
// to return the remaining width on a given line (and the height of a single line).
@@ -181,6 +188,10 @@ public:
virtual int marginBottom() const { return m_marginBottom; }
virtual int marginLeft() const { return m_marginLeft; }
virtual int marginRight() const { return m_marginRight; }
+ void setMarginTop(int margin) { m_marginTop = margin; }
+ void setMarginBottom(int margin) { m_marginBottom = margin; }
+ void setMarginLeft(int margin) { m_marginLeft = margin; }
+ void setMarginRight(int margin) { m_marginRight = margin; }
virtual int marginBefore() const;
virtual int marginAfter() const;
virtual int marginStart() const;
@@ -189,7 +200,7 @@ public:
void setMarginEnd(int);
void setMarginBefore(int);
void setMarginAfter(int);
-
+
// The following five functions are used to implement collapsing margins.
// All objects know their maximal positive and negative margins. The
// formula for computing a collapsed margin is |maxPosMargin| - |maxNegmargin|.
@@ -198,24 +209,8 @@ public:
// methods.
enum MarginSign { PositiveMargin, NegativeMargin };
virtual bool isSelfCollapsingBlock() const { return false; }
- int collapsedMarginBefore() const
- {
- return maxMarginBefore(PositiveMargin) - maxMarginBefore(NegativeMargin);
- }
- int collapsedMarginAfter() const
- {
- return maxMarginAfter(PositiveMargin) - maxMarginAfter(NegativeMargin);
-}
- virtual int maxMarginBefore(MarginSign sign) const
- {
- int beforeMargin = marginBefore();
- return (sign == PositiveMargin) ? std::max(0, beforeMargin) : -std::min(0, beforeMargin);
- }
- virtual int maxMarginAfter(MarginSign sign) const
- {
- int afterMargin = marginAfter();
- return (sign == PositiveMargin) ? std::max(0, afterMargin) : -std::min(0, afterMargin);
- }
+ virtual int collapsedMarginBefore() const { return marginBefore(); }
+ virtual int collapsedMarginAfter() const { return marginAfter(); }
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
@@ -267,9 +262,11 @@ public:
void setInlineBoxWrapper(InlineBox* boxWrapper) { m_inlineBoxWrapper = boxWrapper; }
void deleteLineBoxWrapper();
- virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
- virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
- virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
+ enum ApplyTransform { IncludeTransform, ExcludeTransform };
+ virtual int topmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
@@ -282,12 +279,14 @@ public:
virtual void computeLogicalWidth();
virtual void computeLogicalHeight();
- bool stretchesToViewHeight() const
+ bool stretchesToViewport() const
{
- return document()->inQuirksMode() && style()->height().isAuto() && !isFloatingOrPositioned() && (isRoot() || isBody()) && !isBlockFlowRoot();
+ return document()->inQuirksMode() && style()->logicalHeight().isAuto() && !isFloatingOrPositioned() && (isRoot() || isBody()) && !isWritingModeRoot();
}
virtual IntSize intrinsicSize() const { return IntSize(); }
+ int intrinsicLogicalWidth() const { return style()->isHorizontalWritingMode() ? intrinsicSize().width() : intrinsicSize().height(); }
+ int intrinsicLogicalHeight() const { return style()->isHorizontalWritingMode() ? intrinsicSize().height() : intrinsicSize().width(); }
// Whether or not the element shrinks to its intrinsic width (rather than filling the width
// of a containing block). HTML4 buttons, <select>s, <input>s, legends, and floating/compact elements do this.
@@ -296,11 +295,11 @@ public:
int computeLogicalWidthUsing(LogicalWidthType, int availableLogicalWidth);
int computeLogicalHeightUsing(const Length& height);
- int computeReplacedWidthUsing(Length width) const;
- int computeReplacedHeightUsing(Length height) const;
+ int computeReplacedLogicalWidthUsing(Length width) const;
+ int computeReplacedLogicalHeightUsing(Length height) const;
- virtual int computeReplacedWidth(bool includeMaxWidth = true) const;
- virtual int computeReplacedHeight() const;
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
int computePercentageLogicalHeight(const Length& height);
@@ -311,11 +310,12 @@ public:
// There are a few cases where we need to refer specifically to the available physical width and available physical height.
// Relative positioning is one of those cases, since left/top offsets are physical.
- int availableWidth() const { return style()->isVerticalBlockFlow() ? availableLogicalWidth() : availableLogicalHeight(); }
- int availableHeight() const { return style()->isVerticalBlockFlow() ? availableLogicalHeight() : availableLogicalWidth(); }
+ int availableWidth() const { return style()->isHorizontalWritingMode() ? availableLogicalWidth() : availableLogicalHeight(); }
+ int availableHeight() const { return style()->isHorizontalWritingMode() ? availableLogicalHeight() : availableLogicalWidth(); }
virtual int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
+ int scrollbarLogicalHeight() const { return style()->isHorizontalWritingMode() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); }
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
bool canBeScrolledAndHasScrollableArea() const;
virtual bool canBeProgramaticallyScrolled(bool) const;
@@ -367,9 +367,12 @@ public:
bool shrinkToAvoidFloats() const;
virtual bool avoidsFloats() const;
- virtual void markDescendantBlocksAndLinesForLayout(bool inLayout = true);
+ virtual void markForPaginationRelayoutIfNeeded() { }
+
+ bool isWritingModeRoot() const { return !parent() || parent()->style()->writingMode() != style()->writingMode(); }
- bool isBlockFlowRoot() const { return !parent() || parent()->style()->blockFlow() != style()->blockFlow(); }
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
#ifdef ANDROID_LAYOUT
int getVisibleWidth() const { return m_visibleWidth; }
@@ -426,16 +429,6 @@ private:
// These include tables, positioned objects, floats and flexible boxes.
virtual void computePreferredLogicalWidths() { setPreferredLogicalWidthsDirty(false); }
- void setMarginStartUsing(const RenderStyle*, int);
- void setMarginEndUsing(const RenderStyle*, int);
- void setMarginBeforeUsing(const RenderStyle*, int);
- void setMarginAfterUsing(const RenderStyle*, int);
-
- int marginStartUsing(const RenderStyle*) const;
- int marginEndUsing(const RenderStyle*) const;
- int marginBeforeUsing(const RenderStyle*) const;
- int marginAfterUsing(const RenderStyle*) const;
-
private:
// The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent).
IntRect m_frameRect;
diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
index bbb9c2c..ec065a6 100644
--- a/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -324,7 +324,7 @@ int RenderBoxModelObject::relativePositionOffsetX() const
// call availableWidth on our containing block.
if (!style()->left().isAuto()) {
RenderBlock* cb = containingBlock();
- if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL)
+ if (!style()->right().isAuto() && !containingBlock()->style()->isLeftToRightDirection())
return -style()->right().calcValue(cb->availableWidth());
return style()->left().calcValue(cb->availableWidth());
}
@@ -348,13 +348,13 @@ int RenderBoxModelObject::relativePositionOffsetY() const
if (!style()->top().isAuto()
&& (!containingBlock->style()->height().isAuto()
|| !style()->top().isPercent()
- || containingBlock->stretchesToViewHeight()))
+ || containingBlock->stretchesToViewport()))
return style()->top().calcValue(containingBlock->availableHeight());
if (!style()->bottom().isAuto()
&& (!containingBlock->style()->height().isAuto()
|| !style()->bottom().isPercent()
- || containingBlock->stretchesToViewHeight()))
+ || containingBlock->stretchesToViewport()))
return -style()->bottom().calcValue(containingBlock->availableHeight());
return 0;
@@ -855,23 +855,25 @@ int RenderBoxModelObject::verticalPosition(bool firstLine) const
const Font& f = parent()->style(firstLine)->font();
int fontsize = f.pixelSize();
+ LineDirectionMode lineDirection = parent()->style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
+
if (va == SUB)
vpos += fontsize / 5 + 1;
else if (va == SUPER)
vpos -= fontsize / 3 + 1;
else if (va == TEXT_TOP)
- vpos += baselinePosition(firstLine) - f.ascent();
+ vpos += baselinePosition(firstLine, lineDirection) - f.ascent();
else if (va == MIDDLE)
- vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
+ vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine, lineDirection) / 2 + baselinePosition(firstLine, lineDirection);
else if (va == TEXT_BOTTOM) {
vpos += f.descent();
// lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case.
if (!isReplaced() || style()->display() == INLINE_BLOCK)
- vpos -= (lineHeight(firstLine) - baselinePosition(firstLine));
+ vpos -= (lineHeight(firstLine, lineDirection) - baselinePosition(firstLine, lineDirection));
} else if (va == BASELINE_MIDDLE)
- vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine);
+ vpos += -lineHeight(firstLine, lineDirection) / 2 + baselinePosition(firstLine, lineDirection);
else if (va == LENGTH)
- vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine));
+ vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine, lineDirection));
}
return vpos;
@@ -1061,7 +1063,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx,
graphicsContext->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
graphicsContext->clipOutRoundedRect(innerBorderRect, innerTopLeftRadius, innerTopRightRadius, innerBottomLeftRadius, innerBottomRightRadius);
- roundedPath = Path::createRoundedRectangle(borderRect, topLeft, topRight, bottomLeft, bottomRight);
+ roundedPath.addRoundedRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
graphicsContext->addPath(roundedPath);
}
@@ -1752,24 +1754,29 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
context->save();
- if (hasBorderRadius)
- context->clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
- else
+ Path path;
+ if (hasBorderRadius) {
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ context->clip(path);
+ path.clear();
+ } else
context->clip(rect);
IntSize extraOffset(2 * w + max(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0);
context->translate(extraOffset.width(), extraOffset.height());
shadowOffset -= extraOffset;
- context->beginPath();
- context->addPath(Path::createRectangle(outerRect));
+ path.addRect(outerRect);
if (hasBorderRadius) {
if (shadowSpread > 0)
uniformlyExpandBorderRadii(-shadowSpread, topLeft, topRight, bottomLeft, bottomRight);
- context->addPath(Path::createRoundedRectangle(holeRect, topLeft, topRight, bottomLeft, bottomRight));
+ path.addRoundedRect(holeRect, topLeft, topRight, bottomLeft, bottomRight);
} else
- context->addPath(Path::createRectangle(holeRect));
+ path.addRect(holeRect);
+
+ context->beginPath();
+ context->addPath(path);
context->setFillRule(RULE_EVENODD);
context->setFillColor(fillColor, s->colorSpace());
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
index 83c9367..33d7ca2 100644
--- a/WebCore/rendering/RenderBoxModelObject.h
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -33,6 +33,10 @@ const int PositionTop = -0x7fffffff;
const int PositionBottom = 0x7fffffff;
const int PositionUndefined = 0x80000000;
+// Modes for some of the line-related functions.
+enum LinePositionMode { PositionOnContainingLine, PositionOfInteriorLineBoxes };
+enum LineDirectionMode { HorizontalLine, VerticalLine };
+
// This class is the base for all objects that adhere to the CSS box model as described
// at http://www.w3.org/TR/CSS21/box.html
@@ -98,8 +102,8 @@ public:
virtual int marginStart() const = 0;
virtual int marginEnd() const = 0;
- bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; }
- bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; }
+ bool hasInlineDirectionBordersPaddingOrMargin() const { return hasInlineDirectionBordersOrPadding() || marginStart()|| marginEnd(); }
+ bool hasInlineDirectionBordersOrPadding() const { return borderStart() || borderEnd() || paddingStart()|| paddingEnd(); }
virtual int containingBlockLogicalWidthForContent() const;
@@ -112,6 +116,10 @@ public:
// The difference between this inline's baseline position and the line's baseline position.
int verticalPosition(bool firstLine) const;
+
+ // Overridden by subclasses to determine line height and baseline position.
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
// Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed
void destroyLayer();
diff --git a/WebCore/rendering/RenderButton.cpp b/WebCore/rendering/RenderButton.cpp
index 8357bd4..2642f23 100644
--- a/WebCore/rendering/RenderButton.cpp
+++ b/WebCore/rendering/RenderButton.cpp
@@ -45,6 +45,10 @@ RenderButton::RenderButton(Node* node)
{
}
+RenderButton::~RenderButton()
+{
+}
+
void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
if (!m_inner) {
diff --git a/WebCore/rendering/RenderButton.h b/WebCore/rendering/RenderButton.h
index 1fc5eb6..252edb4 100644
--- a/WebCore/rendering/RenderButton.h
+++ b/WebCore/rendering/RenderButton.h
@@ -34,7 +34,8 @@ class RenderTextFragment;
// to date as the button changes.
class RenderButton : public RenderFlexibleBox {
public:
- RenderButton(Node*);
+ explicit RenderButton(Node*);
+ virtual ~RenderButton();
virtual const char* renderName() const { return "RenderButton"; }
virtual bool isRenderButton() const { return true; }
diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp
index 639221d..c357be1 100644
--- a/WebCore/rendering/RenderCounter.cpp
+++ b/WebCore/rendering/RenderCounter.cpp
@@ -35,7 +35,7 @@ namespace WebCore {
using namespace HTMLNames;
-typedef HashMap<RefPtr<AtomicStringImpl>, CounterNode*> CounterMap;
+typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<CounterNode> > CounterMap;
typedef HashMap<const RenderObject*, CounterMap*> CounterMaps;
static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter);
@@ -235,10 +235,12 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
{
ASSERT(object);
- if (object->m_hasCounterNodeMap)
- if (CounterMap* nodeMap = counterMaps().get(object))
- if (CounterNode* node = nodeMap->get(identifier.impl()))
+ if (object->m_hasCounterNodeMap) {
+ if (CounterMap* nodeMap = counterMaps().get(object)) {
+ if (CounterNode* node = nodeMap->get(identifier.impl()).get())
return node;
+ }
+ }
bool isReset = false;
int value = 0;
@@ -247,9 +249,9 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
CounterNode* newParent = 0;
CounterNode* newPreviousSibling = 0;
- CounterNode* newNode = new CounterNode(object, isReset, value);
+ RefPtr<CounterNode> newNode = CounterNode::create(object, isReset, value);
if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling))
- newParent->insertAfter(newNode, newPreviousSibling, identifier);
+ newParent->insertAfter(newNode.get(), newPreviousSibling, identifier);
CounterMap* nodeMap;
if (object->m_hasCounterNodeMap)
nodeMap = counterMaps().get(object);
@@ -260,7 +262,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
}
nodeMap->set(identifier.impl(), newNode);
if (newNode->parent() || !object->nextInPreOrder(object->parent()))
- return newNode;
+ return newNode.get();
// Checking if some nodes that were previously counter tree root nodes
// should become children of this node now.
CounterMaps& maps = counterMaps();
@@ -268,7 +270,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) {
if (!currentRenderer->m_hasCounterNodeMap)
continue;
- CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl());
+ CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl()).get();
if (!currentCounter)
continue;
if (currentCounter->parent()) {
@@ -282,7 +284,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
if (currentRenderer->lastChild())
currentRenderer = currentRenderer->lastChild();
}
- return newNode;
+ return newNode.get();
}
RenderCounter::RenderCounter(Document* node, const CounterContent& counter)
@@ -292,6 +294,10 @@ RenderCounter::RenderCounter(Document* node, const CounterContent& counter)
{
}
+RenderCounter::~RenderCounter()
+{
+}
+
const char* RenderCounter::renderName() const
{
return "RenderCounter";
@@ -345,9 +351,9 @@ void RenderCounter::invalidate(const AtomicString& identifier)
static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node)
{
CounterNode* previous;
- for (CounterNode* child = node->lastDescendant(); child && child != node; child = previous) {
+ for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) {
previous = child->previousInPreOrder();
- child->parent()->removeChild(child, identifier);
+ child->parent()->removeChild(child.get(), identifier);
ASSERT(counterMaps().get(child->renderer())->get(identifier.impl()) == child);
counterMaps().get(child->renderer())->remove(identifier.impl());
if (!child->renderer()->documentBeingDestroyed()) {
@@ -355,7 +361,6 @@ static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier,
if (children)
children->invalidateCounters(child->renderer(), identifier);
}
- delete child;
}
RenderObject* renderer = node->renderer();
if (!renderer->documentBeingDestroyed()) {
@@ -364,7 +369,6 @@ static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier,
}
if (CounterNode* parent = node->parent())
parent->removeChild(node, identifier);
- delete node;
}
void RenderCounter::destroyCounterNodes(RenderObject* renderer)
@@ -377,7 +381,7 @@ void RenderCounter::destroyCounterNodes(RenderObject* renderer)
CounterMap::const_iterator end = map->end();
for (CounterMap::const_iterator it = map->begin(); it != end; ++it) {
AtomicString identifier(it->first.get());
- destroyCounterNodeWithoutMapRemoval(identifier, it->second);
+ destroyCounterNodeWithoutMapRemoval(identifier, it->second.get());
}
maps.remove(mapsIterator);
delete map;
@@ -392,7 +396,7 @@ void RenderCounter::destroyCounterNode(RenderObject* renderer, const AtomicStrin
CounterMap::iterator mapIterator = map->find(identifier.impl());
if (mapIterator == map->end())
return;
- destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second);
+ destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second.get());
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,
@@ -422,21 +426,24 @@ static void updateCounters(RenderObject* renderer)
CounterMap* counterMap = counterMaps().get(renderer);
ASSERT(counterMap);
for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) {
- CounterNode* node = counterMap->get(it->first.get());
+ RefPtr<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);
+ if (node != counterMap->get(it->first.get()))
+ continue;
CounterNode* parent = node->parent();
if (newParent == parent && newPreviousSibling == node->previousSibling())
continue;
if (parent)
- parent->removeChild(node, it->first.get());
+ parent->removeChild(node.get(), it->first.get());
if (newParent)
- newParent->insertAfter(node, newPreviousSibling, it->first.get());
+ newParent->insertAfter(node.get(), newPreviousSibling, it->first.get());
}
}
diff --git a/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h
index 8d981df..9373193 100644
--- a/WebCore/rendering/RenderCounter.h
+++ b/WebCore/rendering/RenderCounter.h
@@ -32,6 +32,7 @@ class CounterNode;
class RenderCounter : public RenderText {
public:
RenderCounter(Document*, const CounterContent&);
+ virtual ~RenderCounter();
// Removes the reference to the CounterNode associated with this renderer
// if its identifier matches the argument.
diff --git a/WebCore/rendering/RenderEmbeddedObject.cpp b/WebCore/rendering/RenderEmbeddedObject.cpp
index aa301e2..16613a5 100644
--- a/WebCore/rendering/RenderEmbeddedObject.cpp
+++ b/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -206,7 +206,7 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(int tx, int ty, FloatRect&
float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
replacementTextRect.setLocation(FloatPoint(x, y));
- path = Path::createRoundedRectangle(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
+ path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
return true;
}
diff --git a/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp
index d3b88c1..12386e9 100644
--- a/WebCore/rendering/RenderFieldset.cpp
+++ b/WebCore/rendering/RenderFieldset.cpp
@@ -71,34 +71,43 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren)
legend->setNeedsLayout(true);
legend->layoutIfNeeded();
- int xPos;
- if (style()->direction() == RTL) {
+ int logicalLeft;
+ if (style()->isLeftToRightDirection()) {
switch (legend->style()->textAlign()) {
- case LEFT:
- xPos = borderLeft() + paddingLeft();
- break;
- case CENTER:
- xPos = (width() - legend->width()) / 2;
- break;
- default:
- xPos = width() - paddingRight() - borderRight() - legend->width() - legend->marginRight();
+ case CENTER:
+ logicalLeft = (logicalWidth() - logicalWidthForChild(legend)) / 2;
+ break;
+ case RIGHT:
+ logicalLeft = logicalWidth() - borderEnd() - paddingEnd() - logicalWidthForChild(legend);
+ break;
+ default:
+ logicalLeft = borderStart() + paddingStart() + marginStartForChild(legend);
+ break;
}
} else {
switch (legend->style()->textAlign()) {
- case RIGHT:
- xPos = width() - paddingRight() - borderRight() - legend->width();
- break;
- case CENTER:
- xPos = (width() - legend->width()) / 2;
- break;
- default:
- xPos = borderLeft() + paddingLeft() + legend->marginLeft();
+ case LEFT:
+ logicalLeft = borderStart() + paddingStart();
+ break;
+ case CENTER: {
+ // Make sure that the extra pixel goes to the end side in RTL (since it went to the end side
+ // in LTR).
+ int centeredWidth = logicalWidth() - logicalWidthForChild(legend);
+ logicalLeft = centeredWidth - centeredWidth / 2;
+ break;
+ }
+ default:
+ logicalLeft = logicalWidth() - borderStart() - paddingStart() - marginStartForChild(legend) - logicalWidthForChild(legend);
+ break;
}
}
- int b = borderTop();
- int h = legend->height();
- legend->setLocation(xPos, max((b-h)/2, 0));
- setHeight(max(b, h) + paddingTop());
+
+ setLogicalLeftForChild(legend, logicalLeft);
+
+ int b = borderBefore();
+ int h = logicalHeightForChild(legend);
+ setLogicalTopForChild(legend, max((b - h) / 2, 0));
+ setLogicalHeight(max(b, h) + paddingBefore());
}
return legend;
}
@@ -129,10 +138,18 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
if (!legend)
return RenderBlock::paintBoxDecorations(paintInfo, tx, ty);
- int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
- int legendBottom = ty + legend->y() + legend->height();
- h -= yOff;
- ty += yOff;
+ // FIXME: We need to work with "rl" and "bt" block flow directions. In those
+ // cases the legend is embedded in the right and bottom borders respectively.
+ // https://bugs.webkit.org/show_bug.cgi?id=47236
+ if (style()->isHorizontalWritingMode()) {
+ int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
+ h -= yOff;
+ ty += yOff;
+ } else {
+ int xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2;
+ w -= xOff;
+ tx += xOff;
+ }
paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
@@ -141,21 +158,24 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
if (!style()->hasBorder())
return;
-
- // Save time by not saving and restoring the GraphicsContext in the straight border case
- if (!style()->hasBorderRadius())
- return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->x(), legend->width(), legendBottom);
- // We have rounded borders, create a clipping region
- // around the legend and paint the border as normal
+ // Create a clipping region around the legend and paint the border as normal
GraphicsContext* graphicsContext = paintInfo.context;
graphicsContext->save();
- int clipTop = ty;
- int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height());
+ // FIXME: We need to work with "rl" and "bt" block flow directions. In those
+ // cases the legend is embedded in the right and bottom borders respectively.
+ // https://bugs.webkit.org/show_bug.cgi?id=47236
+ if (style()->isHorizontalWritingMode()) {
+ int clipTop = ty;
+ int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height());
+ graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop, legend->width(), clipHeight));
+ } else {
+ int clipLeft = tx;
+ int clipWidth = max(static_cast<int>(style()->borderLeftWidth()), legend->width());
+ graphicsContext->clipOut(IntRect(clipLeft, ty + legend->y(), clipWidth, legend->height()));
+ }
- graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop,
- legend->width(), clipHeight));
paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true);
graphicsContext->restore();
@@ -172,95 +192,20 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty)
if (!legend)
return RenderBlock::paintMask(paintInfo, tx, ty);
- int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
- h -= yOff;
- ty += yOff;
-
- paintMaskImages(paintInfo, tx, ty, w, h);
-}
-
-void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, int tx, int ty, int w, int h,
- const RenderStyle* style, int lx, int lw, int lb)
-{
- const Color& tc = style->visitedDependentColor(CSSPropertyBorderTopColor);
- const Color& bc = style->visitedDependentColor(CSSPropertyBorderBottomColor);
-
- EBorderStyle ts = style->borderTopStyle();
- EBorderStyle bs = style->borderBottomStyle();
- EBorderStyle ls = style->borderLeftStyle();
- EBorderStyle rs = style->borderRightStyle();
-
- bool render_t = ts > BHIDDEN;
- bool render_l = ls > BHIDDEN;
- bool render_r = rs > BHIDDEN;
- bool render_b = bs > BHIDDEN;
-
- int borderLeftWidth = style->borderLeftWidth();
- int borderRightWidth = style->borderRightWidth();
-
- if (render_t) {
- if (lx >= borderLeftWidth)
- drawLineForBoxSide(graphicsContext, tx, ty, tx + min(lx, w), ty + style->borderTopWidth(), BSTop, tc, ts,
- (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0),
- (lx >= w && render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0));
- if (lx + lw <= w - borderRightWidth)
- drawLineForBoxSide(graphicsContext, tx + max(0, lx + lw), ty, tx + w, ty + style->borderTopWidth(), BSTop, tc, ts,
- (lx + lw <= 0 && render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0),
- (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0));
+ // FIXME: We need to work with "rl" and "bt" block flow directions. In those
+ // cases the legend is embedded in the right and bottom borders respectively.
+ // https://bugs.webkit.org/show_bug.cgi?id=47236
+ if (style()->isHorizontalWritingMode()) {
+ int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
+ h -= yOff;
+ ty += yOff;
+ } else {
+ int xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2;
+ w -= xOff;
+ tx += xOff;
}
- if (render_b)
- drawLineForBoxSide(graphicsContext, tx, ty + h - style->borderBottomWidth(), tx + w, ty + h, BSBottom, bc, bs,
- (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? style->borderLeftWidth() : 0),
- (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? style->borderRightWidth() : 0));
-
- if (render_l) {
- const Color& lc = style->visitedDependentColor(CSSPropertyBorderLeftColor);
- int startY = ty;
-
- bool ignore_top =
- (tc == lc) &&
- (ls >= OUTSET) &&
- (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
-
- bool ignore_bottom =
- (bc == lc) &&
- (ls >= OUTSET) &&
- (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
-
- if (lx < borderLeftWidth && lx + lw > 0) {
- // The legend intersects the border.
- ignore_top = true;
- startY = lb;
- }
-
- drawLineForBoxSide(graphicsContext, tx, startY, tx + borderLeftWidth, ty + h, BSLeft, lc, ls,
- ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
- }
-
- if (render_r) {
- const Color& rc = style->visitedDependentColor(CSSPropertyBorderRightColor);
- int startY = ty;
-
- bool ignore_top =
- (tc == rc) &&
- (rs >= DOTTED || rs == INSET) &&
- (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
-
- bool ignore_bottom =
- (bc == rc) &&
- (rs >= DOTTED || rs == INSET) &&
- (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
-
- if (lx < w && lx + lw > w - borderRightWidth) {
- // The legend intersects the border.
- ignore_top = true;
- startY = lb;
- }
-
- drawLineForBoxSide(graphicsContext, tx + w - borderRightWidth, startY, tx + w, ty + h, BSRight, rc, rs,
- ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
- }
+ paintMaskImages(paintInfo, tx, ty, w, h);
}
void RenderFieldset::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
diff --git a/WebCore/rendering/RenderFieldset.h b/WebCore/rendering/RenderFieldset.h
index bc8e8ae..bada78c 100644
--- a/WebCore/rendering/RenderFieldset.h
+++ b/WebCore/rendering/RenderFieldset.h
@@ -30,7 +30,7 @@ namespace WebCore {
class RenderFieldset : public RenderBlock {
public:
- RenderFieldset(Node*);
+ explicit RenderFieldset(Node*);
RenderBox* findLegend() const;
@@ -48,8 +48,6 @@ private:
virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
virtual void paintMask(PaintInfo&, int tx, int ty);
-
- void paintBorderMinusLegend(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, int lx, int lw, int lb);
};
inline RenderFieldset* toRenderFieldset(RenderObject* object)
diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp
index cdb0470..3da8530 100644
--- a/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/WebCore/rendering/RenderFileUploadControl.cpp
@@ -124,8 +124,11 @@ void RenderFileUploadControl::chooseIconForFiles(FileChooser* chooser, const Vec
void RenderFileUploadControl::click()
{
+ // Requires a user gesture to open the file dialog.
+ if (!frame() || !frame()->loader()->isProcessingUserGesture())
+ return;
if (Chrome* chromePointer = chrome())
- chromePointer->runOpenPanel(node()->document()->frame(), m_fileChooser);
+ chromePointer->runOpenPanel(frame(), m_fileChooser);
}
Chrome* RenderFileUploadControl::chrome() const
@@ -213,14 +216,14 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
const String& displayedFilename = fileTextValue();
unsigned length = displayedFilename.length();
const UChar* string = displayedFilename.characters();
- TextRun textRun(string, length, false, 0, 0, style()->direction() == RTL, style()->unicodeBidi() == Override);
+ TextRun textRun(string, length, false, 0, 0, !style()->isLeftToRightDirection(), style()->unicodeBidi() == Override);
// Determine where the filename should be placed
int contentLeft = tx + borderLeft() + paddingLeft();
int buttonAndIconWidth = m_button->renderBox()->width() + afterButtonSpacing
+ (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0);
int textX;
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
textX = contentLeft + buttonAndIconWidth;
else
textX = contentLeft + contentWidth() - buttonAndIconWidth - style()->font().width(textRun);
@@ -228,7 +231,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
RenderButton* buttonRenderer = toRenderButton(m_button->renderer());
int textY = buttonRenderer->absoluteBoundingBoxRect().y()
+ buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop()
- + buttonRenderer->baselinePosition(true, false);
+ + buttonRenderer->baselinePosition(true, HorizontalLine, PositionOnContainingLine);
paintInfo.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace());
@@ -239,7 +242,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
// Determine where the icon should be placed
int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
int iconX;
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
iconX = contentLeft + m_button->renderBox()->width() + afterButtonSpacing;
else
iconX = contentLeft + contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - iconWidth;
diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp
index 636c873..83ec721 100644
--- a/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/WebCore/rendering/RenderFlexibleBox.cpp
@@ -44,7 +44,7 @@ public:
FlexBoxIterator(RenderFlexibleBox* parent)
{
box = parent;
- if (box->style()->boxOrient() == HORIZONTAL && box->style()->direction() == RTL)
+ if (box->style()->boxOrient() == HORIZONTAL && !box->style()->isLeftToRightDirection())
forward = box->style()->boxDirection() != BNORMAL;
else
forward = box->style()->boxDirection() == BNORMAL;
@@ -266,12 +266,12 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int /*pageHeight FIXM
// bottom margin max values to 0. This way we don't factor in the values
// twice when we collapse with our previous vertically adjacent and
// following vertically adjacent blocks.
- int pos = maxPosMarginBefore();
- int neg = maxNegMarginBefore();
- if (maxPosMarginAfter() > pos)
- pos = maxPosMarginAfter();
- if (maxNegMarginAfter() > neg)
- neg = maxNegMarginAfter();
+ int pos = maxPositiveMarginBefore();
+ int neg = maxNegativeMarginBefore();
+ if (maxPositiveMarginAfter() > pos)
+ pos = maxPositiveMarginAfter();
+ if (maxNegativeMarginAfter() > neg)
+ neg = maxNegativeMarginAfter();
setMaxMarginBeforeValues(pos, neg);
setMaxMarginAfterValues(0, 0);
}
@@ -342,8 +342,6 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
- bool paginated = view()->layoutState()->isPaginated();
-
RenderBox* child;
RenderBlock::startDelayUpdateScrollInfo();
@@ -374,11 +372,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
// Compute the child's vertical margins.
child->computeBlockDirectionMargins(this);
- if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
- RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
- if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
- }
+ if (!child->needsLayout())
+ child->markForPaginationRelayoutIfNeeded();
// Now do the layout.
child->layoutIfNeeded();
@@ -407,7 +402,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
}
if (!iterator.first() && hasLineIfEmpty())
- setHeight(height() + lineHeight(true, true));
+ setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
setHeight(height() + toAdd);
@@ -425,7 +420,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->style()->hasStaticX()) {
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
child->layer()->setStaticX(xPos);
else child->layer()->setStaticX(width() - xPos);
}
@@ -448,11 +443,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
if (oldChildHeight != child->height())
child->setChildNeedsLayout(true, false);
- if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
- RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
- if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
- }
+ if (!child->needsLayout())
+ child->markForPaginationRelayoutIfNeeded();
child->layoutIfNeeded();
@@ -583,8 +575,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
RenderBlock::finishDelayUpdateScrollInfo();
- if (remainingSpace > 0 && ((style()->direction() == LTR && style()->boxPack() != BSTART) ||
- (style()->direction() == RTL && style()->boxPack() != BEND))) {
+ if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != BSTART)
+ || (!style()->isLeftToRightDirection() && style()->boxPack() != BEND))) {
// Children must be repositioned.
int offset = 0;
if (style()->boxPack() == BJUSTIFY) {
@@ -653,7 +645,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
{
int xPos = borderLeft() + paddingLeft();
int yPos = borderTop() + paddingTop();
- if (style()->direction() == RTL)
+ if (!style()->isLeftToRightDirection())
xPos = width() - paddingRight() - borderRight();
int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
bool heightSpecified = false;
@@ -667,8 +659,6 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
- bool paginated = view()->layoutState()->isPaginated();
-
RenderBox* child;
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
@@ -696,7 +686,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->style()->hasStaticX()) {
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
child->layer()->setStaticX(borderLeft()+paddingLeft());
else
child->layer()->setStaticX(borderRight()+paddingRight());
@@ -718,11 +708,8 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
// Add in the child's marginTop to our height.
setHeight(height() + child->marginTop());
- if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
- RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
- if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
- childRenderBlock->markForPaginationRelayout();
- }
+ if (!child->needsLayout())
+ child->markForPaginationRelayoutIfNeeded();
// Now do a layout.
child->layoutIfNeeded();
@@ -735,13 +722,13 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
childX += child->marginLeft() + max(0, (contentWidth() - (child->width() + child->marginLeft() + child->marginRight()))/2);
break;
case BEND:
- if (style()->direction() == RTL)
+ if (!style()->isLeftToRightDirection())
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
default: // BSTART/BSTRETCH
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
@@ -758,7 +745,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
yPos = height();
if (!iterator.first() && hasLineIfEmpty())
- setHeight(height() + lineHeight(true, true));
+ setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
setHeight(height() + toAdd);
@@ -934,103 +921,102 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
void RenderFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
{
int maxLineCount = 0;
- RenderBox* child = iterator.first();
- while (child) {
- if (!child->isPositioned()) {
- if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
- (child->style()->height().isAuto() && child->isBlockFlow() && !child->needsLayout())) {
- child->setChildNeedsLayout(true, false);
-
- // Dirty all the positioned objects.
- if (child->isRenderBlock()) {
- toRenderBlock(child)->markPositionedObjectsForLayout();
- toRenderBlock(child)->clearTruncation();
- }
+ for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ if (child->isPositioned())
+ continue;
+
+ if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
+ || (child->style()->height().isAuto() && child->isBlockFlow() && !child->needsLayout())) {
+ child->setChildNeedsLayout(true, false);
+
+ // Dirty all the positioned objects.
+ if (child->isRenderBlock()) {
+ toRenderBlock(child)->markPositionedObjectsForLayout();
+ toRenderBlock(child)->clearTruncation();
}
- child->layoutIfNeeded();
- if (child->style()->height().isAuto() && child->isBlockFlow())
- maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
}
- child = iterator.next();
+ child->layoutIfNeeded();
+ if (child->style()->height().isAuto() && child->isBlockFlow())
+ maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
}
-
- // Get the # of lines and then alter all block flow children with auto height to use the
+
+ // Get the number of lines and then alter all block flow children with auto height to use the
// specified height. We always try to leave room for at least one line.
LineClampValue lineClamp = style()->lineClamp();
int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
- if (numVisibleLines < maxLineCount) {
- for (child = iterator.first(); child; child = iterator.next()) {
- if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
- continue;
-
- RenderBlock* blockChild = toRenderBlock(child);
- int lineCount = blockChild->lineCount();
- if (lineCount <= numVisibleLines)
- continue;
-
- int newHeight = blockChild->heightForLineCount(numVisibleLines);
- if (newHeight == child->height())
- continue;
-
- child->setChildNeedsLayout(true, false);
- child->setOverrideSize(newHeight);
- m_flexingChildren = true;
- child->layoutIfNeeded();
- m_flexingChildren = false;
- child->setOverrideSize(-1);
-
- // FIXME: For now don't support RTL.
- if (style()->direction() != LTR)
- continue;
-
- // Get the last line
- RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
- if (!lastLine)
- continue;
-
- RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
- if (!lastVisibleLine)
- continue;
-
- const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
- DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
- DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
- const Font& font = style(numVisibleLines == 1)->font();
-
- // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
- int totalWidth;
- InlineBox* anchorBox = lastLine->lastChild();
- if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
- totalWidth = anchorBox->logicalWidth() + font.width(TextRun(ellipsisAndSpace, 2));
- else {
- anchorBox = 0;
- totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
- }
-
- // See if this width can be accommodated on the last visible line
- RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
- RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
-
- // FIXME: Directions of src/destBlock could be different from our direction and from one another.
- if (srcBlock->style()->direction() != LTR)
- continue;
- if (destBlock->style()->direction() != LTR)
- continue;
- int ltr = true;
-
- int blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
- int blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
-
- int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
- if (!lastVisibleLine->canAccommodateEllipsis(ltr, blockEdge,
- lastVisibleLine->x() + lastVisibleLine->logicalWidth(),
- totalWidth))
- continue;
-
- // Let the truncation code kick in.
- lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
- destBlock->setHasMarkupTruncation(true);
+ if (numVisibleLines >= maxLineCount)
+ return;
+
+ for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
+ continue;
+
+ RenderBlock* blockChild = toRenderBlock(child);
+ int lineCount = blockChild->lineCount();
+ if (lineCount <= numVisibleLines)
+ continue;
+
+ int newHeight = blockChild->heightForLineCount(numVisibleLines);
+ if (newHeight == child->height())
+ continue;
+
+ child->setChildNeedsLayout(true, false);
+ child->setOverrideSize(newHeight);
+ m_flexingChildren = true;
+ child->layoutIfNeeded();
+ m_flexingChildren = false;
+ child->setOverrideSize(-1);
+
+ // FIXME: For now don't support RTL.
+ if (style()->direction() != LTR)
+ continue;
+
+ // Get the last line
+ RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
+ if (!lastLine)
+ continue;
+
+ RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
+ if (!lastVisibleLine)
+ continue;
+
+ const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
+ const Font& font = style(numVisibleLines == 1)->font();
+
+ // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
+ int totalWidth;
+ InlineBox* anchorBox = lastLine->lastChild();
+ if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
+ totalWidth = anchorBox->logicalWidth() + font.width(TextRun(ellipsisAndSpace, 2));
+ else {
+ anchorBox = 0;
+ totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
}
+
+ // See if this width can be accommodated on the last visible line
+ RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
+ RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
+
+ // FIXME: Directions of src/destBlock could be different from our direction and from one another.
+ if (!srcBlock->style()->isLeftToRightDirection())
+ continue;
+
+ bool leftToRight = destBlock->style()->isLeftToRightDirection();
+ if (!leftToRight)
+ continue;
+
+ int blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
+ int blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
+
+ int blockEdge = leftToRight ? blockRightEdge : blockLeftEdge;
+ if (!lastVisibleLine->canAccommodateEllipsis(leftToRight, blockEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
+ continue;
+
+ // Let the truncation code kick in.
+ lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
+ destBlock->setHasMarkupTruncation(true);
}
}
diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp
index 839e963..f9f6988 100644
--- a/WebCore/rendering/RenderForeignObject.cpp
+++ b/WebCore/rendering/RenderForeignObject.cpp
@@ -41,6 +41,10 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node)
{
}
+RenderForeignObject::~RenderForeignObject()
+{
+}
+
void RenderForeignObject::paint(PaintInfo& paintInfo, int, int)
{
if (paintInfo.context->paintingDisabled())
diff --git a/WebCore/rendering/RenderForeignObject.h b/WebCore/rendering/RenderForeignObject.h
index 87423e6..bdf96ce 100644
--- a/WebCore/rendering/RenderForeignObject.h
+++ b/WebCore/rendering/RenderForeignObject.h
@@ -33,7 +33,8 @@ class SVGForeignObjectElement;
class RenderForeignObject : public RenderSVGBlock {
public:
- RenderForeignObject(SVGForeignObjectElement*);
+ explicit RenderForeignObject(SVGForeignObjectElement*);
+ virtual ~RenderForeignObject();
virtual const char* renderName() const { return "RenderForeignObject"; }
diff --git a/WebCore/rendering/RenderFrame.h b/WebCore/rendering/RenderFrame.h
index bdcaa4c..a7a859f 100644
--- a/WebCore/rendering/RenderFrame.h
+++ b/WebCore/rendering/RenderFrame.h
@@ -32,7 +32,7 @@ class HTMLFrameElement;
class RenderFrame : public RenderFrameBase {
public:
- RenderFrame(HTMLFrameElement*);
+ explicit RenderFrame(HTMLFrameElement*);
FrameEdgeInfo edgeInfo() const;
diff --git a/WebCore/rendering/RenderFrameBase.h b/WebCore/rendering/RenderFrameBase.h
index cd3cf0c..4fad560 100644
--- a/WebCore/rendering/RenderFrameBase.h
+++ b/WebCore/rendering/RenderFrameBase.h
@@ -33,7 +33,7 @@ namespace WebCore {
// Base class for RenderFrame and RenderIFrame
class RenderFrameBase : public RenderPart {
protected:
- RenderFrameBase(Element*);
+ explicit RenderFrameBase(Element*);
public:
void layoutWithFlattening(bool fixedWidth, bool fixedHeight);
diff --git a/WebCore/rendering/RenderHTMLCanvas.h b/WebCore/rendering/RenderHTMLCanvas.h
index 473dad5..2230b39 100644
--- a/WebCore/rendering/RenderHTMLCanvas.h
+++ b/WebCore/rendering/RenderHTMLCanvas.h
@@ -34,7 +34,7 @@ class HTMLCanvasElement;
class RenderHTMLCanvas : public RenderReplaced {
public:
- RenderHTMLCanvas(HTMLCanvasElement*);
+ explicit RenderHTMLCanvas(HTMLCanvasElement*);
virtual bool isCanvas() const { return true; }
virtual bool requiresLayer() const;
diff --git a/WebCore/rendering/RenderIFrame.h b/WebCore/rendering/RenderIFrame.h
index 325e2b3..0bb3182 100644
--- a/WebCore/rendering/RenderIFrame.h
+++ b/WebCore/rendering/RenderIFrame.h
@@ -32,7 +32,7 @@ namespace WebCore {
class RenderIFrame : public RenderFrameBase {
public:
- RenderIFrame(Element*);
+ explicit RenderIFrame(Element*);
#if USE(ACCELERATED_COMPOSITING)
bool requiresAcceleratedCompositing() const;
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index c8e31e6..e6f4dbe 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -131,6 +131,9 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
if (hasBoxDecorations() || hasMask())
RenderReplaced::imageChanged(newImage, rect);
+
+ if (!m_imageResource)
+ return;
if (newImage != m_imageResource->imagePtr() || !newImage)
return;
@@ -195,6 +198,9 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
void RenderImage::notifyFinished(CachedResource* newImage)
{
+ if (!m_imageResource)
+ return;
+
if (documentBeingDestroyed())
return;
@@ -327,6 +333,9 @@ void RenderImage::paintFocusRings(PaintInfo& paintInfo, const RenderStyle* style
RefPtr<HTMLCollection> areas = mapElement->areas();
unsigned numAreas = areas->length();
+
+ if (theme()->supportsFocusRing(style))
+ return; // The theme draws the focus ring.
// FIXME: Clip the paths to the image bounding box.
for (unsigned k = 0; k < numAreas; ++k) {
@@ -405,9 +414,9 @@ void RenderImage::updateAltText()
#endif
}
-bool RenderImage::isWidthSpecified() const
+bool RenderImage::isLogicalWidthSpecified() const
{
- switch (style()->width().type()) {
+ switch (style()->logicalWidth().type()) {
case Fixed:
case Percent:
return true;
@@ -422,9 +431,9 @@ bool RenderImage::isWidthSpecified() const
return false;
}
-bool RenderImage::isHeightSpecified() const
+bool RenderImage::isLogicalHeightSpecified() const
{
- switch (style()->height().type()) {
+ switch (style()->logicalHeight().type()) {
case Fixed:
case Percent:
return true;
@@ -439,7 +448,7 @@ bool RenderImage::isHeightSpecified() const
return false;
}
-int RenderImage::computeReplacedWidth(bool includeMaxWidth) const
+int RenderImage::computeReplacedLogicalWidth(bool includeMaxWidth) const
{
if (m_imageResource->imageHasRelativeWidth())
if (RenderObject* cb = isPositioned() ? container() : containingBlock()) {
@@ -447,19 +456,21 @@ int RenderImage::computeReplacedWidth(bool includeMaxWidth) const
m_imageResource->setImageContainerSize(IntSize(toRenderBox(cb)->availableWidth(), toRenderBox(cb)->availableHeight()));
}
- int width;
- if (isWidthSpecified())
- width = computeReplacedWidthUsing(style()->width());
- else if (m_imageResource->usesImageContainerSize())
- width = m_imageResource->imageSize(style()->effectiveZoom()).width();
- else if (m_imageResource->imageHasRelativeWidth())
- width = 0; // If the image is relatively-sized, set the width to 0 until there is a set container size.
+ int logicalWidth;
+ if (isLogicalWidthSpecified())
+ logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
+ else if (m_imageResource->usesImageContainerSize()) {
+ IntSize size = m_imageResource->imageSize(style()->effectiveZoom());
+ logicalWidth = style()->isHorizontalWritingMode() ? size.width() : size.height();
+ } else if (m_imageResource->imageHasRelativeWidth())
+ logicalWidth = 0; // If the image is relatively-sized, set the width to 0 until there is a set container size.
else
- width = calcAspectRatioWidth();
+ logicalWidth = calcAspectRatioLogicalWidth();
- int minW = computeReplacedWidthUsing(style()->minWidth());
- int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : computeReplacedWidthUsing(style()->maxWidth());
+ int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
+ int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
+<<<<<<< HEAD
#ifdef ANDROID_LAYOUT
width = max(minW, min(width, maxW));
// in SSR mode, we will fit the image to its container width
@@ -472,23 +483,28 @@ int RenderImage::computeReplacedWidth(bool includeMaxWidth) const
#else
return max(minW, min(width, maxW));
#endif
+=======
+ return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
+>>>>>>> webkit.org at r70209
}
-int RenderImage::computeReplacedHeight() const
+int RenderImage::computeReplacedLogicalHeight() const
{
- int height;
- if (isHeightSpecified())
- height = computeReplacedHeightUsing(style()->height());
- else if (m_imageResource->usesImageContainerSize())
- height = m_imageResource->imageSize(style()->effectiveZoom()).height();
- else if (m_imageResource->imageHasRelativeHeight())
- height = 0; // If the image is relatively-sized, set the height to 0 until there is a set container size.
+ int logicalHeight;
+ if (isLogicalHeightSpecified())
+ logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
+ else if (m_imageResource->usesImageContainerSize()) {
+ IntSize size = m_imageResource->imageSize(style()->effectiveZoom());
+ logicalHeight = style()->isHorizontalWritingMode() ? size.height() : size.width();
+ } else if (m_imageResource->imageHasRelativeHeight())
+ logicalHeight = 0; // If the image is relatively-sized, set the height to 0 until there is a set container size.
else
- height = calcAspectRatioHeight();
+ logicalHeight = calcAspectRatioLogicalHeight();
- int minH = computeReplacedHeightUsing(style()->minHeight());
- int maxH = style()->maxHeight().isUndefined() ? height : computeReplacedHeightUsing(style()->maxHeight());
+ int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
+ int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
+<<<<<<< HEAD
#ifdef ANDROID_LAYOUT
height = max(minH, min(height, maxH));
// in SSR mode, we will fit the image to its container width
@@ -511,26 +527,31 @@ int RenderImage::computeReplacedHeight() const
#else
return max(minH, min(height, maxH));
#endif
+=======
+ return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
+>>>>>>> webkit.org at r70209
}
-int RenderImage::calcAspectRatioWidth() const
+int RenderImage::calcAspectRatioLogicalWidth() const
{
- IntSize size = intrinsicSize();
- if (!size.height())
+ int intrinsicWidth = intrinsicLogicalWidth();
+ int intrinsicHeight = intrinsicLogicalHeight();
+ if (!intrinsicHeight)
return 0;
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
- return size.width(); // Don't bother scaling.
- return RenderBox::computeReplacedHeight() * size.width() / size.height();
+ return intrinsicWidth; // Don't bother scaling.
+ return RenderBox::computeReplacedLogicalHeight() * intrinsicWidth / intrinsicHeight;
}
-int RenderImage::calcAspectRatioHeight() const
+int RenderImage::calcAspectRatioLogicalHeight() const
{
- IntSize size = intrinsicSize();
- if (!size.width())
+ int intrinsicWidth = intrinsicLogicalWidth();
+ int intrinsicHeight = intrinsicLogicalHeight();
+ if (!intrinsicWidth)
return 0;
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
- return size.height(); // Don't bother scaling.
- return RenderBox::computeReplacedWidth() * size.height() / size.width();
+ return intrinsicHeight; // Don't bother scaling.
+ return RenderBox::computeReplacedLogicalWidth() * intrinsicHeight / intrinsicWidth;
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 022d792..308c863 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/WebCore/rendering/RenderImage.h
@@ -58,8 +58,8 @@ protected:
void paintFocusRings(PaintInfo&, const RenderStyle*);
virtual void paint(PaintInfo&, int tx, int ty);
- bool isWidthSpecified() const;
- bool isHeightSpecified() const;
+ bool isLogicalWidthSpecified() const;
+ bool isLogicalHeightSpecified() const;
virtual void intrinsicSizeChanged()
{
@@ -80,11 +80,11 @@ private:
virtual void notifyFinished(CachedResource*);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
- virtual int computeReplacedWidth(bool includeMaxWidth = true) const;
- virtual int computeReplacedHeight() const;
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
- int calcAspectRatioWidth() const;
- int calcAspectRatioHeight() const;
+ int calcAspectRatioLogicalWidth() const;
+ int calcAspectRatioLogicalHeight() const;
private:
// Text to display as long as the image isn't available.
diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp
index b4bfe2f..4b28268 100644
--- a/WebCore/rendering/RenderInline.cpp
+++ b/WebCore/rendering/RenderInline.cpp
@@ -31,6 +31,7 @@
#include "RenderArena.h"
#include "RenderBlock.h"
#include "RenderLayer.h"
+#include "RenderTheme.h"
#include "RenderView.h"
#include "TransformState.h"
#include "VisiblePosition.h"
@@ -471,28 +472,28 @@ static int computeMargin(const RenderInline* renderer, const Length& margin)
int RenderInline::marginLeft() const
{
- if (!style()->isVerticalBlockFlow())
+ if (!style()->isHorizontalWritingMode())
return 0;
return computeMargin(this, style()->marginLeft());
}
int RenderInline::marginRight() const
{
- if (!style()->isVerticalBlockFlow())
+ if (!style()->isHorizontalWritingMode())
return 0;
return computeMargin(this, style()->marginRight());
}
int RenderInline::marginTop() const
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
return 0;
return computeMargin(this, style()->marginTop());
}
int RenderInline::marginBottom() const
{
- if (style()->isVerticalBlockFlow())
+ if (style()->isHorizontalWritingMode())
return 0;
return computeMargin(this, style()->marginBottom());
}
@@ -878,7 +879,7 @@ InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
return flowBox;
}
-int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
+int RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
{
if (firstLine && document()->usesFirstLineRules()) {
RenderStyle* s = style(firstLine);
@@ -892,6 +893,12 @@ int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
return m_lineHeight;
}
+int RenderInline::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
+{
+ const Font& f = style(firstLine)->font();
+ return f.ascent() + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2;
+}
+
int RenderInline::verticalPositionFromCache(bool firstLine) const
{
if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
@@ -993,15 +1000,10 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
RenderStyle* styleToUse = style();
if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
- int ow = styleToUse->outlineWidth();
- Color oc = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
-
- Vector<IntRect> focusRingRects;
- addFocusRingRects(focusRingRects, tx, ty);
- if (styleToUse->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(focusRingRects, ow, styleToUse->outlineOffset(), oc);
- else
- addPDFURLRect(graphicsContext, unionRect(focusRingRects));
+ if (!theme()->supportsFocusRing(styleToUse)) {
+ // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
+ paintFocusRing(graphicsContext, tx, ty, styleToUse);
+ }
}
if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h
index feb8b8f..1eb32ff 100644
--- a/WebCore/rendering/RenderInline.h
+++ b/WebCore/rendering/RenderInline.h
@@ -32,7 +32,7 @@ class Position;
class RenderInline : public RenderBoxModelObject {
public:
- RenderInline(Node*);
+ explicit RenderInline(Node*);
virtual void destroy();
@@ -133,7 +133,8 @@ private:
virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); }
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual void childBecameNonInline(RenderObject* child);
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 63233e5..a160381 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -978,7 +978,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), DeviceColorSpace);
+ p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
p->fillRect(clipRect);
#endif
}
@@ -1986,7 +1986,7 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
m_scrollDimensionsDirty = false;
- bool ltr = renderer()->style()->direction() == LTR;
+ bool ltr = renderer()->style()->isLeftToRightDirection();
int clientWidth = box->clientWidth();
int clientHeight = box->clientHeight();
@@ -2234,9 +2234,9 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
context->clip(absRect);
IntRect largerCorner = absRect;
largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
- context->setStrokeColor(Color(makeRGB(217, 217, 217)), DeviceColorSpace);
+ context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
context->setStrokeThickness(1.0f);
- context->setFillColor(Color::transparent, DeviceColorSpace);
+ context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
context->drawRect(largerCorner);
context->restore();
}
@@ -2811,7 +2811,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
useTemporaryClipRects = compositor()->inCompositingMode();
#endif
- IntRect hitTestArea = result.rectFromPoint(hitTestPoint);
+ IntRect hitTestArea = result.rectForPoint(hitTestPoint);
// Apply a transform if we have one.
if (transform() && !appliedTransform) {
@@ -3094,7 +3094,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
IntRect localClipRect(hitTestRect);
localClipRect.intersect(colRect);
- if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectFromPoint(hitTestPoint))) {
+ if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectForPoint(hitTestPoint))) {
RenderLayer* hitLayer = 0;
if (!columnIndex) {
// Apply a translation transform to change where the layer paints.
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index 536cdab..52a814c 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -43,7 +43,7 @@
#include "HTMLIFrameElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
-#include "InspectorTimelineAgent.h"
+#include "InspectorInstrumentation.h"
#include "KeyframeList.h"
#include "PluginViewBase.h"
#include "RenderBox.h"
@@ -1104,26 +1104,10 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
ASSERT(!m_owningLayer->m_usedTransparency);
}
-#if ENABLE(INSPECTOR)
-static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer)
-{
- Frame* frame = renderer->frame();
- if (!frame)
- return 0;
- Page* page = frame->page();
- if (!page)
- return 0;
- return page->inspectorTimelineAgent();
-}
-#endif
-
// Up-call from compositing layer drawing callback.
void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip)
{
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer()))
- timelineAgent->willPaint(clip);
-#endif
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame(), clip);
// We have to use the same root as for hit testing, because both methods
// can compute and cache clipRects.
@@ -1149,10 +1133,7 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co
paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer());
-#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer()))
- timelineAgent->didPaint();
-#endif
+ InspectorInstrumentation::didPaint(cookie);
}
bool RenderLayerBacking::showDebugBorders() const
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index 835d21e..835d21e 100755..100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h
index b4e3afe..b4e3afe 100755..100644
--- a/WebCore/rendering/RenderLayerCompositor.h
+++ b/WebCore/rendering/RenderLayerCompositor.h
diff --git a/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp
index 760d2ea..1e58e63 100644
--- a/WebCore/rendering/RenderLineBoxList.cpp
+++ b/WebCore/rendering/RenderLineBoxList.cpp
@@ -203,6 +203,10 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn
}
if (bottomForPaginationCheck - topForPaginationCheck <= v->printRect().height()) {
if (ty + bottomForPaginationCheck > v->printRect().bottom()) {
+ if (RootInlineBox* nextRootBox = curr->root()->nextRootBox())
+ bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->topVisibleOverflow(), nextRootBox->lineTop()));
+ }
+ if (ty + bottomForPaginationCheck > v->printRect().bottom()) {
if (ty + topForPaginationCheck < v->truncatedAt())
v->setBestTruncatedAt(ty + topForPaginationCheck, renderer);
// If we were able to truncate, don't paint.
diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp
index 39442e1..532c551 100644
--- a/WebCore/rendering/RenderListBox.cpp
+++ b/WebCore/rendering/RenderListBox.cpp
@@ -238,9 +238,9 @@ void RenderListBox::computeLogicalHeight()
}
}
-int RenderListBox::baselinePosition(bool, bool) const
+int RenderListBox::baselinePosition(bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const
{
- return height() + marginTop() + marginBottom() - baselineAdjustment;
+ return RenderBox::baselinePosition(firstLine, lineDirection, linePositionMode) - baselineAdjustment;
}
IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index)
@@ -334,7 +334,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in
unsigned length = itemText.length();
const UChar* string = itemText.characters();
- TextRun textRun(string, length, 0, 0, 0, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, false, false);
+ TextRun textRun(string, length, 0, 0, 0, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override, false, false);
// Draw the item text
if (itemStyle->visibility() != HIDDEN)
diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h
index c69f205..072fc91 100644
--- a/WebCore/rendering/RenderListBox.h
+++ b/WebCore/rendering/RenderListBox.h
@@ -71,7 +71,7 @@ private:
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
virtual void computePreferredLogicalWidths();
- virtual int baselinePosition(bool firstLine, bool isRootLineBox) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual void computeLogicalHeight();
virtual void layout();
diff --git a/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp
index b414f38..1f600fe 100644
--- a/WebCore/rendering/RenderListItem.cpp
+++ b/WebCore/rendering/RenderListItem.cpp
@@ -102,7 +102,7 @@ static Node* enclosingList(const RenderListItem* listItem)
static RenderListItem* previousListItem(Node* list, const RenderListItem* item)
{
- for (RenderObject* renderer = item->previousInPreOrder(); renderer != list->renderer(); renderer = renderer->previousInPreOrder()) {
+ for (RenderObject* renderer = item->previousInPreOrder(); renderer && renderer != list->renderer(); renderer = renderer->previousInPreOrder()) {
if (!renderer->isListItem())
continue;
Node* otherList = enclosingList(toRenderListItem(renderer));
@@ -261,7 +261,7 @@ void RenderListItem::positionListMarker()
// FIXME: Inline flows in the line box hierarchy that have self-painting layers should act as cutoff points
// and really shouldn't keep propagating overflow up. This won't really break anything other than repainting
// not being as tight as it could be though.
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
int leftLineOffset = logicalLeftOffsetForLine(yOffset, logicalLeftOffsetForLine(yOffset, false), false);
markerXPos = leftLineOffset - xOffset - paddingLeft() - borderLeft() + m_marker->marginLeft();
m_marker->inlineBoxWrapper()->adjustPosition(markerXPos - markerOldX, 0);
@@ -326,12 +326,12 @@ String RenderListItem::markerTextWithSuffix() const
const String markerSuffix = m_marker->suffix();
Vector<UChar> resultVector;
- if (m_marker->style()->direction() == RTL)
+ if (!m_marker->style()->isLeftToRightDirection())
resultVector.append(markerSuffix.characters(), markerSuffix.length());
resultVector.append(markerText.characters(), markerText.length());
- if (m_marker->style()->direction() == LTR)
+ if (m_marker->style()->isLeftToRightDirection())
resultVector.append(markerSuffix.characters(), markerSuffix.length());
return String::adopt(resultVector);
diff --git a/WebCore/rendering/RenderListItem.h b/WebCore/rendering/RenderListItem.h
index f7bd661..2fcb6c4 100644
--- a/WebCore/rendering/RenderListItem.h
+++ b/WebCore/rendering/RenderListItem.h
@@ -31,7 +31,7 @@ class RenderListMarker;
class RenderListItem : public RenderBlock {
public:
- RenderListItem(Node*);
+ explicit RenderListItem(Node*);
int value() const { if (!m_isValueUpToDate) updateValueNow(); return m_value; }
void updateValue();
diff --git a/WebCore/rendering/RenderListMarker.cpp b/WebCore/rendering/RenderListMarker.cpp
index 18811df..ab5da61 100644
--- a/WebCore/rendering/RenderListMarker.cpp
+++ b/WebCore/rendering/RenderListMarker.cpp
@@ -504,7 +504,6 @@ static UChar listMarkerSuffix(EListStyleType type, int value)
case Footnotes:
case NoneListStyle:
case Square:
- ASSERT_NOT_REACHED();
return ' ';
case Afar:
case Amharic:
@@ -1155,7 +1154,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
context->drawEllipse(marker);
return;
case Circle:
- context->setFillColor(Color::transparent, DeviceColorSpace);
+ context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
context->drawEllipse(marker);
return;
case Square:
@@ -1257,7 +1256,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
const Font& font = style()->font();
const UChar suffix = listMarkerSuffix(type, m_listItem->value());
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
int width = font.width(textRun);
context->drawText(style()->font(), textRun, marker.location());
UChar suffixSpace[2] = { suffix, ' ' };
@@ -1444,7 +1443,7 @@ void RenderListMarker::updateMargins()
if (isInside()) {
if (isImage()) {
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
marginRight = cMarkerPadding;
else
marginLeft = cMarkerPadding;
@@ -1452,7 +1451,7 @@ void RenderListMarker::updateMargins()
case Disc:
case Circle:
case Square:
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
marginLeft = -1;
marginRight = font.ascent() - minPreferredLogicalWidth() + 1;
} else {
@@ -1464,7 +1463,7 @@ void RenderListMarker::updateMargins()
break;
}
} else {
- if (style()->direction() == LTR) {
+ if (style()->isLeftToRightDirection()) {
if (isImage())
marginLeft = -minPreferredLogicalWidth() - cMarkerPadding;
else {
@@ -1506,20 +1505,18 @@ void RenderListMarker::updateMargins()
style()->setMarginRight(Length(marginRight, Fixed));
}
-int RenderListMarker::lineHeight(bool, bool) const
+int RenderListMarker::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
if (!isImage())
- return m_listItem->lineHeight(false, true);
- return height();
+ return m_listItem->lineHeight(firstLine, direction, PositionOfInteriorLineBoxes);
+ return RenderBox::lineHeight(firstLine, direction, linePositionMode);
}
-int RenderListMarker::baselinePosition(bool, bool) const
+int RenderListMarker::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
- if (!isImage()) {
- const Font& font = style()->font();
- return font.ascent() + (lineHeight(false) - font.height())/2;
- }
- return height();
+ if (!isImage())
+ return m_listItem->baselinePosition(firstLine, direction, PositionOfInteriorLineBoxes);
+ return RenderBox::baselinePosition(firstLine, direction, linePositionMode);
}
String RenderListMarker::suffix() const
@@ -1532,7 +1529,7 @@ String RenderListMarker::suffix() const
// If the suffix is not ' ', an extra space is needed
if (suffix != ' ') {
- if (style()->direction() == LTR)
+ if (style()->isLeftToRightDirection())
resultVector.append(' ');
else
resultVector.prepend(' ');
diff --git a/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h
index 1e55898..fe025c3 100644
--- a/WebCore/rendering/RenderListMarker.h
+++ b/WebCore/rendering/RenderListMarker.h
@@ -58,8 +58,8 @@ private:
virtual InlineBox* createInlineBox();
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
- virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
bool isImage() const;
bool isText() const { return !isImage(); }
diff --git a/WebCore/rendering/RenderMarquee.cpp b/WebCore/rendering/RenderMarquee.cpp
index bb917f8..90383d8 100644
--- a/WebCore/rendering/RenderMarquee.cpp
+++ b/WebCore/rendering/RenderMarquee.cpp
@@ -66,6 +66,10 @@ RenderMarquee::RenderMarquee(RenderLayer* l)
{
}
+RenderMarquee::~RenderMarquee()
+{
+}
+
int RenderMarquee::marqueeSpeed() const
{
int result = m_layer->renderer()->style()->marqueeSpeed();
@@ -110,7 +114,7 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge
ASSERT(box);
RenderStyle* s = box->style();
if (isHorizontal()) {
- bool ltr = s->direction() == LTR;
+ bool ltr = s->isLeftToRightDirection();
int clientWidth = box->clientWidth();
int contentWidth = ltr ? box->rightmostPosition(true, false) : box->leftmostPosition(true, false);
if (ltr)
diff --git a/WebCore/rendering/RenderMarquee.h b/WebCore/rendering/RenderMarquee.h
index 1651454..79998ed 100644
--- a/WebCore/rendering/RenderMarquee.h
+++ b/WebCore/rendering/RenderMarquee.h
@@ -55,7 +55,8 @@ class RenderLayer;
// This class handles the auto-scrolling of layers with overflow: marquee.
class RenderMarquee : public Noncopyable {
public:
- RenderMarquee(RenderLayer*);
+ explicit RenderMarquee(RenderLayer*);
+ virtual ~RenderMarquee();
int speed() const { return m_speed; }
int marqueeSpeed() const;
diff --git a/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp
index a589a2d..49a536c 100644
--- a/WebCore/rendering/RenderMedia.cpp
+++ b/WebCore/rendering/RenderMedia.cpp
@@ -34,6 +34,7 @@
#include "MediaControlElements.h"
#include "MouseEvent.h"
#include "Page.h"
+#include "RenderLayer.h"
#include "RenderTheme.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
@@ -599,31 +600,80 @@ void RenderMedia::forwardEvent(Event* event)
}
}
-int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderMedia::topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf);
+ int top = RenderImage::topmostPosition(includeOverflowInterior, includeSelf, applyTransform);
+ if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
+ return top;
+
+ top = min(top, m_controlsShadowRoot->renderBox()->transformedFrameRect().y() + m_controlsShadowRoot->renderBox()->topmostPosition(includeOverflowInterior, includeSelf, applyTransform));
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.y();
+ }
+
+ return top;
+}
+
+int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
+{
+ int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return bottom;
- return max(bottom, m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf));
+ bottom = max(bottom, m_controlsShadowRoot->renderBox()->transformedFrameRect().y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf, applyTransform));
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.height() + transformRect.y();
+ }
+
+ return bottom;
}
-int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf);
+ int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return right;
- return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf));
+ right = max(right, m_controlsShadowRoot->renderBox()->transformedFrameRect().x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf, applyTransform));
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.width() + transformRect.x();
+ }
+
+ return right;
}
-int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf);
+ int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return left;
- return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf));
+ left = min(left, m_controlsShadowRoot->renderBox()->transformedFrameRect().x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf, applyTransform));
+
+ if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
+ int top = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
+ IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
+ return transformRect.x();
+ }
+
+ return left;
}
diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h
index 4c980b5..aa725ff 100644
--- a/WebCore/rendering/RenderMedia.h
+++ b/WebCore/rendering/RenderMedia.h
@@ -85,9 +85,10 @@ private:
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;
- virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
+ virtual int topmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
+ virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true, ApplyTransform = IncludeTransform) const;
void createControlsShadowRoot();
void destroyControlsShadowRoot();
diff --git a/WebCore/rendering/RenderMediaControls.h b/WebCore/rendering/RenderMediaControls.h
index f05c549..9edeef1 100644
--- a/WebCore/rendering/RenderMediaControls.h
+++ b/WebCore/rendering/RenderMediaControls.h
@@ -26,6 +26,8 @@
#ifndef RenderMediaControls_h
#define RenderMediaControls_h
+#if ENABLE(VIDEO)
+
#include "RenderObject.h"
#include "MediaControlElements.h"
@@ -41,4 +43,6 @@ public:
} // namespace WebCore
+#endif // ENABLE(VIDEO)
+
#endif // RenderMediaControls_h
diff --git a/WebCore/rendering/RenderMediaControlsChromium.cpp b/WebCore/rendering/RenderMediaControlsChromium.cpp
index ab650da..f938a52 100644
--- a/WebCore/rendering/RenderMediaControlsChromium.cpp
+++ b/WebCore/rendering/RenderMediaControlsChromium.cpp
@@ -63,7 +63,7 @@ static bool hasSource(const HTMLMediaElement* mediaElement)
static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
{
IntRect imageRect = image->rect();
- context->drawImage(image, DeviceColorSpace, rect);
+ context->drawImage(image, ColorSpaceDeviceRGB, rect);
return true;
}
@@ -120,9 +120,9 @@ static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, c
context->save();
context->setShouldAntialias(true);
context->setStrokeStyle(SolidStroke);
- context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), DeviceColorSpace);
+ context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), ColorSpaceDeviceRGB);
context->setStrokeThickness(style->borderLeftWidth());
- context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), DeviceColorSpace);
+ context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB);
context->drawRect(rect);
context->restore();
@@ -189,13 +189,13 @@ static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintI
GraphicsContext* context = paintInfo.context;
Color originalColor = context->strokeColor();
if (originalColor != Color::white)
- context->setStrokeColor(Color::white, DeviceColorSpace);
+ context->setStrokeColor(Color::white, ColorSpaceDeviceRGB);
int x = rect.x() + rect.width() / 2;
context->drawLine(IntPoint(x, rect.y()), IntPoint(x, rect.y() + rect.height()));
if (originalColor != Color::white)
- context->setStrokeColor(originalColor, DeviceColorSpace);
+ context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
return true;
}
@@ -224,17 +224,17 @@ static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& p
// Draw the left border using CSS defined width and color.
context->setStrokeThickness(object->style()->borderLeftWidth());
- context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), DeviceColorSpace);
+ context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), ColorSpaceDeviceRGB);
context->drawLine(IntPoint(rect.x() + 1, rect.y()),
IntPoint(rect.x() + 1, rect.y() + rect.height()));
// Draw the right border using CSS defined width and color.
context->setStrokeThickness(object->style()->borderRightWidth());
- context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), DeviceColorSpace);
+ context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), ColorSpaceDeviceRGB);
context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
- context->setStrokeColor(originalColor, DeviceColorSpace);
+ context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
context->setStrokeThickness(originalThickness);
context->setStrokeStyle(originalStyle);
}
diff --git a/WebCore/rendering/RenderMeter.cpp b/WebCore/rendering/RenderMeter.cpp
index 226d605..f60e350 100644
--- a/WebCore/rendering/RenderMeter.cpp
+++ b/WebCore/rendering/RenderMeter.cpp
@@ -105,7 +105,7 @@ IntRect RenderMeter::valuePartRect() const
if (rect.height() <= rect.width()) {
int width = static_cast<int>(rect.width()*valueRatio());
- if (style()->direction() == RTL) {
+ if (!style()->isLeftToRightDirection()) {
rect.setX(rect.x() + (rect.width() - width));
rect.setWidth(width);
} else
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index eb75ce2..9d2895f 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -1154,6 +1154,16 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in
}
}
#endif
+
+void RenderObject::paintFocusRing(GraphicsContext* context, int tx, int ty, RenderStyle* style)
+{
+ Vector<IntRect> focusRingRects;
+ addFocusRingRects(focusRingRects, tx, ty);
+ if (style->outlineStyleIsAuto())
+ context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
+ else
+ addPDFURLRect(context, unionRect(focusRingRects));
+}
void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect)
{
@@ -1184,12 +1194,7 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(styleToUse)) {
// Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- Vector<IntRect> focusRingRects;
- addFocusRingRects(focusRingRects, tx, ty);
- if (styleToUse->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(focusRingRects, ow, offset, oc);
- else
- addPDFURLRect(graphicsContext, unionRect(focusRingRects));
+ paintFocusRing(graphicsContext, tx, ty, styleToUse);
}
}
@@ -2227,7 +2232,7 @@ void RenderObject::updateDragState(bool dragOn)
{
bool valueChanged = (dragOn != m_isDragging);
m_isDragging = dragOn;
- if (valueChanged && style()->affectedByDragRules())
+ if (valueChanged && style()->affectedByDragRules() && node())
node()->setNeedsStyleRecalc();
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
curr->updateDragState(dragOn);
@@ -2275,17 +2280,6 @@ bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int /*x*/,
return false;
}
-int RenderObject::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
-{
- return style(firstLine)->computedLineHeight();
-}
-
-int RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
-{
- const Font& f = style(firstLine)->font();
- return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
-}
-
void RenderObject::scheduleRelayout()
{
if (isRenderView()) {
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index 70b0da5..9c29ce1 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -291,7 +291,9 @@ public:
bool isHTMLMarquee() const;
+ inline bool isBeforeContent() const;
inline bool isAfterContent() const;
+ static inline bool isBeforeContent(const RenderObject* obj) { return obj && obj->isBeforeContent(); }
static inline bool isAfterContent(const RenderObject* obj) { return obj && obj->isAfterContent(); }
bool childrenInline() const { return m_childrenInline; }
@@ -314,8 +316,9 @@ public:
virtual bool isSVGContainer() const { return false; }
virtual bool isSVGGradientStop() const { return false; }
virtual bool isSVGHiddenContainer() const { return false; }
- virtual bool isRenderPath() const { return false; }
+ virtual bool isSVGPath() const { return false; }
virtual bool isSVGText() const { return false; }
+ virtual bool isSVGTextPath() const { return false; }
virtual bool isSVGInline() const { return false; }
virtual bool isSVGInlineText() const { return false; }
virtual bool isSVGImage() const { return false; }
@@ -482,11 +485,6 @@ public:
void updateFillImages(const FillLayer*, const FillLayer*);
void updateImage(StyleImage*, StyleImage*);
- // for discussion of lineHeight see CSS2 spec
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
- // for the vertical-align property of inline elements
- // the offset of baseline from the top of the object.
- virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
virtual void paint(PaintInfo&, int tx, int ty);
// Recursive function that computes the size and position of this object and all its descendants.
@@ -748,6 +746,7 @@ protected:
// Overrides should call the superclass at the start
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ void paintFocusRing(GraphicsContext*, int tx, int ty, RenderStyle*);
void paintOutline(GraphicsContext*, int tx, int ty, int w, int h);
void addPDFURLRect(GraphicsContext*, const IntRect&);
@@ -860,6 +859,16 @@ inline bool RenderObject::documentBeingDestroyed() const
return !document()->renderer();
}
+inline bool RenderObject::isBeforeContent() const
+{
+ if (style()->styleType() != BEFORE)
+ return false;
+ // Text nodes don't have their own styles, so ignore the style on a text node.
+ if (isText() && !isBR())
+ return false;
+ return true;
+}
+
inline bool RenderObject::isAfterContent() const
{
if (style()->styleType() != AFTER)
diff --git a/WebCore/rendering/RenderObjectChildList.cpp b/WebCore/rendering/RenderObjectChildList.cpp
index 96ec800..c7c8e44 100644
--- a/WebCore/rendering/RenderObjectChildList.cpp
+++ b/WebCore/rendering/RenderObjectChildList.cpp
@@ -461,7 +461,10 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo
generatedContentContainer->setStyle(pseudoElementStyle);
owner->addChild(generatedContentContainer, insertBefore);
}
- generatedContentContainer->addChild(renderer);
+ if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
+ generatedContentContainer->addChild(renderer);
+ else
+ renderer->destroy();
}
}
}
diff --git a/WebCore/rendering/RenderProgress.cpp b/WebCore/rendering/RenderProgress.cpp
index d6e2dc7..d2e9424 100644
--- a/WebCore/rendering/RenderProgress.cpp
+++ b/WebCore/rendering/RenderProgress.cpp
@@ -137,7 +137,7 @@ void RenderProgress::updateAnimationState()
IntRect RenderProgress::valuePartRect() const
{
IntRect rect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), lround((width() - borderLeft() - paddingLeft() - borderRight() - paddingRight()) * position()), height() - borderTop() - paddingTop() - borderBottom() - paddingBottom());
- if (style()->direction() == RTL)
+ if (!style()->isLeftToRightDirection())
rect.setX(width() - borderRight() - paddingRight() - rect.width());
return rect;
}
diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp
index d3b449c..a087038 100644
--- a/WebCore/rendering/RenderReplaced.cpp
+++ b/WebCore/rendering/RenderReplaced.cpp
@@ -57,13 +57,6 @@ RenderReplaced::~RenderReplaced()
{
}
-void RenderReplaced::setStyle(PassRefPtr<RenderStyle> newStyle)
-{
- if (newStyle->blockFlow() != TopToBottomBlockFlow)
- newStyle->setBlockFlow(TopToBottomBlockFlow);
- RenderBox::setStyle(newStyle);
-}
-
void RenderReplaced::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBox::styleDidChange(diff, oldStyle);
@@ -88,8 +81,7 @@ void RenderReplaced::layout()
m_overflow.clear();
addShadowOverflow();
- repainter.repaintAfterLayout();
-
+ repainter.repaintAfterLayout();
setNeedsLayout(false);
}
@@ -207,54 +199,54 @@ static inline bool lengthIsSpecified(Length length)
return lengthType == Fixed || lengthType == Percent;
}
-int RenderReplaced::computeReplacedWidth(bool includeMaxWidth) const
+int RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const
{
- int width;
+ int logicalWidth;
if (lengthIsSpecified(style()->width()))
- width = computeReplacedWidthUsing(style()->width());
+ logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
else if (m_hasIntrinsicSize)
- width = calcAspectRatioWidth();
+ logicalWidth = calcAspectRatioLogicalWidth();
else
- width = intrinsicSize().width();
+ logicalWidth = intrinsicLogicalWidth();
- int minW = computeReplacedWidthUsing(style()->minWidth());
- int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : computeReplacedWidthUsing(style()->maxWidth());
+ int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
+ int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
- return max(minW, min(width, maxW));
+ return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
}
-int RenderReplaced::computeReplacedHeight() const
+int RenderReplaced::computeReplacedLogicalHeight() const
{
- int height;
- if (lengthIsSpecified(style()->height()))
- height = computeReplacedHeightUsing(style()->height());
+ int logicalHeight;
+ if (lengthIsSpecified(style()->logicalHeight()))
+ logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
else if (m_hasIntrinsicSize)
- height = calcAspectRatioHeight();
+ logicalHeight = calcAspectRatioLogicalHeight();
else
- height = intrinsicSize().height();
+ logicalHeight = intrinsicLogicalHeight();
- int minH = computeReplacedHeightUsing(style()->minHeight());
- int maxH = style()->maxHeight().isUndefined() ? height : computeReplacedHeightUsing(style()->maxHeight());
+ int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
+ int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
- return max(minH, min(height, maxH));
+ return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
}
-int RenderReplaced::calcAspectRatioWidth() const
+int RenderReplaced::calcAspectRatioLogicalWidth() const
{
- int intrinsicWidth = intrinsicSize().width();
- int intrinsicHeight = intrinsicSize().height();
+ int intrinsicWidth = intrinsicLogicalWidth();
+ int intrinsicHeight = intrinsicLogicalHeight();
if (!intrinsicHeight)
return 0;
- return RenderBox::computeReplacedHeight() * intrinsicWidth / intrinsicHeight;
+ return RenderBox::computeReplacedLogicalHeight() * intrinsicWidth / intrinsicHeight;
}
-int RenderReplaced::calcAspectRatioHeight() const
+int RenderReplaced::calcAspectRatioLogicalHeight() const
{
- int intrinsicWidth = intrinsicSize().width();
- int intrinsicHeight = intrinsicSize().height();
+ int intrinsicWidth = intrinsicLogicalWidth();
+ int intrinsicHeight = intrinsicLogicalHeight();
if (!intrinsicWidth)
return 0;
- return RenderBox::computeReplacedWidth() * intrinsicHeight / intrinsicWidth;
+ return RenderBox::computeReplacedLogicalWidth() * intrinsicHeight / intrinsicWidth;
}
void RenderReplaced::computePreferredLogicalWidths()
@@ -262,7 +254,7 @@ void RenderReplaced::computePreferredLogicalWidths()
ASSERT(preferredLogicalWidthsDirty());
int borderAndPadding = borderAndPaddingWidth();
- m_maxPreferredLogicalWidth = computeReplacedWidth(false) + borderAndPadding;
+ m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(false) + borderAndPadding;
if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
@@ -277,16 +269,6 @@ void RenderReplaced::computePreferredLogicalWidths()
setPreferredLogicalWidthsDirty(false);
}
-int RenderReplaced::lineHeight(bool, bool) const
-{
- return height() + marginTop() + marginBottom();
-}
-
-int RenderReplaced::baselinePosition(bool, bool) const
-{
- return height() + marginTop() + marginBottom();
-}
-
unsigned RenderReplaced::caretMaxRenderedOffset() const
{
return 1;
diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h
index 872f6d0..fbc5151 100644
--- a/WebCore/rendering/RenderReplaced.h
+++ b/WebCore/rendering/RenderReplaced.h
@@ -32,15 +32,13 @@ public:
RenderReplaced(Node*, const IntSize& intrinsicSize);
virtual ~RenderReplaced();
- virtual void setStyle(PassRefPtr<RenderStyle>);
-
protected:
virtual void layout();
virtual IntSize intrinsicSize() const;
- virtual int computeReplacedWidth(bool includeMaxWidth = true) const;
- virtual int computeReplacedHeight() const;
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
virtual int minimumReplacedHeight() const { return 0; }
virtual void setSelectionState(SelectionState);
@@ -62,13 +60,10 @@ private:
virtual bool canHaveChildren() const { return false; }
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
- virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
-
virtual void computePreferredLogicalWidths();
- int calcAspectRatioWidth() const;
- int calcAspectRatioHeight() const;
+ int calcAspectRatioLogicalWidth() const;
+ int calcAspectRatioLogicalHeight() const;
virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { }
diff --git a/WebCore/rendering/RenderRuby.cpp b/WebCore/rendering/RenderRuby.cpp
index 2f543d5..7e19a79 100644
--- a/WebCore/rendering/RenderRuby.cpp
+++ b/WebCore/rendering/RenderRuby.cpp
@@ -44,8 +44,8 @@ static RenderRubyRun* lastRubyRun(const RenderObject* ruby)
RenderObject* child = ruby->lastChild();
if (child && ruby->isAfterContent(child))
child = child->previousSibling();
- ASSERT(!child || child->isRubyRun());
- return static_cast<RenderRubyRun*>(child);
+ ASSERT(!child || child->isRubyRun() || child->isBeforeContent());
+ return child && child->isRubyRun() ? static_cast<RenderRubyRun*>(child) : 0;
}
static inline RenderRubyRun* findRubyRunParent(RenderObject* child)
@@ -75,15 +75,25 @@ bool RenderRubyAsInline::isChildAllowed(RenderObject* child, RenderStyle*) const
void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild)
{
- // Note: ':after' content is handled implicitly below
+ // Insert :before and :after content outside of ruby runs.
+ if (child->isBeforeContent() || child->isAfterContent()) {
+ RenderInline::addChild(child, beforeChild);
+ return;
+ }
+ // If the child is a ruby run, just add it normally.
if (child->isRubyRun()) {
RenderInline::addChild(child, beforeChild);
return;
}
- if (beforeChild && !isAfterContent(beforeChild) && !beforeChild->isRubyRun()) {
- if (RenderRubyRun* run = findRubyRunParent(beforeChild)) {
+ if (beforeChild && !isAfterContent(beforeChild)) {
+ // insert child into run
+ ASSERT(!beforeChild->isRubyRun());
+ RenderObject* run = beforeChild;
+ while (run && !run->isRubyRun())
+ run = run->parent();
+ if (run) {
run->addChild(child, beforeChild);
return;
}
@@ -104,15 +114,15 @@ void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild
void RenderRubyAsInline::removeChild(RenderObject* child)
{
- // If the child's parent is *this, i.e. a ruby run or ':after' content,
+ // If the child's parent is *this (a ruby run or :before or :after content),
// just use the normal remove method.
- if (child->parent() == this) {
- ASSERT(child->isRubyRun() || child->isAfterContent());
+ if (child->isRubyRun() || child->isBeforeContent() || child->isAfterContent()) {
RenderInline::removeChild(child);
return;
}
- // Find the containing run
+ // Otherwise find the containing run and remove it from there.
+ ASSERT(child->parent() != this);
RenderRubyRun* run = findRubyRunParent(child);
ASSERT(run);
run->removeChild(child);
@@ -139,9 +149,13 @@ bool RenderRubyAsBlock::isChildAllowed(RenderObject* child, RenderStyle*) const
void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
{
- // Note: ':after' content is handled implicitely below
+ // Insert :before and :after content outside of ruby runs.
+ if (child->isBeforeContent() || child->isAfterContent()) {
+ RenderBlock::addChild(child, beforeChild);
+ return;
+ }
- // if child is a ruby run, just add it normally
+ // If the child is a ruby run, just add it normally.
if (child->isRubyRun()) {
RenderBlock::addChild(child, beforeChild);
return;
@@ -157,7 +171,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
run->addChild(child, beforeChild);
return;
}
- ASSERT(false); // beforeChild should always have a run as parent!
+ ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
// Emergency fallback: fall through and just append.
}
@@ -174,14 +188,15 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
void RenderRubyAsBlock::removeChild(RenderObject* child)
{
- // If the child's parent is *this, just use the normal remove method.
- if (child->parent() == this) {
- // This should happen only during destruction of the whole ruby element, though.
+ // If the child's parent is *this (a ruby run or :before or :after content),
+ // just use the normal remove method.
+ if (child->isRubyRun() || child->isBeforeContent() || child->isAfterContent()) {
RenderBlock::removeChild(child);
return;
}
- // Find the containing run
+ // Otherwise find the containing run and remove it from there.
+ ASSERT(child->parent() != this);
RenderRubyRun* run = findRubyRunParent(child);
ASSERT(run);
run->removeChild(child);
diff --git a/WebCore/rendering/RenderSVGAllInOne.cpp b/WebCore/rendering/RenderSVGAllInOne.cpp
index 9c30d88..7002747 100644
--- a/WebCore/rendering/RenderSVGAllInOne.cpp
+++ b/WebCore/rendering/RenderSVGAllInOne.cpp
@@ -30,8 +30,6 @@
#include "RenderSVGGradientStop.cpp"
#include "RenderSVGHiddenContainer.cpp"
#include "RenderSVGImage.cpp"
-#include "RenderSVGInline.cpp"
-#include "RenderSVGInlineText.cpp"
#include "RenderSVGModelObject.cpp"
#include "RenderSVGResource.cpp"
#include "RenderSVGResourceClipper.cpp"
@@ -47,24 +45,32 @@
#include "RenderSVGResourceSolidColor.cpp"
#include "RenderSVGRoot.cpp"
#include "RenderSVGShadowTreeRootContainer.cpp"
-#include "RenderSVGTSpan.cpp"
-#include "RenderSVGText.cpp"
-#include "RenderSVGTextPath.cpp"
#include "RenderSVGTransformableContainer.cpp"
#include "RenderSVGViewportContainer.cpp"
-#include "SVGCharacterData.cpp"
-#include "SVGCharacterLayoutInfo.cpp"
#include "SVGImageBufferTools.cpp"
-#include "SVGInlineFlowBox.cpp"
-#include "SVGInlineTextBox.cpp"
#include "SVGMarkerLayoutInfo.cpp"
#include "SVGRenderSupport.cpp"
#include "SVGRenderTreeAsText.cpp"
#include "SVGResources.cpp"
#include "SVGResourcesCache.cpp"
#include "SVGResourcesCycleSolver.cpp"
-#include "SVGRootInlineBox.cpp"
#include "SVGShadowTreeElements.cpp"
-#include "SVGTextChunkLayoutInfo.cpp"
-#include "SVGTextLayoutUtilities.cpp"
-#include "SVGTextQuery.cpp"
+
+// FIXME: As soon as all SVG renderers live in rendering/svg, this file should be moved there as well, removing the need for the svg/ includes below.
+#include "svg/RenderSVGInline.cpp"
+#include "svg/RenderSVGInlineText.cpp"
+#include "svg/RenderSVGTSpan.cpp"
+#include "svg/RenderSVGText.cpp"
+#include "svg/RenderSVGTextPath.cpp"
+#include "svg/SVGInlineFlowBox.cpp"
+#include "svg/SVGInlineTextBox.cpp"
+#include "svg/SVGRootInlineBox.cpp"
+#include "svg/SVGTextChunk.cpp"
+#include "svg/SVGTextChunkBuilder.cpp"
+#include "svg/SVGTextLayoutAttributes.cpp"
+#include "svg/SVGTextLayoutAttributesBuilder.cpp"
+#include "svg/SVGTextLayoutEngine.cpp"
+#include "svg/SVGTextLayoutEngineBaseline.cpp"
+#include "svg/SVGTextLayoutEngineSpacing.cpp"
+#include "svg/SVGTextMetrics.cpp"
+#include "svg/SVGTextQuery.cpp"
diff --git a/WebCore/rendering/RenderSVGBlock.h b/WebCore/rendering/RenderSVGBlock.h
index c1379da..a9dd5db 100644
--- a/WebCore/rendering/RenderSVGBlock.h
+++ b/WebCore/rendering/RenderSVGBlock.h
@@ -31,7 +31,7 @@ class SVGElement;
class RenderSVGBlock : public RenderBlock {
public:
- RenderSVGBlock(SVGElement*);
+ explicit RenderSVGBlock(SVGElement*);
private:
virtual void setStyle(PassRefPtr<RenderStyle>);
diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp
index b5974ca..0761562 100644
--- a/WebCore/rendering/RenderSVGContainer.cpp
+++ b/WebCore/rendering/RenderSVGContainer.cpp
@@ -43,6 +43,10 @@ RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
{
}
+RenderSVGContainer::~RenderSVGContainer()
+{
+}
+
void RenderSVGContainer::layout()
{
ASSERT(needsLayout());
diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h
index b0c952f..5bdbf32 100644
--- a/WebCore/rendering/RenderSVGContainer.h
+++ b/WebCore/rendering/RenderSVGContainer.h
@@ -33,7 +33,8 @@ class SVGElement;
class RenderSVGContainer : public RenderSVGModelObject {
public:
- RenderSVGContainer(SVGStyledElement*);
+ explicit RenderSVGContainer(SVGStyledElement*);
+ virtual ~RenderSVGContainer();
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
diff --git a/WebCore/rendering/RenderSVGGradientStop.cpp b/WebCore/rendering/RenderSVGGradientStop.cpp
index ebf7385..a5e5808 100644
--- a/WebCore/rendering/RenderSVGGradientStop.cpp
+++ b/WebCore/rendering/RenderSVGGradientStop.cpp
@@ -72,7 +72,7 @@ void RenderSVGGradientStop::layout()
SVGGradientElement* RenderSVGGradientStop::gradientElement() const
{
- Node* parentNode = node()->parent();
+ ContainerNode* parentNode = node()->parent();
if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag))
return static_cast<SVGGradientElement*>(parentNode);
return 0;
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp
index ee1d214..fb14ffe 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.cpp
+++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp
@@ -25,7 +25,7 @@
#if ENABLE(SVG)
#include "RenderSVGHiddenContainer.h"
-#include "RenderPath.h"
+#include "RenderSVGPath.h"
#include "SVGStyledElement.h"
namespace WebCore {
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h
index 97800d4..c591a88 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.h
+++ b/WebCore/rendering/RenderSVGHiddenContainer.h
@@ -34,7 +34,7 @@ namespace WebCore {
// <defs>, <linearGradient>, <radialGradient> are all good examples
class RenderSVGHiddenContainer : public RenderSVGContainer {
public:
- RenderSVGHiddenContainer(SVGStyledElement*);
+ explicit RenderSVGHiddenContainer(SVGStyledElement*);
virtual const char* renderName() const { return "RenderSVGHiddenContainer"; }
diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp
index a89a738..a569759 100644
--- a/WebCore/rendering/RenderSVGImage.cpp
+++ b/WebCore/rendering/RenderSVGImage.cpp
@@ -47,6 +47,7 @@ namespace WebCore {
RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
: RenderSVGModelObject(impl)
+ , m_updateCachedRepaintRect(true)
, m_needsTransformUpdate(true)
, m_imageResource(RenderImageResource::create())
{
@@ -62,36 +63,45 @@ void RenderSVGImage::layout()
{
ASSERT(needsLayout());
- LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
+ LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
SVGImageElement* image = static_cast<SVGImageElement*>(node());
- bool updateCachedBoundariesInParents = false;
+ bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_updateCachedRepaintRect;
if (m_needsTransformUpdate) {
m_localTransform = image->animatedLocalTransform();
m_needsTransformUpdate = false;
- updateCachedBoundariesInParents = true;
}
- // FIXME: Optimize caching the repaint rects.
- FloatRect oldBoundaries = m_localBounds;
- m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
- m_cachedLocalRepaintRect = FloatRect();
-
- if (!updateCachedBoundariesInParents)
- updateCachedBoundariesInParents = oldBoundaries != m_localBounds;
+ if (m_updateCachedRepaintRect) {
+ m_repaintBoundingBox = m_objectBoundingBox;
+ SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
+ m_updateCachedRepaintRect = false;
+ }
// Invalidate all resources of this client if our layout changed.
if (m_everHadLayout && selfNeedsLayout())
SVGResourcesCache::clientLayoutChanged(this);
// If our bounds changed, notify the parents.
- if (updateCachedBoundariesInParents)
+ if (transformOrBoundariesUpdate)
RenderSVGModelObject::setNeedsBoundariesUpdate();
repainter.repaintAfterLayout();
setNeedsLayout(false);
}
+void RenderSVGImage::updateFromElement()
+{
+ SVGImageElement* image = static_cast<SVGImageElement*>(node());
+
+ FloatRect oldBoundaries = m_objectBoundingBox;
+ m_objectBoundingBox = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
+ if (m_objectBoundingBox != oldBoundaries) {
+ m_updateCachedRepaintRect = true;
+ setNeedsLayout(true);
+ }
+}
+
void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
{
if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage())
@@ -112,14 +122,14 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) {
Image* image = m_imageResource->image();
- FloatRect destRect = m_localBounds;
+ FloatRect destRect = m_objectBoundingBox;
FloatRect srcRect(0, 0, image->width(), image->height());
SVGImageElement* imageElement = static_cast<SVGImageElement*>(node());
if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
- childPaintInfo.context->drawImage(image, DeviceColorSpace, destRect, srcRect);
+ childPaintInfo.context->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect);
}
SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context);
@@ -148,7 +158,7 @@ bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu
return false;
if (hitRules.canHitFill) {
- if (m_localBounds.contains(localPoint)) {
+ if (m_objectBoundingBox.contains(localPoint)) {
updateHitTestResult(result, roundedIntPoint(localPoint));
return true;
}
@@ -158,18 +168,6 @@ bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu
return false;
}
-FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const
-{
- // If we already have a cached repaint rect, return that
- if (!m_cachedLocalRepaintRect.isEmpty())
- return m_cachedLocalRepaintRect;
-
- m_cachedLocalRepaintRect = m_localBounds;
- SVGRenderSupport::intersectRepaintRectWithResources(this, m_cachedLocalRepaintRect);
-
- return m_cachedLocalRepaintRect;
-}
-
void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*)
{
// The image resource defaults to nullImage until the resource arrives.
diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h
index da94568..485d6ab 100644
--- a/WebCore/rendering/RenderSVGImage.h
+++ b/WebCore/rendering/RenderSVGImage.h
@@ -42,6 +42,7 @@ public:
virtual ~RenderSVGImage();
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
+ virtual void updateFromElement();
RenderImageResource* imageResource() { return m_imageResource.get(); }
const RenderImageResource* imageResource() const { return m_imageResource.get(); }
@@ -52,9 +53,9 @@ private:
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
- virtual FloatRect objectBoundingBox() const { return m_localBounds; }
- virtual FloatRect strokeBoundingBox() const { return m_localBounds; }
- virtual FloatRect repaintRectInLocalCoordinates() const;
+ virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
@@ -69,10 +70,11 @@ private:
virtual AffineTransform localTransform() const { return m_localTransform; }
+ bool m_updateCachedRepaintRect : 1;
bool m_needsTransformUpdate : 1;
AffineTransform m_localTransform;
- FloatRect m_localBounds;
- mutable FloatRect m_cachedLocalRepaintRect;
+ FloatRect m_objectBoundingBox;
+ FloatRect m_repaintBoundingBox;
OwnPtr<RenderImageResource> m_imageResource;
};
diff --git a/WebCore/rendering/RenderSVGInlineText.cpp b/WebCore/rendering/RenderSVGInlineText.cpp
deleted file mode 100644
index f5ea5fc..0000000
--- a/WebCore/rendering/RenderSVGInlineText.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * (C) 2008 Rob Buis <buis@kde.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-
-#if ENABLE(SVG)
-#include "RenderSVGInlineText.h"
-
-#include "FloatConversion.h"
-#include "FloatQuad.h"
-#include "RenderBlock.h"
-#include "RenderSVGRoot.h"
-#include "SVGInlineTextBox.h"
-#include "SVGRootInlineBox.h"
-#include "VisiblePosition.h"
-
-namespace WebCore {
-
-RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> str)
- : RenderText(n, str)
-{
-}
-
-void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
-{
- RenderText::styleDidChange(diff, oldStyle);
-
- // FIXME: Should optimize this.
- // SVG text is always transformed.
- if (RefPtr<StringImpl> textToTransform = originalText())
- setText(textToTransform.release(), true);
-}
-
-InlineTextBox* RenderSVGInlineText::createTextBox()
-{
- InlineTextBox* box = new (renderArena()) SVGInlineTextBox(this);
- box->setHasVirtualLogicalHeight();
- return box;
-}
-
-IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*)
-{
- return IntRect();
-}
-
-IntRect RenderSVGInlineText::linesBoundingBox() const
-{
- IntRect boundingBox;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- boundingBox.unite(box->calculateBoundaries());
- return boundingBox;
-}
-
-bool RenderSVGInlineText::characterStartsNewTextChunk(int position) const
-{
- ASSERT(m_attributes.xValues().size() == textLength());
- ASSERT(m_attributes.yValues().size() == textLength());
- ASSERT(position >= 0);
- ASSERT(position < static_cast<int>(textLength()));
-
- int currentPosition = 0;
- unsigned size = m_attributes.characterDataValues().size();
- for (unsigned i = 0; i < size; ++i) {
- const SVGTextLayoutAttributes::CharacterData& data = m_attributes.characterDataValues().at(i);
-
- // We found the desired character.
- if (currentPosition == position) {
- if (isVerticalWritingMode(style()->svgStyle()))
- return m_attributes.yValues().at(position) != SVGTextLayoutAttributes::emptyValue();
-
- return m_attributes.xValues().at(position) != SVGTextLayoutAttributes::emptyValue();
- }
-
- currentPosition += data.spansCharacters;
- if (currentPosition > position)
- break;
- }
-
- // The desired position is available in the x/y list, but not in the character data values list.
- // That means the previous character data described a single glyph, consisting of multiple unicode characters.
- // The consequence is that the desired character does not define a new absolute x/y position, even if present in the x/y test.
- // This code is tested by svg/W3C-SVG-1.1/text-text-06-t.svg (and described in detail, why this influences chunk detection).
- ASSERT(currentPosition > position);
- return false;
-}
-
-}
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGModelObject.h b/WebCore/rendering/RenderSVGModelObject.h
index 9de217c..fb8f89f 100644
--- a/WebCore/rendering/RenderSVGModelObject.h
+++ b/WebCore/rendering/RenderSVGModelObject.h
@@ -47,7 +47,7 @@ class SVGStyledElement;
class RenderSVGModelObject : public RenderObject {
public:
- RenderSVGModelObject(SVGStyledElement*);
+ explicit RenderSVGModelObject(SVGStyledElement*);
virtual bool requiresLayer() const { return false; }
diff --git a/WebCore/rendering/RenderSVGResource.cpp b/WebCore/rendering/RenderSVGResource.cpp
index 0c943e5..f4c65d5 100644
--- a/WebCore/rendering/RenderSVGResource.cpp
+++ b/WebCore/rendering/RenderSVGResource.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- * 2007 Rob Buis <buis@kde.org>
- * 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -33,124 +33,102 @@
namespace WebCore {
-inline void RenderSVGResource::adjustColorForPseudoRules(const RenderStyle* style, bool useFillPaint, Color& color)
-{
- if (style->insideLink() != InsideVisitedLink)
- return;
-
- RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK);
- SVGPaint* visitedPaint = useFillPaint ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint();
- if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_URI)
- return;
-
- Color visitedColor;
- if (visitedPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
- visitedColor = visitedStyle->color();
- else
- visitedColor = visitedPaint->color();
-
- if (visitedColor.isValid())
- color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha());
-}
-
-// FIXME: This method and strokePaintingResource() should be refactored, to share even more code
-RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style)
+static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor)
{
ASSERT(object);
ASSERT(style);
+ // If we have no style at all, ignore it.
const SVGRenderStyle* svgStyle = style->svgStyle();
- if (!svgStyle || !svgStyle->hasFill())
+ if (!svgStyle)
return 0;
- SVGPaint* fillPaint = svgStyle->fillPaint();
- ASSERT(fillPaint);
-
- RenderSVGResource* fillPaintingResource = 0;
-
- SVGPaint::SVGPaintType paintType = fillPaint->paintType();
- if (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
- if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object))
- fillPaintingResource = resources->fill();
- }
-
- if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintingResource) {
- RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
- fillPaintingResource = solidResource;
-
- Color fillColor;
- if (fillPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
- fillColor = style->visitedDependentColor(CSSPropertyColor);
- else
- fillColor = fillPaint->color();
-
- adjustColorForPseudoRules(style, true /* useFillPaint */, fillColor);
-
- // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
- if (fillColor.isValid())
- solidResource->setColor(fillColor);
- else
- fillPaintingResource = 0;
+ // If we have no fill/stroke, return 0.
+ if (mode == ApplyToFillMode) {
+ if (!svgStyle->hasFill())
+ return 0;
+ } else {
+ if (!svgStyle->hasStroke())
+ return 0;
}
- if (!fillPaintingResource) {
- // default value (black), see bug 11017
- RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
- solidResource->setColor(Color::black);
- fillPaintingResource = solidResource;
- }
+ SVGPaint* paint = mode == ApplyToFillMode ? svgStyle->fillPaint() : svgStyle->strokePaint();
+ ASSERT(paint);
- return fillPaintingResource;
-}
-
-RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style)
-{
- ASSERT(object);
- ASSERT(style);
-
- const SVGRenderStyle* svgStyle = style->svgStyle();
- if (!svgStyle || !svgStyle->hasStroke())
+ SVGPaint::SVGPaintType paintType = paint->paintType();
+ if (paintType == SVGPaint::SVG_PAINTTYPE_NONE)
return 0;
- SVGPaint* strokePaint = svgStyle->strokePaint();
- ASSERT(strokePaint);
+ Color color;
+ if (paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR
+ || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR)
+ color = paint->color();
+ else if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paintType == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR)
+ color = style->visitedDependentColor(CSSPropertyColor);
+
+ if (style->insideLink() == InsideVisitedLink) {
+ RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK);
+ ASSERT(visitedStyle);
+
+ if (SVGPaint* visitedPaint = mode == ApplyToFillMode ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint()) {
+ // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'.
+ if (visitedPaint->paintType() < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaint->paintType() != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) {
+ const Color& visitedColor = visitedPaint->color();
+ if (visitedColor.isValid())
+ color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha());
+ }
+ }
+ }
- RenderSVGResource* strokePaintingResource = 0;
- FloatRect objectBoundingBox = object->objectBoundingBox();
+ // If the primary resource is just a color, return immediately.
+ RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource();
+ if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) {
+ // If an invalid fill color is specified, fallback to fill/stroke="none".
+ if (!color.isValid())
+ return 0;
- SVGPaint::SVGPaintType paintType = strokePaint->paintType();
- if (!objectBoundingBox.isEmpty() && (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)) {
- if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object))
- strokePaintingResource = resources->stroke();
+ colorResource->setColor(color);
+ return colorResource;
}
- if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintingResource) {
- RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
- strokePaintingResource = solidResource;
+ // If no resources are associated with the given renderer, return the color resource.
+ SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+ if (!resources) {
+ // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black".
+ if (!color.isValid())
+ color = Color::black;
- Color strokeColor;
- if (strokePaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
- strokeColor = style->visitedDependentColor(CSSPropertyColor);
- else
- strokeColor = strokePaint->color();
+ colorResource->setColor(color);
+ return colorResource;
+ }
- adjustColorForPseudoRules(style, false /* useFillPaint */, strokeColor);
+ // If the requested resource is not available, return the color resource.
+ RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke();
+ if (!uriResource) {
+ // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black".
+ if (!color.isValid())
+ color = Color::black;
- // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
- if (strokeColor.isValid())
- solidResource->setColor(strokeColor);
- else
- strokePaintingResource = 0;
+ colorResource->setColor(color);
+ return colorResource;
}
- if (!strokePaintingResource) {
- // default value (black), see bug 11017
- RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource();
- solidResource->setColor(Color::black);
- strokePaintingResource = solidResource;
- }
+ // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller
+ // so it can use the solid color painting resource, if applyResource() on the URI resource failed.
+ fallbackColor = color;
+ return uriResource;
+}
+
+RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
+{
+ return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor);
+}
- return strokePaintingResource;
+RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor)
+{
+ return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor);
}
RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource()
diff --git a/WebCore/rendering/RenderSVGResource.h b/WebCore/rendering/RenderSVGResource.h
index a70ce52..0230e98 100644
--- a/WebCore/rendering/RenderSVGResource.h
+++ b/WebCore/rendering/RenderSVGResource.h
@@ -75,15 +75,12 @@ public:
return 0;
}
- // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns only)
- static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*);
- static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*);
+ // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only)
+ static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor);
+ static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor);
static RenderSVGResourceSolidColor* sharedSolidPaintingResource();
static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true);
-
-private:
- static void adjustColorForPseudoRules(const RenderStyle*, bool useFillPaint, Color&);
};
}
diff --git a/WebCore/rendering/RenderSVGResourceClipper.cpp b/WebCore/rendering/RenderSVGResourceClipper.cpp
index ef44a79..e7b9fbb 100644
--- a/WebCore/rendering/RenderSVGResourceClipper.cpp
+++ b/WebCore/rendering/RenderSVGResourceClipper.cpp
@@ -136,7 +136,7 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const
return false;
// Fallback to masking, if there is more than one clipping path.
if (clipPath.isEmpty()) {
- clipPath = styled->toClipPath();
+ styled->toClipPath(clipPath);
clipRule = svgStyle->clipRule();
} else
return false;
@@ -178,7 +178,7 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons
FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect);
if (shouldCreateClipData && !clampedAbsoluteTargetRect.isEmpty()) {
- if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, DeviceRGB))
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, ColorSpaceDeviceRGB))
return false;
GraphicsContext* maskContext = clipperData->clipMaskImage->context();
@@ -247,7 +247,7 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
}
// Only shapes, paths and texts are allowed for clipping.
- if (!renderer->isRenderPath() && !renderer->isSVGText())
+ if (!renderer->isSVGPath() && !renderer->isSVGText())
continue;
// Save the old RenderStyle of the current object for restoring after drawing
@@ -289,7 +289,7 @@ void RenderSVGResourceClipper::calculateClipContentRepaintRect()
RenderObject* renderer = childNode->renderer();
if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
continue;
- if (!renderer->isRenderPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
+ if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
continue;
RenderStyle* style = renderer->style();
if (!style || style->display() == NONE || style->visibility() != VISIBLE)
@@ -315,7 +315,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin
RenderObject* renderer = childNode->renderer();
if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
continue;
- if (!renderer->isRenderPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
+ if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer())
continue;
IntPoint hitPoint;
HitTestResult result(hitPoint);
diff --git a/WebCore/rendering/RenderSVGResourceContainer.cpp b/WebCore/rendering/RenderSVGResourceContainer.cpp
index 41ab91f..fb30efd 100644
--- a/WebCore/rendering/RenderSVGResourceContainer.cpp
+++ b/WebCore/rendering/RenderSVGResourceContainer.cpp
@@ -179,7 +179,7 @@ void RenderSVGResourceContainer::registerResource()
// FIXME: This does not belong here.
AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
{
- if (!object->isRenderPath())
+ if (!object->isSVGPath())
return resourceTransform;
SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp
index 4dccad6..3203ddf 100644
--- a/WebCore/rendering/RenderSVGResourceFilter.cpp
+++ b/WebCore/rendering/RenderSVGResourceFilter.cpp
@@ -39,6 +39,7 @@
#include "SVGFilter.h"
#include "SVGFilterElement.h"
#include "SVGFilterPrimitiveStandardAttributes.h"
+#include "SVGImageBufferTools.h"
#include "SVGStyledElement.h"
#include "SVGUnitTypes.h"
#include <wtf/Vector.h>
@@ -150,70 +151,93 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
}
OwnPtr<FilterData> filterData(new FilterData);
+ FloatRect targetBoundingBox = object->objectBoundingBox();
+
+ SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
+ filterData->boundaries = filterElement->filterBoundingBox(targetBoundingBox);
+ if (filterData->boundaries.isEmpty())
+ return false;
+
+ // Determine absolute transformation matrix for filter.
+ AffineTransform absoluteTransform;
+ SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+ if (!absoluteTransform.isInvertible())
+ return false;
+
+ // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile.
+ filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), absoluteTransform.e(), absoluteTransform.f());
+
+ // Determine absolute boundaries of the filter and the drawing region.
+ FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
+ FloatRect drawingRegion = object->strokeBoundingBox();
+ drawingRegion.intersect(filterData->boundaries);
+ FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion);
+
+ // Create the SVGFilter object.
+ bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
+ filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
+
+ // Create all relevant filter primitives.
filterData->builder = buildPrimitives();
if (!filterData->builder)
return false;
- FloatRect paintRect = object->strokeBoundingBox();
-
// Calculate the scale factor for the use of filterRes.
// Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
- SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
- filterData->boundaries = filterElement->filterBoundingBox(object->objectBoundingBox());
- if (filterData->boundaries.isEmpty())
- return false;
-
- FloatSize scale(1.0f, 1.0f);
+ FloatSize scale(1, 1);
if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
- scale.setWidth(filterElement->filterResX() / filterData->boundaries.width());
- scale.setHeight(filterElement->filterResY() / filterData->boundaries.height());
+ scale.setWidth(filterElement->filterResX() / absoluteFilterBoundaries.width());
+ scale.setHeight(filterElement->filterResY() / absoluteFilterBoundaries.height());
}
if (scale.isEmpty())
return false;
- // clip sourceImage to filterRegion
- FloatRect clippedSourceRect = paintRect;
- clippedSourceRect.intersect(filterData->boundaries);
-
- // scale filter size to filterRes
- FloatRect tempSourceRect = clippedSourceRect;
-
- // scale to big sourceImage size to kMaxFilterSize
+ // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
+ FloatRect tempSourceRect = absoluteDrawingRegion;
tempSourceRect.scale(scale.width(), scale.height());
fitsInMaximumImageSize(tempSourceRect.size(), scale);
- // prepare Filters
- bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
- filterData->filter = SVGFilter::create(paintRect, filterData->boundaries, primitiveBoundingBoxMode);
+ // Set the scale level in SVGFilter.
filterData->filter->setFilterResolution(scale);
FilterEffect* lastEffect = filterData->builder->lastEffect();
if (!lastEffect)
return false;
-
+
+ // Determine the filter primitive subregions of every effect.
lastEffect->determineFilterPrimitiveSubregion(filterData->filter.get());
- // At least one FilterEffect has a too big image size,
- // recalculate the effect sizes with new scale factors.
if (!fitsInMaximumImageSize(filterData->filter->maxImageSize(), scale)) {
+ // At least one FilterEffect has a too big image size,
+ // recalculate the effect sizes with new scale factor.
filterData->filter->setFilterResolution(scale);
lastEffect->determineFilterPrimitiveSubregion(filterData->filter.get());
}
- clippedSourceRect.scale(scale.width(), scale.height());
-
- // Draw the content of the current element and it's childs to a imageBuffer to get the SourceGraphic.
- // The size of the SourceGraphic is clipped to the size of the filterRegion.
- IntRect bufferRect = enclosingIntRect(clippedSourceRect);
- OwnPtr<ImageBuffer> sourceGraphic(ImageBuffer::create(bufferRect.size(), LinearRGB));
-
- if (!sourceGraphic.get())
+ // If the drawingRegion is empty, we have something like <g filter=".."/>.
+ // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
+ if (drawingRegion.isEmpty()) {
+ ASSERT(!m_filter.contains(object));
+ filterData->savedContext = context;
+ m_filter.set(object, filterData.leakPtr());
return false;
+ }
+ absoluteDrawingRegion.scale(scale.width(), scale.height());
+
+ OwnPtr<ImageBuffer> sourceGraphic;
+ if (!SVGImageBufferTools::createImageBuffer(absoluteDrawingRegion, absoluteDrawingRegion, sourceGraphic, ColorSpaceLinearRGB))
+ return false;
+
GraphicsContext* sourceGraphicContext = sourceGraphic->context();
- sourceGraphicContext->translate(-clippedSourceRect.x(), -clippedSourceRect.y());
- sourceGraphicContext->scale(scale);
- sourceGraphicContext->clearRect(FloatRect(FloatPoint(), paintRect.size()));
+ ASSERT(sourceGraphicContext);
+
+ sourceGraphicContext->translate(-absoluteDrawingRegion.x(), -absoluteDrawingRegion.y());
+ if (scale.width() != 1 || scale.height() != 1)
+ sourceGraphicContext->scale(scale);
+
+ sourceGraphicContext->concatCTM(filterData->shearFreeAbsoluteTransform);
+ sourceGraphicContext->clearRect(FloatRect(FloatPoint(), absoluteDrawingRegion.size()));
filterData->sourceGraphicBuffer = sourceGraphic.release();
filterData->savedContext = context;
@@ -248,7 +272,8 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
context = filterData->savedContext;
filterData->savedContext = 0;
#if !PLATFORM(CG)
- filterData->sourceGraphicBuffer->transformColorSpace(DeviceRGB, LinearRGB);
+ if (filterData->sourceGraphicBuffer)
+ filterData->sourceGraphicBuffer->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
#endif
}
@@ -264,16 +289,23 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
#if !PLATFORM(CG)
ImageBuffer* resultImage = lastEffect->resultImage();
if (resultImage)
- resultImage->transformColorSpace(LinearRGB, DeviceRGB);
+ resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB);
#endif
filterData->builded = true;
}
ImageBuffer* resultImage = lastEffect->resultImage();
- if (resultImage)
- context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->filterPrimitiveSubregion());
- }
+ if (resultImage) {
+ context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
+ context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height()));
+ context->clip(lastEffect->maxEffectRect());
+ context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->absolutePaintRect());
+ context->scale(filterData->filter->filterResolution());
+
+ context->concatCTM(filterData->shearFreeAbsoluteTransform);
+ }
+ }
filterData->sourceGraphicBuffer.clear();
}
diff --git a/WebCore/rendering/RenderSVGResourceFilter.h b/WebCore/rendering/RenderSVGResourceFilter.h
index 314c94d..c64f5c6 100644
--- a/WebCore/rendering/RenderSVGResourceFilter.h
+++ b/WebCore/rendering/RenderSVGResourceFilter.h
@@ -42,7 +42,8 @@ namespace WebCore {
struct FilterData {
FilterData()
- : builded(false)
+ : savedContext(0)
+ , builded(false)
{
}
@@ -50,6 +51,7 @@ struct FilterData {
RefPtr<SVGFilterBuilder> builder;
OwnPtr<ImageBuffer> sourceGraphicBuffer;
GraphicsContext* savedContext;
+ AffineTransform shearFreeAbsoluteTransform;
FloatRect boundaries;
FloatSize scale;
bool builded;
diff --git a/WebCore/rendering/RenderSVGResourceFilterPrimitive.h b/WebCore/rendering/RenderSVGResourceFilterPrimitive.h
index 4b23737..b054203 100644
--- a/WebCore/rendering/RenderSVGResourceFilterPrimitive.h
+++ b/WebCore/rendering/RenderSVGResourceFilterPrimitive.h
@@ -36,7 +36,7 @@ namespace WebCore {
class RenderSVGResourceFilterPrimitive : public RenderSVGHiddenContainer {
public:
- RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement);
+ explicit RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement);
private:
virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; }
diff --git a/WebCore/rendering/RenderSVGResourceGradient.cpp b/WebCore/rendering/RenderSVGResourceGradient.cpp
index 1c33de4..a757147 100644
--- a/WebCore/rendering/RenderSVGResourceGradient.cpp
+++ b/WebCore/rendering/RenderSVGResourceGradient.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- * 2008 Eric Seidel <eric@webkit.org>
- * 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
#include "GradientAttributes.h"
#include "GraphicsContext.h"
+#include "RenderSVGText.h"
#include "SVGImageBufferTools.h"
#include "SVGRenderSupport.h"
#include <wtf/UnusedParam.h>
@@ -36,6 +37,7 @@ namespace WebCore {
RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node)
: RenderSVGResourceContainer(node)
+ , m_shouldCollectGradientAttributes(true)
#if PLATFORM(CG)
, m_savedContext(0)
#endif
@@ -58,6 +60,7 @@ void RenderSVGResourceGradient::removeAllClientsFromCache(bool markForInvalidati
m_gradient.clear();
}
+ m_shouldCollectGradientAttributes = true;
markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
}
@@ -75,9 +78,9 @@ void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool
static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context,
GraphicsContext*& savedContext,
OwnPtr<ImageBuffer>& imageBuffer,
- const RenderObject* object)
+ RenderObject* object)
{
- const RenderObject* textRootBlock = SVGRenderSupport::findTextRootObject(object);
+ RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object);
ASSERT(textRootBlock);
AffineTransform absoluteTransform;
@@ -89,7 +92,7 @@ static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& con
return false;
OwnPtr<ImageBuffer> maskImage;
- if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, DeviceRGB))
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB))
return false;
GraphicsContext* maskImageContext = maskImage->context();
@@ -108,10 +111,11 @@ static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& con
static inline AffineTransform clipToTextMask(GraphicsContext* context,
OwnPtr<ImageBuffer>& imageBuffer,
FloatRect& targetRect,
- const RenderObject* object,
- GradientData* gradientData)
+ RenderObject* object,
+ bool boundingBoxMode,
+ const AffineTransform& gradientTransform)
{
- const RenderObject* textRootBlock = SVGRenderSupport::findTextRootObject(object);
+ RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object);
ASSERT(textRootBlock);
targetRect = textRootBlock->repaintRectInLocalCoordinates();
@@ -125,12 +129,12 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context,
SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, imageBuffer);
AffineTransform matrix;
- if (gradientData->boundingBoxMode) {
+ if (boundingBoxMode) {
FloatRect maskBoundingBox = textRootBlock->objectBoundingBox();
matrix.translate(maskBoundingBox.x(), maskBoundingBox.y());
matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height());
}
- matrix.multLeft(gradientData->transform);
+ matrix.multLeft(gradientTransform);
return matrix;
}
#endif
@@ -150,13 +154,22 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
if (!gradientElement)
return false;
- gradientElement->updateAnimatedSVGAttribute(anyQName());
+ if (m_shouldCollectGradientAttributes) {
+ gradientElement->updateAnimatedSVGAttribute(anyQName());
+ collectGradientAttributes(gradientElement);
+ m_shouldCollectGradientAttributes = false;
+ }
+
+ // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified,
+ // then the given effect (e.g. a gradient or a filter) will be ignored.
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ if (boundingBoxMode() && objectBoundingBox.isEmpty())
+ return false;
if (!m_gradient.contains(object))
m_gradient.set(object, new GradientData);
GradientData* gradientData = m_gradient.get(object);
-
bool isPaintingText = resourceMode & ApplyToTextMode;
// Create gradient object
@@ -167,16 +180,18 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
// resource, so don't apply it here. For non-CG platforms, we want the text bounding
// box applied to the gradient space transform now, so the gradient shader can use it.
#if PLATFORM(CG)
- if (gradientData->boundingBoxMode && !isPaintingText) {
+ if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) {
#else
- if (gradientData->boundingBoxMode) {
+ if (boundingBoxMode() && !objectBoundingBox.isEmpty()) {
#endif
- FloatRect objectBoundingBox = object->objectBoundingBox();
gradientData->userspaceTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
gradientData->userspaceTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
}
- gradientData->userspaceTransform.multLeft(gradientData->transform);
+ AffineTransform gradientTransform;
+ calculateGradientTransform(gradientTransform);
+
+ gradientData->userspaceTransform.multLeft(gradientTransform);
gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform);
}
@@ -230,8 +245,11 @@ void RenderSVGResourceGradient::postApplyResource(RenderObject* object, Graphics
context = m_savedContext;
m_savedContext = 0;
+ AffineTransform gradientTransform;
+ calculateGradientTransform(gradientTransform);
+
FloatRect targetRect;
- gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, object, gradientData));
+ gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, object, boundingBoxMode(), gradientTransform));
context->setFillGradient(gradientData->gradient);
context->fillRect(targetRect);
diff --git a/WebCore/rendering/RenderSVGResourceGradient.h b/WebCore/rendering/RenderSVGResourceGradient.h
index 4de4272..bc0b864 100644
--- a/WebCore/rendering/RenderSVGResourceGradient.h
+++ b/WebCore/rendering/RenderSVGResourceGradient.h
@@ -37,10 +37,7 @@ namespace WebCore {
struct GradientData {
RefPtr<Gradient> gradient;
-
- bool boundingBoxMode;
AffineTransform userspaceTransform;
- AffineTransform transform;
};
class GraphicsContext;
@@ -59,9 +56,14 @@ public:
protected:
void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const;
+
+ virtual bool boundingBoxMode() const = 0;
+ virtual void calculateGradientTransform(AffineTransform&) = 0;
+ virtual void collectGradientAttributes(SVGGradientElement*) = 0;
virtual void buildGradient(GradientData*, SVGGradientElement*) const = 0;
private:
+ bool m_shouldCollectGradientAttributes : 1;
HashMap<RenderObject*, GradientData*> m_gradient;
#if PLATFORM(CG)
diff --git a/WebCore/rendering/RenderSVGResourceLinearGradient.cpp b/WebCore/rendering/RenderSVGResourceLinearGradient.cpp
index e34e524..ce8d69e 100644
--- a/WebCore/rendering/RenderSVGResourceLinearGradient.cpp
+++ b/WebCore/rendering/RenderSVGResourceLinearGradient.cpp
@@ -40,25 +40,26 @@ RenderSVGResourceLinearGradient::~RenderSVGResourceLinearGradient()
{
}
+void RenderSVGResourceLinearGradient::collectGradientAttributes(SVGGradientElement* gradientElement)
+{
+ m_attributes = LinearGradientAttributes();
+ static_cast<SVGLinearGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes);
+}
+
void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const
{
SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradientElement);
- LinearGradientAttributes attributes = linearGradientElement->collectGradientProperties();
// Determine gradient start/end points
FloatPoint startPoint;
FloatPoint endPoint;
- linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint);
+ linearGradientElement->calculateStartEndPoints(m_attributes, startPoint, endPoint);
gradientData->gradient = Gradient::create(startPoint, endPoint);
- gradientData->gradient->setSpreadMethod(attributes.spreadMethod());
-
- // Record current gradient transform
- gradientData->transform = attributes.gradientTransform();
- gradientData->boundingBoxMode = attributes.boundingBoxMode();
+ gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod());
// Add stops
- addStops(gradientData, attributes.stops());
+ addStops(gradientData, m_attributes.stops());
}
}
diff --git a/WebCore/rendering/RenderSVGResourceLinearGradient.h b/WebCore/rendering/RenderSVGResourceLinearGradient.h
index c1f84c2..9e4530d 100644
--- a/WebCore/rendering/RenderSVGResourceLinearGradient.h
+++ b/WebCore/rendering/RenderSVGResourceLinearGradient.h
@@ -23,6 +23,7 @@
#define RenderSVGResourceLinearGradient_h
#if ENABLE(SVG)
+#include "LinearGradientAttributes.h"
#include "RenderSVGResourceGradient.h"
namespace WebCore {
@@ -39,7 +40,13 @@ public:
virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
static RenderSVGResourceType s_resourceType;
+ virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); }
+ virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); }
+ virtual void collectGradientAttributes(SVGGradientElement*);
virtual void buildGradient(GradientData*, SVGGradientElement*) const;
+
+private:
+ LinearGradientAttributes m_attributes;
};
}
diff --git a/WebCore/rendering/RenderSVGResourceMasker.cpp b/WebCore/rendering/RenderSVGResourceMasker.cpp
index 3e81929..10133b2 100644
--- a/WebCore/rendering/RenderSVGResourceMasker.cpp
+++ b/WebCore/rendering/RenderSVGResourceMasker.cpp
@@ -107,7 +107,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
if (!maskElement)
return false;
- if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskerData->maskImage, LinearRGB))
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskerData->maskImage, ColorSpaceLinearRGB))
return false;
GraphicsContext* maskImageContext = maskerData->maskImage->context();
@@ -156,7 +156,7 @@ void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, c
maskImageContext->restore();
#if !PLATFORM(CG)
- maskerData->maskImage->transformColorSpace(DeviceRGB, LinearRGB);
+ maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
#endif
// Create the luminance mask.
diff --git a/WebCore/rendering/RenderSVGResourcePattern.cpp b/WebCore/rendering/RenderSVGResourcePattern.cpp
index ccbdaca..d2e4563 100644
--- a/WebCore/rendering/RenderSVGResourcePattern.cpp
+++ b/WebCore/rendering/RenderSVGResourcePattern.cpp
@@ -37,6 +37,7 @@ RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResource
RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node)
: RenderSVGResourceContainer(node)
+ , m_shouldCollectPatternAttributes(true)
{
}
@@ -56,6 +57,7 @@ void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidatio
m_pattern.clear();
}
+ m_shouldCollectPatternAttributes = true;
markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
}
@@ -84,22 +86,34 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle*
if (!patternElement)
return false;
- patternElement->updateAnimatedSVGAttribute(anyQName());
+ if (m_shouldCollectPatternAttributes) {
+ patternElement->updateAnimatedSVGAttribute(anyQName());
+
+ m_attributes = PatternAttributes();
+ patternElement->collectPatternAttributes(m_attributes);
+ m_shouldCollectPatternAttributes = false;
+ }
+
+ // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified,
+ // then the given effect (e.g. a gradient or a filter) will be ignored.
+ FloatRect objectBoundingBox = object->objectBoundingBox();
+ if (m_attributes.boundingBoxMode() && objectBoundingBox.isEmpty())
+ return false;
if (!m_pattern.contains(object))
m_pattern.set(object, new PatternData);
PatternData* patternData = m_pattern.get(object);
if (!patternData->pattern) {
- PatternAttributes attributes = patternElement->collectPatternProperties();
-
// If we couldn't determine the pattern content element root, stop here.
- if (!attributes.patternContentElement())
+ if (!m_attributes.patternContentElement())
return false;
// Compute all necessary transformations to build the tile image & the pattern.
FloatRect tileBoundaries;
- AffineTransform tileImageTransform = buildTileImageTransform(object, attributes, patternElement, tileBoundaries);
+ AffineTransform tileImageTransform;
+ if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform))
+ return false;
AffineTransform absoluteTransform;
SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
@@ -107,7 +121,7 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle*
FloatRect absoluteTileBoundaries = absoluteTransform.mapRect(tileBoundaries);
// Build tile image.
- OwnPtr<ImageBuffer> tileImage = createTileImage(object, attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
+ OwnPtr<ImageBuffer> tileImage = createTileImage(object, m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
if (!tileImage)
return false;
@@ -124,7 +138,7 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle*
patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
patternData->transform.scale(tileBoundaries.width() / absoluteTileBoundaries.width(), tileBoundaries.height() / absoluteTileBoundaries.height());
- AffineTransform patternTransform = attributes.patternTransform();
+ AffineTransform patternTransform = m_attributes.patternTransform();
if (!patternTransform.isIdentity())
patternData->transform.multiply(patternTransform);
@@ -201,19 +215,21 @@ static inline FloatRect calculatePatternBoundaries(const PatternAttributes& attr
attributes.height().value(patternElement));
}
-AffineTransform RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer,
- const PatternAttributes& attributes,
- const SVGPatternElement* patternElement,
- FloatRect& patternBoundaries) const
+bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer,
+ const PatternAttributes& attributes,
+ const SVGPatternElement* patternElement,
+ FloatRect& patternBoundaries,
+ AffineTransform& tileImageTransform) const
{
ASSERT(renderer);
ASSERT(patternElement);
- FloatRect objectBoundingBox = renderer->objectBoundingBox();
+ FloatRect objectBoundingBox = renderer->objectBoundingBox();
patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement);
+ if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0)
+ return false;
AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(), patternElement->preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height());
- AffineTransform tileImageTransform;
// Apply viewBox/objectBoundingBox transformations.
if (!viewBoxCTM.isIdentity())
@@ -223,7 +239,7 @@ AffineTransform RenderSVGResourcePattern::buildTileImageTransform(RenderObject*
tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height());
}
- return tileImageTransform;
+ return true;
}
PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject* object,
@@ -246,7 +262,7 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject*
OwnPtr<ImageBuffer> tileImage;
- if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, DeviceRGB))
+ if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB))
return PassOwnPtr<ImageBuffer>();
GraphicsContext* tileImageContext = tileImage->context();
diff --git a/WebCore/rendering/RenderSVGResourcePattern.h b/WebCore/rendering/RenderSVGResourcePattern.h
index 9a067c2..ba4aec4 100644
--- a/WebCore/rendering/RenderSVGResourcePattern.h
+++ b/WebCore/rendering/RenderSVGResourcePattern.h
@@ -27,6 +27,7 @@
#include "FloatRect.h"
#include "ImageBuffer.h"
#include "Pattern.h"
+#include "PatternAttributes.h"
#include "RenderSVGResourceContainer.h"
#include "SVGPatternElement.h"
#include "SVGUnitTypes.h"
@@ -41,8 +42,6 @@ struct PatternData {
AffineTransform transform;
};
-struct PatternAttributes;
-
class RenderSVGResourcePattern : public RenderSVGResourceContainer {
public:
RenderSVGResourcePattern(SVGPatternElement*);
@@ -61,11 +60,13 @@ public:
static RenderSVGResourceType s_resourceType;
private:
- AffineTransform buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries) const;
+ bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const;
PassOwnPtr<ImageBuffer> createTileImage(RenderObject*, const PatternAttributes&, const FloatRect& tileBoundaries,
const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform) const;
+ bool m_shouldCollectPatternAttributes : 1;
+ PatternAttributes m_attributes;
HashMap<RenderObject*, PatternData*> m_pattern;
};
diff --git a/WebCore/rendering/RenderSVGResourceRadialGradient.cpp b/WebCore/rendering/RenderSVGResourceRadialGradient.cpp
index a8904c8..300afcb 100644
--- a/WebCore/rendering/RenderSVGResourceRadialGradient.cpp
+++ b/WebCore/rendering/RenderSVGResourceRadialGradient.cpp
@@ -40,30 +40,31 @@ RenderSVGResourceRadialGradient::~RenderSVGResourceRadialGradient()
{
}
+void RenderSVGResourceRadialGradient::collectGradientAttributes(SVGGradientElement* gradientElement)
+{
+ m_attributes = RadialGradientAttributes();
+ static_cast<SVGRadialGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes);
+}
+
void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const
{
SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradientElement);
- RadialGradientAttributes attributes = radialGradientElement->collectGradientProperties();
// Determine gradient focal/center points and radius
FloatPoint focalPoint;
FloatPoint centerPoint;
float radius;
- radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius);
+ radialGradientElement->calculateFocalCenterPointsAndRadius(m_attributes, focalPoint, centerPoint, radius);
gradientData->gradient = Gradient::create(focalPoint,
- 0.0f, // SVG does not support a "focus radius"
+ 0, // SVG does not support a "focus radius"
centerPoint,
radius);
- gradientData->gradient->setSpreadMethod(attributes.spreadMethod());
-
- // Record current gradient transform
- gradientData->transform = attributes.gradientTransform();
- gradientData->boundingBoxMode = attributes.boundingBoxMode();
+ gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod());
// Add stops
- addStops(gradientData, attributes.stops());
+ addStops(gradientData, m_attributes.stops());
}
}
diff --git a/WebCore/rendering/RenderSVGResourceRadialGradient.h b/WebCore/rendering/RenderSVGResourceRadialGradient.h
index 0583f99..6492ee3 100644
--- a/WebCore/rendering/RenderSVGResourceRadialGradient.h
+++ b/WebCore/rendering/RenderSVGResourceRadialGradient.h
@@ -23,6 +23,7 @@
#define RenderSVGResourceRadialGradient_h
#if ENABLE(SVG)
+#include "RadialGradientAttributes.h"
#include "RenderSVGResourceGradient.h"
namespace WebCore {
@@ -39,7 +40,13 @@ public:
virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
static RenderSVGResourceType s_resourceType;
+ virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); }
+ virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); }
+ virtual void collectGradientAttributes(SVGGradientElement*);
virtual void buildGradient(GradientData*, SVGGradientElement*) const;
+
+private:
+ RadialGradientAttributes m_attributes;
};
}
diff --git a/WebCore/rendering/RenderSVGResourceSolidColor.cpp b/WebCore/rendering/RenderSVGResourceSolidColor.cpp
index 51ad658..8228c80 100644
--- a/WebCore/rendering/RenderSVGResourceSolidColor.cpp
+++ b/WebCore/rendering/RenderSVGResourceSolidColor.cpp
@@ -52,7 +52,7 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl
ASSERT(resourceMode != ApplyToDefaultMode);
const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0;
- ColorSpace colorSpace = style ? style->colorSpace() : DeviceColorSpace;
+ ColorSpace colorSpace = style ? style->colorSpace() : ColorSpaceDeviceRGB;
if (resourceMode & ApplyToFillMode) {
context->setAlpha(svgStyle ? svgStyle->fillOpacity() : 1.0f);
@@ -90,7 +90,7 @@ void RenderSVGResourceSolidColor::postApplyResource(RenderObject*, GraphicsConte
#if PLATFORM(SKIA) && !PLATFORM(ANDROID)
// FIXME: Move this into the GraphicsContext
// WebKit implicitly expects us to reset the path.
- // For example in fillAndStrokePath() of RenderPath.cpp the path is
+ // For example in fillAndStrokePath() of RenderSVGPath.cpp the path is
// added back to the context after filling. This is because internally it
// calls CGContextFillPath() which closes the path.
context->beginPath();
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
index 82b10d5..215aac7 100644
--- a/WebCore/rendering/RenderSVGRoot.cpp
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -53,14 +53,8 @@ RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
setReplaced(true);
}
-int RenderSVGRoot::lineHeight(bool, bool) const
+RenderSVGRoot::~RenderSVGRoot()
{
- return height() + marginTop() + marginBottom();
-}
-
-int RenderSVGRoot::baselinePosition(bool, bool) const
-{
- return height() + marginTop() + marginBottom();
}
void RenderSVGRoot::computePreferredLogicalWidths()
@@ -68,7 +62,7 @@ void RenderSVGRoot::computePreferredLogicalWidths()
ASSERT(preferredLogicalWidthsDirty());
int borderAndPadding = borderAndPaddingWidth();
- int width = computeReplacedWidth(false) + borderAndPadding;
+ int width = computeReplacedLogicalWidth(false) + borderAndPadding;
if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
@@ -82,10 +76,10 @@ void RenderSVGRoot::computePreferredLogicalWidths()
setPreferredLogicalWidthsDirty(false);
}
-int RenderSVGRoot::computeReplacedWidth(bool includeMaxWidth) const
+int RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) const
{
- int replacedWidth = RenderBox::computeReplacedWidth(includeMaxWidth);
- if (!style()->width().isPercent())
+ int replacedWidth = RenderBox::computeReplacedLogicalWidth(includeMaxWidth);
+ if (!style()->logicalWidth().isPercent())
return replacedWidth;
// FIXME: Investigate in size rounding issues
@@ -93,10 +87,10 @@ int RenderSVGRoot::computeReplacedWidth(bool includeMaxWidth) const
return static_cast<int>(roundf(replacedWidth * svg->currentScale()));
}
-int RenderSVGRoot::computeReplacedHeight() const
+int RenderSVGRoot::computeReplacedLogicalHeight() const
{
- int replacedHeight = RenderBox::computeReplacedHeight();
- if (!style()->height().isPercent())
+ int replacedHeight = RenderBox::computeReplacedLogicalHeight();
+ if (!style()->logicalHeight().isPercent())
return replacedHeight;
// FIXME: Investigate in size rounding issues
diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h
index 3c29b87..1b6aa22 100644
--- a/WebCore/rendering/RenderSVGRoot.h
+++ b/WebCore/rendering/RenderSVGRoot.h
@@ -35,7 +35,8 @@ class AffineTransform;
class RenderSVGRoot : public RenderBox {
public:
- RenderSVGRoot(SVGStyledElement*);
+ explicit RenderSVGRoot(SVGStyledElement*);
+ virtual ~RenderSVGRoot();
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
@@ -51,11 +52,9 @@ private:
virtual bool isSVGRoot() const { return true; }
virtual const char* renderName() const { return "RenderSVGRoot"; }
- virtual int lineHeight(bool b, bool isRootLineBox = false) const;
- virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
virtual void computePreferredLogicalWidths();
- virtual int computeReplacedWidth(bool includeMaxWidth = true) const;
- virtual int computeReplacedHeight() const;
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.h b/WebCore/rendering/RenderSVGTransformableContainer.h
index b63b91c..b49a403 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.h
+++ b/WebCore/rendering/RenderSVGTransformableContainer.h
@@ -29,7 +29,7 @@ namespace WebCore {
class SVGStyledTransformableElement;
class RenderSVGTransformableContainer : public RenderSVGContainer {
public:
- RenderSVGTransformableContainer(SVGStyledTransformableElement*);
+ explicit RenderSVGTransformableContainer(SVGStyledTransformableElement*);
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
diff --git a/WebCore/rendering/RenderSVGViewportContainer.h b/WebCore/rendering/RenderSVGViewportContainer.h
index 7b5702b..63c336c 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.h
+++ b/WebCore/rendering/RenderSVGViewportContainer.h
@@ -32,7 +32,7 @@ namespace WebCore {
// thus we inherit from RenderSVGContainer instead of RenderSVGTransformableContainer
class RenderSVGViewportContainer : public RenderSVGContainer {
public:
- RenderSVGViewportContainer(SVGStyledElement*);
+ explicit RenderSVGViewportContainer(SVGStyledElement*);
private:
virtual bool isSVGContainer() const { return true; }
diff --git a/WebCore/rendering/RenderScrollbarTheme.cpp b/WebCore/rendering/RenderScrollbarTheme.cpp
index 19143cc..e32d87a 100644
--- a/WebCore/rendering/RenderScrollbarTheme.cpp
+++ b/WebCore/rendering/RenderScrollbarTheme.cpp
@@ -109,7 +109,7 @@ IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollb
void RenderScrollbarTheme::paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect)
{
// FIXME: Implement.
- context->fillRect(cornerRect, Color::white, DeviceColorSpace);
+ context->fillRect(cornerRect, Color::white, ColorSpaceDeviceRGB);
}
void RenderScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp
index 33df244..35d72f4 100644
--- a/WebCore/rendering/RenderSlider.cpp
+++ b/WebCore/rendering/RenderSlider.cpp
@@ -159,7 +159,7 @@ RenderSlider::~RenderSlider()
m_thumb->detach();
}
-int RenderSlider::baselinePosition(bool, bool) const
+int RenderSlider::baselinePosition(bool /*firstLine*/, LineDirectionMode, LinePositionMode) const
{
return height() + marginTop();
}
diff --git a/WebCore/rendering/RenderSlider.h b/WebCore/rendering/RenderSlider.h
index d214e41..fa743de 100644
--- a/WebCore/rendering/RenderSlider.h
+++ b/WebCore/rendering/RenderSlider.h
@@ -42,7 +42,7 @@ namespace WebCore {
virtual const char* renderName() const { return "RenderSlider"; }
virtual bool isSlider() const { return true; }
- virtual int baselinePosition(bool, bool) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual void computePreferredLogicalWidths();
virtual void layout();
virtual void updateFromElement();
diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp
index ca33036..117a6ae 100644
--- a/WebCore/rendering/RenderTable.cpp
+++ b/WebCore/rendering/RenderTable.cpp
@@ -71,6 +71,10 @@ RenderTable::RenderTable(Node* node)
#endif
}
+RenderTable::~RenderTable()
+{
+}
+
void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBlock::styleDidChange(diff, oldStyle);
@@ -791,7 +795,7 @@ int RenderTable::calcBorderLeft() const
if (tb.style() > BHIDDEN)
borderWidth = tb.width();
- int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
+ int leftmostColumn = !style()->isLeftToRightDirection() ? numEffCols() - 1 : 0;
RenderTableCol* colGroup = colElement(leftmostColumn);
if (colGroup) {
const BorderValue& gb = style()->borderLeft();
@@ -850,7 +854,7 @@ int RenderTable::calcBorderRight() const
if (tb.style() > BHIDDEN)
borderWidth = tb.width();
- int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
+ int rightmostColumn = !style()->isLeftToRightDirection() ? 0 : numEffCols() - 1;
RenderTableCol* colGroup = colElement(rightmostColumn);
if (colGroup) {
const BorderValue& gb = style()->borderRight();
@@ -1186,7 +1190,7 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
ty += y();
// Check kids first.
- if (!hasOverflowClip() || overflowClipRect(tx, ty).intersects(result.rectFromPoint(xPos, yPos))) {
+ if (!hasOverflowClip() || overflowClipRect(tx, ty).intersects(result.rectForPoint(xPos, yPos))) {
for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) &&
child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
@@ -1198,7 +1202,7 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// Check our bounds next.
IntRect boundsRect = IntRect(tx, ty, width(), height());
- if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && boundsRect.intersects(result.rectFromPoint(xPos, yPos))) {
+ if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && boundsRect.intersects(result.rectForPoint(xPos, yPos))) {
updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
if (!result.addNodeToRectBasedTestResult(node(), xPos, yPos, boundsRect))
return true;
diff --git a/WebCore/rendering/RenderTable.h b/WebCore/rendering/RenderTable.h
index 58d4915..beb48f4 100644
--- a/WebCore/rendering/RenderTable.h
+++ b/WebCore/rendering/RenderTable.h
@@ -38,7 +38,8 @@ class TableLayout;
class RenderTable : public RenderBlock {
public:
- RenderTable(Node*);
+ explicit RenderTable(Node*);
+ virtual ~RenderTable();
int getColumnPos(int col) const { return m_columnPos[col]; }
diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp
index 06f4726..88cdd5e 100644
--- a/WebCore/rendering/RenderTableCell.cpp
+++ b/WebCore/rendering/RenderTableCell.cpp
@@ -174,34 +174,34 @@ void RenderTableCell::layout()
int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingTop();
- if (!includeIntrinsicPadding || !style()->isVerticalBlockFlow())
+ if (!includeIntrinsicPadding || !style()->isHorizontalWritingMode())
return result;
- return result + (style()->blockFlow() == TopToBottomBlockFlow ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
+ return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
}
int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingBottom();
- if (!includeIntrinsicPadding || !style()->isVerticalBlockFlow())
+ if (!includeIntrinsicPadding || !style()->isHorizontalWritingMode())
return result;
- return result + (style()->blockFlow() == TopToBottomBlockFlow ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
+ return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
}
int RenderTableCell::paddingLeft(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingLeft();
- if (!includeIntrinsicPadding || style()->isVerticalBlockFlow())
+ if (!includeIntrinsicPadding || style()->isHorizontalWritingMode())
return result;
- return result + (style()->blockFlow() == LeftToRightBlockFlow ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
+ return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
}
int RenderTableCell::paddingRight(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingRight();
- if (!includeIntrinsicPadding || style()->isVerticalBlockFlow())
+ if (!includeIntrinsicPadding || style()->isHorizontalWritingMode())
return result;
- return result + (style()->blockFlow() == LeftToRightBlockFlow ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
+ return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
}
int RenderTableCell::paddingBefore(bool includeIntrinsicPadding) const
@@ -246,7 +246,7 @@ IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* rep
if (!table()->collapseBorders() || table()->needsSectionRecalc())
return RenderBlock::clippedOverflowRectForRepaint(repaintContainer);
- bool rtl = table()->style()->direction() == RTL;
+ bool rtl = !table()->style()->isLeftToRightDirection();
int outlineSize = style()->outlineSize();
int left = max(borderHalfLeft(true), outlineSize);
int right = max(borderHalfRight(true), outlineSize);
@@ -300,10 +300,11 @@ void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContain
RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
}
-int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const
+int RenderTableCell::baselinePosition(bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const
{
- if (isRootLineBox)
- return RenderBox::baselinePosition(firstLine, isRootLineBox);
+ // FIXME: This function still needs to be patched for writing-mode.
+ if (linePositionMode == PositionOfInteriorLineBoxes)
+ return RenderBlock::baselinePosition(firstLine, lineDirection, linePositionMode);
// <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
// the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there
@@ -723,7 +724,7 @@ int RenderTableCell::borderAfter() const
int RenderTableCell::borderHalfLeft(bool outer) const
{
- CollapsedBorderValue border = collapsedLeftBorder(table()->style()->direction() == RTL);
+ CollapsedBorderValue border = collapsedLeftBorder(!table()->style()->isLeftToRightDirection());
if (border.exists())
return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
return 0;
@@ -731,7 +732,7 @@ int RenderTableCell::borderHalfLeft(bool outer) const
int RenderTableCell::borderHalfRight(bool outer) const
{
- CollapsedBorderValue border = collapsedRightBorder(table()->style()->direction() == RTL);
+ CollapsedBorderValue border = collapsedRightBorder(!table()->style()->isLeftToRightDirection());
if (border.exists())
return (border.width() + (outer ? 1 : 0)) / 2;
return 0;
@@ -843,7 +844,7 @@ static void addBorderStyle(RenderTableCell::CollapsedBorderStyles& borderStyles,
void RenderTableCell::collectBorderStyles(CollapsedBorderStyles& borderStyles) const
{
- bool rtl = table()->style()->direction() == RTL;
+ bool rtl = !table()->style()->isLeftToRightDirection();
addBorderStyle(borderStyles, collapsedLeftBorder(rtl));
addBorderStyle(borderStyles, collapsedRightBorder(rtl));
addBorderStyle(borderStyles, collapsedTopBorder());
@@ -870,7 +871,7 @@ void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int
if (!table()->currentBorderStyle())
return;
- bool rtl = table()->style()->direction() == RTL;
+ bool rtl = !table()->style()->isLeftToRightDirection();
CollapsedBorderValue leftVal = collapsedLeftBorder(rtl);
CollapsedBorderValue rightVal = collapsedRightBorder(rtl);
CollapsedBorderValue topVal = collapsedTopBorder();
diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h
index 79376e9..31879d6 100644
--- a/WebCore/rendering/RenderTableCell.h
+++ b/WebCore/rendering/RenderTableCell.h
@@ -31,7 +31,7 @@ namespace WebCore {
class RenderTableCell : public RenderBlock {
public:
- RenderTableCell(Node*);
+ explicit RenderTableCell(Node*);
// FIXME: need to implement cellIndex
int cellIndex() const { return 0; }
@@ -88,7 +88,7 @@ public:
void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject);
- virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool firstLine = false, LineDirectionMode = HorizontalLine, LinePositionMode = PositionOnContainingLine) const;
void setIntrinsicPaddingBefore(int p) { m_intrinsicPaddingBefore = p; }
void setIntrinsicPaddingAfter(int p) { m_intrinsicPaddingAfter = p; }
diff --git a/WebCore/rendering/RenderTableCol.h b/WebCore/rendering/RenderTableCol.h
index c5f9afc..8255937 100644
--- a/WebCore/rendering/RenderTableCol.h
+++ b/WebCore/rendering/RenderTableCol.h
@@ -34,7 +34,7 @@ class RenderTable;
class RenderTableCol : public RenderBox {
public:
- RenderTableCol(Node*);
+ explicit RenderTableCol(Node*);
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
@@ -50,7 +50,6 @@ private:
virtual const char* renderName() const { return "RenderTableCol"; }
virtual bool isTableCol() const { return true; }
- virtual int lineHeight(bool) const { return 0; }
virtual void updateFromElement();
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
diff --git a/WebCore/rendering/RenderTableRow.h b/WebCore/rendering/RenderTableRow.h
index 588252b..20aa424 100644
--- a/WebCore/rendering/RenderTableRow.h
+++ b/WebCore/rendering/RenderTableRow.h
@@ -31,7 +31,7 @@ namespace WebCore {
class RenderTableRow : public RenderBox {
public:
- RenderTableRow(Node*);
+ explicit RenderTableRow(Node*);
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
@@ -50,7 +50,6 @@ private:
virtual void destroy();
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
- virtual int lineHeight(bool, bool) const { return 0; }
virtual void layout();
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index 37f2025..e9aa3cb 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -692,7 +692,7 @@ int RenderTableSection::layoutRows(int toAdd)
IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height());
- if (style()->direction() == RTL)
+ if (!style()->isLeftToRightDirection())
cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
else
cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
@@ -748,9 +748,27 @@ int RenderTableSection::layoutRows(int toAdd)
return height();
}
-int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderTableSection::topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf);
+ int top = RenderBox::topmostPosition(includeOverflowInterior, includeSelf, applyTransform);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return top;
+
+ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
+ for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
+ if (curr->isTableCell()) {
+ RenderTableCell* cell = toRenderTableCell(curr);
+ top = min(top, cell->transformedFrameRect().y() + cell->topmostPosition(false));
+ }
+ }
+ }
+
+ return top;
+}
+
+int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
+{
+ int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!includeOverflowInterior && hasOverflowClip())
return bottom;
@@ -758,7 +776,7 @@ int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includ
for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(curr);
- bottom = max(bottom, cell->y() + cell->lowestPosition(false));
+ bottom = max(bottom, cell->transformedFrameRect().y() + cell->lowestPosition(false));
}
}
}
@@ -766,9 +784,9 @@ int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includ
return bottom;
}
-int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf);
+ int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!includeOverflowInterior && hasOverflowClip())
return right;
@@ -776,7 +794,7 @@ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool inc
for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(curr);
- right = max(right, cell->x() + cell->rightmostPosition(false));
+ right = max(right, cell->transformedFrameRect().x() + cell->rightmostPosition(false));
}
}
}
@@ -784,9 +802,9 @@ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool inc
return right;
}
-int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
{
- int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf);
+ int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf, applyTransform);
if (!includeOverflowInterior && hasOverflowClip())
return left;
@@ -794,7 +812,7 @@ int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool incl
for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(curr);
- left = min(left, cell->x() + cell->leftmostPosition(false));
+ left = min(left, cell->transformedFrameRect().x() + cell->leftmostPosition(false));
}
}
}
@@ -998,7 +1016,7 @@ int RenderTableSection::calcOuterBorderRight(bool rtl) const
void RenderTableSection::recalcOuterBorder()
{
- bool rtl = table()->style()->direction() == RTL;
+ bool rtl = !table()->style()->isLeftToRightDirection();
m_outerBorderTop = calcOuterBorderTop();
m_outerBorderBottom = calcOuterBorderBottom();
m_outerBorderLeft = calcOuterBorderLeft(rtl);
@@ -1136,9 +1154,9 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
if (startrow == m_rowPos.size() || (startrow > 0 && (m_rowPos[startrow] > top)))
--startrow;
- int bottom = relativeY + h + os - 1;
+ int bottom = relativeY + h + os;
endrow = std::lower_bound(m_rowPos.begin(), m_rowPos.end(), bottom) - m_rowPos.begin();
- if ((endrow == m_rowPos.size()) || (endrow > 0 && m_rowPos[endrow - 1] == bottom))
+ if (endrow == m_rowPos.size())
--endrow;
if (!endrow && ty + m_rowPos[0] - table()->outerBorderTop() <= y + h + os)
@@ -1147,7 +1165,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
unsigned startcol = 0;
unsigned endcol = totalCols;
// FIXME: Implement RTL.
- if (!m_hasOverflowingCell && style()->direction() == LTR) {
+ if (!m_hasOverflowingCell && style()->isLeftToRightDirection()) {
int relativeX = x - tx;
int left = relativeX - os;
Vector<int>& columnPos = table()->columnPositions();
@@ -1155,9 +1173,9 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
if ((startcol == columnPos.size()) || (startcol > 0 && (columnPos[startcol] > left)))
--startcol;
- int right = relativeX + w + os - 1;
+ int right = relativeX + w + os;
endcol = std::lower_bound(columnPos.begin(), columnPos.end(), right) - columnPos.begin();
- if (endcol == columnPos.size() || (endcol > 0 && (columnPos[endcol - 1] == right)))
+ if (endcol == columnPos.size())
--endcol;
if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os)
@@ -1305,7 +1323,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
tx += x();
ty += y();
- if (hasOverflowClip() && !overflowClipRect(tx, ty).intersects(result.rectFromPoint(xPos, yPos)))
+ if (hasOverflowClip() && !overflowClipRect(tx, ty).intersects(result.rectForPoint(xPos, yPos)))
return false;
if (m_hasOverflowingCell) {
@@ -1332,7 +1350,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
--leftrow;
Vector<int>& columnPos = table()->columnPositions();
- bool rtl = style()->direction() == RTL;
+ bool rtl = !style()->isLeftToRightDirection();
int relativeX = xPos - tx;
if (rtl)
relativeX = columnPos[columnPos.size() - 1] - relativeX;
diff --git a/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h
index 6d2f752..fce1e0f 100644
--- a/WebCore/rendering/RenderTableSection.h
+++ b/WebCore/rendering/RenderTableSection.h
@@ -136,9 +136,10 @@ private:
virtual void removeChild(RenderObject* oldChild);
- virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const;
- virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf) const;
- virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const;
+ virtual int topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform = IncludeTransform) const;
+ virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform = IncludeTransform) const;
+ virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform = IncludeTransform) const;
+ virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform = IncludeTransform) const;
virtual void paint(PaintInfo&, int tx, int ty);
virtual void paintCell(RenderTableCell*, PaintInfo&, int tx, int ty);
@@ -148,8 +149,6 @@ private:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
- virtual int lineHeight(bool, bool) const { return 0; }
-
bool ensureRows(int);
void clearGrid();
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index fada8b4..510d830 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -511,7 +511,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
switch (cbStyle->textAlign()) {
case TAAUTO:
case JUSTIFY:
- rightAligned = cbStyle->direction() == RTL;
+ rightAligned = !cbStyle->isLeftToRightDirection();
break;
case RIGHT:
case WEBKIT_RIGHT:
@@ -1084,35 +1084,6 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
}
ASSERT(m_text);
-#if ENABLE(SVG)
- if (isSVGInlineText()) {
- if (style() && style()->whiteSpace() == PRE) {
- // Spec: When xml:space="preserve", the SVG user agent will do the following using a
- // copy of the original character data content. It will convert all newline and tab
- // characters into space characters. Then, it will draw all space characters, including
- // leading, trailing and multiple contiguous space characters.
-
- m_text.replace('\n', ' ');
-
- // If xml:space="preserve" is set, white-space is set to "pre", which
- // preserves leading, trailing & contiguous space character for us.
- } else {
- // Spec: When xml:space="default", the SVG user agent will do the following using a
- // copy of the original character data content. First, it will remove all newline
- // characters. Then it will convert all tab characters into space characters.
- // Then, it will strip off all leading and trailing space characters.
- // Then, all contiguous space characters will be consolidated.
-
- m_text.replace('\n', StringImpl::empty());
-
- // If xml:space="default" is set, white-space is set to "nowrap", which handles
- // leading, trailing & contiguous space character removal for us.
- }
-
- m_text.replace('\t', ' ');
- }
-#endif
-
if (style()) {
transformText(m_text);
@@ -1168,12 +1139,6 @@ String RenderText::textWithoutTranscoding() const
return text;
}
-int RenderText::lineHeight(bool firstLine, bool) const
-{
- // Always use the interior line height of the parent (e.g., if our parent is an inline block).
- return parent()->lineHeight(firstLine, true);
-}
-
void RenderText::dirtyLineBoxes(bool fullLayout)
{
if (fullLayout)
@@ -1224,7 +1189,7 @@ void RenderText::positionLineBox(InlineBox* box)
return;
}
- m_containsReversedText |= s->direction() == RTL;
+ m_containsReversedText |= !s->isLeftToRightDirection();
}
unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h
index e3a6997..964a1d3 100644
--- a/WebCore/rendering/RenderText.h
+++ b/WebCore/rendering/RenderText.h
@@ -74,8 +74,6 @@ public:
virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
- virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
-
virtual int minPreferredLogicalWidth() const;
virtual int maxPreferredLogicalWidth() const;
diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp
index f48081b..4855bab 100644
--- a/WebCore/rendering/RenderTextControl.cpp
+++ b/WebCore/rendering/RenderTextControl.cpp
@@ -262,10 +262,12 @@ void RenderTextControl::setSelectionRange(int start, int end)
frame->selection()->setSelection(newSelection);
}
-VisibleSelection RenderTextControl::selection(int start, int end) const
+PassRefPtr<Range> RenderTextControl::selection(int start, int end) const
{
- return VisibleSelection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY),
- VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY));
+ if (!m_innerText)
+ return 0;
+
+ return Range::create(document(), m_innerText, start, m_innerText, end);
}
VisiblePosition RenderTextControl::visiblePositionForIndex(int index)
@@ -407,7 +409,7 @@ void RenderTextControl::computeLogicalHeight()
m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() +
m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom());
- adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true));
+ adjustControlHeightBasedOnLineHeight(m_innerText->renderBox()->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes));
setHeight(height() + borderAndPaddingHeight());
// We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h
index a33f11d..84d7b0b 100644
--- a/WebCore/rendering/RenderTextControl.h
+++ b/WebCore/rendering/RenderTextControl.h
@@ -46,7 +46,7 @@ public:
void setSelectionEnd(int);
void select();
void setSelectionRange(int start, int end);
- VisibleSelection selection(int start, int end) const;
+ PassRefPtr<Range> selection(int start, int end) const;
virtual void subtreeHasChanged();
String text();
diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp
index d3fe3f6..2c93164 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.cpp
+++ b/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -102,9 +102,9 @@ void RenderTextControlMultiLine::adjustControlHeightBasedOnLineHeight(int lineHe
setHeight(height() + lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows());
}
-int RenderTextControlMultiLine::baselinePosition(bool, bool) const
+int RenderTextControlMultiLine::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
- return height() + marginTop() + marginBottom();
+ return RenderBox::baselinePosition(firstLine, direction, linePositionMode);
}
void RenderTextControlMultiLine::updateFromElement()
diff --git a/WebCore/rendering/RenderTextControlMultiLine.h b/WebCore/rendering/RenderTextControlMultiLine.h
index fbca308..e061e89 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.h
+++ b/WebCore/rendering/RenderTextControlMultiLine.h
@@ -43,7 +43,7 @@ private:
virtual float getAvgCharWidth(AtomicString family);
virtual int preferredContentWidth(float charWidth) const;
virtual void adjustControlHeightBasedOnLineHeight(int lineHeight);
- virtual int baselinePosition(bool firstLine, bool isRootLineBox) const;
+ virtual int baselinePosition(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual void updateFromElement();
virtual void cacheSelection(int start, int end);
diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp
index 7edbe7f..ea03c61 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -372,7 +372,7 @@ void RenderTextControlSingleLine::forwardEvent(Event* event)
if (event->type() == eventNames().blurEvent) {
if (innerTextRenderer) {
if (RenderLayer* innerLayer = innerTextRenderer->layer())
- innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0);
+ innerLayer->scrollToOffset(!style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
}
capsLockStateMayHaveChanged();
@@ -687,11 +687,18 @@ void RenderTextControlSingleLine::updateFromElement()
} else {
if (!inputElement()->suggestedValue().isNull())
setInnerTextValue(inputElement()->suggestedValue());
- else if (!node()->isHTMLElement() || !static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer())
- // For HTMLInputElement, update the renderer value only if the
- // formControlValueMatchesRenderer() flag is false. It protects an
- // unacceptable renderer value from being overwritten with the DOM value.
- setInnerTextValue(inputElement()->value());
+ else {
+ bool shouldUpdateValue = true;
+ if (node()->isHTMLElement()) {
+ // For HTMLInputElement, update the renderer value if the element
+ // supports placeholder or the formControlValueMatchesRenderer()
+ // flag is false. It protects an unacceptable renderer value from
+ // being overwritten with the DOM value.
+ shouldUpdateValue = static_cast<HTMLTextFormControlElement*>(node())->supportsPlaceholder() || !static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer();
+ }
+ if (shouldUpdateValue)
+ setInnerTextValue(inputElement()->value());
+ }
}
if (m_searchPopupIsVisible)
@@ -723,7 +730,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const
textBlockStyle->setOverflowY(OHIDDEN);
// Do not allow line-height to be smaller than our default.
- if (textBlockStyle->font().lineSpacing() > lineHeight(true, true))
+ if (textBlockStyle->font().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
textBlockStyle->setLineHeight(Length(-100.0f, Percent));
WebCore::EDisplay display = (m_innerBlock || inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK);
diff --git a/WebCore/rendering/RenderTextFragment.cpp b/WebCore/rendering/RenderTextFragment.cpp
index b14308d..705c095 100644
--- a/WebCore/rendering/RenderTextFragment.cpp
+++ b/WebCore/rendering/RenderTextFragment.cpp
@@ -44,6 +44,10 @@ RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str)
{
}
+RenderTextFragment::~RenderTextFragment()
+{
+}
+
PassRefPtr<StringImpl> RenderTextFragment::originalText() const
{
Node* e = node();
diff --git a/WebCore/rendering/RenderTextFragment.h b/WebCore/rendering/RenderTextFragment.h
index e023042..abb3fa4 100644
--- a/WebCore/rendering/RenderTextFragment.h
+++ b/WebCore/rendering/RenderTextFragment.h
@@ -35,6 +35,7 @@ class RenderTextFragment : public RenderText {
public:
RenderTextFragment(Node*, StringImpl*, int startOffset, int length);
RenderTextFragment(Node*, StringImpl*);
+ virtual ~RenderTextFragment();
virtual bool isTextFragment() const { return true; }
diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm
index 7982834..b632d9a 100644
--- a/WebCore/rendering/RenderThemeMac.mm
+++ b/WebCore/rendering/RenderThemeMac.mm
@@ -905,7 +905,7 @@ NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* rende
}
[cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
- [cell setBaseWritingDirection:style->direction() == LTR ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
+ [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
[cell setMinValue:element->min()];
[cell setMaxValue:element->max()];
RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
@@ -959,12 +959,12 @@ bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInf
paintInfo.context->save();
- if (renderProgress->style()->direction() == RTL) {
+ if (!renderProgress->style()->isLeftToRightDirection()) {
paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
paintInfo.context->scale(FloatSize(-1, 1));
}
- paintInfo.context->drawImageBuffer(imageBuffer.get(), DeviceColorSpace, rect.location());
+ paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, rect.location());
paintInfo.context->restore();
return false;
@@ -1141,11 +1141,11 @@ bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paint
// Draw the separator to the left of the arrows
paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
IntPoint(leftEdgeOfSeparator, bounds.bottom()));
- paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
+ paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
diff --git a/WebCore/rendering/RenderThemeSafari.cpp b/WebCore/rendering/RenderThemeSafari.cpp
index 07b8eb8..8d66ba7 100644
--- a/WebCore/rendering/RenderThemeSafari.cpp
+++ b/WebCore/rendering/RenderThemeSafari.cpp
@@ -830,8 +830,8 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& pa
paintInfo.context->save();
- paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), DeviceColorSpace);
- paintInfo.context->setStrokeColor(NoStroke, DeviceColorSpace);
+ paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
+ paintInfo.context->setStrokeColor(NoStroke, ColorSpaceDeviceRGB);
FloatPoint arrow[3];
arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
@@ -851,11 +851,11 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& pa
// Draw the separator to the left of the arrows
paintInfo.context->setStrokeThickness(1.0f);
paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
IntPoint(leftEdgeOfSeparator, bounds.bottom()));
- paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
+ paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp
index b4fb8eb..f0f8268 100644
--- a/WebCore/rendering/RenderThemeWin.cpp
+++ b/WebCore/rendering/RenderThemeWin.cpp
@@ -92,6 +92,21 @@
#define PBS_DISABLED 4
#define PBS_DEFAULTED 5
+// Spin button parts
+#define SPNP_UP 1
+#define SPNP_DOWN 2
+
+// Spin button states
+#define DNS_NORMAL 1
+#define DNS_HOT 2
+#define DNS_PRESSED 3
+#define DNS_DISABLED 4
+#define UPS_NORMAL 1
+#define UPS_HOT 2
+#define UPS_PRESSED 3
+#define UPS_DISABLED 4
+
+
SOFT_LINK_LIBRARY(uxtheme)
SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
@@ -154,6 +169,7 @@ RenderThemeWin::RenderThemeWin()
, m_textFieldTheme(0)
, m_menuListTheme(0)
, m_sliderTheme(0)
+ , m_spinButtonTheme(0)
{
haveTheme = uxthemeLibrary() && IsThemeActive();
}
@@ -194,6 +210,13 @@ HANDLE RenderThemeWin::sliderTheme() const
return m_sliderTheme;
}
+HANDLE RenderThemeWin::spinButtonTheme() const
+{
+ if (haveTheme && !m_spinButtonTheme)
+ m_spinButtonTheme = OpenThemeData(0, L"Spin");
+ return m_spinButtonTheme;
+}
+
void RenderThemeWin::close()
{
// This method will need to be called when the OS theme changes to flush our cached themes.
@@ -205,7 +228,9 @@ void RenderThemeWin::close()
CloseThemeData(m_menuListTheme);
if (m_sliderTheme)
CloseThemeData(m_sliderTheme);
- m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = 0;
+ if (m_spinButtonTheme)
+ CloseThemeData(m_spinButtonTheme);
+ m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = m_spinButtonTheme = 0;
haveTheme = uxthemeLibrary() && IsThemeActive();
}
@@ -368,7 +393,7 @@ bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const
return supportsFocus(style->appearance());
}
-unsigned RenderThemeWin::determineClassicState(RenderObject* o)
+unsigned RenderThemeWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
{
unsigned state = 0;
switch (o->style()->appearance()) {
@@ -397,6 +422,18 @@ unsigned RenderThemeWin::determineClassicState(RenderObject* o)
state |= DFCS_INACTIVE;
else if (isPressed(o))
state |= DFCS_PUSHED;
+ break;
+ case InnerSpinButtonPart: {
+ bool isUpButton = subPart == SpinButtonUp;
+ state = isUpButton ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
+ if (!isEnabled(o) || isReadOnlyControl(o))
+ state |= DFCS_INACTIVE;
+ else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
+ state |= DFCS_PUSHED;
+ else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
+ state |= DFCS_HOT;
+ break;
+ }
default:
break;
}
@@ -452,7 +489,20 @@ unsigned RenderThemeWin::determineButtonState(RenderObject* o)
return result;
}
-ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o)
+unsigned RenderThemeWin::determineSpinButtonState(RenderObject* o, ControlSubPart subPart)
+{
+ bool isUpButton = subPart == SpinButtonUp;
+ unsigned result = isUpButton ? UPS_NORMAL : DNS_NORMAL;
+ if (!isEnabled(o) || isReadOnlyControl(o))
+ result = isUpButton ? UPS_DISABLED : DNS_DISABLED;
+ else if (isPressed(o) && isUpButton == isSpinUpButtonPartPressed(o))
+ result = isUpButton ? UPS_PRESSED : DNS_PRESSED;
+ else if (isHovered(o) && isUpButton == isSpinUpButtonPartHovered(o))
+ result = isUpButton ? UPS_HOT : DNS_HOT;
+ return result;
+}
+
+ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o, ControlSubPart subPart)
{
ThemeData result;
switch (o->style()->appearance()) {
@@ -490,16 +540,20 @@ ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o)
result.m_part = TKP_THUMBRIGHT;
result.m_state = determineSliderThumbState(o);
break;
+ case InnerSpinButtonPart:
+ result.m_part = DFC_SCROLL;
+ result.m_state = determineClassicState(o, subPart);
+ break;
default:
break;
}
return result;
}
-ThemeData RenderThemeWin::getThemeData(RenderObject* o)
+ThemeData RenderThemeWin::getThemeData(RenderObject* o, ControlSubPart subPart)
{
if (!haveTheme)
- return getClassicThemeData(o);
+ return getClassicThemeData(o, subPart);
ThemeData result;
switch (o->style()->appearance()) {
@@ -549,6 +603,10 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o)
result.m_part = TKP_THUMBRIGHT;
result.m_state = determineSliderThumbState(o);
break;
+ case InnerSpinButtonPart:
+ result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
+ result.m_state = determineSpinButtonState(o, subPart);
+ break;
}
return result;
@@ -618,6 +676,31 @@ bool RenderThemeWin::paintButton(RenderObject* o, const PaintInfo& i, const IntR
return false;
}
+void RenderThemeWin::adjustInnerSpinButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ int width = ::GetSystemMetrics(SM_CXVSCROLL);
+ if (width <= 0)
+ width = 17; // Vista's default.
+ style->setWidth(Length(width, Fixed));
+ style->setMinWidth(Length(width, Fixed));
+}
+
+bool RenderThemeWin::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
+{
+ // We split the specified rectangle into two vertically. We can't draw a
+ // spin button of which height is less than 2px.
+ if (r.height() < 2)
+ return false;
+ IntRect upRect(r);
+ upRect.setHeight(r.height() / 2);
+ IntRect downRect(r);
+ downRect.setY(upRect.bottom());
+ downRect.setHeight(r.height() - upRect.height());
+ drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonUp), upRect);
+ drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonDown), downRect);
+ return false;
+}
+
void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
{
// If the width and height are both specified, then we have nothing to do.
diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h
index 1efb117..c05d2ee 100644
--- a/WebCore/rendering/RenderThemeWin.h
+++ b/WebCore/rendering/RenderThemeWin.h
@@ -77,6 +77,9 @@ public:
virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&);
+
virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
@@ -139,6 +142,12 @@ public:
#endif
private:
+ enum ControlSubPart {
+ None,
+ SpinButtonDown,
+ SpinButtonUp,
+ };
+
RenderThemeWin();
~RenderThemeWin();
@@ -146,24 +155,27 @@ private:
void close();
unsigned determineState(RenderObject*);
- unsigned determineClassicState(RenderObject*);
+ unsigned determineClassicState(RenderObject*, ControlSubPart = None);
unsigned determineSliderThumbState(RenderObject*);
unsigned determineButtonState(RenderObject*);
+ unsigned determineSpinButtonState(RenderObject*, ControlSubPart = None);
bool supportsFocus(ControlPart) const;
- ThemeData getThemeData(RenderObject*);
- ThemeData getClassicThemeData(RenderObject* o);
+ ThemeData getThemeData(RenderObject*, ControlSubPart = None);
+ ThemeData getClassicThemeData(RenderObject* o, ControlSubPart = None);
HANDLE buttonTheme() const;
HANDLE textFieldTheme() const;
HANDLE menuListTheme() const;
HANDLE sliderTheme() const;
+ HANDLE spinButtonTheme() const;
mutable HANDLE m_buttonTheme;
mutable HANDLE m_textFieldTheme;
mutable HANDLE m_menuListTheme;
mutable HANDLE m_sliderTheme;
+ mutable HANDLE m_spinButtonTheme;
};
};
diff --git a/WebCore/rendering/RenderThemeWinCE.cpp b/WebCore/rendering/RenderThemeWinCE.cpp
index 66cda11..27b8783 100644
--- a/WebCore/rendering/RenderThemeWinCE.cpp
+++ b/WebCore/rendering/RenderThemeWinCE.cpp
@@ -378,12 +378,12 @@ bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const Paint
IntRect cancelBounds(IntPoint(x, y), cancelSize);
paintInfo.context->save();
paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius);
- paintInfo.context->fillRect(cancelBounds, buttonColor, DeviceColorSpace);
+ paintInfo.context->fillRect(cancelBounds, buttonColor, ColorSpaceDeviceRGB);
// Draw the 'x'
IntSize xSize(3, 3);
IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize);
- paintInfo.context->setStrokeColor(Color::white, DeviceColorSpace);
+ paintInfo.context->setStrokeColor(Color::white, ColorSpaceDeviceRGB);
paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size());
paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom()));
@@ -490,8 +490,8 @@ bool RenderThemeWinCE::paintSliderTrack(RenderObject* o, const PaintInfo& i, con
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, DeviceColorSpace);
- i.context->setFillColor(Color::gray, DeviceColorSpace);
+ i.context->setStrokeColor(Color::gray, ColorSpaceDeviceRGB);
+ i.context->setFillColor(Color::gray, ColorSpaceDeviceRGB);
i.context->fillRect(r);
#if ENABLE(VIDEO)
HTMLMediaElement* mediaElement = mediaElementParent(o->node());
@@ -502,7 +502,7 @@ bool RenderThemeWinCE::paintSliderTrack(RenderObject* o, const PaintInfo& i, con
left = right;
}
#endif
- i.context->setStrokeColor(Color::black, DeviceColorSpace);
+ i.context->setStrokeColor(Color::black, ColorSpaceDeviceRGB);
i.context->drawLine(left, IntPoint(r.right() - 2, left.y()));
i.context->restore();
return rc;
@@ -512,8 +512,8 @@ bool RenderThemeWinCE::paintSliderThumb(RenderObject* o, const PaintInfo& i, con
{
bool rc = RenderTheme::paintSliderThumb(o, i, r);
i.context->save();
- i.context->setStrokeColor(Color::black, DeviceColorSpace);
- i.context->setFillColor(Color::black, DeviceColorSpace);
+ i.context->setStrokeColor(Color::black, ColorSpaceDeviceRGB);
+ i.context->setFillColor(Color::black, ColorSpaceDeviceRGB);
#if ENABLE(VIDEO)
HTMLMediaElement* mediaElement = mediaElementParent(o->node());
if (mediaElement) {
diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp
index ab6247b..ec36b7e 100644
--- a/WebCore/rendering/RenderTreeAsText.cpp
+++ b/WebCore/rendering/RenderTreeAsText.cpp
@@ -50,11 +50,11 @@
#include <wtf/Vector.h>
#if ENABLE(SVG)
-#include "RenderPath.h"
#include "RenderSVGContainer.h"
#include "RenderSVGGradientStop.h"
#include "RenderSVGImage.h"
#include "RenderSVGInlineText.h"
+#include "RenderSVGPath.h"
#include "RenderSVGRoot.h"
#include "RenderSVGText.h"
#include "SVGRenderTreeAsText.h"
@@ -440,8 +440,8 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo
if (o.containingBlock()->isTableCell())
y -= toRenderTableCell(o.containingBlock())->intrinsicPaddingBefore();
ts << "text run at (" << run.m_x << "," << y << ") width " << run.m_logicalWidth;
- if (run.direction() == RTL || run.m_dirOverride) {
- ts << (run.direction() == RTL ? " RTL" : " LTR");
+ if (!run.isLeftToRightDirection() || run.m_dirOverride) {
+ ts << (!run.isLeftToRightDirection() ? " RTL" : " LTR");
if (run.m_dirOverride)
ts << " override";
}
@@ -453,8 +453,8 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo
void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavior behavior)
{
#if ENABLE(SVG)
- if (o.isRenderPath()) {
- write(ts, *toRenderPath(&o), indent);
+ if (o.isSVGPath()) {
+ write(ts, *toRenderSVGPath(&o), indent);
return;
}
if (o.isSVGGradientStop()) {
diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp
index 470499a..32ba91b 100644
--- a/WebCore/rendering/RenderVideo.cpp
+++ b/WebCore/rendering/RenderVideo.cpp
@@ -246,14 +246,14 @@ void RenderVideo::updatePlayer()
mediaPlayer->setVisible(true);
}
-int RenderVideo::computeReplacedWidth(bool includeMaxWidth) const
+int RenderVideo::computeReplacedLogicalWidth(bool includeMaxWidth) const
{
- return RenderReplaced::computeReplacedWidth(includeMaxWidth);
+ return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
}
-int RenderVideo::computeReplacedHeight() const
+int RenderVideo::computeReplacedLogicalHeight() const
{
- return RenderReplaced::computeReplacedHeight();
+ return RenderReplaced::computeReplacedLogicalHeight();
}
int RenderVideo::minimumReplacedHeight() const
diff --git a/WebCore/rendering/RenderVideo.h b/WebCore/rendering/RenderVideo.h
index 24f473d..9091490 100644
--- a/WebCore/rendering/RenderVideo.h
+++ b/WebCore/rendering/RenderVideo.h
@@ -70,8 +70,8 @@ private:
virtual void layout();
- virtual int computeReplacedWidth(bool includeMaxWidth = true) const;
- virtual int computeReplacedHeight() const;
+ virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual int computeReplacedLogicalHeight() const;
virtual int minimumReplacedHeight() const;
void updatePlayer();
diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp
index 1ae1589..260a081 100644
--- a/WebCore/rendering/RenderView.cpp
+++ b/WebCore/rendering/RenderView.cpp
@@ -54,6 +54,7 @@ RenderView::RenderView(Node* node, FrameView* view)
, m_selectionEndPos(-1)
, m_maximalOutlineSize(0)
, m_pageHeight(0)
+ , m_pageHeightChanged(false)
, m_layoutState(0)
, m_layoutStateDisableCount(0)
{
@@ -127,6 +128,8 @@ void RenderView::layout()
// FIXME: May be better to push a clip and avoid issuing offscreen repaints.
state.m_clipped = false;
state.m_pageHeight = m_pageHeight;
+ state.m_pageHeightChanged = m_pageHeightChanged;
+ m_pageHeightChanged = false;
m_layoutState = &state;
if (needsLayout())
diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h
index b03312f..8f64766 100644
--- a/WebCore/rendering/RenderView.h
+++ b/WebCore/rendering/RenderView.h
@@ -54,8 +54,8 @@ public:
// The same as the FrameView's layoutHeight/layoutWidth but with null check guards.
int viewHeight() const;
int viewWidth() const;
- int viewLogicalWidth() const { return style()->isVerticalBlockFlow() ? viewWidth() : viewHeight(); }
- int viewLogicalHeight() const { return style()->isVerticalBlockFlow() ? viewHeight() : viewWidth(); }
+ int viewLogicalWidth() const { return style()->isHorizontalWritingMode() ? viewWidth() : viewHeight(); }
+ int viewLogicalHeight() const { return style()->isHorizontalWritingMode() ? viewHeight() : viewWidth(); }
float zoomFactor() const;
@@ -138,7 +138,7 @@ public:
{
if (m_pageHeight != height) {
m_pageHeight = height;
- markDescendantBlocksAndLinesForLayout();
+ m_pageHeightChanged = true;
}
}
@@ -181,11 +181,11 @@ public: // used by layout function
int docWidth() const;
// These functions may only be accessed by LayoutStateMaintainer.
- bool pushLayoutState(RenderBox* renderer, const IntSize& offset, int pageHeight = 0, ColumnInfo* colInfo = 0)
+ bool pushLayoutState(RenderBox* renderer, const IntSize& offset, int pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
{
// We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
if (!doingFullRepaint() || renderer->hasColumns() || m_layoutState->isPaginated()) {
- m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, colInfo);
+ m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo);
return true;
}
return false;
@@ -233,6 +233,7 @@ protected:
private:
unsigned m_pageHeight;
+ bool m_pageHeightChanged;
LayoutState* m_layoutState;
unsigned m_layoutStateDisableCount;
#if USE(ACCELERATED_COMPOSITING)
@@ -260,14 +261,14 @@ void toRenderView(const RenderView*);
class LayoutStateMaintainer : public Noncopyable {
public:
// ctor to push now
- LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false, int pageHeight = 0, ColumnInfo* colInfo = 0)
+ LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false, int pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
: m_view(view)
, m_disabled(disableState)
, m_didStart(false)
, m_didEnd(false)
, m_didCreateLayoutState(false)
{
- push(root, offset, pageHeight, colInfo);
+ push(root, offset, pageHeight, pageHeightChanged, colInfo);
}
// ctor to maybe push later
@@ -285,11 +286,11 @@ public:
ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop().
}
- void push(RenderBox* root, IntSize offset, int pageHeight = 0, ColumnInfo* colInfo = 0)
+ void push(RenderBox* root, IntSize offset, int pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
{
ASSERT(!m_didStart);
// We push state even if disabled, because we still need to store layoutDelta
- m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, colInfo);
+ m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, pageHeightChanged, colInfo);
if (m_disabled && m_didCreateLayoutState)
m_view->disableLayoutState();
m_didStart = true;
diff --git a/WebCore/rendering/RenderWordBreak.h b/WebCore/rendering/RenderWordBreak.h
index acd8179..db31eec 100644
--- a/WebCore/rendering/RenderWordBreak.h
+++ b/WebCore/rendering/RenderWordBreak.h
@@ -35,7 +35,7 @@ class HTMLElement;
class RenderWordBreak : public RenderText {
public:
- RenderWordBreak(HTMLElement*);
+ explicit RenderWordBreak(HTMLElement*);
virtual const char* renderName() const;
virtual bool isWordBreak() const;
diff --git a/WebCore/rendering/RenderingAllInOne.cpp b/WebCore/rendering/RenderingAllInOne.cpp
new file mode 100644
index 0000000..7a3a705
--- /dev/null
+++ b/WebCore/rendering/RenderingAllInOne.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include "AutoTableLayout.cpp"
+#include "BidiRun.cpp"
+#include "CounterNode.cpp"
+#include "EllipsisBox.cpp"
+#include "FixedTableLayout.cpp"
+#include "HitTestResult.cpp"
+#include "InlineBox.cpp"
+#include "InlineFlowBox.cpp"
+#include "InlineTextBox.cpp"
+#include "LayoutState.cpp"
+#include "MediaControlElements.cpp"
+#include "PointerEventsHitRules.cpp"
+#include "RenderApplet.cpp"
+#include "RenderArena.cpp"
+#include "RenderBR.cpp"
+#include "RenderBlock.cpp"
+#include "RenderBlockLineLayout.cpp"
+#include "RenderBox.cpp"
+#include "RenderBoxModelObject.cpp"
+#include "RenderButton.cpp"
+#include "RenderCounter.cpp"
+#include "RenderDataGrid.cpp"
+#include "RenderEmbeddedObject.cpp"
+#include "RenderFieldset.cpp"
+#include "RenderFileUploadControl.cpp"
+#include "RenderFlexibleBox.cpp"
+#include "RenderForeignObject.cpp"
+#include "RenderFrame.cpp"
+#include "RenderFrameBase.cpp"
+#include "RenderFrameSet.cpp"
+#include "RenderHTMLCanvas.cpp"
+#include "RenderIFrame.cpp"
+#include "RenderImage.cpp"
+#include "RenderImageResource.cpp"
+#include "RenderImageResourceStyleImage.cpp"
+#include "RenderIndicator.cpp"
+#include "RenderInline.cpp"
+#include "RenderLayer.cpp"
+#include "RenderLayerCompositor.cpp"
+#include "RenderLineBoxList.cpp"
+#include "RenderListBox.cpp"
+#include "RenderListItem.cpp"
+#include "RenderListMarker.cpp"
+#include "RenderMarquee.cpp"
+#include "RenderMedia.cpp"
+#include "RenderMediaControls.cpp"
+#include "RenderMenuList.cpp"
+#include "RenderMeter.cpp"
+#include "RenderObject.cpp"
+#include "RenderObjectChildList.cpp"
+#include "RenderPart.cpp"
+#include "RenderProgress.cpp"
+#include "RenderReplaced.cpp"
+#include "RenderReplica.cpp"
+#include "RenderRuby.cpp"
+#include "RenderRubyBase.cpp"
+#include "RenderRubyRun.cpp"
+#include "RenderRubyText.cpp"
+#include "RenderScrollbar.cpp"
+#include "RenderScrollbarPart.cpp"
+#include "RenderScrollbarTheme.cpp"
+#include "RenderSlider.cpp"
+#include "RenderTable.cpp"
+#include "RenderTableCell.cpp"
+#include "RenderTableCol.cpp"
+#include "RenderTableRow.cpp"
+#include "RenderTableSection.cpp"
+#include "RenderText.cpp"
+#include "RenderTextControl.cpp"
+#include "RenderTextControlMultiLine.cpp"
+#include "RenderTextControlSingleLine.cpp"
+#include "RenderTextFragment.cpp"
+#include "RenderTheme.cpp"
+#include "RenderThemeWin.cpp"
+#include "RenderTreeAsText.cpp"
+#include "RenderVideo.cpp"
+#include "RenderView.cpp"
+#include "RenderWidget.cpp"
+#include "RenderWordBreak.cpp"
+#include "RootInlineBox.cpp"
+#include "ScrollBehavior.cpp"
+#include "ShadowElement.cpp"
+#include "TextControlInnerElements.cpp"
+#include "TransformState.cpp"
+#include "break_lines.cpp"
diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp
index 52586c5..c7fcaeb 100644
--- a/WebCore/rendering/RootInlineBox.cpp
+++ b/WebCore/rendering/RootInlineBox.cpp
@@ -46,8 +46,9 @@ RootInlineBox::RootInlineBox(RenderBlock* block)
, m_lineTop(0)
, m_lineBottom(0)
, m_paginationStrut(0)
+ , m_blockLogicalHeight(0)
{
- setIsVertical(!block->style()->isVerticalBlockFlow());
+ setIsVertical(!block->style()->isHorizontalWritingMode());
}
@@ -199,7 +200,7 @@ void RootInlineBox::adjustPosition(int dx, int dy)
InlineFlowBox::adjustPosition(dx, dy);
m_lineTop += dy;
m_lineBottom += dy;
- m_blockHeight += dy;
+ m_blockLogicalHeight += dy;
}
void RootInlineBox::childRemoved(InlineBox* box)
@@ -240,10 +241,12 @@ int RootInlineBox::alignBoxesInBlockDirection(int heightOfBlock, GlyphOverflowAn
placeBoxesInBlockDirection(heightOfBlock, maxHeight, maxAscent, noQuirksMode, lineTop, lineBottom);
computeBlockDirectionOverflow(lineTop, lineBottom, noQuirksMode, textBoxDataMap);
setLineTopBottomPositions(lineTop, lineBottom);
-
- heightOfBlock += maxHeight;
-
- return heightOfBlock;
+
+ // Detect integer overflow.
+ if (heightOfBlock > numeric_limits<int>::max() - maxHeight)
+ return numeric_limits<int>::max();
+
+ return heightOfBlock + maxHeight;
}
GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
diff --git a/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h
index 8c75072..4a0b485 100644
--- a/WebCore/rendering/RootInlineBox.h
+++ b/WebCore/rendering/RootInlineBox.h
@@ -69,8 +69,8 @@ public:
unsigned lineBreakPos() const { return m_lineBreakPos; }
void setLineBreakPos(unsigned p) { m_lineBreakPos = p; }
- int blockHeight() const { return m_blockHeight; }
- void setBlockHeight(int h) { m_blockHeight = h; }
+ int blockLogicalHeight() const { return m_blockLogicalHeight; }
+ void setBlockLogicalHeight(int h) { m_blockLogicalHeight = h; }
bool endsWithBreak() const { return m_endsWithBreak; }
void setEndsWithBreak(bool b) { m_endsWithBreak = b; }
@@ -88,6 +88,9 @@ public:
virtual void clearTruncation();
+ virtual int baselinePosition() const { return boxModelObject()->baselinePosition(m_firstLine, m_isVertical ? VerticalLine : HorizontalLine, PositionOfInteriorLineBoxes); }
+ virtual int lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, m_isVertical ? VerticalLine : HorizontalLine, PositionOfInteriorLineBoxes); }
+
#if PLATFORM(MAC)
void addHighlightOverflow();
void paintCustomHighlight(PaintInfo&, int tx, int ty, const AtomicString& highlightType);
@@ -143,8 +146,8 @@ private:
// good for as long as the line has not been marked dirty.
OwnPtr<Vector<RenderBox*> > m_floats;
- // The height of the block at the end of this line. This is where the next line starts.
- int m_blockHeight;
+ // The logical height of the block at the end of this line. This is where the next line starts.
+ int m_blockLogicalHeight;
WTF::Unicode::Direction m_lineBreakBidiStatusEor : 5;
WTF::Unicode::Direction m_lineBreakBidiStatusLastStrong : 5;
diff --git a/WebCore/rendering/SVGCharacterData.h b/WebCore/rendering/SVGCharacterData.h
deleted file mode 100644
index 5143042..0000000
--- a/WebCore/rendering/SVGCharacterData.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 SVGCharacterData_h
-#define SVGCharacterData_h
-
-#if ENABLE(SVG)
-#include <wtf/HashMap.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-
-namespace WebCore {
-
-class AffineTransform;
-class RenderObject;
-
-// Holds extra data, when the character is laid out on a path
-struct SVGCharOnPath : RefCounted<SVGCharOnPath> {
- static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); }
-
- float xScale;
- float yScale;
-
- float xShift;
- float yShift;
-
- float orientationAngle;
-
- bool hidden : 1;
-
-private:
- SVGCharOnPath()
- : xScale(1.0f)
- , yScale(1.0f)
- , xShift(0.0f)
- , yShift(0.0f)
- , orientationAngle(0.0f)
- , hidden(false)
- {
- }
-};
-
-struct SVGChar {
- SVGChar()
- : x(0.0f)
- , y(0.0f)
- , angle(0.0f)
- , orientationShiftX(0.0f)
- , orientationShiftY(0.0f)
- , drawnSeperated(false)
- , newTextChunk(false)
- {
- }
-
- float x;
- float y;
- float angle;
-
- float orientationShiftX;
- float orientationShiftY;
-
- RefPtr<SVGCharOnPath> pathData;
-
- // Determines wheter this char needs to be drawn seperated
- bool drawnSeperated : 1;
-
- // Determines wheter this char starts a new chunk
- bool newTextChunk : 1;
-
- // Helper methods
- bool isHidden() const;
- AffineTransform characterTransform() const;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
-#endif // SVGCharacterData_h
diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp
deleted file mode 100644
index 71ff1aa..0000000
--- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "SVGCharacterLayoutInfo.h"
-
-#if ENABLE(SVG)
-#include "InlineFlowBox.h"
-#include "InlineTextBox.h"
-#include "RenderSVGTextPath.h"
-#include "SVGCharacterData.h"
-#include "SVGLengthList.h"
-#include "SVGNumberList.h"
-#include "SVGTextPositioningElement.h"
-
-#include <float.h>
-
-namespace WebCore {
-
-// Helper function
-static float calculateBaselineShift(RenderObject* item)
-{
- ASSERT(item);
- ASSERT(item->style());
- ASSERT(item->node());
- ASSERT(item->node()->isSVGElement());
-
- const Font& font = item->style()->font();
- const SVGRenderStyle* svgStyle = item->style()->svgStyle();
-
- float baselineShift = 0.0f;
- if (svgStyle->baselineShift() == BS_LENGTH) {
- SVGLength baselineShiftValueLength = svgStyle->baselineShiftValue();
- if (baselineShiftValueLength.unitType() == LengthTypePercentage)
- baselineShift = baselineShiftValueLength.valueAsPercentage() * font.pixelSize();
- else
- baselineShift = baselineShiftValueLength.value(static_cast<SVGElement*>(item->node()));
- } else {
- float baselineAscent = font.ascent() + font.descent();
-
- switch (svgStyle->baselineShift()) {
- case BS_BASELINE:
- break;
- case BS_SUB:
- baselineShift = -baselineAscent / 2.0f;
- break;
- case BS_SUPER:
- baselineShift = baselineAscent / 2.0f;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- return baselineShift;
-}
-
-SVGCharacterLayoutInfo::SVGCharacterLayoutInfo()
- : curx(0.0f)
- , cury(0.0f)
- , angle(0.0f)
- , dx(0.0f)
- , dy(0.0f)
- , shiftx(0.0f)
- , shifty(0.0f)
- , pathExtraAdvance(0.0f)
- , pathTextLength(0.0f)
- , pathChunkLength(0.0f)
- , nextDrawnSeperated(false)
- , xStackChanged(false)
- , yStackChanged(false)
- , dxStackChanged(false)
- , dyStackChanged(false)
- , angleStackChanged(false)
- , baselineShiftStackChanged(false)
- , pathLayout(false)
- , currentOffset(0.0f)
- , startOffset(0.0f)
- , layoutPathLength(0.0f)
-{
-}
-
-bool SVGCharacterLayoutInfo::xValueAvailable() const
-{
- return xStack.isEmpty() ? false : xStack.last().position() < xStack.last().size();
-}
-
-bool SVGCharacterLayoutInfo::yValueAvailable() const
-{
- return yStack.isEmpty() ? false : yStack.last().position() < yStack.last().size();
-}
-
-bool SVGCharacterLayoutInfo::dxValueAvailable() const
-{
- return dxStack.isEmpty() ? false : dxStack.last().position() < dxStack.last().size();
-}
-
-bool SVGCharacterLayoutInfo::dyValueAvailable() const
-{
- return dyStack.isEmpty() ? false : dyStack.last().position() < dyStack.last().size();
-}
-
-bool SVGCharacterLayoutInfo::angleValueAvailable() const
-{
- return angleStack.isEmpty() ? false : angleStack.last().position() < angleStack.last().size();
-}
-
-bool SVGCharacterLayoutInfo::baselineShiftValueAvailable() const
-{
- return !baselineShiftStack.isEmpty();
-}
-
-float SVGCharacterLayoutInfo::xValueNext() const
-{
- ASSERT(!xStack.isEmpty());
- return xStack.last().valueAtCurrentPosition();
-}
-
-float SVGCharacterLayoutInfo::yValueNext() const
-{
- ASSERT(!yStack.isEmpty());
- return yStack.last().valueAtCurrentPosition();
-}
-
-float SVGCharacterLayoutInfo::dxValueNext() const
-{
- ASSERT(!dxStack.isEmpty());
- return dxStack.last().valueAtCurrentPosition();
-}
-
-float SVGCharacterLayoutInfo::dyValueNext() const
-{
- ASSERT(!dyStack.isEmpty());
- return dyStack.last().valueAtCurrentPosition();
-}
-
-float SVGCharacterLayoutInfo::angleValueNext() const
-{
- ASSERT(!angleStack.isEmpty());
- return angleStack.last().valueAtCurrentPosition();
-}
-
-float SVGCharacterLayoutInfo::baselineShiftValueNext() const
-{
- ASSERT(!baselineShiftStack.isEmpty());
- return baselineShiftStack.last();
-}
-
-
-bool SVGCharacterLayoutInfo::isInitialLayout() const
-{
- return xStack.isEmpty()
- && yStack.isEmpty()
- && dxStack.isEmpty()
- && dyStack.isEmpty()
- && angleStack.isEmpty()
- && baselineShiftStack.isEmpty()
- && curx == 0.0f
- && cury == 0.0f;
-}
-
-void SVGCharacterLayoutInfo::processedSingleCharacter()
-{
- xStackWalk();
- yStackWalk();
- dxStackWalk();
- dyStackWalk();
- angleStackWalk();
- baselineShiftStackWalk();
-}
-
-void SVGCharacterLayoutInfo::processedChunk(float savedShiftX, float savedShiftY)
-{
- // baseline-shift doesn't span across ancestors, unlike dx/dy.
- curx += savedShiftX - shiftx;
- cury += savedShiftY - shifty;
-
- if (inPathLayout()) {
- shiftx = savedShiftX;
- shifty = savedShiftY;
- }
-
- // rotation also doesn't span
- angle = 0.0f;
-
- if (xStackChanged) {
- ASSERT(!xStack.isEmpty());
- xStack.removeLast();
- xStackChanged = false;
- }
-
- if (yStackChanged) {
- ASSERT(!yStack.isEmpty());
- yStack.removeLast();
- yStackChanged = false;
- }
-
- if (dxStackChanged) {
- ASSERT(!dxStack.isEmpty());
- dxStack.removeLast();
- dxStackChanged = false;
- }
-
- if (dyStackChanged) {
- ASSERT(!dyStack.isEmpty());
- dyStack.removeLast();
- dyStackChanged = false;
- }
-
- if (angleStackChanged) {
- ASSERT(!angleStack.isEmpty());
- angleStack.removeLast();
- angleStackChanged = false;
- }
-
- if (baselineShiftStackChanged) {
- ASSERT(!baselineShiftStack.isEmpty());
- baselineShiftStack.removeLast();
- baselineShiftStackChanged = false;
- }
-}
-
-bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset)
-{
- if (layoutPathLength <= 0.0f)
- return false;
-
- if (newOffset != FLT_MIN)
- currentOffset = startOffset + newOffset;
-
- // Respect translation along path (extraAdvance is orthogonal to the path)
- currentOffset += extraAdvance;
-
- float offset = currentOffset + glyphAdvance / 2.0f;
- currentOffset += glyphAdvance + pathExtraAdvance;
-
- if (offset < 0.0f || offset > layoutPathLength)
- return false;
-
- bool ok = false;
- FloatPoint point = layoutPath.pointAtLength(offset, ok);
- ASSERT(ok);
-
- curx = point.x();
- cury = point.y();
-
- angle = layoutPath.normalAngleAtLength(offset, ok);
- ASSERT(ok);
-
- return true;
-}
-
-bool SVGCharacterLayoutInfo::inPathLayout() const
-{
- return pathLayout;
-}
-
-void SVGCharacterLayoutInfo::setInPathLayout(bool value)
-{
- pathLayout = value;
-
- pathExtraAdvance = 0.0f;
- pathTextLength = 0.0f;
- pathChunkLength = 0.0f;
-}
-
-void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float textAnchorStartOffset)
-{
- bool wasInitialLayout = isInitialLayout();
-
- RenderSVGTextPath* textPath = toRenderSVGTextPath(flowBox->renderer());
- Path path = textPath->layoutPath();
-
- float baselineShift = calculateBaselineShift(textPath);
-
- layoutPath = path;
- layoutPathLength = path.length();
-
- if (layoutPathLength <= 0.0f)
- return;
-
- startOffset = textPath->startOffset();
-
- if (textPath->startOffset() >= 0.0f && textPath->startOffset() <= 1.0f)
- startOffset *= layoutPathLength;
-
- startOffset += textAnchorStartOffset;
- currentOffset = startOffset;
-
- // Only baseline-shift is handled through the normal layout system
- addStackContent(BaselineShiftStack, baselineShift);
-
- if (wasInitialLayout) {
- xStackChanged = false;
- yStackChanged = false;
- dxStackChanged = false;
- dyStackChanged = false;
- angleStackChanged = false;
- baselineShiftStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement* element)
-{
- bool wasInitialLayout = isInitialLayout();
- float baselineShift = calculateBaselineShift(element->renderer());
-
- addStackContent(XStack, element->x(), element);
- addStackContent(YStack, element->y(), element);
- addStackContent(DxStack, element->dx(), element);
- addStackContent(DyStack, element->dy(), element);
- addStackContent(AngleStack, element->rotate());
- addStackContent(BaselineShiftStack, baselineShift);
-
- if (wasInitialLayout) {
- xStackChanged = false;
- yStackChanged = false;
- dxStackChanged = false;
- dyStackChanged = false;
- angleStackChanged = false;
- baselineShiftStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGNumberList* list)
-{
- unsigned length = list->numberOfItems();
- if (!length)
- return;
-
- PositionedFloatVector newLayoutInfo;
-
- // TODO: Convert more efficiently!
- ExceptionCode ec = 0;
- for (unsigned i = 0; i < length; ++i) {
- float value = list->getItem(i, ec);
- ASSERT(!ec);
-
- newLayoutInfo.append(value);
- }
-
- addStackContent(type, newLayoutInfo);
-}
-
-void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGLengthList* list, const SVGElement* context)
-{
- unsigned length = list->numberOfItems();
- if (!length)
- return;
-
- PositionedFloatVector newLayoutInfo;
-
- ExceptionCode ec = 0;
- for (unsigned i = 0; i < length; ++i) {
- float value = list->getItem(i, ec).value(context);
- ASSERT(!ec);
-
- newLayoutInfo.append(value);
- }
-
- addStackContent(type, newLayoutInfo);
-}
-
-void SVGCharacterLayoutInfo::addStackContent(StackType type, const PositionedFloatVector& list)
-{
- switch (type) {
- case XStack:
- xStackChanged = true;
- xStack.append(list);
- break;
- case YStack:
- yStackChanged = true;
- yStack.append(list);
- break;
- case DxStack:
- dxStackChanged = true;
- dxStack.append(list);
- break;
- case DyStack:
- dyStackChanged = true;
- dyStack.append(list);
- break;
- case AngleStack:
- angleStackChanged = true;
- angleStack.append(list);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void SVGCharacterLayoutInfo::addStackContent(StackType type, float value)
-{
- if (value == 0.0f)
- return;
-
- switch (type) {
- case BaselineShiftStack:
- baselineShiftStackChanged = true;
- baselineShiftStack.append(value);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void SVGCharacterLayoutInfo::xStackWalk()
-{
- unsigned i = 1;
-
- while (!xStack.isEmpty()) {
- PositionedFloatVector& cur = xStack.last();
- if (i + cur.position() < cur.size()) {
- cur.advance(i);
- break;
- }
-
- i += cur.position();
- xStack.removeLast();
- xStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::yStackWalk()
-{
- unsigned i = 1;
-
- while (!yStack.isEmpty()) {
- PositionedFloatVector& cur = yStack.last();
- if (i + cur.position() < cur.size()) {
- cur.advance(i);
- break;
- }
-
- i += cur.position();
- yStack.removeLast();
- yStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::dxStackWalk()
-{
- unsigned i = 1;
-
- while (!dxStack.isEmpty()) {
- PositionedFloatVector& cur = dxStack.last();
- if (i + cur.position() < cur.size()) {
- cur.advance(i);
- break;
- }
-
- i += cur.position();
- dxStack.removeLast();
- dxStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::dyStackWalk()
-{
- unsigned i = 1;
-
- while (!dyStack.isEmpty()) {
- PositionedFloatVector& cur = dyStack.last();
- if (i + cur.position() < cur.size()) {
- cur.advance(i);
- break;
- }
-
- i += cur.position();
- dyStack.removeLast();
- dyStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::angleStackWalk()
-{
- unsigned i = 1;
-
- while (!angleStack.isEmpty()) {
- PositionedFloatVector& cur = angleStack.last();
- if (i + cur.position() < cur.size()) {
- cur.advance(i);
- break;
- }
-
- i += cur.position();
- angleStack.removeLast();
- angleStackChanged = false;
- }
-}
-
-void SVGCharacterLayoutInfo::baselineShiftStackWalk()
-{
- if (!baselineShiftStack.isEmpty()) {
- baselineShiftStack.removeLast();
- baselineShiftStackChanged = false;
- }
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h
deleted file mode 100644
index 7549283..0000000
--- a/WebCore/rendering/SVGCharacterLayoutInfo.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef SVGCharacterLayoutInfo_h
-#define SVGCharacterLayoutInfo_h
-
-#if ENABLE(SVG)
-#include "Path.h"
-#include <wtf/Assertions.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class InlineFlowBox;
-class SVGElement;
-class SVGLengthList;
-class SVGNumberList;
-class SVGTextPositioningElement;
-
-template<class Type>
-class PositionedVector : public Vector<Type> {
-public:
- PositionedVector<Type>()
- : m_position(0)
- {
- }
-
- unsigned position() const
- {
- return m_position;
- }
-
- void advance(unsigned position)
- {
- m_position += position;
- ASSERT(m_position < Vector<Type>::size());
- }
-
- Type valueAtCurrentPosition() const
- {
- ASSERT(m_position < Vector<Type>::size());
- return Vector<Type>::at(m_position);
- }
-
-private:
- unsigned m_position;
-};
-
-class PositionedFloatVector : public PositionedVector<float> { };
-struct SVGChar;
-
-struct SVGCharacterLayoutInfo {
- SVGCharacterLayoutInfo();
-
- enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack };
-
- bool xValueAvailable() const;
- bool yValueAvailable() const;
- bool dxValueAvailable() const;
- bool dyValueAvailable() const;
- bool angleValueAvailable() const;
- bool baselineShiftValueAvailable() const;
-
- float xValueNext() const;
- float yValueNext() const;
- float dxValueNext() const;
- float dyValueNext() const;
- float angleValueNext() const;
- float baselineShiftValueNext() const;
-
- void processedChunk(float savedShiftX, float savedShiftY);
- void processedSingleCharacter();
-
- bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset);
-
- // Used for text-on-path.
- void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0f);
-
- bool inPathLayout() const;
- void setInPathLayout(bool value);
-
- // Used for anything else.
- void addLayoutInformation(SVGTextPositioningElement*);
-
- // Global position
- float curx;
- float cury;
-
- // Global rotation
- float angle;
-
- // Accumulated dx/dy values
- float dx;
- float dy;
-
- // Accumulated baseline-shift values
- float shiftx;
- float shifty;
-
- // Path specific advance values to handle lengthAdjust
- float pathExtraAdvance;
- float pathTextLength;
- float pathChunkLength;
-
- // Result vector
- Vector<SVGChar> svgChars;
- bool nextDrawnSeperated : 1;
-
-private:
- // Used for baseline-shift.
- void addStackContent(StackType, float);
-
- // Used for angle.
- void addStackContent(StackType, SVGNumberList*);
-
- // Used for x/y/dx/dy.
- void addStackContent(StackType, SVGLengthList*, const SVGElement*);
-
- void addStackContent(StackType, const PositionedFloatVector&);
-
- void xStackWalk();
- void yStackWalk();
- void dxStackWalk();
- void dyStackWalk();
- void angleStackWalk();
- void baselineShiftStackWalk();
-
- bool isInitialLayout() const;
-
-private:
- bool xStackChanged : 1;
- bool yStackChanged : 1;
- bool dxStackChanged : 1;
- bool dyStackChanged : 1;
- bool angleStackChanged : 1;
- bool baselineShiftStackChanged : 1;
-
- // text on path layout
- bool pathLayout : 1;
- float currentOffset;
- float startOffset;
- float layoutPathLength;
- Path layoutPath;
-
- Vector<PositionedFloatVector> xStack;
- Vector<PositionedFloatVector> yStack;
- Vector<PositionedFloatVector> dxStack;
- Vector<PositionedFloatVector> dyStack;
- Vector<PositionedFloatVector> angleStack;
- Vector<float> baselineShiftStack;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
-#endif // SVGCharacterLayoutInfo_h
diff --git a/WebCore/rendering/SVGImageBufferTools.cpp b/WebCore/rendering/SVGImageBufferTools.cpp
index 709bf10..903aa21 100644
--- a/WebCore/rendering/SVGImageBufferTools.cpp
+++ b/WebCore/rendering/SVGImageBufferTools.cpp
@@ -50,7 +50,7 @@ void SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(
}
}
-bool SVGImageBufferTools::createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ImageColorSpace colorSpace)
+bool SVGImageBufferTools::createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace)
{
IntSize imageSize(roundedImageBufferSize(clampedAbsoluteTargetRect.size()));
IntSize unclampedImageSize(SVGImageBufferTools::roundedImageBufferSize(absoluteTargetRect.size()));
diff --git a/WebCore/rendering/SVGImageBufferTools.h b/WebCore/rendering/SVGImageBufferTools.h
index 8894aae..9bcc7a4 100644
--- a/WebCore/rendering/SVGImageBufferTools.h
+++ b/WebCore/rendering/SVGImageBufferTools.h
@@ -34,7 +34,7 @@ class RenderObject;
class SVGImageBufferTools : public Noncopyable {
public:
- static bool createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ImageColorSpace);
+ static bool createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ColorSpace);
static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&);
static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&);
diff --git a/WebCore/rendering/SVGInlineFlowBox.cpp b/WebCore/rendering/SVGInlineFlowBox.cpp
deleted file mode 100644
index 4008938..0000000
--- a/WebCore/rendering/SVGInlineFlowBox.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGInlineFlowBox.h"
-
-#if ENABLE(SVG)
-#include "GraphicsContext.h"
-#include "SVGRenderSupport.h"
-
-namespace WebCore {
-
-void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int)
-{
- ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
- ASSERT(!paintInfo.context->paintingDisabled());
-
- RenderObject* boxRenderer = renderer();
- ASSERT(boxRenderer);
-
- PaintInfo childPaintInfo(paintInfo);
- childPaintInfo.context->save();
-
- if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
- for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
- child->paint(childPaintInfo, 0, 0);
- }
-
- SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
- childPaintInfo.context->restore();
-}
-
-IntRect SVGInlineFlowBox::calculateBoundaries() const
-{
- IntRect childRect;
- for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
- childRect.unite(child->calculateBoundaries());
- return childRect;
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp
deleted file mode 100644
index c367598..0000000
--- a/WebCore/rendering/SVGInlineTextBox.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-/**
- * Copyright (C) 2007 Rob Buis <buis@kde.org>
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGInlineTextBox.h"
-
-#if ENABLE(SVG)
-#include "FloatConversion.h"
-#include "GraphicsContext.h"
-#include "InlineFlowBox.h"
-#include "RenderBlock.h"
-#include "RenderSVGResource.h"
-#include "SVGRootInlineBox.h"
-#include "SVGTextLayoutUtilities.h"
-
-#include <float.h>
-
-using namespace std;
-
-namespace WebCore {
-
-SVGInlineTextBox::SVGInlineTextBox(RenderObject* object)
- : InlineTextBox(object)
- , m_logicalHeight(0)
- , m_paintingResource(0)
- , m_paintingResourceMode(ApplyToDefaultMode)
-{
-}
-
-SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const
-{
- // Find associated root inline box
- InlineFlowBox* parentBox = parent();
-
- while (parentBox && !parentBox->isRootInlineBox())
- parentBox = parentBox->parent();
-
- ASSERT(parentBox);
- ASSERT(parentBox->isRootInlineBox());
-
- if (!parentBox->isSVGRootInlineBox())
- return 0;
-
- return static_cast<SVGRootInlineBox*>(parentBox);
-}
-
-void SVGInlineTextBox::measureCharacter(RenderStyle* style, int position, int& charsConsumed, String& glyphName, String& unicodeString, float& glyphWidth, float& glyphHeight) const
-{
- ASSERT(style);
-
- int offset = direction() == RTL ? end() - position : start() + position;
- int extraCharsAvailable = len() - position - 1;
- const UChar* characters = textRenderer()->characters();
-
- const Font& font = style->font();
- glyphWidth = font.floatWidth(svgTextRunForInlineTextBox(characters + offset, 1, style, this), extraCharsAvailable, charsConsumed, glyphName);
- glyphHeight = font.height();
-
- // The unicodeString / glyphName pair is needed for kerning calculations.
- unicodeString = String(characters + offset, charsConsumed);
-}
-
-int SVGInlineTextBox::offsetForPosition(int xCoordinate, bool includePartialGlyphs) const
-{
- ASSERT(!m_currentChunkPart.isValid());
- float x = xCoordinate;
-
- RenderText* textRenderer = this->textRenderer();
- ASSERT(textRenderer);
-
- RenderStyle* style = textRenderer->style();
- ASSERT(style);
-
- RenderBlock* containingBlock = textRenderer->containingBlock();
- ASSERT(containingBlock);
-
- // Move incoming relative x position to absolute position, as the character origins stored in the chunk parts use absolute coordinates
- x += containingBlock->x();
-
- // Figure out which text chunk part is hit
- SVGTextChunkPart hitPart;
-
- const Vector<SVGTextChunkPart>::const_iterator end = m_svgTextChunkParts.end();
- for (Vector<SVGTextChunkPart>::const_iterator it = m_svgTextChunkParts.begin(); it != end; ++it) {
- const SVGTextChunkPart& part = *it;
-
- // Check whether we're past the hit part.
- if (x < part.firstCharacter->x)
- break;
-
- hitPart = part;
- }
-
- // If we did not hit anything, just exit.
- if (!hitPart.isValid())
- return 0;
-
- // Before calling Font::offsetForPosition(), subtract the start position of the first character
- // in the hit text chunk part, to pass in coordinates, which are relative to the text chunk part, as
- // constructTextRun() only builds a TextRun for the current chunk part, not the whole inline text box.
- x -= hitPart.firstCharacter->x;
-
- m_currentChunkPart = hitPart;
- TextRun textRun(constructTextRun(style));
- m_currentChunkPart = SVGTextChunkPart();
-
- // Eventually handle lengthAdjust="spacingAndGlyphs".
- // FIXME: Need to revisit the whole offsetForPosition concept for vertical text selection.
- if (!m_chunkTransformation.isIdentity())
- textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(m_chunkTransformation.a()));
-
- return hitPart.offset + style->font().offsetForPosition(textRun, x, includePartialGlyphs);
-}
-
-int SVGInlineTextBox::positionForOffset(int) const
-{
- // SVG doesn't use the offset <-> position selection system.
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-FloatRect SVGInlineTextBox::selectionRectForTextChunkPart(const SVGTextChunkPart& part, int partStartPos, int partEndPos, RenderStyle* style)
-{
- // Map startPos/endPos positions into chunk part
- mapStartEndPositionsIntoChunkPartCoordinates(partStartPos, partEndPos, part);
-
- if (partStartPos >= partEndPos)
- return FloatRect();
-
- // Set current chunk part, so constructTextRun() works properly.
- m_currentChunkPart = part;
-
- const Font& font = style->font();
- Vector<SVGChar>::const_iterator character = part.firstCharacter;
- FloatPoint textOrigin(character->x, character->y - font.ascent());
-
- FloatRect partRect(font.selectionRectForText(constructTextRun(style), textOrigin, part.height, partStartPos, partEndPos));
- m_currentChunkPart = SVGTextChunkPart();
-
- return character->characterTransform().mapRect(partRect);
-}
-
-IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos)
-{
- ASSERT(!m_currentChunkPart.isValid());
-
- int boxStart = start();
- startPos = max(startPos - boxStart, 0);
- endPos = min(endPos - boxStart, static_cast<int>(len()));
-
- if (startPos >= endPos)
- return IntRect();
-
- RenderText* text = textRenderer();
- ASSERT(text);
-
- RenderStyle* style = text->style();
- ASSERT(style);
-
- FloatRect selectionRect;
-
- // Figure out which text chunk part is hit
- const Vector<SVGTextChunkPart>::const_iterator end = m_svgTextChunkParts.end();
- for (Vector<SVGTextChunkPart>::const_iterator it = m_svgTextChunkParts.begin(); it != end; ++it)
- selectionRect.unite(selectionRectForTextChunkPart(*it, startPos, endPos, style));
-
- // Resepect possible chunk transformation
- if (m_chunkTransformation.isIdentity())
- return enclosingIntRect(selectionRect);
-
- return enclosingIntRect(m_chunkTransformation.mapRect(selectionRect));
-}
-
-void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int)
-{
- ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
- ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
- ASSERT(truncation() == cNoTruncation);
-
- if (renderer()->style()->visibility() != VISIBLE)
- return;
-
- // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
- // If we ever need that for SVG, it's very easy to refactor and reuse the code.
-
- RenderObject* parentRenderer = parent()->renderer();
- ASSERT(parentRenderer);
-
- RenderStyle* style = parentRenderer->style();
- ASSERT(style);
-
- const SVGRenderStyle* svgStyle = style->svgStyle();
- ASSERT(svgStyle);
-
- bool hasFill = svgStyle->hasFill();
- bool hasStroke = svgStyle->hasStroke();
- bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
-
- // Determine whether or not we're selected.
- bool isPrinting = parentRenderer->document()->printing();
- bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone;
- if (!hasSelection && paintSelectedTextOnly)
- return;
-
- RenderStyle* selectionStyle = style;
- if (hasSelection) {
- selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
- if (selectionStyle) {
- const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
- ASSERT(svgSelectionStyle);
-
- if (!hasFill)
- hasFill = svgSelectionStyle->hasFill();
- if (!hasStroke)
- hasStroke = svgSelectionStyle->hasStroke();
- } else
- selectionStyle = style;
- }
-
- // Compute text match marker rects. It needs to traverse all text chunk parts to figure
- // out the union selection rect of all text chunk parts that contribute to the selection.
- computeTextMatchMarkerRect(style);
- ASSERT(!m_currentChunkPart.isValid());
-
- const Vector<SVGTextChunkPart>::const_iterator end = m_svgTextChunkParts.end();
- for (Vector<SVGTextChunkPart>::const_iterator it = m_svgTextChunkParts.begin(); it != end; ++it) {
- ASSERT(!m_paintingResource);
-
- // constructTextRun() uses the current chunk part to figure out what text to render.
- m_currentChunkPart = *it;
- paintInfo.context->save();
-
- // Prepare context and draw text
- if (!m_chunkTransformation.isIdentity())
- paintInfo.context->concatCTM(m_chunkTransformation);
-
- Vector<SVGChar>::const_iterator firstCharacter = m_currentChunkPart.firstCharacter;
- AffineTransform characterTransform = firstCharacter->characterTransform();
- if (!characterTransform.isIdentity())
- paintInfo.context->concatCTM(characterTransform);
-
- FloatPoint textOrigin(firstCharacter->x, firstCharacter->y);
-
- // Draw background once (not in both fill/stroke phases)
- if (!isPrinting && !paintSelectedTextOnly && hasSelection)
- paintSelection(paintInfo.context, textOrigin, style);
-
- // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
- int decorations = style->textDecorationsInEffect();
- if (decorations & UNDERLINE)
- paintDecoration(paintInfo.context, textOrigin, UNDERLINE, hasSelection);
- if (decorations & OVERLINE)
- paintDecoration(paintInfo.context, textOrigin, OVERLINE, hasSelection);
-
- // Fill text
- if (hasFill) {
- m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode;
- paintText(paintInfo.context, textOrigin, style, selectionStyle, hasSelection, paintSelectedTextOnly);
- }
-
- // Stroke text
- if (hasStroke) {
- m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode;
- paintText(paintInfo.context, textOrigin, style, selectionStyle, hasSelection, paintSelectedTextOnly);
- }
-
- // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text.
- if (decorations & LINE_THROUGH)
- paintDecoration(paintInfo.context, textOrigin, LINE_THROUGH, hasSelection);
-
- m_paintingResourceMode = ApplyToDefaultMode;
- paintInfo.context->restore();
- }
-
- m_currentChunkPart = SVGTextChunkPart();
- ASSERT(!m_paintingResource);
-}
-
-bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, RenderObject* renderer, RenderStyle* style)
-{
- ASSERT(renderer);
- ASSERT(style);
- ASSERT(m_paintingResourceMode != ApplyToDefaultMode);
-
- if (m_paintingResourceMode & ApplyToFillMode)
- m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style);
- else if (m_paintingResourceMode & ApplyToStrokeMode)
- m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style);
- else {
- // We're either called for stroking or filling.
- ASSERT_NOT_REACHED();
- }
-
- if (!m_paintingResource)
- return false;
-
- m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode);
- return true;
-}
-
-void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context)
-{
- ASSERT(m_paintingResource);
-
- RenderObject* parentRenderer = parent()->renderer();
- ASSERT(parentRenderer);
-
- m_paintingResource->postApplyResource(parentRenderer, context, m_paintingResourceMode);
- m_paintingResource = 0;
-}
-
-bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, TextRun& textRun, RenderStyle* style)
-{
- bool acquiredResource = acquirePaintingResource(context, parent()->renderer(), style);
-
-#if ENABLE(SVG_FONTS)
- // SVG Fonts need access to the painting resource used to draw the current text chunk.
- if (acquiredResource)
- textRun.setActivePaintingResource(m_paintingResource);
-#endif
-
- return acquiredResource;
-}
-
-void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun)
-{
- releasePaintingResource(context);
-
-#if ENABLE(SVG_FONTS)
- textRun.setActivePaintingResource(0);
-#endif
-}
-
-TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style) const
-{
- ASSERT(m_currentChunkPart.isValid());
- return svgTextRunForInlineTextBox(textRenderer()->text()->characters() + start() + m_currentChunkPart.offset, m_currentChunkPart.length, style, this);
-}
-
-void SVGInlineTextBox::mapStartEndPositionsIntoChunkPartCoordinates(int& startPos, int& endPos, const SVGTextChunkPart& part) const
-{
- if (startPos >= endPos)
- return;
-
- // Take <text x="10 50 100">ABC</text> as example. We're called three times from paint(), because all absolute positioned
- // characters are drawn on their own. For each of them we want to find out whehter it's selected. startPos=0, endPos=1
- // could mean A, B or C is hit, depending on which chunk part is processed at the moment. With the offset & length values
- // of each chunk part we can easily find out which one is meant to be selected. Bail out for the other chunk parts.
- // If starPos is behind the current chunk or the endPos ends before this text chunk part, we're not meant to be selected.
- if (startPos >= part.offset + part.length || endPos <= part.offset) {
- startPos = 0;
- endPos = -1;
- return;
- }
-
- // The current processed chunk part is hit. When painting the selection, constructTextRun() builds
- // a TextRun object whose startPos is 0 and endPos is chunk part length. The code below maps the incoming
- // startPos/endPos range into a [0, part length] coordinate system, relative to the current chunk part.
- if (startPos < part.offset)
- startPos = 0;
- else
- startPos -= part.offset;
-
- if (endPos > part.offset + part.length)
- endPos = part.length;
- else {
- ASSERT(endPos >= part.offset);
- endPos -= part.offset;
- }
-
- ASSERT(startPos < endPos);
-}
-
-void SVGInlineTextBox::selectionStartEnd(int& startPos, int& endPos)
-{
- InlineTextBox::selectionStartEnd(startPos, endPos);
-
- if (!m_currentChunkPart.isValid())
- return;
-
- mapStartEndPositionsIntoChunkPartCoordinates(startPos, endPos, m_currentChunkPart);
-}
-
-void SVGInlineTextBox::computeTextMatchMarkerRect(RenderStyle* style)
-{
- ASSERT(!m_currentChunkPart.isValid());
- Node* node = renderer()->node();
- if (!node || !node->inDocument())
- return;
-
- Document* document = renderer()->document();
- Vector<DocumentMarker> markers = document->markers()->markersForNode(renderer()->node());
-
- Vector<DocumentMarker>::iterator markerEnd = markers.end();
- for (Vector<DocumentMarker>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) {
- const DocumentMarker& marker = *markerIt;
-
- // SVG is only interessted in the TextMatch marker, for now.
- if (marker.type != DocumentMarker::TextMatch)
- continue;
-
- FloatRect markerRect;
- int partStartPos = max(marker.startOffset - start(), static_cast<unsigned>(0));
- int partEndPos = min(marker.endOffset - start(), static_cast<unsigned>(len()));
-
- // Iterate over all text chunk parts, to see which ones have to be highlighted
- const Vector<SVGTextChunkPart>::const_iterator end = m_svgTextChunkParts.end();
- for (Vector<SVGTextChunkPart>::const_iterator it = m_svgTextChunkParts.begin(); it != end; ++it)
- markerRect.unite(selectionRectForTextChunkPart(*it, partStartPos, partEndPos, style));
-
- if (!m_chunkTransformation.isIdentity())
- markerRect = m_chunkTransformation.mapRect(markerRect);
-
- document->markers()->setRenderedRectForMarker(node, marker, renderer()->localToAbsoluteQuad(markerRect).enclosingBoundingBox());
- }
-}
-
-static inline float positionOffsetForDecoration(ETextDecoration decoration, const Font& font, float thickness)
-{
- // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
- // Compatible with Batik/Opera.
- if (decoration == UNDERLINE)
- return font.ascent() + thickness * 1.5f;
- if (decoration == OVERLINE)
- return thickness;
- if (decoration == LINE_THROUGH)
- return font.ascent() * 5.0f / 8.0f;
-
- ASSERT_NOT_REACHED();
- return 0.0f;
-}
-
-static inline float thicknessForDecoration(ETextDecoration, const Font& font)
-{
- // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
- // Compatible with Batik/Opera
- return font.size() / 20.0f;
-}
-
-static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowBox* parentBox, ETextDecoration decoration)
-{
- // Lookup render object which has text-decoration set.
- RenderObject* renderer = 0;
- while (parentBox) {
- renderer = parentBox->renderer();
-
- // Explicitely check textDecoration() not textDecorationsInEffect(), which is inherited to
- // children, as we want to lookup the render object whose style defined the text-decoration.
- if (renderer->style() && renderer->style()->textDecoration() & decoration)
- break;
-
- parentBox = parentBox->parent();
- }
-
- ASSERT(renderer);
- return renderer;
-}
-
-void SVGInlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& textOrigin, ETextDecoration decoration, bool hasSelection)
-{
- // Find out which render style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours.
- RenderObject* decorationRenderer = findRenderObjectDefininingTextDecoration(parent(), decoration);
- RenderStyle* decorationStyle = decorationRenderer->style();
- ASSERT(decorationStyle);
-
- const SVGRenderStyle* svgDecorationStyle = decorationStyle->svgStyle();
- ASSERT(svgDecorationStyle);
-
- bool hasDecorationFill = svgDecorationStyle->hasFill();
- bool hasDecorationStroke = svgDecorationStyle->hasStroke();
-
- if (hasSelection) {
- if (RenderStyle* pseudoStyle = decorationRenderer->getCachedPseudoStyle(SELECTION)) {
- decorationStyle = pseudoStyle;
-
- svgDecorationStyle = decorationStyle->svgStyle();
- ASSERT(svgDecorationStyle);
-
- if (!hasDecorationFill)
- hasDecorationFill = svgDecorationStyle->hasFill();
- if (!hasDecorationStroke)
- hasDecorationStroke = svgDecorationStyle->hasStroke();
- }
- }
-
- if (decorationStyle->visibility() == HIDDEN)
- return;
-
- if (hasDecorationFill) {
- m_paintingResourceMode = ApplyToFillMode;
- paintDecorationWithStyle(context, textOrigin, decorationRenderer, decoration);
- }
-
- if (hasDecorationStroke) {
- m_paintingResourceMode = ApplyToStrokeMode;
- paintDecorationWithStyle(context, textOrigin, decorationRenderer, decoration);
- }
-}
-
-void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, const FloatPoint& textOrigin, RenderObject* decorationRenderer, ETextDecoration decoration)
-{
- ASSERT(!m_paintingResource);
- ASSERT(m_paintingResourceMode != ApplyToDefaultMode);
- ASSERT(m_currentChunkPart.isValid());
-
- RenderStyle* decorationStyle = decorationRenderer->style();
- ASSERT(decorationStyle);
-
- const Font& font = decorationStyle->font();
-
- // The initial y value refers to overline position.
- float thickness = thicknessForDecoration(decoration, font);
- float x = textOrigin.x();
- float y = textOrigin.y() - font.ascent() + positionOffsetForDecoration(decoration, font, thickness);
-
- context->save();
- context->beginPath();
- context->addPath(Path::createRectangle(FloatRect(x, y, m_currentChunkPart.width, thickness)));
-
- if (acquirePaintingResource(context, decorationRenderer, decorationStyle))
- releasePaintingResource(context);
-
- context->restore();
-}
-
-void SVGInlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& textOrigin, RenderStyle* style)
-{
- // See if we have a selection to paint at all.
- int startPos, endPos;
- selectionStartEnd(startPos, endPos);
- if (startPos >= endPos)
- return;
-
- Color backgroundColor = renderer()->selectionBackgroundColor();
- if (!backgroundColor.isValid() || !backgroundColor.alpha())
- return;
-
- const Font& font = style->font();
-
- FloatPoint selectionOrigin = textOrigin;
- selectionOrigin.move(0, -font.ascent());
-
- context->save();
- context->setFillColor(backgroundColor, style->colorSpace());
- context->fillRect(font.selectionRectForText(constructTextRun(style), selectionOrigin, m_currentChunkPart.height, startPos, endPos), backgroundColor, style->colorSpace());
- context->restore();
-}
-
-void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, const FloatPoint& textOrigin, RenderStyle* style, TextRun& textRun, int startPos, int endPos)
-{
- const Font& font = style->font();
- const ShadowData* shadow = style->textShadow();
-
- FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - font.ascent()), FloatSize(m_currentChunkPart.width, m_currentChunkPart.height));
- do {
- if (!prepareGraphicsContextForTextPainting(context, textRun, style))
- break;
-
- FloatSize extraOffset;
- if (shadow)
- extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */);
-
- font.drawText(context, textRun, textOrigin + extraOffset, startPos, endPos);
- restoreGraphicsContextAfterTextPainting(context, textRun);
-
- if (!shadow)
- break;
-
- if (shadow->next())
- context->restore();
- else
- context->clearShadow();
-
- shadow = shadow->next();
- } while (shadow);
-}
-
-void SVGInlineTextBox::paintText(GraphicsContext* context, const FloatPoint& textOrigin, RenderStyle* style, RenderStyle* selectionStyle, bool hasSelection, bool paintSelectedTextOnly)
-{
- ASSERT(style);
- ASSERT(selectionStyle);
- ASSERT(m_currentChunkPart.isValid());
-
- int startPos = 0;
- int endPos = 0;
- selectionStartEnd(startPos, endPos);
-
- // Fast path if there is no selection, just draw the whole chunk part using the regular style
- TextRun textRun(constructTextRun(style));
- if (!hasSelection || startPos >= endPos) {
- paintTextWithShadows(context, textOrigin, style, textRun, 0, m_currentChunkPart.length);
- return;
- }
-
- // Eventually draw text using regular style until the start position of the selection
- if (startPos > 0 && !paintSelectedTextOnly)
- paintTextWithShadows(context, textOrigin, style, textRun, 0, startPos);
-
- // Draw text using selection style from the start to the end position of the selection
- if (style != selectionStyle)
- SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, selectionStyle);
-
- TextRun selectionTextRun(constructTextRun(selectionStyle));
- paintTextWithShadows(context, textOrigin, selectionStyle, textRun, startPos, endPos);
-
- if (style != selectionStyle)
- SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, style);
-
- // Eventually draw text using regular style from the end position of the selection to the end of the current chunk part
- if (endPos < m_currentChunkPart.length && !paintSelectedTextOnly)
- paintTextWithShadows(context, textOrigin, style, textRun, endPos, m_currentChunkPart.length);
-}
-
-void SVGInlineTextBox::buildLayoutInformation(SVGCharacterLayoutInfo& info, SVGLastGlyphInfo& lastGlyph)
-{
- RenderText* textRenderer = this->textRenderer();
- ASSERT(textRenderer);
-
- RenderStyle* style = textRenderer->style();
- ASSERT(style);
-
- RenderObject* parentRenderer = parent()->renderer();
- ASSERT(parentRenderer);
- ASSERT(parentRenderer->node());
- ASSERT(parentRenderer->node()->isSVGElement());
- SVGElement* lengthContext = static_cast<SVGElement*>(parentRenderer->node());
-
- const Font& font = style->font();
- const UChar* characters = textRenderer->characters();
-
- TextDirection textDirection = direction();
- unsigned startPosition = start();
- unsigned endPosition = end();
- unsigned length = len();
-
- const SVGRenderStyle* svgStyle = style->svgStyle();
- bool isVerticalText = isVerticalWritingMode(svgStyle);
-
- int charsConsumed = 0;
- for (unsigned i = 0; i < length; i += charsConsumed) {
- SVGChar svgChar;
-
- if (info.inPathLayout())
- svgChar.pathData = SVGCharOnPath::create();
-
- float glyphWidth = 0.0f;
- float glyphHeight = 0.0f;
- String glyphName;
- String unicodeString;
- measureCharacter(style, i, charsConsumed, glyphName, unicodeString, glyphWidth, glyphHeight);
-
- bool assignedX = false;
- bool assignedY = false;
-
- if (info.xValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && !isVerticalText))) {
- if (!isVerticalText)
- svgChar.newTextChunk = true;
-
- assignedX = true;
- svgChar.drawnSeperated = true;
- info.curx = info.xValueNext();
- }
-
- if (info.yValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && isVerticalText))) {
- if (isVerticalText)
- svgChar.newTextChunk = true;
-
- assignedY = true;
- svgChar.drawnSeperated = true;
- info.cury = info.yValueNext();
- }
-
- float dx = 0.0f;
- float dy = 0.0f;
-
- // Apply x-axis shift
- if (info.dxValueAvailable()) {
- svgChar.drawnSeperated = true;
-
- dx = info.dxValueNext();
- info.dx += dx;
-
- if (!info.inPathLayout())
- info.curx += dx;
- }
-
- // Apply y-axis shift
- if (info.dyValueAvailable()) {
- svgChar.drawnSeperated = true;
-
- dy = info.dyValueNext();
- info.dy += dy;
-
- if (!info.inPathLayout())
- info.cury += dy;
- }
-
- // Take letter & word spacing and kerning into account
- float spacing = font.letterSpacing() + calculateCSSKerning(lengthContext, style);
-
- const UChar* currentCharacter = characters + (textDirection == RTL ? endPosition - i : startPosition + i);
- const UChar* lastCharacter = 0;
-
- if (textDirection == RTL) {
- if (i < endPosition)
- lastCharacter = characters + endPosition - i + 1;
- } else {
- if (i > 0)
- lastCharacter = characters + startPosition + i - 1;
- }
-
- // FIXME: SVG Kerning doesn't get applied on texts on path.
- bool appliedSVGKerning = applySVGKerning(info, style, lastGlyph, unicodeString, glyphName, isVerticalText);
- if (info.nextDrawnSeperated || spacing != 0.0f || appliedSVGKerning) {
- info.nextDrawnSeperated = false;
- svgChar.drawnSeperated = true;
- }
-
- if (currentCharacter && Font::treatAsSpace(*currentCharacter) && lastCharacter && !Font::treatAsSpace(*lastCharacter)) {
- spacing += font.wordSpacing();
-
- if (spacing != 0.0f && !info.inPathLayout())
- info.nextDrawnSeperated = true;
- }
-
- float orientationAngle = glyphOrientationToAngle(svgStyle, isVerticalText, *currentCharacter);
-
- float xOrientationShift = 0.0f;
- float yOrientationShift = 0.0f;
- float glyphAdvance = applyGlyphAdvanceAndShiftRespectingOrientation(isVerticalText, orientationAngle, glyphWidth, glyphHeight,
- font, svgChar, xOrientationShift, yOrientationShift);
-
- // Handle textPath layout mode
- if (info.inPathLayout()) {
- float extraAdvance = isVerticalText ? dy : dx;
- float newOffset = FLT_MIN;
-
- if (assignedX && !isVerticalText)
- newOffset = info.curx;
- else if (assignedY && isVerticalText)
- newOffset = info.cury;
-
- float correctedGlyphAdvance = glyphAdvance;
-
- // Handle lengthAdjust="spacingAndGlyphs" by specifying per-character scale operations
- if (info.pathTextLength && info.pathChunkLength) {
- if (isVerticalText) {
- svgChar.pathData->yScale = info.pathChunkLength / info.pathTextLength;
- spacing *= svgChar.pathData->yScale;
- correctedGlyphAdvance *= svgChar.pathData->yScale;
- } else {
- svgChar.pathData->xScale = info.pathChunkLength / info.pathTextLength;
- spacing *= svgChar.pathData->xScale;
- correctedGlyphAdvance *= svgChar.pathData->xScale;
- }
- }
-
- // Handle letter & word spacing on text path
- float pathExtraAdvance = info.pathExtraAdvance;
- info.pathExtraAdvance += spacing;
-
- svgChar.pathData->hidden = !info.nextPathLayoutPointAndAngle(correctedGlyphAdvance, extraAdvance, newOffset);
- svgChar.drawnSeperated = true;
-
- info.pathExtraAdvance = pathExtraAdvance;
- }
-
- // Apply rotation
- if (info.angleValueAvailable())
- info.angle = info.angleValueNext();
-
- // Apply baseline-shift
- if (info.baselineShiftValueAvailable()) {
- svgChar.drawnSeperated = true;
- float shift = info.baselineShiftValueNext();
-
- if (isVerticalText)
- info.shiftx += shift;
- else
- info.shifty -= shift;
- }
-
- // Take dominant-baseline / alignment-baseline into account
- yOrientationShift += alignmentBaselineToShift(isVerticalText, textRenderer, font);
-
- svgChar.x = info.curx;
- svgChar.y = info.cury;
- svgChar.angle = info.angle;
-
- // For text paths any shift (dx/dy/baseline-shift) has to be applied after the rotation
- if (!info.inPathLayout()) {
- svgChar.x += info.shiftx + xOrientationShift;
- svgChar.y += info.shifty + yOrientationShift;
-
- if (orientationAngle != 0.0f)
- svgChar.angle += orientationAngle;
-
- if (svgChar.angle != 0.0f)
- svgChar.drawnSeperated = true;
- } else {
- svgChar.pathData->orientationAngle = orientationAngle;
-
- if (isVerticalText)
- svgChar.angle -= 90.0f;
-
- svgChar.pathData->xShift = info.shiftx + xOrientationShift;
- svgChar.pathData->yShift = info.shifty + yOrientationShift;
-
- // Translate to glyph midpoint
- if (isVerticalText) {
- svgChar.pathData->xShift += info.dx;
- svgChar.pathData->yShift -= glyphAdvance / 2.0f;
- } else {
- svgChar.pathData->xShift -= glyphAdvance / 2.0f;
- svgChar.pathData->yShift += info.dy;
- }
- }
-
- // Advance to new position
- if (isVerticalText) {
- svgChar.drawnSeperated = true;
- info.cury += glyphAdvance + spacing;
- } else
- info.curx += glyphAdvance + spacing;
-
- // Advance to next character group
- for (int k = 0; k < charsConsumed; ++k) {
- info.svgChars.append(svgChar);
- info.processedSingleCharacter();
- svgChar.drawnSeperated = false;
- svgChar.newTextChunk = false;
- }
- }
-}
-
-FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int position, const SVGChar& character) const
-{
- int charsConsumed = 0;
- String glyphName;
- String unicodeString;
- float glyphWidth = 0.0f;
- float glyphHeight = 0.0f;
- measureCharacter(style, position, charsConsumed, glyphName, unicodeString, glyphWidth, glyphHeight);
-
- FloatRect glyphRect(character.x, character.y - style->font().ascent(), glyphWidth, glyphHeight);
- glyphRect = character.characterTransform().mapRect(glyphRect);
- if (m_chunkTransformation.isIdentity())
- return glyphRect;
-
- return m_chunkTransformation.mapRect(glyphRect);
-}
-
-IntRect SVGInlineTextBox::calculateBoundaries() const
-{
- FloatRect textRect;
- int baseline = baselinePosition(true);
-
- const Vector<SVGTextChunkPart>::const_iterator end = m_svgTextChunkParts.end();
- for (Vector<SVGTextChunkPart>::const_iterator it = m_svgTextChunkParts.begin(); it != end; ++it)
- textRect.unite(it->firstCharacter->characterTransform().mapRect(FloatRect(it->firstCharacter->x, it->firstCharacter->y - baseline, it->width, it->height)));
-
- if (m_chunkTransformation.isIdentity())
- return enclosingIntRect(textRect);
-
- return enclosingIntRect(m_chunkTransformation.mapRect(textRect));
-}
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp
index 644ff70..608cf4d 100644
--- a/WebCore/rendering/SVGRenderSupport.cpp
+++ b/WebCore/rendering/SVGRenderSupport.cpp
@@ -32,7 +32,7 @@
#include "ImageBuffer.h"
#include "NodeRenderStyle.h"
#include "RenderLayer.h"
-#include "RenderPath.h"
+#include "RenderSVGPath.h"
#include "RenderSVGResource.h"
#include "RenderSVGResourceClipper.h"
#include "RenderSVGResourceFilter.h"
@@ -220,9 +220,9 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
// When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) {
- // When the layout size changed and when using relative values tell the RenderPath to update its Path object
- if (child->isRenderPath())
- toRenderPath(child)->setNeedsPathUpdate();
+ // When the layout size changed and when using relative values tell the RenderSVGPath to update its Path object
+ if (child->isSVGPath())
+ toRenderSVGPath(child)->setNeedsPathUpdate();
needsLayout = true;
}
@@ -347,16 +347,6 @@ void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const
}
}
-const RenderObject* SVGRenderSupport::findTextRootObject(const RenderObject* start)
-{
- while (start && !start->isSVGText())
- start = start->parent();
- ASSERT(start);
- ASSERT(start->isSVGText());
-
- return start;
-}
-
}
#endif
diff --git a/WebCore/rendering/SVGRenderSupport.h b/WebCore/rendering/SVGRenderSupport.h
index 54622d2..7814863 100644
--- a/WebCore/rendering/SVGRenderSupport.h
+++ b/WebCore/rendering/SVGRenderSupport.h
@@ -70,7 +70,6 @@ public:
static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*);
// FIXME: These methods do not belong here.
- static const RenderObject* findTextRootObject(const RenderObject* start);
static const RenderSVGRoot* findTreeRootObject(const RenderObject* start);
private:
diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp
index 4e26f52..b7f7f95 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.cpp
+++ b/WebCore/rendering/SVGRenderTreeAsText.cpp
@@ -40,11 +40,11 @@
#include "PatternAttributes.h"
#include "RadialGradientAttributes.h"
#include "RenderImage.h"
-#include "RenderPath.h"
#include "RenderSVGContainer.h"
#include "RenderSVGGradientStop.h"
#include "RenderSVGImage.h"
#include "RenderSVGInlineText.h"
+#include "RenderSVGPath.h"
#include "RenderSVGResourceClipper.h"
#include "RenderSVGResourceFilter.h"
#include "RenderSVGResourceGradient.h"
@@ -57,15 +57,21 @@
#include "RenderSVGRoot.h"
#include "RenderSVGText.h"
#include "RenderTreeAsText.h"
-#include "SVGCharacterLayoutInfo.h"
+#include "SVGCircleElement.h"
+#include "SVGEllipseElement.h"
#include "SVGInlineTextBox.h"
+#include "SVGLineElement.h"
#include "SVGLinearGradientElement.h"
+#include "SVGPathElement.h"
+#include "SVGPathParserFactory.h"
#include "SVGPatternElement.h"
+#include "SVGPointList.h"
+#include "SVGPolyElement.h"
#include "SVGRadialGradientElement.h"
+#include "SVGRectElement.h"
#include "SVGRootInlineBox.h"
#include "SVGStopElement.h"
#include "SVGStyledElement.h"
-#include "SVGTextLayoutUtilities.h"
#include <math.h>
@@ -316,12 +322,13 @@ static void writeStyle(TextStream& ts, const RenderObject& object)
writeNameValuePair(ts, "transform", object.localTransform());
writeIfNotDefault(ts, "image rendering", svgStyle->imageRendering(), SVGRenderStyle::initialImageRendering());
writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity());
- if (object.isRenderPath()) {
- const RenderPath& path = static_cast<const RenderPath&>(object);
+ if (object.isSVGPath()) {
+ const RenderSVGPath& path = static_cast<const RenderSVGPath&>(object);
ASSERT(path.node());
ASSERT(path.node()->isSVGElement());
- if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderPath*>(&path), path.style())) {
+ Color fallbackColor;
+ if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) {
TextStreamSeparator s(" ");
ts << " [stroke={" << s;
writeSVGPaintingResource(ts, strokePaintingResource);
@@ -348,7 +355,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object)
ts << "}]";
}
- if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderPath*>(&path), path.style())) {
+ if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) {
TextStreamSeparator s(" ");
ts << " [fill={" << s;
writeSVGPaintingResource(ts, fillPaintingResource);
@@ -372,10 +379,46 @@ static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& obj
return ts;
}
-static TextStream& operator<<(TextStream& ts, const RenderPath& path)
+static TextStream& operator<<(TextStream& ts, const RenderSVGPath& path)
{
writePositionAndStyle(ts, path);
- writeNameAndQuotedValue(ts, "data", path.path().debugString());
+
+ ASSERT(path.node()->isSVGElement());
+ SVGElement* svgElement = static_cast<SVGElement*>(path.node());
+
+ if (svgElement->hasTagName(SVGNames::rectTag)) {
+ SVGRectElement* element = static_cast<SVGRectElement*>(svgElement);
+ writeNameValuePair(ts, "x", element->x().value(element));
+ writeNameValuePair(ts, "y", element->y().value(element));
+ writeNameValuePair(ts, "width", element->width().value(element));
+ writeNameValuePair(ts, "height", element->height().value(element));
+ } else if (svgElement->hasTagName(SVGNames::lineTag)) {
+ SVGLineElement* element = static_cast<SVGLineElement*>(svgElement);
+ writeNameValuePair(ts, "x1", element->x1().value(element));
+ writeNameValuePair(ts, "y1", element->y1().value(element));
+ writeNameValuePair(ts, "x2", element->x2().value(element));
+ writeNameValuePair(ts, "y2", element->y2().value(element));
+ } else if (svgElement->hasTagName(SVGNames::ellipseTag)) {
+ SVGEllipseElement* element = static_cast<SVGEllipseElement*>(svgElement);
+ writeNameValuePair(ts, "cx", element->cx().value(element));
+ writeNameValuePair(ts, "cy", element->cy().value(element));
+ writeNameValuePair(ts, "rx", element->rx().value(element));
+ writeNameValuePair(ts, "ry", element->ry().value(element));
+ } else if (svgElement->hasTagName(SVGNames::circleTag)) {
+ SVGCircleElement* element = static_cast<SVGCircleElement*>(svgElement);
+ writeNameValuePair(ts, "cx", element->cx().value(element));
+ writeNameValuePair(ts, "cy", element->cy().value(element));
+ writeNameValuePair(ts, "r", element->r().value(element));
+ } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) {
+ SVGPolyElement* element = static_cast<SVGPolyElement*>(svgElement);
+ writeNameAndQuotedValue(ts, "points", element->points()->valueAsString());
+ } else if (svgElement->hasTagName(SVGNames::pathTag)) {
+ SVGPathElement* element = static_cast<SVGPathElement*>(svgElement);
+ String pathString;
+ SVGPathParserFactory::self()->buildStringFromSVGPathSegList(element->pathSegList(), pathString, UnalteredParsing);
+ writeNameAndQuotedValue(ts, "data", pathString);
+ } else
+ ASSERT_NOT_REACHED();
return ts;
}
@@ -387,116 +430,72 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root)
static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text)
{
SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox());
-
if (!box)
return;
- Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks());
- ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight() << " contains " << chunks.size() << " chunk(s)";
+ ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight();
+
+ // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now.
+ ts << " contains 1 chunk(s)";
if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor)))
writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).name());
}
-static inline bool containsInlineTextBox(SVGTextChunk& chunk, SVGInlineTextBox* box)
-{
- Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
- Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
-
- bool found = false;
- for (; boxIt != boxEnd; ++boxIt) {
- SVGInlineBoxCharacterRange& range = *boxIt;
-
- if (box == static_cast<SVGInlineTextBox*>(range.box)) {
- found = true;
- break;
- }
- }
-
- return found;
-}
-
static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent)
{
- SVGRootInlineBox* rootBox = textBox->svgRootInlineBox();
- if (!rootBox)
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+ if (fragments.isEmpty())
return;
- Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(rootBox->svgTextChunks());
-
- Vector<SVGTextChunk>::iterator it = chunks.begin();
- Vector<SVGTextChunk>::iterator end = chunks.end();
+ RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer());
+ ASSERT(textRenderer);
- // Write text chunks
- unsigned int i = 1;
- for (; it != end; ++it) {
- SVGTextChunk& cur = *it;
-
- // Write inline box character ranges
- Vector<SVGInlineBoxCharacterRange>::iterator boxIt = cur.boxes.begin();
- Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = cur.boxes.end();
-
- if (!containsInlineTextBox(cur, textBox)) {
- i++;
- continue;
- }
+ const SVGRenderStyle* svgStyle = textRenderer->style()->svgStyle();
+ String text = textBox->textRenderer()->text();
+ unsigned fragmentsSize = fragments.size();
+ for (unsigned i = 0; i < fragmentsSize; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
writeIndent(ts, indent + 1);
- unsigned int j = 1;
- ts << "chunk " << i << " ";
+ unsigned startOffset = fragment.positionListOffset;
+ unsigned endOffset = fragment.positionListOffset + fragment.length;
- if (cur.anchor == TA_MIDDLE) {
+ // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now.
+ ts << "chunk 1 ";
+ ETextAnchor anchor = svgStyle->textAnchor();
+ bool isVerticalText = svgStyle->isVerticalWritingMode();
+ if (anchor == TA_MIDDLE) {
ts << "(middle anchor";
- if (cur.isVerticalText)
+ if (isVerticalText)
ts << ", vertical";
ts << ") ";
- } else if (cur.anchor == TA_END) {
+ } else if (anchor == TA_END) {
ts << "(end anchor";
- if (cur.isVerticalText)
+ if (isVerticalText)
ts << ", vertical";
ts << ") ";
- } else if (cur.isVerticalText)
+ } else if (isVerticalText)
ts << "(vertical) ";
+ startOffset -= textBox->start();
+ endOffset -= textBox->start();
+ // </hack>
+
+ ts << "text run " << i + 1 << " at (" << fragment.x << "," << fragment.y << ")";
+ ts << " startOffset " << startOffset << " endOffset " << endOffset;
+ if (isVerticalText)
+ ts << " height " << fragment.height;
+ else
+ ts << " width " << fragment.width;
- unsigned int totalOffset = 0;
-
- for (; boxIt != boxEnd; ++boxIt) {
- SVGInlineBoxCharacterRange& range = *boxIt;
-
- unsigned int offset = range.endOffset - range.startOffset;
- ASSERT(cur.start + totalOffset <= cur.end);
-
- totalOffset += offset;
-
- if (textBox != static_cast<SVGInlineTextBox*>(range.box)) {
- j++;
- continue;
- }
-
- FloatPoint topLeft = topLeftPositionOfCharacterRange(cur.start + totalOffset - offset, cur.start + totalOffset);
-
- ts << "text run " << j << " at (" << topLeft.x() << "," << topLeft.y() << ") ";
- ts << "startOffset " << range.startOffset << " endOffset " << range.endOffset;
-
- if (cur.isVerticalText)
- ts << " height " << cummulatedHeightOfInlineBoxCharacterRange(range);
- else
- ts << " width " << cummulatedWidthOfInlineBoxCharacterRange(range);
-
- if (textBox->direction() == RTL || textBox->m_dirOverride) {
- ts << (textBox->direction() == RTL ? " RTL" : " LTR");
-
- if (textBox->m_dirOverride)
- ts << " override";
- }
-
- ts << ": " << quoteAndEscapeNonPrintables(String(textBox->textRenderer()->text()).substring(textBox->start() + range.startOffset, offset)) << "\n";
-
- j++;
+ if (!textBox->isLeftToRightDirection() || textBox->m_dirOverride) {
+ ts << (textBox->isLeftToRightDirection() ? " LTR" : " RTL");
+ if (textBox->m_dirOverride)
+ ts << " override";
}
- i++;
+ ts << ": " << quoteAndEscapeNonPrintables(text.substring(fragment.positionListOffset, fragment.length)) << "\n";
}
}
@@ -582,7 +581,9 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i
// Dump final results that are used for rendering. No use in asking SVGPatternElement for its patternUnits(), as it may
// link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties()
- PatternAttributes attributes = static_cast<SVGPatternElement*>(pattern->node())->collectPatternProperties();
+ PatternAttributes attributes;
+ static_cast<SVGPatternElement*>(pattern->node())->collectPatternAttributes(attributes);
+
writeNameValuePair(ts, "patternUnits", boundingBoxModeString(attributes.boundingBoxMode()));
writeNameValuePair(ts, "patternContentUnits", boundingBoxModeString(attributes.boundingBoxModeContent()));
@@ -597,7 +598,8 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i
// link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradient->node());
- LinearGradientAttributes attributes = linearGradientElement->collectGradientProperties();
+ LinearGradientAttributes attributes;
+ linearGradientElement->collectGradientAttributes(attributes);
writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode());
FloatPoint startPoint;
@@ -612,7 +614,8 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i
// link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradient->node());
- RadialGradientAttributes attributes = radialGradientElement->collectGradientProperties();
+ RadialGradientAttributes attributes;
+ radialGradientElement->collectGradientAttributes(attributes);
writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode());
FloatPoint focalPoint;
@@ -672,7 +675,7 @@ void writeSVGImage(TextStream& ts, const RenderSVGImage& image, int indent)
writeResources(ts, image, indent);
}
-void write(TextStream& ts, const RenderPath& path, int indent)
+void write(TextStream& ts, const RenderSVGPath& path, int indent)
{
writeStandardPrefix(ts, path, indent);
ts << path << "\n";
diff --git a/WebCore/rendering/SVGRenderTreeAsText.h b/WebCore/rendering/SVGRenderTreeAsText.h
index e279cfe..4e9ba5d 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.h
+++ b/WebCore/rendering/SVGRenderTreeAsText.h
@@ -39,16 +39,16 @@ namespace WebCore {
class RenderBlock;
class RenderImage;
class RenderObject;
- class RenderPath;
class RenderSVGGradientStop;
class RenderSVGImage;
+ class RenderSVGPath;
class RenderSVGRoot;
class RenderText;
class AffineTransform;
class SVGUnitTypes;
// functions used by the main RenderTreeAsText code
-void write(TextStream&, const RenderPath&, int indent);
+void write(TextStream&, const RenderSVGPath&, int indent);
void write(TextStream&, const RenderSVGRoot&, int indent);
void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent);
void writeSVGResourceContainer(TextStream&, const RenderObject&, int indent);
diff --git a/WebCore/rendering/SVGResources.cpp b/WebCore/rendering/SVGResources.cpp
index 799301b..f796f3b 100644
--- a/WebCore/rendering/SVGResources.cpp
+++ b/WebCore/rendering/SVGResources.cpp
@@ -160,11 +160,17 @@ static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document*
return 0;
id = SVGURIReference::getTarget(paint->uri());
- if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id))
- return container;
+ RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
+ if (!container) {
+ hasPendingResource = true;
+ return 0;
+ }
+
+ RenderSVGResourceType resourceType = container->resourceType();
+ if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
+ return 0;
- hasPendingResource = true;
- return 0;
+ return container;
}
static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element)
@@ -445,6 +451,8 @@ bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
if (!clipper)
return false;
+ ASSERT(clipper->resourceType() == ClipperResourceType);
+
if (!m_clipperFilterMaskerData)
m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
@@ -465,6 +473,8 @@ bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
if (!filter)
return false;
+ ASSERT(filter->resourceType() == FilterResourceType);
+
if (!m_clipperFilterMaskerData)
m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
@@ -485,6 +495,8 @@ bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
if (!markerStart)
return false;
+ ASSERT(markerStart->resourceType() == MarkerResourceType);
+
if (!m_markerData)
m_markerData = MarkerData::create();
@@ -504,6 +516,8 @@ bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
if (!markerMid)
return false;
+ ASSERT(markerMid->resourceType() == MarkerResourceType);
+
if (!m_markerData)
m_markerData = MarkerData::create();
@@ -523,6 +537,8 @@ bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
if (!markerEnd)
return false;
+ ASSERT(markerEnd->resourceType() == MarkerResourceType);
+
if (!m_markerData)
m_markerData = MarkerData::create();
@@ -542,6 +558,8 @@ bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
if (!masker)
return false;
+ ASSERT(masker->resourceType() == MaskerResourceType);
+
if (!m_clipperFilterMaskerData)
m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
@@ -561,6 +579,10 @@ bool SVGResources::setFill(RenderSVGResourceContainer* fill)
if (!fill)
return false;
+ ASSERT(fill->resourceType() == PatternResourceType
+ || fill->resourceType() == LinearGradientResourceType
+ || fill->resourceType() == RadialGradientResourceType);
+
if (!m_fillStrokeData)
m_fillStrokeData = FillStrokeData::create();
@@ -580,6 +602,10 @@ bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
if (!stroke)
return false;
+ ASSERT(stroke->resourceType() == PatternResourceType
+ || stroke->resourceType() == LinearGradientResourceType
+ || stroke->resourceType() == RadialGradientResourceType);
+
if (!m_fillStrokeData)
m_fillStrokeData = FillStrokeData::create();
diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp
deleted file mode 100644
index 715003f..0000000
--- a/WebCore/rendering/SVGRootInlineBox.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
- * (C) 2006 Apple Computer Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGRootInlineBox.h"
-
-#if ENABLE(SVG)
-#include "GraphicsContext.h"
-#include "RenderBlock.h"
-#include "SVGInlineFlowBox.h"
-#include "SVGInlineTextBox.h"
-#include "SVGRenderSupport.h"
-#include "SVGTextLayoutUtilities.h"
-#include "SVGTextPositioningElement.h"
-
-// Text chunk part propagation can be traced by setting this variable > 0.
-#define DEBUG_CHUNK_PART_PROPAGATION 0
-
-namespace WebCore {
-
-void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int)
-{
- ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
- ASSERT(!paintInfo.context->paintingDisabled());
-
- RenderObject* boxRenderer = renderer();
- ASSERT(boxRenderer);
-
- PaintInfo childPaintInfo(paintInfo);
- childPaintInfo.context->save();
-
- if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
- for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
- child->paint(childPaintInfo, 0, 0);
- }
-
- SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
- childPaintInfo.context->restore();
-}
-
-void SVGRootInlineBox::computePerCharacterLayoutInformation()
-{
- // Clean up any previous layout information
- m_svgChars.clear();
- m_svgTextChunks.clear();
-
- // Build layout information for all contained render objects
- SVGCharacterLayoutInfo charInfo;
- buildLayoutInformation(this, charInfo);
- m_svgChars = charInfo.svgChars;
-
- // Now all layout information are available for every character
- // contained in any of our child inline/flow boxes. Build list
- // of text chunks now, to be able to apply text-anchor shifts.
- SVGTextChunkLayoutInfo chunkInfo;
- chunkInfo.buildTextChunks(m_svgChars.begin(), m_svgChars.end(), this);
-
- // Layout all text chunks
- // text-anchor needs to be applied to individual chunks.
- chunkInfo.layoutTextChunks();
- m_svgTextChunks = chunkInfo.textChunks();
-
- // Propagate text chunk part information to all SVGInlineTextBoxes, see SVGTextChunkLayoutInfo.h for details
- propagateTextChunkPartInformation();
-
- // Layout all child boxes.
- layoutChildBoxes(this);
-
- // Resize our root box and our RenderSVGText parent block
- layoutRootBox();
-}
-
-void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo& info)
-{
- if (start->isRootInlineBox()) {
- ASSERT(start->renderer()->node()->hasTagName(SVGNames::textTag));
-
- SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(start->renderer()->node());
- ASSERT(positioningElement);
- ASSERT(positioningElement->parentNode());
-
- info.addLayoutInformation(positioningElement);
- }
-
- SVGLastGlyphInfo lastGlyph;
-
- for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
- if (curr->renderer()->isText())
- static_cast<SVGInlineTextBox*>(curr)->buildLayoutInformation(info, lastGlyph);
- else {
- ASSERT(curr->isInlineFlowBox());
- InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);
-
- // Skip generated content.
- if (!flowBox->renderer()->node())
- continue;
-
- bool isAnchor = flowBox->renderer()->node()->hasTagName(SVGNames::aTag);
- bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag);
-
- if (!isTextPath && !isAnchor) {
- SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(flowBox->renderer()->node());
- ASSERT(positioningElement);
- ASSERT(positioningElement->parentNode());
-
- info.addLayoutInformation(positioningElement);
- } else if (!isAnchor) {
- info.setInPathLayout(true);
-
- // Handle text-anchor/textLength on path, which is special.
- SVGTextContentElement* textContent = 0;
- Node* node = flowBox->renderer()->node();
- if (node && node->isSVGElement())
- textContent = static_cast<SVGTextContentElement*>(node);
- ASSERT(textContent);
-
- ELengthAdjust lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
- ETextAnchor anchor = flowBox->renderer()->style()->svgStyle()->textAnchor();
- float textAnchorStartOffset = 0.0f;
-
- // Initialize sub-layout. We need to create text chunks from the textPath
- // children using our standard layout code, to be able to measure the
- // text length using our normal methods and not textPath specific hacks.
- Vector<SVGTextChunk> tempChunks;
-
- SVGCharacterLayoutInfo tempCharInfo;
- buildLayoutInformation(flowBox, tempCharInfo);
-
- SVGTextChunkLayoutInfo tempChunkInfo;
- tempChunkInfo.buildTextChunks(tempCharInfo.svgChars.begin(), tempCharInfo.svgChars.end(), flowBox);
- tempChunks = tempChunkInfo.textChunks();
-
- Vector<SVGTextChunk>::iterator it = tempChunks.begin();
- Vector<SVGTextChunk>::iterator end = tempChunks.end();
-
- float computedLength = 0.0f;
-
- for (; it != end; ++it) {
- SVGTextChunk& chunk = *it;
-
- // Apply text-length calculation
- info.pathExtraAdvance += calculateTextLengthCorrectionForTextChunk(chunk, lengthAdjust, computedLength);
-
- if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
- info.pathTextLength += computedLength;
- info.pathChunkLength += chunk.textLength;
- }
-
- // Calculate text-anchor start offset
- if (anchor == TA_START)
- continue;
-
- textAnchorStartOffset += calculateTextAnchorShiftForTextChunk(chunk, anchor);
- }
-
- info.addLayoutInformation(flowBox, textAnchorStartOffset);
- }
-
- float shiftxSaved = info.shiftx;
- float shiftySaved = info.shifty;
-
- buildLayoutInformation(flowBox, info);
- info.processedChunk(shiftxSaved, shiftySaved);
-
- if (isTextPath)
- info.setInPathLayout(false);
- }
- }
-}
-
-void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start)
-{
- for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) {
- if (child->renderer()->isText()) {
- SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
- IntRect boxRect = textBox->calculateBoundaries();
- textBox->setX(boxRect.x());
- textBox->setY(boxRect.y());
- textBox->setLogicalWidth(boxRect.width());
- textBox->setLogicalHeight(boxRect.height());
- } else {
- ASSERT(child->isInlineFlowBox());
-
- // Skip generated content.
- if (!child->renderer()->node())
- continue;
-
- SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
- layoutChildBoxes(flowBox);
-
- IntRect boxRect = flowBox->calculateBoundaries();
- flowBox->setX(boxRect.x());
- flowBox->setY(boxRect.y());
- flowBox->setLogicalWidth(boxRect.width());
- flowBox->setLogicalHeight(boxRect.height());
- }
- }
-}
-
-void SVGRootInlineBox::layoutRootBox()
-{
- RenderBlock* parentBlock = block();
- ASSERT(parentBlock);
-
- IntRect childRect;
- for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
- // Skip generated content.
- if (!child->renderer()->node())
- continue;
- childRect.unite(child->calculateBoundaries());
- }
-
- int xBlock = childRect.x();
- int yBlock = childRect.y();
- int widthBlock = childRect.width();
- int heightBlock = childRect.height();
-
- // Finally, assign the root block position, now that all content is laid out.
- parentBlock->setLocation(xBlock, yBlock);
- parentBlock->setWidth(widthBlock);
- parentBlock->setHeight(heightBlock);
-
- // Position all children relative to the parent block.
- for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
- // Skip generated content.
- if (!child->renderer()->node())
- continue;
- child->adjustPosition(-xBlock, -yBlock);
- }
-
- // Position ourselves.
- setX(0);
- setY(0);
- setLogicalWidth(widthBlock);
- setLogicalHeight(heightBlock);
- setBlockHeight(heightBlock);
- setLineTopBottomPositions(0, heightBlock);
-}
-
-void SVGRootInlineBox::propagateTextChunkPartInformation()
-{
-#if DEBUG_CHUNK_PART_PROPAGATION > 0
- ListHashSet<SVGInlineTextBox*> boxes;
-#endif
-
- // Loop through all text chunks
- const Vector<SVGTextChunk>::const_iterator end = m_svgTextChunks.end();
- for (Vector<SVGTextChunk>::const_iterator it = m_svgTextChunks.begin(); it != end; ++it) {
- const SVGTextChunk& chunk = *it;
- int processedChunkCharacters = 0;
-
- // Loop through all ranges contained in this chunk
- const Vector<SVGInlineBoxCharacterRange>::const_iterator boxEnd = chunk.boxes.end();
- for (Vector<SVGInlineBoxCharacterRange>::const_iterator boxIt = chunk.boxes.begin(); boxIt != boxEnd; ++boxIt) {
- const SVGInlineBoxCharacterRange& range = *boxIt;
- ASSERT(range.box->isSVGInlineTextBox());
-
- // Access style & font information of this text box
- SVGInlineTextBox* rangeTextBox = static_cast<SVGInlineTextBox*>(range.box);
- rangeTextBox->setChunkTransformation(chunk.ctm);
-
- RenderText* text = rangeTextBox->textRenderer();
- ASSERT(text);
-
- RenderStyle* style = text->style();
- ASSERT(style);
-
- const Font& font = style->font();
-
- // Figure out first and last character of this range in this chunk
- int rangeLength = range.endOffset - range.startOffset;
- Vector<SVGChar>::iterator itCharBegin = chunk.start + processedChunkCharacters;
- Vector<SVGChar>::iterator itCharEnd = chunk.start + processedChunkCharacters + rangeLength;
- ASSERT(itCharEnd <= chunk.end);
-
- // Loop through all characters in range
- int processedRangeCharacters = 0;
- for (Vector<SVGChar>::iterator itChar = itCharBegin; itChar != itCharEnd; ++itChar) {
- if (itChar->isHidden()) {
- ++processedRangeCharacters;
- continue;
- }
-
- // Determine how many characters - starting from the current - can be drawn at once.
- Vector<SVGChar>::iterator itSearch = itChar + 1;
- while (itSearch != itCharEnd) {
- if (itSearch->drawnSeperated || itSearch->isHidden())
- break;
-
- ++itSearch;
- }
-
- // Calculate text chunk part information for this chunk sub-range
- const UChar* partStart = text->characters() + rangeTextBox->start() + range.startOffset + processedRangeCharacters;
-
- SVGTextChunkPart part;
- part.firstCharacter = itChar;
- part.length = itSearch - itChar;
- part.width = font.floatWidth(svgTextRunForInlineTextBox(partStart, part.length, style, rangeTextBox));
- part.height = font.height();
- part.offset = range.startOffset + processedRangeCharacters;
- rangeTextBox->addChunkPartInformation(part);
- processedRangeCharacters += part.length;
-
- // Skip processed characters
- itChar = itSearch - 1;
- }
-
- ASSERT(processedRangeCharacters == rangeLength);
- processedChunkCharacters += rangeLength;
-
-#if DEBUG_CHUNK_PART_PROPAGATION > 0
- boxes.add(rangeTextBox);
-#endif
- }
- }
-
-#if DEBUG_CHUNK_PART_PROPAGATION > 0
- {
- fprintf(stderr, "Propagated text chunk part information:\n");
-
- ListHashSet<SVGInlineTextBox*>::const_iterator it = boxes.begin();
- const ListHashSet<SVGInlineTextBox*>::const_iterator end = boxes.end();
-
- for (; it != end; ++it) {
- const SVGInlineTextBox* box = *it;
- const Vector<SVGTextChunkPart>& parts = box->svgTextChunkParts();
-
- fprintf(stderr, " Box %p contains %i text chunk parts:\n", box, static_cast<int>(parts.size()));
- Vector<SVGTextChunkPart>::const_iterator partIt = parts.begin();
- const Vector<SVGTextChunkPart>::const_iterator partEnd = parts.end();
- for (; partIt != partEnd; ++partIt) {
- const SVGTextChunkPart& part = *partIt;
- fprintf(stderr, " -> firstCharacter x=%lf, y=%lf, offset=%i, length=%i, width=%lf, height=%lf, textRenderer=%p\n"
- , part.firstCharacter->x, part.firstCharacter->y, part.offset, part.length, part.width, part.height, box->textRenderer());
- }
- }
- }
-#endif
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGTextChunkLayoutInfo.cpp b/WebCore/rendering/SVGTextChunkLayoutInfo.cpp
deleted file mode 100644
index a7a6d87..0000000
--- a/WebCore/rendering/SVGTextChunkLayoutInfo.cpp
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGTextChunkLayoutInfo.h"
-
-#if ENABLE(SVG)
-#include "InlineFlowBox.h"
-#include "SVGInlineTextBox.h"
-#include "SVGRenderStyle.h"
-
-// Text chunk creation is complex and the whole process
-// can easily be traced by setting this variable > 0.
-#define DEBUG_CHUNK_BUILDING 0
-
-namespace WebCore {
-
-static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWidthOnly)
-{
- float length = 0.0f;
- Vector<SVGChar>::iterator charIt = chunk.start;
-
- Vector<SVGInlineBoxCharacterRange>::iterator it = chunk.boxes.begin();
- Vector<SVGInlineBoxCharacterRange>::iterator end = chunk.boxes.end();
-
- for (; it != end; ++it) {
- SVGInlineBoxCharacterRange& range = *it;
-
- SVGInlineTextBox* box = static_cast<SVGInlineTextBox*>(range.box);
- RenderStyle* style = box->renderer()->style();
-
- for (int i = range.startOffset; i < range.endOffset; ++i) {
- ASSERT(charIt <= chunk.end);
-
- // Determine how many characters - starting from the current - can be measured at once.
- // Important for non-absolute positioned non-latin1 text (ie. Arabic) where ie. the width
- // of a string is not the sum of the boundaries of all contained glyphs.
- Vector<SVGChar>::iterator itSearch = charIt + 1;
- Vector<SVGChar>::iterator endSearch = charIt + range.endOffset - i;
- while (itSearch != endSearch) {
- // No need to check for 'isHidden()' here as this function is not called for text paths.
- if (itSearch->drawnSeperated)
- break;
-
- itSearch++;
- }
-
- unsigned int positionOffset = itSearch - charIt;
-
- // Calculate width/height of subrange
- SVGInlineBoxCharacterRange subRange;
- subRange.box = range.box;
- subRange.startOffset = i;
- subRange.endOffset = i + positionOffset;
-
- if (calcWidthOnly)
- length += cummulatedWidthOfInlineBoxCharacterRange(subRange);
- else
- length += cummulatedHeightOfInlineBoxCharacterRange(subRange);
-
- // Calculate gap between the previous & current range
- // <text x="10 50 70">ABCD</text> - we need to take the gaps between A & B into account
- // so add "40" as width, and analogous for B & C, add "20" as width.
- if (itSearch > chunk.start && itSearch < chunk.end) {
- SVGChar& lastCharacter = *(itSearch - 1);
- SVGChar& currentCharacter = *itSearch;
-
- int charsConsumed = 0;
- float glyphWidth = 0.0f;
- float glyphHeight = 0.0f;
- String glyphName;
- String unicodeString;
- box->measureCharacter(style, i + positionOffset - 1, charsConsumed, glyphName, unicodeString, glyphWidth, glyphHeight);
-
- if (calcWidthOnly)
- length += currentCharacter.x - lastCharacter.x - glyphWidth;
- else
- length += currentCharacter.y - lastCharacter.y - glyphHeight;
- }
-
- // Advance processed characters
- i += positionOffset - 1;
- charIt = itSearch;
- }
- }
-
- ASSERT(charIt == chunk.end);
- return length;
-}
-
-static float cummulatedWidthOfTextChunk(SVGTextChunk& chunk)
-{
- return cummulatedWidthOrHeightOfTextChunk(chunk, true);
-}
-
-static float cummulatedHeightOfTextChunk(SVGTextChunk& chunk)
-{
- return cummulatedWidthOrHeightOfTextChunk(chunk, false);
-}
-
-float calculateTextAnchorShiftForTextChunk(SVGTextChunk& chunk, ETextAnchor anchor)
-{
- float shift = 0.0f;
-
- if (chunk.isVerticalText)
- shift = cummulatedHeightOfTextChunk(chunk);
- else
- shift = cummulatedWidthOfTextChunk(chunk);
-
- if (anchor == TA_MIDDLE)
- shift *= -0.5f;
- else
- shift *= -1.0f;
-
- return shift;
-}
-
-static void applyTextAnchorToTextChunk(SVGTextChunk& chunk)
-{
- // This method is not called for chunks containing chars aligned on a path.
- // -> all characters are visible, no need to check for "isHidden()" anywhere.
-
- if (chunk.anchor == TA_START)
- return;
-
- float shift = calculateTextAnchorShiftForTextChunk(chunk, chunk.anchor);
-
- // Apply correction to chunk
- Vector<SVGChar>::iterator chunkIt = chunk.start;
- for (; chunkIt != chunk.end; ++chunkIt) {
- SVGChar& curChar = *chunkIt;
-
- if (chunk.isVerticalText)
- curChar.y += shift;
- else
- curChar.x += shift;
- }
-
- // Move inline boxes
- Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
- Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
-
- for (; boxIt != boxEnd; ++boxIt) {
- SVGInlineBoxCharacterRange& range = *boxIt;
-
- InlineBox* curBox = range.box;
- ASSERT(curBox->isSVGInlineTextBox());
-
- // Move target box
- if (chunk.isVerticalText)
- curBox->setY(curBox->y() + static_cast<int>(shift));
- else
- curBox->setX(curBox->x() + static_cast<int>(shift));
- }
-}
-
-float calculateTextLengthCorrectionForTextChunk(SVGTextChunk& chunk, ELengthAdjust lengthAdjust, float& computedLength)
-{
- if (chunk.textLength <= 0.0f)
- return 0.0f;
-
- computedLength = 0.0f;
-
- float computedWidth = cummulatedWidthOfTextChunk(chunk);
- float computedHeight = cummulatedHeightOfTextChunk(chunk);
- if ((computedWidth <= 0.0f && !chunk.isVerticalText)
- || (computedHeight <= 0.0f && chunk.isVerticalText))
- return 0.0f;
-
- computedLength = chunk.isVerticalText ? computedHeight : computedWidth;
- if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
- if (chunk.isVerticalText)
- chunk.ctm.scaleNonUniform(1.0f, chunk.textLength / computedLength);
- else
- chunk.ctm.scaleNonUniform(chunk.textLength / computedLength, 1.0f);
-
- return 0.0f;
- }
-
- return (chunk.textLength - computedLength) / float(chunk.end - chunk.start);
-}
-
-static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk)
-{
- // This method is not called for chunks containing chars aligned on a path.
- // -> all characters are visible, no need to check for "isHidden()" anywhere.
-
- // lengthAdjust="spacingAndGlyphs" is handled by setting a scale factor for the whole chunk
- float textLength = 0.0f;
- float spacingToApply = calculateTextLengthCorrectionForTextChunk(chunk, chunk.lengthAdjust, textLength);
-
- if (!chunk.ctm.isIdentity() && chunk.lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
- SVGChar& firstChar = *(chunk.start);
-
- // Assure we apply the chunk scaling in the right origin
- AffineTransform newChunkCtm(chunk.ctm);
- newChunkCtm.translateRight(firstChar.x, firstChar.y);
- newChunkCtm.translate(-firstChar.x, -firstChar.y);
-
- chunk.ctm = newChunkCtm;
- }
-
- // Apply correction to chunk
- if (spacingToApply != 0.0f) {
- Vector<SVGChar>::iterator chunkIt = chunk.start;
- for (; chunkIt != chunk.end; ++chunkIt) {
- SVGChar& curChar = *chunkIt;
- curChar.drawnSeperated = true;
-
- if (chunk.isVerticalText)
- curChar.y += (chunkIt - chunk.start) * spacingToApply;
- else
- curChar.x += (chunkIt - chunk.start) * spacingToApply;
- }
- }
-}
-
-void SVGTextChunkLayoutInfo::startTextChunk()
-{
- m_chunk.boxes.clear();
- m_chunk.boxes.append(SVGInlineBoxCharacterRange());
-
- m_chunk.start = m_charsIt;
- m_assignChunkProperties = true;
-}
-
-void SVGTextChunkLayoutInfo::closeTextChunk()
-{
- ASSERT(!m_chunk.boxes.last().isOpen());
- ASSERT(m_chunk.boxes.last().isClosed());
-
- m_chunk.end = m_charsIt;
- ASSERT(m_chunk.end >= m_chunk.start);
-
- m_svgTextChunks.append(m_chunk);
-}
-
-void SVGTextChunkLayoutInfo::buildTextChunks(Vector<SVGChar>::iterator begin, Vector<SVGChar>::iterator end, InlineFlowBox* start)
-{
- m_charsBegin = begin;
- m_charsEnd = end;
-
- m_charsIt = begin;
- m_chunk = SVGTextChunk(begin);
-
- recursiveBuildTextChunks(start);
- ASSERT(m_charsIt == m_charsEnd);
-}
-
-void SVGTextChunkLayoutInfo::recursiveBuildTextChunks(InlineFlowBox* start)
-{
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> buildTextChunks(start=%p)\n", start);
-#endif
-
- for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
- if (curr->renderer()->isText()) {
- InlineTextBox* textBox = static_cast<InlineTextBox*>(curr);
-
- unsigned length = textBox->len();
- ASSERT(length > 0);
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Handle inline text box (%p) with %i characters (start: %i, end: %i), handlingTextPath=%i\n",
- textBox, length, textBox->start(), textBox->end(), (int) m_handlingTextPath);
-#endif
-
- RenderText* text = textBox->textRenderer();
- ASSERT(text);
- ASSERT(text->node());
-
- SVGTextContentElement* textContent = 0;
- Node* node = text->node()->parent();
- while (node && node->isSVGElement() && !textContent) {
- if (static_cast<SVGElement*>(node)->isTextContent())
- textContent = static_cast<SVGTextContentElement*>(node);
- else
- node = node->parentNode();
- }
- ASSERT(textContent);
-
- // Start new character range for the first chunk
- bool isFirstCharacter = m_svgTextChunks.isEmpty() && m_chunk.start == m_charsIt && m_chunk.start == m_chunk.end;
- if (isFirstCharacter) {
- ASSERT(m_chunk.boxes.isEmpty());
- m_chunk.boxes.append(SVGInlineBoxCharacterRange());
- } else
- ASSERT(!m_chunk.boxes.isEmpty());
-
- // Walk string to find out new chunk positions, if existent
- for (unsigned i = 0; i < length; ++i) {
- ASSERT(m_charsIt != m_charsEnd);
-
- SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();
- if (range.isOpen()) {
- range.box = curr;
- range.startOffset = !i ? 0 : i - 1;
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset);
-#endif
- }
-
- // If a new (or the first) chunk has been started, record it's text-anchor and writing mode.
- if (m_assignChunkProperties) {
- m_assignChunkProperties = false;
-
- m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
- m_chunk.isTextPath = m_handlingTextPath;
- m_chunk.anchor = text->style()->svgStyle()->textAnchor();
- m_chunk.textLength = textContent->textLength().value(textContent);
- m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", m_chunk.isVerticalText, m_chunk.anchor);
-#endif
- }
-
- if (i > 0 && !isFirstCharacter && m_charsIt->newTextChunk) {
- // Close mid chunk & character range
- ASSERT(!range.isOpen());
- ASSERT(!range.isClosed());
-
- range.endOffset = i;
- closeTextChunk();
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " | -> Close mid-text chunk, at endOffset: %i and starting new mid chunk!\n", range.endOffset);
-#endif
-
- // Prepare for next chunk, if we're not at the end
- startTextChunk();
- if (i + 1 == length) {
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " | -> Record last chunk of inline text box!\n");
-#endif
-
- startTextChunk();
- SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();
-
- m_assignChunkProperties = false;
- m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
- m_chunk.isTextPath = m_handlingTextPath;
- m_chunk.anchor = text->style()->svgStyle()->textAnchor();
- m_chunk.textLength = textContent->textLength().value(textContent);
- m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
-
- range.box = curr;
- range.startOffset = i;
-
- ASSERT(!range.isOpen());
- ASSERT(!range.isClosed());
- }
- }
-
- // This should only hold true for the first character of the first chunk
- if (isFirstCharacter)
- isFirstCharacter = false;
-
- ++m_charsIt;
- }
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Finished inline text box!\n");
-#endif
-
- SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();
- if (!range.isOpen() && !range.isClosed()) {
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Last range not closed - closing with endOffset: %i\n", length);
-#endif
-
- // Current text chunk is not yet closed. Finish the current range, but don't start a new chunk.
- range.endOffset = length;
-
- if (m_charsIt != m_charsEnd) {
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Not at last character yet!\n");
-#endif
-
- // If we're not at the end of the last box to be processed, and if the next
- // character starts a new chunk, then close the current chunk and start a new one.
- if (m_charsIt->newTextChunk) {
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n");
-#endif
-
- closeTextChunk();
- startTextChunk();
- } else {
- // Just start a new character range
- m_chunk.boxes.append(SVGInlineBoxCharacterRange());
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Next character does NOT start a new chunk! Starting new character range...\n");
-#endif
- }
- } else {
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Closing final chunk! Finished processing!\n");
-#endif
-
- // Close final chunk, once we're at the end of the last box
- closeTextChunk();
- }
- }
- } else {
- ASSERT(curr->isInlineFlowBox());
- InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);
-
- // Skip generated content.
- if (!flowBox->renderer()->node())
- continue;
-
- bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag);
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath);
-#endif
-
- if (isTextPath)
- m_handlingTextPath = true;
-
- recursiveBuildTextChunks(flowBox);
-
- if (isTextPath)
- m_handlingTextPath = false;
- }
- }
-
-#if DEBUG_CHUNK_BUILDING > 1
- fprintf(stderr, " <- buildTextChunks(start=%p)\n", start);
-#endif
-}
-
-void SVGTextChunkLayoutInfo::layoutTextChunks()
-{
- Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin();
- Vector<SVGTextChunk>::iterator end = m_svgTextChunks.end();
-
- for (; it != end; ++it) {
- SVGTextChunk& chunk = *it;
-
-#if DEBUG_CHUNK_BUILDING > 0
- {
- fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, textLength=%f, lengthAdjust=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n",
- (int) chunk.anchor, chunk.textLength, (int) chunk.lengthAdjust, (int) chunk.isVerticalText,
- (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end - chunk.start));
-
- Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
- Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
-
- unsigned int i = 0;
- for (; boxIt != boxEnd; ++boxIt) {
- SVGInlineBoxCharacterRange& range = *boxIt;
- ++i;
- fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box);
- }
- }
-#endif
-
- if (chunk.isTextPath)
- continue;
-
- // text-path & textLength, with lengthAdjust="spacing" is already handled for textPath layouts.
- applyTextLengthCorrectionToTextChunk(chunk);
-
- // text-anchor is already handled for textPath layouts.
- applyTextAnchorToTextChunk(chunk);
- }
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGTextChunkLayoutInfo.h b/WebCore/rendering/SVGTextChunkLayoutInfo.h
deleted file mode 100644
index e06dd1a..0000000
--- a/WebCore/rendering/SVGTextChunkLayoutInfo.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 SVGTextChunkLayoutInfo_h
-#define SVGTextChunkLayoutInfo_h
-
-#if ENABLE(SVG)
-#include "AffineTransform.h"
-#include "SVGCharacterData.h"
-#include "SVGRenderStyle.h"
-#include "SVGTextContentElement.h"
-
-#include <wtf/Assertions.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class InlineBox;
-class InlineFlowBox;
-class SVGInlineTextBox;
-
-// A SVGTextChunk directly corresponds to the definition of a "text chunk" per SVG 1.1 specification
-// For example, each absolute positioned character starts a text chunk (much more to respect, see spec).
-// Each SVGTextChunk contains a Vector of SVGInlineBoxCharacterRange, describing how many boxes are spanned
-// by this chunk. Following two examples should clarify the code a bit:
-//
-// 1. <text x="10 20 30">ABC</text> - one InlineTextBox is created, three SVGTextChunks each with one SVGInlineBoxCharaterRange
-// [SVGTextChunk 1]
-// [SVGInlineBoxCharacterRange 1, startOffset=0, endOffset=1, box=0x1]
-// [SVGTextChunk 2]
-// [SVGInlineBoxCharacterRange 1, startOffset=1, endOffset=2, box=0x1]
-// [SVGTextChunk 3]
-// [SVGInlineBoxCharacterRange 1, startOffset=2, endOffset=3, box=0x1]
-//
-// 2. <text x="10">A<tspan>B</tspan>C</text> - three InlineTextBoxs are created, one SVGTextChunk, with three SVGInlineBoxCharacterRanges
-// [SVGTextChunk 1]
-// [SVGInlineBoxCharacterRange 1, startOffset=0, endOffset=1, box=0x1]
-// [SVGInlineBoxCharacterRange 2, startOffset=0, endOffset=1, box=0x2]
-// [SVGInlineBoxCharacterRange 3, startOffset=0, endOffset=1, box=0x3]
-//
-// High level overview of the SVG text layout code:
-// Step #1) - Build Vector of SVGChar objects starting from root <text> diving into children
-// Step #2) - Build Vector of SVGTextChunk objects, containing offsets into the InlineTextBoxes and SVGChar vectors
-// Step #3) - Apply chunk post processing (text-anchor / textLength support, which operate on text chunks!)
-// Step #4) - Propagate information, how many chunk "parts" are associated with each SVGInlineTextBox (see below)
-// Step #5) - Layout all InlineBoxes, only by measuring their context rect (x/y/width/height defined through SVGChars and transformations)
-// Step #6) - Layout SVGRootInlineBox, it's parent RenderSVGText block and fixup child positions, to be relative to the root box
-//
-// When painting a range of characters, we have to determine how many can be drawn in a row. Each absolute postioned
-// character is drawn individually. After step #2) we know all text chunks, and how they span across the SVGInlineTextBoxes.
-// In step #4) we build a list of text chunk "parts" and store it in each SVGInlineTextBox. A chunk "part" is a part of a
-// text chunk that lives in a SVGInlineTextBox (consists of a length, width, height and a monotonic offset from the chunk begin)
-// The SVGTextChunkPart object describes this information.
-// When painting we can follow the regular InlineBox flow, we start painting the SVGRootInlineBox, which just asks its children
-// to paint. They can paint on their own because all position information are known. Previously we used to draw _all_ characters
-// from the SVGRootInlineBox, which violates the whole concept of the multiple InlineBoxes, and made text selection very hard to
-// implement.
-
-struct SVGTextChunkPart {
- SVGTextChunkPart()
- : offset(-1)
- , length(-1)
- , width(0)
- , height(0)
- {
- }
-
- bool isValid() const
- {
- return offset != -1
- && length != -1
- && width
- && height;
- }
-
- // First character of this text chunk part, defining the origin to be drawn
- Vector<SVGChar>::const_iterator firstCharacter;
-
- // Start offset in textRenderer()->characters() buffer.
- int offset;
-
- // length/width/height of chunk part
- int length;
- float width;
- float height;
-};
-
-struct SVGInlineBoxCharacterRange {
- SVGInlineBoxCharacterRange()
- : startOffset(INT_MIN)
- , endOffset(INT_MIN)
- , box(0)
- {
- }
-
- bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); }
- bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; }
-
- int startOffset;
- int endOffset;
-
- InlineBox* box;
-};
-
-struct SVGChar;
-
-// Convenience typedef
-typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust;
-
-struct SVGTextChunk {
- SVGTextChunk(Vector<SVGChar>::iterator it)
- : anchor(TA_START)
- , textLength(0.0f)
- , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING)
- , isVerticalText(false)
- , isTextPath(false)
- , start(it)
- , end(it)
- {
- }
-
- // text-anchor support
- ETextAnchor anchor;
-
- // textLength & lengthAdjust support
- float textLength;
- ELengthAdjust lengthAdjust;
- AffineTransform ctm;
-
- // status flags
- bool isVerticalText : 1;
- bool isTextPath : 1;
-
- // main chunk data
- Vector<SVGChar>::iterator start;
- Vector<SVGChar>::iterator end;
-
- Vector<SVGInlineBoxCharacterRange> boxes;
-};
-
-struct SVGTextChunkLayoutInfo {
- SVGTextChunkLayoutInfo()
- : m_assignChunkProperties(true)
- , m_handlingTextPath(false)
- , m_charsIt(0)
- , m_charsBegin(0)
- , m_charsEnd(0)
- , m_chunk(0)
- {
- }
-
- const Vector<SVGTextChunk>& textChunks() const { return m_svgTextChunks; }
-
- void buildTextChunks(Vector<SVGChar>::iterator charsBegin, Vector<SVGChar>::iterator charsEnd, InlineFlowBox* start);
- void layoutTextChunks();
-
-private:
- void startTextChunk();
- void closeTextChunk();
- void recursiveBuildTextChunks(InlineFlowBox* start);
-
- bool m_assignChunkProperties : 1;
- bool m_handlingTextPath : 1;
-
- Vector<SVGChar>::iterator m_charsIt;
- Vector<SVGChar>::iterator m_charsBegin;
- Vector<SVGChar>::iterator m_charsEnd;
-
- Vector<SVGTextChunk> m_svgTextChunks;
- SVGTextChunk m_chunk;
-};
-
-// Helper functions
-float calculateTextAnchorShiftForTextChunk(SVGTextChunk&, ETextAnchor);
-float calculateTextLengthCorrectionForTextChunk(SVGTextChunk&, ELengthAdjust, float& computedLength);
-
-} // namespace WebCore
-
-#endif // ENABLE(SVG)
-#endif // SVGTextChunkLayoutInfo_h
diff --git a/WebCore/rendering/SVGTextLayoutUtilities.cpp b/WebCore/rendering/SVGTextLayoutUtilities.cpp
deleted file mode 100644
index 2debf28..0000000
--- a/WebCore/rendering/SVGTextLayoutUtilities.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGTextLayoutUtilities.h"
-
-#if ENABLE(SVG)
-#include "FloatPoint.h"
-#include "InlineTextBox.h"
-#include "RenderObject.h"
-#include "SVGCharacterData.h"
-#include "SVGCharacterLayoutInfo.h"
-#include "SVGFontElement.h"
-#include "SVGRenderStyle.h"
-#include "SVGTextChunkLayoutInfo.h"
-#include "TextRun.h"
-#include "UnicodeRange.h"
-
-#include <float.h>
-
-namespace WebCore {
-
-bool isVerticalWritingMode(const SVGRenderStyle* style)
-{
- return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB;
-}
-
-static inline EAlignmentBaseline dominantBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font)
-{
- ASSERT(text);
-
- const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0;
- ASSERT(style);
-
- const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0;
-
- EDominantBaseline baseline = style->dominantBaseline();
- if (baseline == DB_AUTO) {
- if (isVerticalText)
- baseline = DB_CENTRAL;
- else
- baseline = DB_ALPHABETIC;
- }
-
- switch (baseline) {
- case DB_USE_SCRIPT:
- // TODO: The dominant-baseline and the baseline-table components are set by
- // determining the predominant script of the character data content.
- return AB_ALPHABETIC;
- case DB_NO_CHANGE:
- {
- if (parentStyle)
- return dominantBaselineToShift(isVerticalText, text->parent(), font);
-
- ASSERT_NOT_REACHED();
- return AB_AUTO;
- }
- case DB_RESET_SIZE:
- {
- if (parentStyle)
- return dominantBaselineToShift(isVerticalText, text->parent(), font);
-
- ASSERT_NOT_REACHED();
- return AB_AUTO;
- }
- case DB_IDEOGRAPHIC:
- return AB_IDEOGRAPHIC;
- case DB_ALPHABETIC:
- return AB_ALPHABETIC;
- case DB_HANGING:
- return AB_HANGING;
- case DB_MATHEMATICAL:
- return AB_MATHEMATICAL;
- case DB_CENTRAL:
- return AB_CENTRAL;
- case DB_MIDDLE:
- return AB_MIDDLE;
- case DB_TEXT_AFTER_EDGE:
- return AB_TEXT_AFTER_EDGE;
- case DB_TEXT_BEFORE_EDGE:
- return AB_TEXT_BEFORE_EDGE;
- default:
- ASSERT_NOT_REACHED();
- return AB_AUTO;
- }
-}
-
-float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font)
-{
- ASSERT(text);
-
- const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0;
- ASSERT(style);
-
- const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0;
-
- EAlignmentBaseline baseline = style->alignmentBaseline();
- if (baseline == AB_AUTO) {
- if (parentStyle && style->dominantBaseline() == DB_AUTO)
- baseline = dominantBaselineToShift(isVerticalText, text->parent(), font);
- else
- baseline = dominantBaselineToShift(isVerticalText, text, font);
-
- ASSERT(baseline != AB_AUTO);
- }
-
- // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
- switch (baseline) {
- case AB_BASELINE:
- {
- if (parentStyle)
- return dominantBaselineToShift(isVerticalText, text->parent(), font);
-
- return 0.0f;
- }
- case AB_BEFORE_EDGE:
- case AB_TEXT_BEFORE_EDGE:
- return font.ascent();
- case AB_MIDDLE:
- return font.xHeight() / 2.0f;
- case AB_CENTRAL:
- // Not needed, we're taking this into account already for vertical text!
- // return (font.ascent() - font.descent()) / 2.0f;
- return 0.0f;
- case AB_AFTER_EDGE:
- case AB_TEXT_AFTER_EDGE:
- case AB_IDEOGRAPHIC:
- return font.descent();
- case AB_ALPHABETIC:
- return 0.0f;
- case AB_HANGING:
- return font.ascent() * 8.0f / 10.0f;
- case AB_MATHEMATICAL:
- return font.ascent() / 2.0f;
- default:
- ASSERT_NOT_REACHED();
- return 0.0f;
- }
-}
-
-float glyphOrientationToAngle(const SVGRenderStyle* svgStyle, bool isVerticalText, const UChar& character)
-{
- switch (isVerticalText ? svgStyle->glyphOrientationVertical() : svgStyle->glyphOrientationHorizontal()) {
- case GO_AUTO:
- {
- // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees.
- // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees.
- unsigned int unicodeRange = findCharUnicodeRange(character);
- if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic)
- return 90.0f;
-
- return 0.0f;
- }
- case GO_90DEG:
- return 90.0f;
- case GO_180DEG:
- return 180.0f;
- case GO_270DEG:
- return 270.0f;
- case GO_0DEG:
- default:
- return 0.0f;
- }
-}
-
-static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
-{
- return fabsf(fmodf(orientationAngle, 180.0f)) == 0.0f;
-}
-
-float applyGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font& font, SVGChar& svgChar, float& xOrientationShift, float& yOrientationShift)
-{
- bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(orientationAngle);
-
- // The function is based on spec requirements:
- //
- // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of
- // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph.
- //
- // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of
- // 180 degrees,then the current text position is incremented according to the horizontal metrics of the glyph.
-
- // vertical orientation handling
- if (isVerticalText) {
- if (orientationAngle == 0.0f) {
- xOrientationShift = -glyphWidth / 2.0f;
- yOrientationShift = font.ascent();
- } else if (orientationAngle == 90.0f) {
- xOrientationShift = -glyphHeight;
- yOrientationShift = font.descent();
- svgChar.orientationShiftY = -font.ascent();
- } else if (orientationAngle == 270.0f) {
- xOrientationShift = glyphHeight;
- yOrientationShift = font.descent();
- svgChar.orientationShiftX = -glyphWidth;
- svgChar.orientationShiftY = -font.ascent();
- } else if (orientationAngle == 180.0f) {
- yOrientationShift = font.ascent();
- svgChar.orientationShiftX = -glyphWidth / 2.0f;
- svgChar.orientationShiftY = font.ascent() - font.descent();
- }
-
- // vertical advance calculation
- if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees)
- return glyphWidth;
-
- return glyphHeight;
- }
-
- // horizontal orientation handling
- if (orientationAngle == 90.0f) {
- xOrientationShift = glyphWidth / 2.0f;
- yOrientationShift = -font.descent();
- svgChar.orientationShiftX = -glyphWidth / 2.0f - font.descent();
- svgChar.orientationShiftY = font.descent();
- } else if (orientationAngle == 270.0f) {
- xOrientationShift = -glyphWidth / 2.0f;
- yOrientationShift = -font.descent();
- svgChar.orientationShiftX = -glyphWidth / 2.0f + font.descent();
- svgChar.orientationShiftY = glyphHeight;
- } else if (orientationAngle == 180.0f) {
- xOrientationShift = glyphWidth / 2.0f;
- svgChar.orientationShiftX = -glyphWidth / 2.0f;
- svgChar.orientationShiftY = font.ascent() - font.descent();
- }
-
- // horizontal advance calculation
- if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees)
- return glyphHeight;
-
- return glyphWidth;
-}
-
-FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator it, Vector<SVGChar>::iterator end)
-{
- float lowX = FLT_MAX, lowY = FLT_MAX;
- for (; it != end; ++it) {
- if (it->isHidden())
- continue;
-
- float x = (*it).x;
- float y = (*it).y;
-
- if (x < lowX)
- lowX = x;
-
- if (y < lowY)
- lowY = y;
- }
-
- return FloatPoint(lowX, lowY);
-}
-
-float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range)
-{
- ASSERT(!range.isOpen());
- ASSERT(range.isClosed());
- ASSERT(range.box->isSVGInlineTextBox());
-
- InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box);
- RenderText* text = textBox->textRenderer();
- RenderStyle* style = text->style();
- return style->font().floatWidth(svgTextRunForInlineTextBox(text->characters() + textBox->start() + range.startOffset, range.endOffset - range.startOffset, style, textBox));
-}
-
-float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range)
-{
- ASSERT(!range.isOpen());
- ASSERT(range.isClosed());
- ASSERT(range.box->isSVGInlineTextBox());
-
- InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box);
- return (range.endOffset - range.startOffset) * textBox->textRenderer()->style()->font().height();
-}
-
-TextRun svgTextRunForInlineTextBox(const UChar* characters, int length, const RenderStyle* style, const InlineTextBox* textBox)
-{
- ASSERT(textBox);
- ASSERT(style);
-
- TextRun run(characters
- , length
- , false /* allowTabs */
- , 0 /* xPos, only relevant with allowTabs=true */
- , 0 /* padding, only relevant for justified text, not relevant for SVG */
- , textBox->direction() == RTL
- , textBox->m_dirOverride || style->visuallyOrdered() /* directionalOverride */);
-
-#if ENABLE(SVG_FONTS)
- run.setReferencingRenderObject(textBox->textRenderer()->parent());
-#endif
-
- // Disable any word/character rounding.
- run.disableRoundingHacks();
-
- // We handle letter & word spacing ourselves.
- run.disableSpacing();
- return run;
-}
-
-float calculateCSSKerning(SVGElement* context, const RenderStyle* style)
-{
- const Font& font = style->font();
- const SVGRenderStyle* svgStyle = style->svgStyle();
-
- SVGLength kerningLength = svgStyle->kerning();
- if (kerningLength.unitType() == LengthTypePercentage)
- return kerningLength.valueAsPercentage() * font.pixelSize();
-
- return kerningLength.value(context);
-}
-
-bool applySVGKerning(SVGCharacterLayoutInfo& info, const RenderStyle* style, SVGLastGlyphInfo& lastGlyph, const String& unicodeString, const String& glyphName, bool isVerticalText)
-{
-#if ENABLE(SVG_FONTS)
- float kerning = 0.0f;
-
- const Font& font = style->font();
- if (!font.isSVGFont()) {
- lastGlyph.isValid = false;
- return false;
- }
-
- SVGFontElement* svgFont = font.svgFont();
- ASSERT(svgFont);
-
- if (lastGlyph.isValid) {
- if (isVerticalText)
- kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName);
- else
- kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName);
- }
-
- lastGlyph.unicode = unicodeString;
- lastGlyph.glyphName = glyphName;
- lastGlyph.isValid = true;
- kerning *= style->font().size() / style->font().primaryFont()->unitsPerEm();
-
- if (kerning != 0.0f) {
- if (isVerticalText)
- info.cury -= kerning;
- else
- info.curx -= kerning;
- return true;
- }
-#else
- UNUSED_PARAM(info);
- UNUSED_PARAM(item);
- UNUSED_PARAM(lastGlyph);
- UNUSED_PARAM(unicodeString);
- UNUSED_PARAM(glyphName);
-#endif
- return false;
-}
-
-}
-
-#endif
diff --git a/WebCore/rendering/SVGTextLayoutUtilities.h b/WebCore/rendering/SVGTextLayoutUtilities.h
deleted file mode 100644
index 459d682..0000000
--- a/WebCore/rendering/SVGTextLayoutUtilities.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
- Copyright (C) Research In Motion Limited 2010. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 SVGTextLayoutUtilities_h
-#define SVGTextLayoutUtilities_h
-
-#if ENABLE(SVG)
-#include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebCore {
-
-class FloatPoint;
-class Font;
-class InlineTextBox;
-class RenderObject;
-class RenderStyle;
-class SVGElement;
-class SVGRenderStyle;
-class TextRun;
-
-struct SVGChar;
-struct SVGCharacterLayoutInfo;
-struct SVGInlineBoxCharacterRange;
-
-struct SVGLastGlyphInfo {
- SVGLastGlyphInfo()
- : isValid(false)
- {
- }
-
- bool isValid;
- String unicode;
- String glyphName;
-};
-
-bool isVerticalWritingMode(const SVGRenderStyle*);
-float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font&);
-float glyphOrientationToAngle(const SVGRenderStyle*, bool isVerticalText, const UChar&);
-float applyGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font&,
- SVGChar&, float& xOrientationShift, float& yOrientationShift);
-FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator start, Vector<SVGChar>::iterator end);
-float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange&);
-float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange&);
-TextRun svgTextRunForInlineTextBox(const UChar*, int length, const RenderStyle*, const InlineTextBox*);
-
-float calculateCSSKerning(SVGElement* context, const RenderStyle*);
-bool applySVGKerning(SVGCharacterLayoutInfo&, const RenderStyle*, SVGLastGlyphInfo&, const String& unicodeString, const String& glyphName, bool isVerticalText);
-
-}
-
-#endif
-#endif
diff --git a/WebCore/rendering/SVGTextQuery.cpp b/WebCore/rendering/SVGTextQuery.cpp
deleted file mode 100644
index 35ca690..0000000
--- a/WebCore/rendering/SVGTextQuery.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- 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
- 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 "SVGTextQuery.h"
-
-#if ENABLE(SVG)
-#include "FloatConversion.h"
-#include "InlineFlowBox.h"
-#include "RenderBlock.h"
-#include "RenderInline.h"
-#include "SVGInlineTextBox.h"
-#include "VisiblePosition.h"
-
-namespace WebCore {
-
-// Base structure for callback user data
-struct SVGTextQuery::Data {
- Data()
- : processedChunkCharacters(0)
- {
- }
-
- unsigned processedChunkCharacters;
-};
-
-static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer)
-{
- if (!renderer)
- return 0;
-
- if (renderer->isRenderBlock()) {
- // If we're given a block element, it has to be a RenderSVGText.
- ASSERT(renderer->isSVGText());
- RenderBlock* renderBlock = toRenderBlock(renderer);
-
- // RenderSVGText only ever contains a single line box.
- InlineFlowBox* flowBox = renderBlock->firstLineBox();
- ASSERT(flowBox == renderBlock->lastLineBox());
- return flowBox;
- }
-
- if (renderer->isRenderInline()) {
- // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath)
- RenderInline* renderInline = toRenderInline(renderer);
-
- // RenderSVGInline only ever contains a single line box.
- InlineFlowBox* flowBox = renderInline->firstLineBox();
- ASSERT(flowBox == renderInline->lastLineBox());
- return flowBox;
- }
-
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-static inline float mapLengthThroughChunkTransformation(const SVGInlineTextBox* textBox, bool isVerticalText, float length)
-{
- const AffineTransform& transform = textBox->chunkTransformation();
- if (transform.isIdentity())
- return length;
-
- return narrowPrecisionToFloat(static_cast<double>(length) * (isVerticalText ? transform.d() : transform.a()));
-}
-
-SVGTextQuery::SVGTextQuery(RenderObject* renderer)
-{
- collectTextBoxesInFlowBox(flowBoxForRenderer(renderer));
-}
-
-void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox)
-{
- if (!flowBox)
- return;
-
- for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) {
- if (child->isInlineFlowBox()) {
- // Skip generated content.
- if (!child->renderer()->node())
- continue;
-
- collectTextBoxesInFlowBox(static_cast<InlineFlowBox*>(child));
- continue;
- }
-
- ASSERT(child->isSVGInlineTextBox());
- m_textBoxes.append(static_cast<SVGInlineTextBox*>(child));
- }
-}
-
-bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextChunkPartCallback chunkPartCallback) const
-{
- ASSERT(!m_textBoxes.isEmpty());
- bool finished = false;
-
- // Loop over all text boxes
- const Vector<SVGInlineTextBox*>::const_iterator end = m_textBoxes.end();
- for (Vector<SVGInlineTextBox*>::const_iterator it = m_textBoxes.begin(); it != end; ++it) {
- const SVGInlineTextBox* textBox = *it;
- const Vector<SVGTextChunkPart>& parts = textBox->svgTextChunkParts();
-
- int processedCharacters = 0;
-
- // Loop over all text chunk parts in this text box, firing a callback for each chunk part.
- const Vector<SVGTextChunkPart>::const_iterator partEnd = parts.end();
- for (Vector<SVGTextChunkPart>::const_iterator partIt = parts.begin(); partIt != partEnd; ++partIt) {
- if ((this->*chunkPartCallback)(queryData, textBox, *partIt)) {
- finished = true;
- break;
- }
-
- processedCharacters += partIt->length;
- }
-
- if (finished)
- break;
-
- queryData->processedChunkCharacters += processedCharacters;
- }
-
- return finished;
-}
-
-bool SVGTextQuery::mapStartAndLengthIntoChunkPartCoordinates(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part, int& startPosition, int& endPosition) const
-{
- // Reuse the same logic used for text selection & painting, to map our query start/length into start/endPositions of the current text chunk part.
- startPosition -= queryData->processedChunkCharacters;
- endPosition -= queryData->processedChunkCharacters;
- textBox->mapStartEndPositionsIntoChunkPartCoordinates(startPosition, endPosition, part);
-
- // If startPosition < endPosition, then the position we're supposed to measure lies in this chunk part.
- return startPosition < endPosition;
-}
-
-float SVGTextQuery::measureCharacterRange(const SVGInlineTextBox* textBox, RenderStyle* style, bool isVerticalText, int startPosition, int length) const
-{
- // FIXME: Vertical writing mode needs to be handled more accurate.
- if (isVerticalText)
- return length * style->font().height();
-
- const UChar* startCharacter = textBox->textRenderer()->characters() + textBox->start() + startPosition;
- return style->font().floatWidth(svgTextRunForInlineTextBox(startCharacter, length, style, textBox));
-}
-
-// numberOfCharacters() implementation
-struct NumberOfCharactersData : SVGTextQuery::Data {
- NumberOfCharactersData()
- : characters(0)
- {
- }
-
- unsigned characters;
-};
-
-bool SVGTextQuery::numberOfCharactersCallback(Data* queryData, const SVGInlineTextBox*, const SVGTextChunkPart& part) const
-{
- NumberOfCharactersData* data = static_cast<NumberOfCharactersData*>(queryData);
- data->characters += part.length;
- return false;
-}
-
-unsigned SVGTextQuery::numberOfCharacters() const
-{
- if (m_textBoxes.isEmpty())
- return 0;
-
- NumberOfCharactersData data;
- executeQuery(&data, &SVGTextQuery::numberOfCharactersCallback);
- return data.characters;
-}
-
-// textLength() implementation
-struct TextLengthData : SVGTextQuery::Data {
- TextLengthData()
- : textLength(0.0f)
- {
- }
-
- float textLength;
-};
-
-bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- TextLengthData* data = static_cast<TextLengthData*>(queryData);
-
- RenderStyle* style = textBox->textRenderer()->style();
- ASSERT(style);
-
- bool isVerticalText = isVerticalWritingMode(style->svgStyle());
- float partLength = isVerticalText ? part.height : part.width;
-
- data->textLength += mapLengthThroughChunkTransformation(textBox, isVerticalText, partLength);
- return false;
-}
-
-float SVGTextQuery::textLength() const
-{
- if (m_textBoxes.isEmpty())
- return 0.0f;
-
- TextLengthData data;
- executeQuery(&data, &SVGTextQuery::textLengthCallback);
- return data.textLength;
-}
-
-// subStringLength() implementation
-struct SubStringLengthData : SVGTextQuery::Data {
- SubStringLengthData(unsigned queryStartPosition, unsigned queryLength)
- : startPosition(queryStartPosition)
- , length(queryLength)
- , subStringLength(0.0f)
- {
- }
-
- unsigned startPosition;
- unsigned length;
-
- float subStringLength;
-};
-
-bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData);
-
- int startPosition = data->startPosition;
- int endPosition = startPosition + data->length;
- if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition))
- return false;
-
- RenderStyle* style = textBox->textRenderer()->style();
- ASSERT(style);
-
- bool isVerticalText = isVerticalWritingMode(style->svgStyle());
- float partLength = measureCharacterRange(textBox, style, isVerticalWritingMode(style->svgStyle()), part.offset + startPosition, endPosition - startPosition);
-
- data->subStringLength += mapLengthThroughChunkTransformation(textBox, isVerticalText, partLength);
- return false;
-}
-
-float SVGTextQuery::subStringLength(unsigned startPosition, unsigned length) const
-{
- if (m_textBoxes.isEmpty())
- return 0.0f;
-
- SubStringLengthData data(startPosition, length);
- executeQuery(&data, &SVGTextQuery::subStringLengthCallback);
- return data.subStringLength;
-}
-
-// startPositionOfCharacter() implementation
-struct StartPositionOfCharacterData : SVGTextQuery::Data {
- StartPositionOfCharacterData(unsigned queryPosition)
- : position(queryPosition)
- {
- }
-
- unsigned position;
- FloatPoint startPosition;
-};
-
-bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterData*>(queryData);
-
- int startPosition = data->position;
- int endPosition = startPosition + 1;
- if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition))
- return false;
-
- const SVGChar& character = *(part.firstCharacter + startPosition);
- data->startPosition = textBox->chunkTransformation().mapPoint(FloatPoint(character.x, character.y));
- return true;
-}
-
-FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const
-{
- if (m_textBoxes.isEmpty())
- return FloatPoint();
-
- StartPositionOfCharacterData data(position);
- executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback);
- return data.startPosition;
-}
-
-// endPositionOfCharacter() implementation
-struct EndPositionOfCharacterData : SVGTextQuery::Data {
- EndPositionOfCharacterData(unsigned queryPosition)
- : position(queryPosition)
- {
- }
-
- unsigned position;
- FloatPoint endPosition;
-};
-
-bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData);
-
- int startPosition = data->position;
- int endPosition = startPosition + 1;
- if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition))
- return false;
-
- const SVGChar& character = *(part.firstCharacter + startPosition);
- data->endPosition = FloatPoint(character.x, character.y);
-
- RenderStyle* style = textBox->textRenderer()->style();
- ASSERT(style);
-
- bool isVerticalText = isVerticalWritingMode(style->svgStyle());
- float glyphAdvance = measureCharacterRange(textBox, style, isVerticalText, part.offset + startPosition, 1);
-
- if (isVerticalText)
- data->endPosition.move(0.0f, glyphAdvance);
- else
- data->endPosition.move(glyphAdvance, 0.0f);
-
- data->endPosition = textBox->chunkTransformation().mapPoint(data->endPosition);
- return true;
-}
-
-FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const
-{
- if (m_textBoxes.isEmpty())
- return FloatPoint();
-
- EndPositionOfCharacterData data(position);
- executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback);
- return data.endPosition;
-}
-
-// rotationOfCharacter() implementation
-struct RotationOfCharacterData : SVGTextQuery::Data {
- RotationOfCharacterData(unsigned queryPosition)
- : position(queryPosition)
- , rotation(0.0f)
- {
- }
-
- unsigned position;
- float rotation;
-};
-
-bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData);
-
- int startPosition = data->position;
- int endPosition = startPosition + 1;
- if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition))
- return false;
-
- const SVGChar& character = *(part.firstCharacter + startPosition);
- data->rotation = character.angle;
- return true;
-}
-
-float SVGTextQuery::rotationOfCharacter(unsigned position) const
-{
- if (m_textBoxes.isEmpty())
- return 0.0f;
-
- RotationOfCharacterData data(position);
- executeQuery(&data, &SVGTextQuery::rotationOfCharacterCallback);
- return data.rotation;
-}
-
-// extentOfCharacter() implementation
-struct ExtentOfCharacterData : SVGTextQuery::Data {
- ExtentOfCharacterData(unsigned queryPosition)
- : position(queryPosition)
- {
- }
-
- unsigned position;
- FloatRect extent;
-};
-
-bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData);
-
- int startPosition = data->position;
- int endPosition = startPosition + 1;
- if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition))
- return false;
-
- RenderStyle* style = textBox->textRenderer()->style();
- ASSERT(style);
-
- const SVGChar& character = *(part.firstCharacter + startPosition);
- data->extent = textBox->calculateGlyphBoundaries(style, part.offset + startPosition, character);
- return true;
-}
-
-FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const
-{
- if (m_textBoxes.isEmpty())
- return FloatRect();
-
- ExtentOfCharacterData data(position);
- executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback);
- return data.extent;
-}
-
-// characterNumberAtPosition() implementation
-struct CharacterNumberAtPositionData : SVGTextQuery::Data {
- CharacterNumberAtPositionData(const FloatPoint& queryPosition)
- : characterNumber(0)
- , position(queryPosition)
- {
- }
-
- unsigned characterNumber;
- FloatPoint position;
-};
-
-bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const
-{
- CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionData*>(queryData);
-
- RenderStyle* style = textBox->textRenderer()->style();
- ASSERT(style);
-
- for (int i = 0; i < part.length; ++i) {
- FloatRect extent(textBox->calculateGlyphBoundaries(style, part.offset + i, *(part.firstCharacter + i)));
- if (extent.contains(data->position))
- return true;
-
- ++data->characterNumber;
- }
-
- return false;
-}
-
-int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const
-{
- if (m_textBoxes.isEmpty())
- return -1;
-
- CharacterNumberAtPositionData data(position);
- if (!executeQuery(&data, &SVGTextQuery::characterNumberAtPositionCallback))
- return -1;
-
- return data.characterNumber;
-}
-
-}
-
-#endif
diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp
index e5228f0..5d5b8b3 100644
--- a/WebCore/rendering/TextControlInnerElements.cpp
+++ b/WebCore/rendering/TextControlInnerElements.cpp
@@ -479,7 +479,7 @@ void InputFieldSpeechButtonElement::setRecognitionResult(int, const String& resu
// here, we take a temporary reference.
RefPtr<HTMLInputElement> holdRef(input);
input->setValue(result);
- input->dispatchFormControlChangeEvent();
+ input->dispatchWebkitSpeechChangeEvent();
renderer()->repaint();
}
diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp
index 623a298..b56bb1e 100644
--- a/WebCore/rendering/style/RenderStyle.cpp
+++ b/WebCore/rendering/style/RenderStyle.cpp
@@ -297,8 +297,12 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
changedContextSensitiveProperties = ContextSensitivePropertyNone;
#if ENABLE(SVG)
- if (m_svgStyle != other->m_svgStyle)
- return m_svgStyle->diff(other->m_svgStyle.get());
+ StyleDifference svgChange = StyleDifferenceEqual;
+ if (m_svgStyle != other->m_svgStyle) {
+ svgChange = m_svgStyle->diff(other->m_svgStyle.get());
+ if (svgChange == StyleDifferenceLayout)
+ return svgChange;
+ }
#endif
if (m_box->width() != other->m_box->width() ||
@@ -442,7 +446,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
return StyleDifferenceLayout;
// Check block flow direction.
- if (inherited_flags._blockFlow != other->inherited_flags._blockFlow)
+ if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode)
return StyleDifferenceLayout;
// Overflow returns a layout hint.
@@ -475,6 +479,15 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
return StyleDifferenceLayout;
+
+#if ENABLE(SVG)
+ // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
+ // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
+ // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches
+ // that are relevant for SVG and might return StyleDifferenceLayout.
+ if (svgChange != StyleDifferenceEqual)
+ return svgChange;
+#endif
// Make sure these left/top/right/bottom checks stay below all layout checks and above
// all visible checks.
@@ -922,52 +935,52 @@ void RenderStyle::setBlendedFontSize(int size)
font().update(currentFontSelector);
}
-void RenderStyle::getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const
+void RenderStyle::getShadowExtent(const ShadowData* shadow, int &top, int &right, int &bottom, int &left) const
{
top = 0;
right = 0;
bottom = 0;
left = 0;
- for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
- if (boxShadow->style() == Inset)
+ for ( ; shadow; shadow = shadow->next()) {
+ if (shadow->style() == Inset)
continue;
- int blurAndSpread = boxShadow->blur() + boxShadow->spread();
+ int blurAndSpread = shadow->blur() + shadow->spread();
- top = min(top, boxShadow->y() - blurAndSpread);
- right = max(right, boxShadow->x() + blurAndSpread);
- bottom = max(bottom, boxShadow->y() + blurAndSpread);
- left = min(left, boxShadow->x() - blurAndSpread);
+ 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 RenderStyle::getBoxShadowHorizontalExtent(int &left, int &right) const
+void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, int &left, int &right) const
{
left = 0;
right = 0;
- for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
- if (boxShadow->style() == Inset)
+ for ( ; shadow; shadow = shadow->next()) {
+ if (shadow->style() == Inset)
continue;
- int blurAndSpread = boxShadow->blur() + boxShadow->spread();
+ int blurAndSpread = shadow->blur() + shadow->spread();
- left = min(left, boxShadow->x() - blurAndSpread);
- right = max(right, boxShadow->x() + blurAndSpread);
+ left = min(left, shadow->x() - blurAndSpread);
+ right = max(right, shadow->x() + blurAndSpread);
}
}
-void RenderStyle::getBoxShadowVerticalExtent(int &top, int &bottom) const
+void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, int &top, int &bottom) const
{
top = 0;
bottom = 0;
- for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
- if (boxShadow->style() == Inset)
+ for ( ; shadow; shadow = shadow->next()) {
+ if (shadow->style() == Inset)
continue;
- int blurAndSpread = boxShadow->blur() + boxShadow->spread();
+ int blurAndSpread = shadow->blur() + shadow->spread();
- top = min(top, boxShadow->y() - blurAndSpread);
- bottom = max(bottom, boxShadow->y() + blurAndSpread);
+ top = min(top, shadow->y() - blurAndSpread);
+ bottom = max(bottom, shadow->y() + blurAndSpread);
}
}
@@ -1066,56 +1079,56 @@ const Color RenderStyle::visitedDependentColor(int colorProperty) const
Length RenderStyle::logicalWidth() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return width();
return height();
}
Length RenderStyle::logicalHeight() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return height();
return width();
}
Length RenderStyle::logicalMinWidth() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return minWidth();
return minHeight();
}
Length RenderStyle::logicalMaxWidth() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return maxWidth();
return maxHeight();
}
Length RenderStyle::logicalMinHeight() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return minHeight();
return minWidth();
}
Length RenderStyle::logicalMaxHeight() const
{
- if (isVerticalBlockFlow())
+ if (isHorizontalWritingMode())
return maxHeight();
return maxWidth();
}
unsigned short RenderStyle::borderBeforeWidth() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return borderTopWidth();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return borderBottomWidth();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return borderLeftWidth();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return borderRightWidth();
}
ASSERT_NOT_REACHED();
@@ -1124,14 +1137,14 @@ unsigned short RenderStyle::borderBeforeWidth() const
unsigned short RenderStyle::borderAfterWidth() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return borderBottomWidth();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return borderTopWidth();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return borderRightWidth();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return borderLeftWidth();
}
ASSERT_NOT_REACHED();
@@ -1140,28 +1153,28 @@ unsigned short RenderStyle::borderAfterWidth() const
unsigned short RenderStyle::borderStartWidth() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? borderLeftWidth() : borderRightWidth();
- return direction() == LTR ? borderTopWidth() : borderBottomWidth();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
+ return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
}
unsigned short RenderStyle::borderEndWidth() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? borderRightWidth() : borderLeftWidth();
- return direction() == LTR ? borderBottomWidth() : borderTopWidth();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
+ return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
}
Length RenderStyle::marginBefore() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return marginTop();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return marginBottom();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return marginLeft();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return marginRight();
}
ASSERT_NOT_REACHED();
@@ -1170,14 +1183,14 @@ Length RenderStyle::marginBefore() const
Length RenderStyle::marginAfter() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return marginBottom();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return marginTop();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return marginRight();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return marginLeft();
}
ASSERT_NOT_REACHED();
@@ -1186,14 +1199,14 @@ Length RenderStyle::marginAfter() const
Length RenderStyle::marginBeforeUsing(const RenderStyle* otherStyle) const
{
- switch (otherStyle->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (otherStyle->writingMode()) {
+ case TopToBottomWritingMode:
return marginTop();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return marginBottom();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return marginLeft();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return marginRight();
}
ASSERT_NOT_REACHED();
@@ -1202,14 +1215,14 @@ Length RenderStyle::marginBeforeUsing(const RenderStyle* otherStyle) const
Length RenderStyle::marginAfterUsing(const RenderStyle* otherStyle) const
{
- switch (otherStyle->blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (otherStyle->writingMode()) {
+ case TopToBottomWritingMode:
return marginBottom();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return marginTop();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return marginRight();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return marginLeft();
}
ASSERT_NOT_REACHED();
@@ -1218,42 +1231,42 @@ Length RenderStyle::marginAfterUsing(const RenderStyle* otherStyle) const
Length RenderStyle::marginStart() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? marginLeft() : marginRight();
- return direction() == LTR ? marginTop() : marginBottom();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? marginLeft() : marginRight();
+ return isLeftToRightDirection() ? marginTop() : marginBottom();
}
Length RenderStyle::marginEnd() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? marginRight() : marginLeft();
- return direction() == LTR ? marginBottom() : marginTop();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? marginRight() : marginLeft();
+ return isLeftToRightDirection() ? marginBottom() : marginTop();
}
Length RenderStyle::marginStartUsing(const RenderStyle* otherStyle) const
{
- if (otherStyle->isVerticalBlockFlow())
- return otherStyle->direction() == LTR ? marginLeft() : marginRight();
- return otherStyle->direction() == LTR ? marginTop() : marginBottom();
+ if (otherStyle->isHorizontalWritingMode())
+ return otherStyle->isLeftToRightDirection() ? marginLeft() : marginRight();
+ return otherStyle->isLeftToRightDirection() ? marginTop() : marginBottom();
}
Length RenderStyle::marginEndUsing(const RenderStyle* otherStyle) const
{
- if (otherStyle->isVerticalBlockFlow())
- return otherStyle->direction() == LTR ? marginRight() : marginLeft();
- return otherStyle->direction() == LTR ? marginBottom() : marginTop();
+ if (otherStyle->isHorizontalWritingMode())
+ return otherStyle->isLeftToRightDirection() ? marginRight() : marginLeft();
+ return otherStyle->isLeftToRightDirection() ? marginBottom() : marginTop();
}
Length RenderStyle::paddingBefore() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return paddingTop();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return paddingBottom();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return paddingLeft();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return paddingRight();
}
ASSERT_NOT_REACHED();
@@ -1262,14 +1275,14 @@ Length RenderStyle::paddingBefore() const
Length RenderStyle::paddingAfter() const
{
- switch (blockFlow()) {
- case TopToBottomBlockFlow:
+ switch (writingMode()) {
+ case TopToBottomWritingMode:
return paddingBottom();
- case BottomToTopBlockFlow:
+ case BottomToTopWritingMode:
return paddingTop();
- case LeftToRightBlockFlow:
+ case LeftToRightWritingMode:
return paddingRight();
- case RightToLeftBlockFlow:
+ case RightToLeftWritingMode:
return paddingLeft();
}
ASSERT_NOT_REACHED();
@@ -1278,16 +1291,16 @@ Length RenderStyle::paddingAfter() const
Length RenderStyle::paddingStart() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? paddingLeft() : paddingRight();
- return direction() == LTR ? paddingTop() : paddingBottom();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? paddingLeft() : paddingRight();
+ return isLeftToRightDirection() ? paddingTop() : paddingBottom();
}
Length RenderStyle::paddingEnd() const
{
- if (isVerticalBlockFlow())
- return direction() == LTR ? paddingRight() : paddingLeft();
- return direction() == LTR ? paddingBottom() : paddingTop();
+ if (isHorizontalWritingMode())
+ return isLeftToRightDirection() ? paddingRight() : paddingLeft();
+ return isLeftToRightDirection() ? paddingBottom() : paddingTop();
}
} // namespace WebCore
diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h
index 6ecbd56..587b473 100644
--- a/WebCore/rendering/style/RenderStyle.h
+++ b/WebCore/rendering/style/RenderStyle.h
@@ -29,7 +29,6 @@
#include "AnimationList.h"
#include "BorderData.h"
#include "BorderValue.h"
-#include "CSSHelper.h"
#include "CSSImageGeneratorValue.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyNames.h"
@@ -179,7 +178,7 @@ protected:
(_force_backgrounds_to_white == other._force_backgrounds_to_white) &&
(_pointerEvents == other._pointerEvents) &&
(_insideLink == other._insideLink) &&
- (_blockFlow == other._blockFlow);
+ (m_writingMode == other.m_writingMode);
}
bool operator!=(const InheritedFlags& other) const { return !(*this == other); }
@@ -207,7 +206,7 @@ protected:
// 43 bits
// CSS Text Layout Module Level 3: Vertical writing support
- unsigned _blockFlow : 2; // EBlockFlowDirection
+ unsigned m_writingMode : 2; // WritingMode
// 45 bits
} inherited_flags;
@@ -284,7 +283,7 @@ protected:
inherited_flags._force_backgrounds_to_white = false;
inherited_flags._pointerEvents = initialPointerEvents();
inherited_flags._insideLink = NotInsideLink;
- inherited_flags._blockFlow = initialBlockFlow();
+ inherited_flags.m_writingMode = initialWritingMode();
noninherited_flags._effectiveDisplay = noninherited_flags._originalDisplay = initialDisplay();
noninherited_flags._overflowX = initialOverflowX();
@@ -307,10 +306,10 @@ protected:
}
private:
- RenderStyle();
+ ALWAYS_INLINE RenderStyle();
// used to create the default style.
- RenderStyle(bool);
- RenderStyle(const RenderStyle&);
+ ALWAYS_INLINE RenderStyle(bool);
+ ALWAYS_INLINE RenderStyle(const RenderStyle&);
public:
static PassRefPtr<RenderStyle> create();
@@ -476,6 +475,8 @@ public:
float effectiveZoom() const { return rareInheritedData->m_effectiveZoom; }
TextDirection direction() const { return static_cast<TextDirection>(inherited_flags._direction); }
+ bool isLeftToRightDirection() const { return direction() == LTR; }
+
Length lineHeight() const { return inherited->line_height; }
int computedLineHeight() const
{
@@ -636,6 +637,11 @@ public:
}
const ShadowData* textShadow() const { return rareInheritedData->textShadow; }
+ void getTextShadowExtent(int& top, int& right, int& bottom, int& left) const { getShadowExtent(textShadow(), top, right, bottom, left); }
+ void getTextShadowHorizontalExtent(int& left, int& right) const { getShadowHorizontalExtent(textShadow(), left, right); }
+ void getTextShadowVerticalExtent(int& top, int& bottom) const { getShadowVerticalExtent(textShadow(), top, bottom); }
+ void getTextShadowInlineDirectionExtent(int& logicalLeft, int& logicalRight) { getShadowInlineDirectionExtent(textShadow(), logicalLeft, logicalRight); }
+
float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
ColorSpace colorSpace() const { return static_cast<ColorSpace>(rareInheritedData->colorSpace); }
float opacity() const { return rareNonInheritedData->opacity; }
@@ -650,9 +656,10 @@ public:
EBoxAlignment boxPack() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->pack); }
const ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); }
- void getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const;
- void getBoxShadowHorizontalExtent(int &left, int &right) const;
- void getBoxShadowVerticalExtent(int &top, int &bottom) const;
+ void getBoxShadowExtent(int& top, int& right, int& bottom, int& left) const { getShadowExtent(boxShadow(), top, right, bottom, left); }
+ void getBoxShadowHorizontalExtent(int& left, int& right) const { getShadowHorizontalExtent(boxShadow(), left, right); }
+ void getBoxShadowVerticalExtent(int& top, int& bottom) const { getShadowVerticalExtent(boxShadow(), top, bottom); }
+ void getBoxShadowInlineDirectionExtent(int& logicalLeft, int& logicalRight) { getShadowInlineDirectionExtent(boxShadow(), logicalLeft, logicalRight); }
StyleReflection* boxReflect() const { return rareNonInheritedData->m_boxReflect.get(); }
EBoxSizing boxSizing() const { return m_box->boxSizing(); }
@@ -742,9 +749,11 @@ public:
bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
- EBlockFlowDirection blockFlow() const { return static_cast<EBlockFlowDirection>(inherited_flags._blockFlow); }
- bool isVerticalBlockFlow() const { return blockFlow() == TopToBottomBlockFlow || blockFlow() == BottomToTopBlockFlow; }
+ WritingMode writingMode() const { return static_cast<WritingMode>(inherited_flags.m_writingMode); }
+ bool isHorizontalWritingMode() const { return writingMode() == TopToBottomWritingMode || writingMode() == BottomToTopWritingMode; }
+ bool isFlippedLinesWritingMode() const { return writingMode() == LeftToRightWritingMode || writingMode() == BottomToTopWritingMode; }
+<<<<<<< HEAD
#ifdef ANDROID_CSS_RING
// called when building nav cache to determine if the ring data is unchanged
const void* ringData() const { return reinterpret_cast<const void*>(rareInheritedData.get()); }
@@ -762,6 +771,10 @@ public:
Color tapHighlightColor() const { return rareInheritedData->tapHighlightColor; }
#endif
+=======
+ ESpeak speak() { return static_cast<ESpeak>(rareInheritedData->speak); }
+
+>>>>>>> webkit.org at r70209
// attribute setter methods
void setDisplay(EDisplay v) { noninherited_flags._effectiveDisplay = v; }
@@ -1054,6 +1067,7 @@ public:
void setTransformOriginX(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); }
void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); }
void setTransformOriginZ(float f) { SET_VAR(rareNonInheritedData.access()->m_transform, m_z, f); }
+ void setSpeak(ESpeak s) { SET_VAR(rareInheritedData, speak, s); }
// End CSS3 Setters
// Apple-specific property setters
@@ -1156,7 +1170,7 @@ public:
originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE;
}
- void setBlockFlow(EBlockFlowDirection v) { inherited_flags._blockFlow = v; }
+ void setWritingMode(WritingMode v) { inherited_flags.m_writingMode = v; }
// To tell if this style matched attribute selectors. This makes it impossible to share.
bool affectedByAttributeSelectors() const { return m_affectedByAttributeSelectors; }
@@ -1197,7 +1211,7 @@ public:
static ECaptionSide initialCaptionSide() { return CAPTOP; }
static EClear initialClear() { return CNONE; }
static TextDirection initialDirection() { return LTR; }
- static EBlockFlowDirection initialBlockFlow() { return TopToBottomBlockFlow; }
+ static WritingMode initialWritingMode() { return TopToBottomWritingMode; }
static EDisplay initialDisplay() { return INLINE; }
static EEmptyCell initialEmptyCells() { return SHOW; }
static EFloat initialFloating() { return FNONE; }
@@ -1262,6 +1276,7 @@ public:
static EKHTMLLineBreak initialKHTMLLineBreak() { return LBNORMAL; }
static EMatchNearestMailBlockquoteColor initialMatchNearestMailBlockquoteColor() { return BCNORMAL; }
static const AtomicString& initialHighlight() { return nullAtom; }
+ static ESpeak initialSpeak() { return SpeakNormal; }
static Hyphens initialHyphens() { return HyphensManual; }
static const AtomicString& initialHyphenationString() { return nullAtom; }
static const AtomicString& initialHyphenationLocale() { return nullAtom; }
@@ -1309,6 +1324,14 @@ public:
#endif
private:
+ void getShadowExtent(const ShadowData*, int& top, int& right, int& bottom, int& left) const;
+ void getShadowHorizontalExtent(const ShadowData*, int& left, int& right) const;
+ void getShadowVerticalExtent(const ShadowData*, int& top, int& bottom) const;
+ void getShadowInlineDirectionExtent(const ShadowData* shadow, int& logicalLeft, int& logicalRight) const
+ {
+ return isHorizontalWritingMode() ? getShadowHorizontalExtent(shadow, logicalLeft, logicalRight) : getShadowVerticalExtent(shadow, logicalLeft, logicalRight);
+ }
+
// Color accessors are all private to make sure callers use visitedDependentColor instead to access them.
const Color& borderLeftColor() const { return surround->border.left().color(); }
const Color& borderRightColor() const { return surround->border.right().color(); }
diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h
index 94d30d5..0112c03 100644
--- a/WebCore/rendering/style/RenderStyleConstants.h
+++ b/WebCore/rendering/style/RenderStyleConstants.h
@@ -129,8 +129,8 @@ enum EUnicodeBidi {
};
// CSS Text Layout Module Level 3: Vertical writing support
-enum EBlockFlowDirection {
- TopToBottomBlockFlow, RightToLeftBlockFlow, LeftToRightBlockFlow, BottomToTopBlockFlow
+enum WritingMode {
+ TopToBottomWritingMode, RightToLeftWritingMode, LeftToRightWritingMode, BottomToTopWritingMode
};
enum EFillAttachment {
@@ -415,6 +415,8 @@ enum ELineClampType { LineClampLineCount, LineClampPercentage };
enum Hyphens { HyphensNone, HyphensManual, HyphensAuto };
+enum ESpeak { SpeakNone, SpeakNormal, SpeakSpellOut, SpeakDigits, SpeakLiteralPunctuation, SpeakNoPunctuation };
+
} // namespace WebCore
#endif // RenderStyleConstants_h
diff --git a/WebCore/rendering/style/SVGRenderStyle.cpp b/WebCore/rendering/style/SVGRenderStyle.cpp
index 7d1ad3b..28f80f2 100644
--- a/WebCore/rendering/style/SVGRenderStyle.cpp
+++ b/WebCore/rendering/style/SVGRenderStyle.cpp
@@ -138,7 +138,7 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const
if (resources != other->resources)
return StyleDifferenceLayout;
- // If markers change, we need a relayout, as marker boundaries are cached in RenderPath.
+ // If markers change, we need a relayout, as marker boundaries are cached in RenderSVGPath.
if (inheritedResources != other->inheritedResources)
return StyleDifferenceLayout;
@@ -190,7 +190,7 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const
return StyleDifferenceRepaint;
}
- // If fill changes, we just need to repaint. Fill boundaries are not influenced by this, only by the Path, that RenderPath contains.
+ // If fill changes, we just need to repaint. Fill boundaries are not influenced by this, only by the Path, that RenderSVGPath contains.
if (fill != other->fill)
return StyleDifferenceRepaint;
diff --git a/WebCore/rendering/style/SVGRenderStyle.h b/WebCore/rendering/style/SVGRenderStyle.h
index d57e4cf..8f0be39 100644
--- a/WebCore/rendering/style/SVGRenderStyle.h
+++ b/WebCore/rendering/style/SVGRenderStyle.h
@@ -67,7 +67,7 @@ public:
static LineJoin initialJoinStyle() { return MiterJoin; }
static EShapeRendering initialShapeRendering() { return SR_AUTO; }
static ETextAnchor initialTextAnchor() { return TA_START; }
- static EWritingMode initialWritingMode() { return WM_LRTB; }
+ static SVGWritingMode initialWritingMode() { return WM_LRTB; }
static EGlyphOrientation initialGlyphOrientationHorizontal() { return GO_0DEG; }
static EGlyphOrientation initialGlyphOrientationVertical() { return GO_AUTO; }
static float initialFillOpacity() { return 1.0f; }
@@ -132,7 +132,7 @@ public:
void setJoinStyle(LineJoin val) { svg_inherited_flags._joinStyle = val; }
void setShapeRendering(EShapeRendering val) { svg_inherited_flags._shapeRendering = val; }
void setTextAnchor(ETextAnchor val) { svg_inherited_flags._textAnchor = val; }
- void setWritingMode(EWritingMode val) { svg_inherited_flags._writingMode = val; }
+ void setWritingMode(SVGWritingMode val) { svg_inherited_flags._writingMode = val; }
void setGlyphOrientationHorizontal(EGlyphOrientation val) { svg_inherited_flags._glyphOrientationHorizontal = val; }
void setGlyphOrientationVertical(EGlyphOrientation val) { svg_inherited_flags._glyphOrientationVertical = val; }
@@ -281,7 +281,7 @@ public:
LineJoin joinStyle() const { return (LineJoin) svg_inherited_flags._joinStyle; }
EShapeRendering shapeRendering() const { return (EShapeRendering) svg_inherited_flags._shapeRendering; }
ETextAnchor textAnchor() const { return (ETextAnchor) svg_inherited_flags._textAnchor; }
- EWritingMode writingMode() const { return (EWritingMode) svg_inherited_flags._writingMode; }
+ SVGWritingMode writingMode() const { return (SVGWritingMode) svg_inherited_flags._writingMode; }
EGlyphOrientation glyphOrientationHorizontal() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationHorizontal; }
EGlyphOrientation glyphOrientationVertical() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationVertical; }
float fillOpacity() const { return fill->opacity; }
@@ -314,6 +314,7 @@ public:
bool hasMarkers() const { return !markerStartResource().isEmpty() || !markerMidResource().isEmpty() || !markerEndResource().isEmpty(); }
bool hasStroke() const { return strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; }
bool hasFill() const { return fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; }
+ bool isVerticalWritingMode() const { return writingMode() == WM_TBRL || writingMode() == WM_TB; }
protected:
// inherit
@@ -350,7 +351,7 @@ protected:
unsigned _textAnchor : 2; // ETextAnchor
unsigned _colorInterpolation : 2; // EColorInterpolation
unsigned _colorInterpolationFilters : 2; // EColorInterpolation
- unsigned _writingMode : 3; // EWritingMode
+ unsigned _writingMode : 3; // SVGWritingMode
unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
} svg_inherited_flags;
diff --git a/WebCore/rendering/style/SVGRenderStyleDefs.h b/WebCore/rendering/style/SVGRenderStyleDefs.h
index 339bb77..de058a2 100644
--- a/WebCore/rendering/style/SVGRenderStyleDefs.h
+++ b/WebCore/rendering/style/SVGRenderStyleDefs.h
@@ -64,7 +64,7 @@ namespace WebCore {
SR_AUTO, SR_OPTIMIZESPEED, SR_CRISPEDGES, SR_GEOMETRICPRECISION
};
- enum EWritingMode {
+ enum SVGWritingMode {
WM_LRTB, WM_LR, WM_RLTB, WM_RL, WM_TBRL, WM_TB
};
diff --git a/WebCore/rendering/style/StyleAllInOne.cpp b/WebCore/rendering/style/StyleAllInOne.cpp
new file mode 100644
index 0000000..25b539f
--- /dev/null
+++ b/WebCore/rendering/style/StyleAllInOne.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include "ContentData.cpp"
+#include "CounterDirectives.cpp"
+#include "FillLayer.cpp"
+#include "KeyframeList.cpp"
+#include "NinePieceImage.cpp"
+#include "RenderStyle.cpp"
+#include "SVGRenderStyle.cpp"
+#include "SVGRenderStyleDefs.cpp"
+#include "ShadowData.cpp"
+#include "StyleBackgroundData.cpp"
+#include "StyleBoxData.cpp"
+#include "StyleCachedImage.cpp"
+#include "StyleFlexibleBoxData.cpp"
+#include "StyleGeneratedImage.cpp"
+#include "StyleInheritedData.cpp"
+#include "StyleMarqueeData.cpp"
+#include "StyleMultiColData.cpp"
+#include "StyleRareInheritedData.cpp"
+#include "StyleRareNonInheritedData.cpp"
+#include "StyleSurroundData.cpp"
+#include "StyleTransformData.cpp"
+#include "StyleVisualData.cpp"
diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp
index 42f2030..af2b555 100644
--- a/WebCore/rendering/style/StyleRareInheritedData.cpp
+++ b/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -57,7 +57,8 @@ StyleRareInheritedData::StyleRareInheritedData()
, textSizeAdjust(RenderStyle::initialTextSizeAdjust())
, resize(RenderStyle::initialResize())
, userSelect(RenderStyle::initialUserSelect())
- , colorSpace(DeviceColorSpace)
+ , colorSpace(ColorSpaceDeviceRGB)
+ , speak(SpeakNormal)
, hyphens(HyphensManual)
{
}
@@ -98,6 +99,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
, resize(o.resize)
, userSelect(o.userSelect)
, colorSpace(o.colorSpace)
+ , speak(o.speak)
, hyphens(o.hyphens)
, hyphenationString(o.hyphenationString)
, hyphenationLocale(o.hyphenationLocale)
@@ -154,6 +156,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
&& resize == o.resize
&& userSelect == o.userSelect
&& colorSpace == o.colorSpace
+ && speak == o.speak
&& hyphens == o.hyphens
&& hyphenationString == o.hyphenationString
&& hyphenationLocale == o.hyphenationLocale;
diff --git a/WebCore/rendering/style/StyleRareInheritedData.h b/WebCore/rendering/style/StyleRareInheritedData.h
index ba914d4..4ebbf88 100644
--- a/WebCore/rendering/style/StyleRareInheritedData.h
+++ b/WebCore/rendering/style/StyleRareInheritedData.h
@@ -91,6 +91,7 @@ public:
unsigned resize : 2; // EResize
unsigned userSelect : 1; // EUserSelect
unsigned colorSpace : 1; // ColorSpace
+ unsigned speak : 3; // ESpeak
unsigned hyphens : 2; // Hyphens
AtomicString hyphenationString;
diff --git a/WebCore/rendering/RenderSVGInline.cpp b/WebCore/rendering/svg/RenderSVGInline.cpp
index 5d12a61..4d0c533 100644
--- a/WebCore/rendering/RenderSVGInline.cpp
+++ b/WebCore/rendering/svg/RenderSVGInline.cpp
@@ -1,8 +1,7 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
* Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -27,6 +26,7 @@
#include "RenderSVGInline.h"
#include "RenderSVGResource.h"
+#include "RenderSVGText.h"
#include "SVGInlineFlowBox.h"
namespace WebCore {
@@ -45,7 +45,7 @@ InlineFlowBox* RenderSVGInline::createInlineFlowBox()
FloatRect RenderSVGInline::objectBoundingBox() const
{
- if (const RenderObject* object = SVGRenderSupport::findTextRootObject(this))
+ if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this))
return object->objectBoundingBox();
return FloatRect();
@@ -53,7 +53,7 @@ FloatRect RenderSVGInline::objectBoundingBox() const
FloatRect RenderSVGInline::strokeBoundingBox() const
{
- if (const RenderObject* object = SVGRenderSupport::findTextRootObject(this))
+ if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this))
return object->strokeBoundingBox();
return FloatRect();
@@ -61,7 +61,7 @@ FloatRect RenderSVGInline::strokeBoundingBox() const
FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const
{
- if (const RenderObject* object = SVGRenderSupport::findTextRootObject(this))
+ if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this))
return object->repaintRectInLocalCoordinates();
return FloatRect();
@@ -84,7 +84,7 @@ void RenderSVGInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer
void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads)
{
- const RenderObject* object = SVGRenderSupport::findTextRootObject(this);
+ RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this);
if (!object)
return;
diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/svg/RenderSVGInline.h
index 92b6fe7..d7b7e66 100644
--- a/WebCore/rendering/RenderSVGInline.h
+++ b/WebCore/rendering/svg/RenderSVGInline.h
@@ -33,7 +33,7 @@ namespace WebCore {
class RenderSVGInline : public RenderInline {
public:
- RenderSVGInline(Node*);
+ explicit RenderSVGInline(Node*);
virtual const char* renderName() const { return "RenderSVGInline"; }
virtual bool requiresLayer() const { return false; }
diff --git a/WebCore/rendering/svg/RenderSVGInlineText.cpp b/WebCore/rendering/svg/RenderSVGInlineText.cpp
new file mode 100644
index 0000000..49727ee
--- /dev/null
+++ b/WebCore/rendering/svg/RenderSVGInlineText.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * Copyright (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGInlineText.h"
+
+#include "FloatConversion.h"
+#include "FloatQuad.h"
+#include "RenderBlock.h"
+#include "RenderSVGRoot.h"
+#include "RenderSVGText.h"
+#include "SVGInlineTextBox.h"
+#include "SVGRootInlineBox.h"
+#include "VisiblePosition.h"
+
+namespace WebCore {
+
+static PassRefPtr<StringImpl> applySVGWhitespaceRules(PassRefPtr<StringImpl> string, bool preserveWhiteSpace)
+{
+ if (preserveWhiteSpace) {
+ // Spec: When xml:space="preserve", the SVG user agent will do the following using a
+ // copy of the original character data content. It will convert all newline and tab
+ // characters into space characters. Then, it will draw all space characters, including
+ // leading, trailing and multiple contiguous space characters.
+ RefPtr<StringImpl> newString = string->replace('\t', ' ');
+ newString = newString->replace('\n', ' ');
+ newString = newString->replace('\r', ' ');
+ return newString.release();
+ }
+
+ // Spec: When xml:space="default", the SVG user agent will do the following using a
+ // copy of the original character data content. First, it will remove all newline
+ // characters. Then it will convert all tab characters into space characters.
+ // Then, it will strip off all leading and trailing space characters.
+ // Then, all contiguous space characters will be consolidated.
+ RefPtr<StringImpl> newString = string->replace('\n', StringImpl::empty());
+ newString = newString->replace('\r', StringImpl::empty());
+ newString = newString->replace('\t', ' ');
+ return newString.release();
+}
+
+RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> string)
+ : RenderText(n, applySVGWhitespaceRules(string, false))
+{
+}
+
+void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderText::styleDidChange(diff, oldStyle);
+
+ if (diff == StyleDifferenceLayout) {
+ // The text metrics may be influenced by style changes.
+ if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this))
+ textRenderer->setNeedsPositioningValuesUpdate();
+ }
+
+ const RenderStyle* newStyle = style();
+ if (!newStyle || newStyle->whiteSpace() != PRE)
+ return;
+
+ if (!oldStyle || oldStyle->whiteSpace() != PRE)
+ setText(applySVGWhitespaceRules(originalText(), true), true);
+}
+
+InlineTextBox* RenderSVGInlineText::createTextBox()
+{
+ InlineTextBox* box = new (renderArena()) SVGInlineTextBox(this);
+ box->setHasVirtualLogicalHeight();
+ return box;
+}
+
+IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*)
+{
+ return IntRect();
+}
+
+IntRect RenderSVGInlineText::linesBoundingBox() const
+{
+ IntRect boundingBox;
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ boundingBox.unite(box->calculateBoundaries());
+ return boundingBox;
+}
+
+bool RenderSVGInlineText::characterStartsNewTextChunk(int position) const
+{
+ ASSERT(m_attributes.xValues().size() == textLength());
+ ASSERT(m_attributes.yValues().size() == textLength());
+ ASSERT(position >= 0);
+ ASSERT(position < static_cast<int>(textLength()));
+
+ // Each <textPath> element starts a new text chunk, regardless of any x/y values.
+ if (!position && parent()->isSVGTextPath() && !previousSibling())
+ return true;
+
+ int currentPosition = 0;
+ unsigned size = m_attributes.textMetricsValues().size();
+ for (unsigned i = 0; i < size; ++i) {
+ const SVGTextMetrics& metrics = m_attributes.textMetricsValues().at(i);
+
+ // We found the desired character.
+ if (currentPosition == position) {
+ return m_attributes.xValues().at(position) != SVGTextLayoutAttributes::emptyValue()
+ || m_attributes.yValues().at(position) != SVGTextLayoutAttributes::emptyValue();
+ }
+
+ currentPosition += metrics.length();
+ if (currentPosition > position)
+ break;
+ }
+
+ // The desired position is available in the x/y list, but not in the character data values list.
+ // That means the previous character data described a single glyph, consisting of multiple unicode characters.
+ // The consequence is that the desired character does not define a new absolute x/y position, even if present in the x/y test.
+ // This code is tested by svg/W3C-SVG-1.1/text-text-06-t.svg (and described in detail, why this influences chunk detection).
+ return false;
+}
+
+VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
+{
+ if (!firstTextBox() || !textLength())
+ return createVisiblePosition(0, DOWNSTREAM);
+
+ RenderStyle* style = this->style();
+ ASSERT(style);
+ int baseline = style->font().ascent();
+
+ RenderBlock* containingBlock = this->containingBlock();
+ ASSERT(containingBlock);
+
+ // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
+ FloatPoint absolutePoint(point);
+ absolutePoint.move(containingBlock->x(), containingBlock->y());
+
+ float closestDistance = std::numeric_limits<float>::max();
+ float closestDistancePosition = 0;
+ const SVGTextFragment* closestDistanceFragment = 0;
+ SVGInlineTextBox* closestDistanceBox = 0;
+
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+ ASSERT(box->isSVGInlineTextBox());
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+
+ unsigned textFragmentsSize = fragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ const SVGTextFragment& fragment = fragments.at(i);
+ FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
+ if (!fragment.transform.isIdentity())
+ fragmentRect = fragment.transform.mapRect(fragmentRect);
+
+ float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
+ powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);
+
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestDistanceBox = textBox;
+ closestDistanceFragment = &fragment;
+ closestDistancePosition = fragmentRect.x();
+ }
+ }
+ }
+
+ if (!closestDistanceFragment)
+ return createVisiblePosition(0, DOWNSTREAM);
+
+ int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
+ return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGInlineText.h b/WebCore/rendering/svg/RenderSVGInlineText.h
index f606918..926ec43 100644
--- a/WebCore/rendering/RenderSVGInlineText.h
+++ b/WebCore/rendering/svg/RenderSVGInlineText.h
@@ -31,11 +31,16 @@
namespace WebCore {
+class SVGInlineTextBox;
+
class RenderSVGInlineText : public RenderText {
public:
RenderSVGInlineText(Node*, PassRefPtr<StringImpl>);
bool characterStartsNewTextChunk(int position) const;
+
+ SVGTextLayoutAttributes& layoutAttributes() { return m_attributes; }
+ const SVGTextLayoutAttributes& layoutAttributes() const { return m_attributes; }
void storeLayoutAttributes(const SVGTextLayoutAttributes& attributes) { m_attributes = attributes; }
private:
@@ -50,6 +55,7 @@ private:
virtual bool requiresLayer() const { return false; }
virtual bool isSVGInlineText() const { return true; }
+ virtual VisiblePosition positionForPoint(const IntPoint&);
virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
virtual IntRect linesBoundingBox() const;
virtual InlineTextBox* createTextBox();
@@ -57,8 +63,22 @@ private:
SVGTextLayoutAttributes m_attributes;
};
+inline RenderSVGInlineText* toRenderSVGInlineText(RenderObject* object)
+{
+ ASSERT(!object || object->isSVGInlineText());
+ return static_cast<RenderSVGInlineText*>(object);
}
-#endif // ENABLE(SVG)
+inline const RenderSVGInlineText* toRenderSVGInlineText(const RenderObject* object)
+{
+ ASSERT(!object || object->isSVGInlineText());
+ return static_cast<const RenderSVGInlineText*>(object);
+}
-#endif // !RenderSVGInlineText_h
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGInlineText(const RenderSVGInlineText*);
+
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGInlineText_h
diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/svg/RenderSVGPath.cpp
index cbe1900..483303f 100644
--- a/WebCore/rendering/RenderPath.cpp
+++ b/WebCore/rendering/svg/RenderSVGPath.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#if ENABLE(SVG)
-#include "RenderPath.h"
+#include "RenderSVGPath.h"
#include "FloatPoint.h"
#include "FloatQuad.h"
@@ -35,6 +35,7 @@
#include "PointerEventsHitRules.h"
#include "RenderSVGContainer.h"
#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceSolidColor.h"
#include "SVGRenderSupport.h"
#include "SVGResources.h"
#include "SVGStyledTransformableElement.h"
@@ -65,7 +66,7 @@ private:
RenderStyle* m_style;
};
-RenderPath::RenderPath(SVGStyledTransformableElement* node)
+RenderSVGPath::RenderSVGPath(SVGStyledTransformableElement* node)
: RenderSVGModelObject(node)
, m_needsBoundariesUpdate(false) // default is false, the cached rects are empty from the beginning
, m_needsPathUpdate(true) // default is true, so we grab a Path object once from SVGStyledTransformableElement
@@ -73,30 +74,36 @@ RenderPath::RenderPath(SVGStyledTransformableElement* node)
{
}
-bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill, WindRule fillRule)
+RenderSVGPath::~RenderSVGPath()
+{
+}
+
+bool RenderSVGPath::fillContains(const FloatPoint& point, bool requiresFill, WindRule fillRule)
{
if (!m_fillBoundingBox.contains(point))
return false;
- if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style()))
+ Color fallbackColor;
+ if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style(), fallbackColor))
return false;
return m_path.contains(point, fillRule);
}
-bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke)
+bool RenderSVGPath::strokeContains(const FloatPoint& point, bool requiresStroke)
{
if (!m_strokeAndMarkerBoundingBox.contains(point))
return false;
- if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style()))
+ Color fallbackColor;
+ if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), fallbackColor))
return false;
BoundingRectStrokeStyleApplier strokeStyle(this, style());
return m_path.strokeContains(&strokeStyle, point);
}
-void RenderPath::layout()
+void RenderSVGPath::layout()
{
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
@@ -105,7 +112,8 @@ void RenderPath::layout()
bool needsPathUpdate = m_needsPathUpdate;
if (needsPathUpdate) {
- m_path = element->toPathData();
+ m_path.clear();
+ element->toPathData(m_path);
m_needsPathUpdate = false;
updateCachedBoundariesInParents = true;
}
@@ -138,18 +146,26 @@ void RenderPath::layout()
setNeedsLayout(false);
}
-void RenderPath::fillAndStrokePath(GraphicsContext* context)
+void RenderSVGPath::fillAndStrokePath(GraphicsContext* context)
{
context->beginPath();
RenderStyle* style = this->style();
- if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style)) {
+ Color fallbackColor;
+ if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, fallbackColor)) {
context->addPath(m_path);
if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode))
fillPaintingResource->postApplyResource(this, context, ApplyToFillMode);
+ else if (fallbackColor.isValid()) {
+ RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
+ fallbackResource->setColor(fallbackColor);
+ if (fallbackResource->applyResource(this, style, context, ApplyToFillMode))
+ fallbackResource->postApplyResource(this, context, ApplyToFillMode);
+ }
}
- RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style);
+ fallbackColor = Color();
+ RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor);
if (!strokePaintingResource)
return;
@@ -172,12 +188,18 @@ void RenderPath::fillAndStrokePath(GraphicsContext* context)
if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode))
strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMode);
+ else if (fallbackColor.isValid()) {
+ RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
+ fallbackResource->setColor(fallbackColor);
+ if (fallbackResource->applyResource(this, style, context, ApplyToStrokeMode))
+ fallbackResource->postApplyResource(this, context, ApplyToStrokeMode);
+ }
if (restoreContext)
context->restore();
}
-void RenderPath::paint(PaintInfo& paintInfo, int, int)
+void RenderSVGPath::paint(PaintInfo& paintInfo, int, int)
{
if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty())
return;
@@ -219,14 +241,14 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
// This method is called from inside paintOutline() since we call paintOutline()
// while transformed to our coord system, return local coords
-void RenderPath::addFocusRingRects(Vector<IntRect>& rects, int, int)
+void RenderSVGPath::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates());
if (!rect.isEmpty())
rects.append(rect);
}
-bool RenderPath::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
+bool RenderSVGPath::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
{
// We only draw in the forground phase, so we only hit-test then.
if (hitTestAction != HitTestForeground)
@@ -253,7 +275,7 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult&
return false;
}
-FloatRect RenderPath::calculateMarkerBoundsIfNeeded()
+FloatRect RenderSVGPath::calculateMarkerBoundsIfNeeded()
{
SVGElement* svgElement = static_cast<SVGElement*>(node());
ASSERT(svgElement && svgElement->document());
@@ -280,7 +302,7 @@ FloatRect RenderPath::calculateMarkerBoundsIfNeeded()
return m_markerLayoutInfo.calculateBoundaries(markerStart, markerMid, markerEnd, svgStyle->strokeWidth().value(svgElement), m_path);
}
-void RenderPath::updateCachedBoundaries()
+void RenderSVGPath::updateCachedBoundaries()
{
if (m_path.isEmpty()) {
m_fillBoundingBox = FloatRect();
diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/svg/RenderSVGPath.h
index 1d35a01..41b0e51 100644
--- a/WebCore/rendering/RenderPath.h
+++ b/WebCore/rendering/svg/RenderSVGPath.h
@@ -21,8 +21,8 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef RenderPath_h
-#define RenderPath_h
+#ifndef RenderSVGPath_h
+#define RenderSVGPath_h
#if ENABLE(SVG)
#include "AffineTransform.h"
@@ -36,9 +36,10 @@ class FloatPoint;
class RenderSVGContainer;
class SVGStyledTransformableElement;
-class RenderPath : public RenderSVGModelObject {
+class RenderSVGPath : public RenderSVGModelObject {
public:
- RenderPath(SVGStyledTransformableElement*);
+ explicit RenderSVGPath(SVGStyledTransformableElement*);
+ virtual ~RenderSVGPath();
const Path& path() const { return m_path; }
void setNeedsPathUpdate() { m_needsPathUpdate = true; }
@@ -55,8 +56,8 @@ private:
virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
- virtual bool isRenderPath() const { return true; }
- virtual const char* renderName() const { return "RenderPath"; }
+ virtual bool isSVGPath() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGPath"; }
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
@@ -83,20 +84,20 @@ private:
AffineTransform m_localTransform;
};
-inline RenderPath* toRenderPath(RenderObject* object)
+inline RenderSVGPath* toRenderSVGPath(RenderObject* object)
{
- ASSERT(!object || object->isRenderPath());
- return static_cast<RenderPath*>(object);
+ ASSERT(!object || object->isSVGPath());
+ return static_cast<RenderSVGPath*>(object);
}
-inline const RenderPath* toRenderPath(const RenderObject* object)
+inline const RenderSVGPath* toRenderSVGPath(const RenderObject* object)
{
- ASSERT(!object || object->isRenderPath());
- return static_cast<const RenderPath*>(object);
+ ASSERT(!object || object->isSVGPath());
+ return static_cast<const RenderSVGPath*>(object);
}
// This will catch anyone doing an unnecessary cast.
-void toRenderPath(const RenderPath*);
+void toRenderSVGPath(const RenderSVGPath*);
}
diff --git a/WebCore/rendering/RenderSVGTSpan.cpp b/WebCore/rendering/svg/RenderSVGTSpan.cpp
index 90ff36c..90ff36c 100644
--- a/WebCore/rendering/RenderSVGTSpan.cpp
+++ b/WebCore/rendering/svg/RenderSVGTSpan.cpp
diff --git a/WebCore/rendering/RenderSVGTSpan.h b/WebCore/rendering/svg/RenderSVGTSpan.h
index 931bd8c..97e0eb0 100644
--- a/WebCore/rendering/RenderSVGTSpan.h
+++ b/WebCore/rendering/svg/RenderSVGTSpan.h
@@ -29,7 +29,7 @@
namespace WebCore {
class RenderSVGTSpan : public RenderSVGInline {
public:
- RenderSVGTSpan(Node*);
+ explicit RenderSVGTSpan(Node*);
virtual const char* renderName() const { return "RenderSVGTSpan"; }
};
}
diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/svg/RenderSVGText.cpp
index 92091af..01a92b0 100644
--- a/WebCore/rendering/RenderSVGText.cpp
+++ b/WebCore/rendering/svg/RenderSVGText.cpp
@@ -1,12 +1,11 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Apple Computer, Inc.
- * 2006 Alexander Kellett <lypanov@kde.org>
- * 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>
+ * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Rob Buis <buis@kde.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -42,20 +41,42 @@
#include "SVGRenderSupport.h"
#include "SVGRootInlineBox.h"
#include "SVGTextElement.h"
-#include "SVGTextLayoutBuilder.h"
+#include "SVGTextLayoutAttributesBuilder.h"
#include "SVGTransformList.h"
#include "SVGURIReference.h"
#include "SimpleFontData.h"
#include "TransformState.h"
+#include "VisiblePosition.h"
namespace WebCore {
RenderSVGText::RenderSVGText(SVGTextElement* node)
: RenderSVGBlock(node)
+ , m_needsPositioningValuesUpdate(true)
, m_needsTransformUpdate(true)
{
}
+RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start)
+{
+ ASSERT(start);
+ while (start && !start->isSVGText())
+ start = start->parent();
+ if (!start || !start->isSVGText())
+ return 0;
+ return toRenderSVGText(start);
+}
+
+const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject* start)
+{
+ ASSERT(start);
+ while (start && !start->isSVGText())
+ start = start->parent();
+ if (!start || !start->isSVGText())
+ return 0;
+ return toRenderSVGText(start);
+}
+
IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
@@ -84,8 +105,13 @@ void RenderSVGText::layout()
updateCachedBoundariesInParents = true;
}
- SVGTextLayoutBuilder layoutBuilder;
- layoutBuilder.buildLayoutAttributesForTextSubtree(this);
+ if (m_needsPositioningValuesUpdate) {
+ // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
+ SVGTextLayoutAttributesBuilder layoutAttributesBuilder;
+ layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this);
+ m_needsPositioningValuesUpdate = false;
+ updateCachedBoundariesInParents = true;
+ }
// Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
// All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
@@ -153,6 +179,23 @@ bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int,
return false;
}
+VisiblePosition RenderSVGText::positionForPoint(const IntPoint& pointInContents)
+{
+ RootInlineBox* rootBox = firstRootBox();
+ if (!rootBox)
+ return createVisiblePosition(0, DOWNSTREAM);
+
+ ASSERT(rootBox->isSVGRootInlineBox());
+ ASSERT(!rootBox->nextRootBox());
+ ASSERT(childrenInline());
+
+ InlineBox* closestBox = static_cast<SVGRootInlineBox*>(rootBox)->closestLeafChildForPosition(pointInContents);
+ if (!closestBox)
+ return createVisiblePosition(0, DOWNSTREAM);
+
+ return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y));
+}
+
void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads)
{
quads.append(localToAbsoluteQuad(strokeBoundingBox()));
diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/svg/RenderSVGText.h
index be19419..deae78c 100644
--- a/WebCore/rendering/RenderSVGText.h
+++ b/WebCore/rendering/svg/RenderSVGText.h
@@ -1,8 +1,7 @@
/*
- * This file is part of the WebKit project.
- *
* Copyright (C) 2006 Apple Computer, Inc.
- * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -37,9 +36,13 @@ class RenderSVGText : public RenderSVGBlock {
public:
RenderSVGText(SVGTextElement* node);
+ void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
virtual FloatRect repaintRectInLocalCoordinates() const;
+ static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*);
+ static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*);
+
private:
virtual const char* renderName() const { return "RenderSVGText"; }
virtual bool isSVGText() const { return true; }
@@ -47,6 +50,7 @@ private:
virtual void paint(PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
+ virtual VisiblePosition positionForPoint(const IntPoint&);
virtual bool requiresLayer() const { return false; }
virtual void layout();
@@ -68,10 +72,26 @@ private:
virtual RenderBlock* firstLineBlock() const;
virtual void updateFirstLetter();
+ bool m_needsPositioningValuesUpdate : 1;
bool m_needsTransformUpdate : 1;
AffineTransform m_localTransform;
};
+inline RenderSVGText* toRenderSVGText(RenderObject* object)
+{
+ ASSERT(!object || object->isSVGText());
+ return static_cast<RenderSVGText*>(object);
+}
+
+inline const RenderSVGText* toRenderSVGText(const RenderObject* object)
+{
+ ASSERT(!object || object->isSVGText());
+ return static_cast<const RenderSVGText*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGText(const RenderSVGText*);
+
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGTextPath.cpp b/WebCore/rendering/svg/RenderSVGTextPath.cpp
index 5d977f9..64ebc6d 100644
--- a/WebCore/rendering/RenderSVGTextPath.cpp
+++ b/WebCore/rendering/svg/RenderSVGTextPath.cpp
@@ -53,7 +53,8 @@ Path RenderSVGTextPath::layoutPath() const
SVGPathElement* pathElement = static_cast<SVGPathElement*>(targetElement);
- Path pathData = pathElement->toPathData();
+ Path pathData;
+ pathElement->toPathData(pathData);
// Spec: The transform attribute on the referenced 'path' element represents a
// supplemental transformation relative to the current user coordinate system for
// the current 'text' element, including any adjustments to the current user coordinate
diff --git a/WebCore/rendering/RenderSVGTextPath.h b/WebCore/rendering/svg/RenderSVGTextPath.h
index 8e6ff42..a71edf5 100644
--- a/WebCore/rendering/RenderSVGTextPath.h
+++ b/WebCore/rendering/svg/RenderSVGTextPath.h
@@ -29,34 +29,36 @@
namespace WebCore {
- class RenderSVGTextPath : public RenderSVGInline {
- public:
- RenderSVGTextPath(Node*);
+class RenderSVGTextPath : public RenderSVGInline {
+public:
+ RenderSVGTextPath(Node*);
- Path layoutPath() const;
- float startOffset() const;
- bool exactAlignment() const;
- bool stretchMethod() const;
+ Path layoutPath() const;
+ float startOffset() const;
+ bool exactAlignment() const;
+ bool stretchMethod() const;
- private:
- virtual const char* renderName() const { return "RenderSVGTextPath"; }
+ virtual bool isSVGTextPath() const { return true; }
- float m_startOffset;
+private:
+ virtual const char* renderName() const { return "RenderSVGTextPath"; }
- bool m_exactAlignment : 1;
- bool m_stretchMethod : 1;
+ float m_startOffset;
- Path m_layoutPath;
- };
+ bool m_exactAlignment : 1;
+ bool m_stretchMethod : 1;
- inline RenderSVGTextPath* toRenderSVGTextPath(RenderObject* object)
- {
- ASSERT(!object || !strcmp(object->renderName(), "RenderSVGTextPath"));
- return static_cast<RenderSVGTextPath*>(object);
- }
+ Path m_layoutPath;
+};
- // This will catch anyone doing an unnecessary cast.
- void toRenderSVGTextPath(const RenderSVGTextPath*);
+inline RenderSVGTextPath* toRenderSVGTextPath(RenderObject* object)
+{
+ ASSERT(!object || !strcmp(object->renderName(), "RenderSVGTextPath"));
+ return static_cast<RenderSVGTextPath*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderSVGTextPath(const RenderSVGTextPath*);
}
diff --git a/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/WebCore/rendering/svg/SVGInlineFlowBox.cpp
new file mode 100644
index 0000000..b35c7e2
--- /dev/null
+++ b/WebCore/rendering/svg/SVGInlineFlowBox.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 Apple Computer Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGInlineFlowBox.h"
+
+#if ENABLE(SVG)
+#include "GraphicsContext.h"
+#include "RenderSVGInlineText.h"
+#include "SVGInlineTextBox.h"
+#include "SVGRenderSupport.h"
+
+using namespace std;
+
+namespace WebCore {
+
+void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo)
+{
+ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
+ ASSERT(!paintInfo.context->paintingDisabled());
+
+ PaintInfo childPaintInfo(paintInfo);
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox())
+ static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo);
+ else if (child->isSVGInlineFlowBox())
+ static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo);
+ }
+}
+
+void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int)
+{
+ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
+ ASSERT(!paintInfo.context->paintingDisabled());
+
+ RenderObject* boxRenderer = renderer();
+ ASSERT(boxRenderer);
+
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+
+ if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox())
+ computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
+
+ child->paint(childPaintInfo, 0, 0);
+ }
+ }
+
+ SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
+ childPaintInfo.context->restore();
+}
+
+IntRect SVGInlineFlowBox::calculateBoundaries() const
+{
+ IntRect childRect;
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
+ childRect.unite(child->calculateBoundaries());
+ return childRect;
+}
+
+void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer)
+{
+ ASSERT(textRenderer);
+
+ Node* node = textRenderer->node();
+ if (!node || !node->inDocument())
+ return;
+
+ RenderStyle* style = textRenderer->style();
+ ASSERT(style);
+
+ Document* document = textRenderer->document();
+ Vector<DocumentMarker> markers = document->markers()->markersForNode(textRenderer->node());
+
+ Vector<DocumentMarker>::iterator markerEnd = markers.end();
+ for (Vector<DocumentMarker>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) {
+ const DocumentMarker& marker = *markerIt;
+
+ // SVG is only interessted in the TextMatch marker, for now.
+ if (marker.type != DocumentMarker::TextMatch)
+ continue;
+
+ FloatRect markerRect;
+ for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ ASSERT(box->isSVGInlineTextBox());
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
+
+ int markerStartPosition = max<int>(marker.startOffset - textBox->start(), 0);
+ int markerEndPosition = min<int>(marker.endOffset - textBox->start(), textBox->len());
+
+ if (markerStartPosition >= markerEndPosition)
+ continue;
+
+ int fragmentStartPosition = 0;
+ int fragmentEndPosition = 0;
+
+ const Vector<SVGTextFragment>& fragments = textBox->textFragments();
+ unsigned textFragmentsSize = fragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ const SVGTextFragment& fragment = fragments.at(i);
+
+ fragmentStartPosition = markerStartPosition;
+ fragmentEndPosition = markerEndPosition;
+ if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
+ continue;
+
+ FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
+ if (!fragment.transform.isIdentity())
+ fragmentRect = fragment.transform.mapRect(fragmentRect);
+
+ markerRect.unite(fragmentRect);
+ }
+ }
+
+ document->markers()->setRenderedRectForMarker(node, marker, textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox());
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGInlineFlowBox.h b/WebCore/rendering/svg/SVGInlineFlowBox.h
index 80600f7..2358f2d 100644
--- a/WebCore/rendering/SVGInlineFlowBox.h
+++ b/WebCore/rendering/svg/SVGInlineFlowBox.h
@@ -29,6 +29,8 @@
namespace WebCore {
+class RenderSVGInlineText;
+
class SVGInlineFlowBox : public InlineFlowBox {
public:
SVGInlineFlowBox(RenderObject* obj)
@@ -37,13 +39,16 @@ public:
{
}
+ virtual bool isSVGInlineFlowBox() const { return true; }
virtual int virtualLogicalHeight() const { return m_logicalHeight; }
void setLogicalHeight(int h) { m_logicalHeight = h; }
+ void paintSelectionBackground(PaintInfo&);
virtual void paint(PaintInfo&, int tx, int ty);
virtual IntRect calculateBoundaries() const;
- void layoutFlowBox();
+
+ static void computeTextMatchMarkerRectForRenderer(RenderSVGInlineText*);
private:
int m_logicalHeight;
diff --git a/WebCore/rendering/svg/SVGInlineTextBox.cpp b/WebCore/rendering/svg/SVGInlineTextBox.cpp
new file mode 100644
index 0000000..0458af5
--- /dev/null
+++ b/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -0,0 +1,610 @@
+/**
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGInlineTextBox.h"
+
+#if ENABLE(SVG)
+#include "FloatConversion.h"
+#include "GraphicsContext.h"
+#include "InlineFlowBox.h"
+#include "RenderBlock.h"
+#include "RenderSVGInlineText.h"
+#include "RenderSVGResource.h"
+#include "RenderSVGResourceSolidColor.h"
+#include "SVGRootInlineBox.h"
+
+using namespace std;
+
+namespace WebCore {
+
+SVGInlineTextBox::SVGInlineTextBox(RenderObject* object)
+ : InlineTextBox(object)
+ , m_logicalHeight(0)
+ , m_paintingResourceMode(ApplyToDefaultMode)
+ , m_startsNewTextChunk(false)
+ , m_paintingResource(0)
+{
+}
+
+int SVGInlineTextBox::offsetForPosition(int, bool) const
+{
+ // SVG doesn't use the standard offset <-> position selection system, as it's not suitable for SVGs complex needs.
+ // vertical text selection, inline boxes spanning multiple lines (contrary to HTML, etc.)
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const
+{
+ RenderText* textRenderer = this->textRenderer();
+ ASSERT(textRenderer);
+
+ RenderStyle* style = textRenderer->style();
+ ASSERT(style);
+
+ TextRun textRun(constructTextRun(style, fragment));
+
+ // Eventually handle lengthAdjust="spacingAndGlyphs".
+ // FIXME: Handle vertical text.
+ if (!fragment.transform.isIdentity())
+ textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale()));
+
+ return fragment.positionListOffset - start() + style->font().offsetForPosition(textRun, position, includePartialGlyphs);
+}
+
+int SVGInlineTextBox::positionForOffset(int) const
+{
+ // SVG doesn't use the offset <-> position selection system.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& fragment, int startPosition, int endPosition, RenderStyle* style)
+{
+ ASSERT(startPosition < endPosition);
+
+ const Font& font = style->font();
+ FloatPoint textOrigin(fragment.x, fragment.y - font.ascent());
+ return font.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height, startPosition, endPosition);
+}
+
+IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosition)
+{
+ int boxStart = start();
+ startPosition = max(startPosition - boxStart, 0);
+ endPosition = min(endPosition - boxStart, static_cast<int>(len()));
+ if (startPosition >= endPosition)
+ return IntRect();
+
+ RenderText* text = textRenderer();
+ ASSERT(text);
+
+ RenderStyle* style = text->style();
+ ASSERT(style);
+
+ FloatRect selectionRect;
+ int fragmentStartPosition = 0;
+ int fragmentEndPosition = 0;
+
+ unsigned textFragmentsSize = m_textFragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ const SVGTextFragment& fragment = m_textFragments.at(i);
+
+ fragmentStartPosition = startPosition;
+ fragmentEndPosition = endPosition;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
+ continue;
+
+ FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
+ if (!fragment.transform.isIdentity())
+ fragmentRect = fragment.transform.mapRect(fragmentRect);
+
+ selectionRect.unite(fragmentRect);
+ }
+
+ return enclosingIntRect(selectionRect);
+}
+
+void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
+{
+ ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
+ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
+ ASSERT(truncation() == cNoTruncation);
+
+ if (renderer()->style()->visibility() != VISIBLE)
+ return;
+
+ RenderObject* parentRenderer = parent()->renderer();
+ ASSERT(parentRenderer);
+ ASSERT(!parentRenderer->document()->printing());
+
+ // Determine whether or not we're selected.
+ bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
+ bool hasSelection = selectionState() != RenderObject::SelectionNone;
+ if (!hasSelection || paintSelectedTextOnly)
+ return;
+
+ Color backgroundColor = renderer()->selectionBackgroundColor();
+ if (!backgroundColor.isValid() || !backgroundColor.alpha())
+ return;
+
+ RenderStyle* style = parentRenderer->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ bool hasFill = svgStyle->hasFill();
+ bool hasStroke = svgStyle->hasStroke();
+
+ RenderStyle* selectionStyle = style;
+ if (hasSelection) {
+ selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
+ if (selectionStyle) {
+ const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
+ ASSERT(svgSelectionStyle);
+
+ if (!hasFill)
+ hasFill = svgSelectionStyle->hasFill();
+ if (!hasStroke)
+ hasStroke = svgSelectionStyle->hasStroke();
+ } else
+ selectionStyle = style;
+ }
+
+ int startPosition, endPosition;
+ selectionStartEnd(startPosition, endPosition);
+
+ int fragmentStartPosition = 0;
+ int fragmentEndPosition = 0;
+ unsigned textFragmentsSize = m_textFragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ SVGTextFragment& fragment = m_textFragments.at(i);
+ ASSERT(!m_paintingResource);
+
+ fragmentStartPosition = startPosition;
+ fragmentEndPosition = endPosition;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
+ continue;
+
+ paintInfo.context->save();
+
+ if (!fragment.transform.isIdentity())
+ paintInfo.context->concatCTM(fragment.transform);
+
+ paintInfo.context->setFillColor(backgroundColor, style->colorSpace());
+ paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor, style->colorSpace());
+
+ m_paintingResourceMode = ApplyToDefaultMode;
+ paintInfo.context->restore();
+ }
+
+ ASSERT(!m_paintingResource);
+}
+
+void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int)
+{
+ ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
+ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
+ ASSERT(truncation() == cNoTruncation);
+
+ if (renderer()->style()->visibility() != VISIBLE)
+ return;
+
+ // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
+ // If we ever need that for SVG, it's very easy to refactor and reuse the code.
+
+ RenderObject* parentRenderer = parent()->renderer();
+ ASSERT(parentRenderer);
+
+ bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
+ bool hasSelection = !parentRenderer->document()->printing() && selectionState() != RenderObject::SelectionNone;
+ if (!hasSelection && paintSelectedTextOnly)
+ return;
+
+ RenderStyle* style = parentRenderer->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ bool hasFill = svgStyle->hasFill();
+ bool hasStroke = svgStyle->hasStroke();
+
+ RenderStyle* selectionStyle = style;
+ if (hasSelection) {
+ selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
+ if (selectionStyle) {
+ const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
+ ASSERT(svgSelectionStyle);
+
+ if (!hasFill)
+ hasFill = svgSelectionStyle->hasFill();
+ if (!hasStroke)
+ hasStroke = svgSelectionStyle->hasStroke();
+ } else
+ selectionStyle = style;
+ }
+
+ unsigned textFragmentsSize = m_textFragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ SVGTextFragment& fragment = m_textFragments.at(i);
+ ASSERT(!m_paintingResource);
+
+ paintInfo.context->save();
+
+ if (!fragment.transform.isIdentity())
+ paintInfo.context->concatCTM(fragment.transform);
+
+ // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
+ int decorations = style->textDecorationsInEffect();
+ if (decorations & UNDERLINE)
+ paintDecoration(paintInfo.context, UNDERLINE, fragment);
+ if (decorations & OVERLINE)
+ paintDecoration(paintInfo.context, OVERLINE, fragment);
+
+ // Fill text
+ if (hasFill) {
+ m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode;
+ paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
+ }
+
+ // Stroke text
+ if (hasStroke) {
+ m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode;
+ paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
+ }
+
+ // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text.
+ if (decorations & LINE_THROUGH)
+ paintDecoration(paintInfo.context, LINE_THROUGH, fragment);
+
+ m_paintingResourceMode = ApplyToDefaultMode;
+ paintInfo.context->restore();
+ }
+
+ ASSERT(!m_paintingResource);
+}
+
+bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, RenderObject* renderer, RenderStyle* style)
+{
+ ASSERT(renderer);
+ ASSERT(style);
+ ASSERT(m_paintingResourceMode != ApplyToDefaultMode);
+
+ Color fallbackColor;
+ if (m_paintingResourceMode & ApplyToFillMode)
+ m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, fallbackColor);
+ else if (m_paintingResourceMode & ApplyToStrokeMode)
+ m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, fallbackColor);
+ else {
+ // We're either called for stroking or filling.
+ ASSERT_NOT_REACHED();
+ }
+
+ if (!m_paintingResource)
+ return false;
+
+ if (!m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode)) {
+ if (fallbackColor.isValid()) {
+ RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
+ fallbackResource->setColor(fallbackColor);
+
+ m_paintingResource = fallbackResource;
+ m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode);
+ }
+ }
+
+ return true;
+}
+
+void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context)
+{
+ ASSERT(m_paintingResource);
+
+ RenderObject* parentRenderer = parent()->renderer();
+ ASSERT(parentRenderer);
+
+ m_paintingResource->postApplyResource(parentRenderer, context, m_paintingResourceMode);
+ m_paintingResource = 0;
+}
+
+bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, TextRun& textRun, RenderStyle* style)
+{
+ bool acquiredResource = acquirePaintingResource(context, parent()->renderer(), style);
+
+#if ENABLE(SVG_FONTS)
+ // SVG Fonts need access to the painting resource used to draw the current text chunk.
+ if (acquiredResource)
+ textRun.setActivePaintingResource(m_paintingResource);
+#endif
+
+ return acquiredResource;
+}
+
+void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun)
+{
+ releasePaintingResource(context);
+
+#if ENABLE(SVG_FONTS)
+ textRun.setActivePaintingResource(0);
+#endif
+}
+
+TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const
+{
+ ASSERT(style);
+ ASSERT(textRenderer());
+
+ RenderText* text = textRenderer();
+ ASSERT(text);
+
+ TextRun run(text->characters() + fragment.positionListOffset
+ , fragment.length
+ , false /* allowTabs */
+ , 0 /* xPos, only relevant with allowTabs=true */
+ , 0 /* padding, only relevant for justified text, not relevant for SVG */
+ , direction() == RTL
+ , m_dirOverride || style->visuallyOrdered() /* directionalOverride */);
+
+#if ENABLE(SVG_FONTS)
+ RenderObject* parentRenderer = parent()->renderer();
+ ASSERT(parentRenderer);
+
+ run.setReferencingRenderObject(parentRenderer);
+#endif
+
+ // Disable any word/character rounding.
+ run.disableRoundingHacks();
+
+ // We handle letter & word spacing ourselves.
+ run.disableSpacing();
+ return run;
+}
+
+bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment& fragment, int& startPosition, int& endPosition) const
+{
+ if (startPosition >= endPosition)
+ return false;
+
+ int offset = static_cast<int>(fragment.positionListOffset) - start();
+ int length = static_cast<int>(fragment.length);
+
+ if (startPosition >= offset + length || endPosition <= offset)
+ return false;
+
+ if (startPosition < offset)
+ startPosition = 0;
+ else
+ startPosition -= offset;
+
+ if (endPosition > offset + length)
+ endPosition = length;
+ else {
+ ASSERT(endPosition >= offset);
+ endPosition -= offset;
+ }
+
+ ASSERT(startPosition < endPosition);
+ return true;
+}
+
+static inline float positionOffsetForDecoration(ETextDecoration decoration, const Font& font, float thickness)
+{
+ // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
+ // Compatible with Batik/Opera.
+ if (decoration == UNDERLINE)
+ return font.ascent() + thickness * 1.5f;
+ if (decoration == OVERLINE)
+ return thickness;
+ if (decoration == LINE_THROUGH)
+ return font.ascent() * 5.0f / 8.0f;
+
+ ASSERT_NOT_REACHED();
+ return 0.0f;
+}
+
+static inline float thicknessForDecoration(ETextDecoration, const Font& font)
+{
+ // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
+ // Compatible with Batik/Opera
+ return font.size() / 20.0f;
+}
+
+static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowBox* parentBox)
+{
+ // Lookup first render object in parent hierarchy which has text-decoration set.
+ RenderObject* renderer = 0;
+ while (parentBox) {
+ renderer = parentBox->renderer();
+
+ if (renderer->style() && renderer->style()->textDecoration() != TDNONE)
+ break;
+
+ parentBox = parentBox->parent();
+ }
+
+ ASSERT(renderer);
+ return renderer;
+}
+
+void SVGInlineTextBox::paintDecoration(GraphicsContext* context, ETextDecoration decoration, const SVGTextFragment& fragment)
+{
+ if (textRenderer()->style()->textDecorationsInEffect() == TDNONE)
+ return;
+
+ // Find out which render style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours.
+ RenderObject* decorationRenderer = findRenderObjectDefininingTextDecoration(parent());
+ RenderStyle* decorationStyle = decorationRenderer->style();
+ ASSERT(decorationStyle);
+
+ if (decorationStyle->visibility() == HIDDEN)
+ return;
+
+ const SVGRenderStyle* svgDecorationStyle = decorationStyle->svgStyle();
+ ASSERT(svgDecorationStyle);
+
+ bool hasDecorationFill = svgDecorationStyle->hasFill();
+ bool hasDecorationStroke = svgDecorationStyle->hasStroke();
+
+ if (hasDecorationFill) {
+ m_paintingResourceMode = ApplyToFillMode;
+ paintDecorationWithStyle(context, decoration, fragment, decorationRenderer);
+ }
+
+ if (hasDecorationStroke) {
+ m_paintingResourceMode = ApplyToStrokeMode;
+ paintDecorationWithStyle(context, decoration, fragment, decorationRenderer);
+ }
+}
+
+void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer)
+{
+ ASSERT(!m_paintingResource);
+ ASSERT(m_paintingResourceMode != ApplyToDefaultMode);
+
+ RenderStyle* decorationStyle = decorationRenderer->style();
+ ASSERT(decorationStyle);
+
+ const Font& font = decorationStyle->font();
+
+ // The initial y value refers to overline position.
+ float thickness = thicknessForDecoration(decoration, font);
+
+ if (fragment.width <= 0 && thickness <= 0)
+ return;
+
+ float y = fragment.y - font.ascent() + positionOffsetForDecoration(decoration, font, thickness);
+
+ Path path;
+ path.addRect(FloatRect(fragment.x, y, fragment.width, thickness));
+
+ context->save();
+ context->beginPath();
+ context->addPath(path);
+
+ if (acquirePaintingResource(context, decorationRenderer, decorationStyle))
+ releasePaintingResource(context);
+
+ context->restore();
+}
+
+void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition)
+{
+ const Font& font = style->font();
+ const ShadowData* shadow = style->textShadow();
+
+ FloatPoint textOrigin(fragment.x, fragment.y);
+ FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - font.ascent()), FloatSize(fragment.width, fragment.height));
+
+ do {
+ if (!prepareGraphicsContextForTextPainting(context, textRun, style))
+ break;
+
+ FloatSize extraOffset;
+ if (shadow)
+ extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */);
+
+ font.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition);
+ restoreGraphicsContextAfterTextPainting(context, textRun);
+
+ if (!shadow)
+ break;
+
+ if (shadow->next())
+ context->restore();
+ else
+ context->clearShadow();
+
+ shadow = shadow->next();
+ } while (shadow);
+}
+
+void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, RenderStyle* selectionStyle, const SVGTextFragment& fragment, bool hasSelection, bool paintSelectedTextOnly)
+{
+ ASSERT(style);
+ ASSERT(selectionStyle);
+
+ int startPosition = 0;
+ int endPosition = 0;
+ if (hasSelection) {
+ selectionStartEnd(startPosition, endPosition);
+ hasSelection = mapStartEndPositionsIntoFragmentCoordinates(fragment, startPosition, endPosition);
+ }
+
+ // Fast path if there is no selection, just draw the whole chunk part using the regular style
+ TextRun textRun(constructTextRun(style, fragment));
+ if (!hasSelection || startPosition >= endPosition) {
+ paintTextWithShadows(context, style, textRun, fragment, 0, fragment.length);
+ return;
+ }
+
+ // Eventually draw text using regular style until the start position of the selection
+ if (startPosition > 0 && !paintSelectedTextOnly)
+ paintTextWithShadows(context, style, textRun, fragment, 0, startPosition);
+
+ // Draw text using selection style from the start to the end position of the selection
+ if (style != selectionStyle)
+ SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, selectionStyle);
+
+ TextRun selectionTextRun(constructTextRun(selectionStyle, fragment));
+ paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition);
+
+ if (style != selectionStyle)
+ SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, style);
+
+ // Eventually draw text using regular style from the end position of the selection to the end of the current chunk part
+ if (endPosition < static_cast<int>(fragment.length) && !paintSelectedTextOnly)
+ paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length);
+}
+
+IntRect SVGInlineTextBox::calculateBoundaries() const
+{
+ FloatRect textRect;
+
+ RenderText* textRenderer = this->textRenderer();
+ ASSERT(textRenderer);
+
+ RenderStyle* style = textRenderer->style();
+ ASSERT(style);
+
+ int baseline = baselinePosition();
+ int heightDifference = baseline - style->font().ascent();
+
+ unsigned textFragmentsSize = m_textFragments.size();
+ for (unsigned i = 0; i < textFragmentsSize; ++i) {
+ const SVGTextFragment& fragment = m_textFragments.at(i);
+ FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height + heightDifference);
+
+ if (!fragment.transform.isIdentity())
+ fragmentRect = fragment.transform.mapRect(fragmentRect);
+
+ textRect.unite(fragmentRect);
+ }
+
+ return enclosingIntRect(textRect);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/svg/SVGInlineTextBox.h
index 24957cf..8e82dda 100644
--- a/WebCore/rendering/SVGInlineTextBox.h
+++ b/WebCore/rendering/svg/SVGInlineTextBox.h
@@ -25,17 +25,13 @@
#if ENABLE(SVG)
#include "InlineTextBox.h"
-#include "SVGTextChunkLayoutInfo.h"
-#include "SVGTextLayoutUtilities.h"
+#include "SVGTextLayoutEngine.h"
namespace WebCore {
class RenderSVGResource;
class SVGRootInlineBox;
-struct SVGCharacterLayoutInfo;
-struct SVGLastGlyphInfo;
-
class SVGInlineTextBox : public InlineTextBox {
public:
SVGInlineTextBox(RenderObject*);
@@ -50,30 +46,26 @@ public:
virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const;
virtual int positionForOffset(int offset) const;
+ void paintSelectionBackground(PaintInfo&);
virtual void paint(PaintInfo&, int tx, int ty);
- virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos);
-
- virtual void selectionStartEnd(int& startPos, int& endPos);
- void mapStartEndPositionsIntoChunkPartCoordinates(int& startPos, int& endPos, const SVGTextChunkPart&) const;
+ virtual IntRect selectionRect(int absx, int absy, int startPosition, int endPosition);
- SVGRootInlineBox* svgRootInlineBox() const;
+ bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const;
- // Helper functions shared with SVGRootInlineBox
- void measureCharacter(RenderStyle*, int position, int& charsConsumed, String& glyphName, String& unicodeString, float& glyphWidth, float& glyphHeight) const;
- FloatRect calculateGlyphBoundaries(RenderStyle*, int position, const SVGChar&) const;
+ virtual IntRect calculateBoundaries() const;
- void buildLayoutInformation(SVGCharacterLayoutInfo&, SVGLastGlyphInfo&);
+ void clearTextFragments() { m_textFragments.clear(); }
+ Vector<SVGTextFragment>& textFragments() { return m_textFragments; }
+ const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; }
- const AffineTransform& chunkTransformation() const { return m_chunkTransformation; }
- void setChunkTransformation(const AffineTransform& transform) { m_chunkTransformation = transform; }
- void addChunkPartInformation(const SVGTextChunkPart& part) { m_svgTextChunkParts.append(part); }
- const Vector<SVGTextChunkPart>& svgTextChunkParts() const { return m_svgTextChunkParts; }
+ bool startsNewTextChunk() const { return m_startsNewTextChunk; }
+ void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; }
- virtual IntRect calculateBoundaries() const;
+ int offsetForPositionInFragment(const SVGTextFragment&, float position, bool includePartialGlyphs) const;
+ FloatRect selectionRectForTextFragment(const SVGTextFragment&, int fragmentStartPosition, int fragmentEndPosition, RenderStyle*);
private:
- TextRun constructTextRun(RenderStyle*) const;
- AffineTransform buildChunkTransformation(SVGChar& firstCharacter) const;
+ TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const;
bool acquirePaintingResource(GraphicsContext*&, RenderObject*, RenderStyle*);
void releasePaintingResource(GraphicsContext*&);
@@ -81,22 +73,17 @@ private:
bool prepareGraphicsContextForTextPainting(GraphicsContext*&, TextRun&, RenderStyle*);
void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&);
- void computeTextMatchMarkerRect(RenderStyle*);
- void paintDecoration(GraphicsContext*, const FloatPoint& textOrigin, ETextDecoration, bool hasSelection);
- void paintDecorationWithStyle(GraphicsContext*, const FloatPoint& textOrigin, RenderObject*, ETextDecoration);
- void paintSelection(GraphicsContext*, const FloatPoint& textOrigin, RenderStyle*);
- void paintText(GraphicsContext*, const FloatPoint& textOrigin, RenderStyle*, RenderStyle* selectionStyle, bool hasSelection, bool paintSelectedTextOnly);
- void paintTextWithShadows(GraphicsContext*, const FloatPoint& textOrigin, RenderStyle*, TextRun&, int startPos, int endPos);
-
- FloatRect selectionRectForTextChunkPart(const SVGTextChunkPart&, int partStartPos, int partEndPos, RenderStyle*);
+ void paintDecoration(GraphicsContext*, ETextDecoration, const SVGTextFragment&);
+ void paintDecorationWithStyle(GraphicsContext*, ETextDecoration, const SVGTextFragment&, RenderObject* decorationRenderer);
+ void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition);
+ void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly);
private:
int m_logicalHeight;
- AffineTransform m_chunkTransformation;
- Vector<SVGTextChunkPart> m_svgTextChunkParts;
- mutable SVGTextChunkPart m_currentChunkPart;
- RenderSVGResource* m_paintingResource;
int m_paintingResourceMode;
+ bool m_startsNewTextChunk : 1;
+ RenderSVGResource* m_paintingResource;
+ Vector<SVGTextFragment> m_textFragments;
};
} // namespace WebCore
diff --git a/WebCore/rendering/svg/SVGRootInlineBox.cpp b/WebCore/rendering/svg/SVGRootInlineBox.cpp
new file mode 100644
index 0000000..7109e1f
--- /dev/null
+++ b/WebCore/rendering/svg/SVGRootInlineBox.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * Copyright (C) 2006 Apple Computer Inc.
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 "SVGRootInlineBox.h"
+
+#if ENABLE(SVG)
+#include "GraphicsContext.h"
+#include "RenderBlock.h"
+#include "RenderSVGInlineText.h"
+#include "SVGInlineFlowBox.h"
+#include "SVGInlineTextBox.h"
+#include "SVGRenderSupport.h"
+#include "SVGTextPositioningElement.h"
+
+namespace WebCore {
+
+void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int)
+{
+ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
+ ASSERT(!paintInfo.context->paintingDisabled());
+
+ RenderObject* boxRenderer = renderer();
+ ASSERT(boxRenderer);
+
+ bool isPrinting = renderer()->document()->printing();
+ bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone;
+
+ PaintInfo childPaintInfo(paintInfo);
+ if (hasSelection) {
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox())
+ static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo);
+ else if (child->isSVGInlineFlowBox())
+ static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo);
+ }
+ }
+
+ childPaintInfo.context->save();
+
+ if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) {
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox())
+ SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
+
+ child->paint(childPaintInfo, 0, 0);
+ }
+ }
+
+ SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context);
+ childPaintInfo.context->restore();
+}
+
+void SVGRootInlineBox::computePerCharacterLayoutInformation()
+{
+ // Perform SVG text layout phase two (see SVGTextLayoutEngine for details).
+ SVGTextLayoutEngine characterLayout;
+ layoutCharactersInTextBoxes(this, characterLayout);
+
+ // Perform SVG text layout phase three (see SVGTextChunkBuilder for details).
+ characterLayout.finishLayout();
+
+ // Perform SVG text layout phase four
+ // Position & resize all SVGInlineText/FlowBoxes in the inline box tree, resize the root box as well as the RenderSVGText parent block.
+ layoutChildBoxes(this);
+ layoutRootBox();
+}
+
+void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGTextLayoutEngine& characterLayout)
+{
+ for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox()) {
+ ASSERT(child->renderer());
+ ASSERT(child->renderer()->isSVGInlineText());
+
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
+ characterLayout.layoutInlineTextBox(textBox);
+ } else {
+ ASSERT(child->isInlineFlowBox());
+
+ // Skip generated content.
+ Node* node = child->renderer()->node();
+ if (!node)
+ continue;
+
+ SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
+ bool isTextPath = node->hasTagName(SVGNames::textPathTag);
+ if (isTextPath) {
+ // Build text chunks for all <textPath> children, using the line layout algorithm.
+ // This is needeed as text-anchor is just an additional startOffset for text paths.
+ SVGTextLayoutEngine lineLayout;
+ layoutCharactersInTextBoxes(flowBox, lineLayout);
+ characterLayout.beginTextPathLayout(child->renderer(), lineLayout);
+ }
+
+ layoutCharactersInTextBoxes(flowBox, characterLayout);
+
+ if (isTextPath)
+ characterLayout.endTextPathLayout();
+ }
+ }
+}
+
+void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start)
+{
+ for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) {
+ if (child->isSVGInlineTextBox()) {
+ ASSERT(child->renderer());
+ ASSERT(child->renderer()->isSVGInlineText());
+
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
+ IntRect boxRect = textBox->calculateBoundaries();
+ textBox->setX(boxRect.x());
+ textBox->setY(boxRect.y());
+ textBox->setLogicalWidth(boxRect.width());
+ textBox->setLogicalHeight(boxRect.height());
+ } else {
+ ASSERT(child->isInlineFlowBox());
+
+ // Skip generated content.
+ if (!child->renderer()->node())
+ continue;
+
+ SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
+ layoutChildBoxes(flowBox);
+
+ IntRect boxRect = flowBox->calculateBoundaries();
+ flowBox->setX(boxRect.x());
+ flowBox->setY(boxRect.y());
+ flowBox->setLogicalWidth(boxRect.width());
+ flowBox->setLogicalHeight(boxRect.height());
+ }
+ }
+}
+
+void SVGRootInlineBox::layoutRootBox()
+{
+ RenderBlock* parentBlock = block();
+ ASSERT(parentBlock);
+
+ IntRect childRect;
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ // Skip generated content.
+ if (!child->renderer()->node())
+ continue;
+ childRect.unite(child->calculateBoundaries());
+ }
+
+ int xBlock = childRect.x();
+ int yBlock = childRect.y();
+ int widthBlock = childRect.width();
+ int heightBlock = childRect.height();
+
+ // Finally, assign the root block position, now that all content is laid out.
+ parentBlock->setLocation(xBlock, yBlock);
+ parentBlock->setWidth(widthBlock);
+ parentBlock->setHeight(heightBlock);
+
+ // Position all children relative to the parent block.
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
+ // Skip generated content.
+ if (!child->renderer()->node())
+ continue;
+ child->adjustPosition(-xBlock, -yBlock);
+ }
+
+ // Position ourselves.
+ setX(0);
+ setY(0);
+ setLogicalWidth(widthBlock);
+ setLogicalHeight(heightBlock);
+ setBlockLogicalHeight(heightBlock);
+ setLineTopBottomPositions(0, heightBlock);
+}
+
+InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const IntPoint& point)
+{
+ InlineBox* firstLeaf = firstLeafChild();
+ InlineBox* lastLeaf = lastLeafChild();
+ if (firstLeaf == lastLeaf)
+ return firstLeaf;
+
+ // FIXME: Check for vertical text!
+ InlineBox* closestLeaf = 0;
+ for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) {
+ if (point.y() < leaf->m_y)
+ continue;
+ if (point.y() > leaf->m_y + leaf->virtualLogicalHeight())
+ continue;
+
+ closestLeaf = leaf;
+ if (point.x() < leaf->m_x + leaf->m_logicalWidth)
+ return leaf;
+ }
+
+ return closestLeaf ? closestLeaf : lastLeaf;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/svg/SVGRootInlineBox.h
index 77e7fcb..418c289 100644
--- a/WebCore/rendering/SVGRootInlineBox.h
+++ b/WebCore/rendering/svg/SVGRootInlineBox.h
@@ -26,10 +26,8 @@
#if ENABLE(SVG)
#include "RootInlineBox.h"
-#include "SVGCharacterData.h"
-#include "SVGCharacterLayoutInfo.h"
#include "SVGRenderSupport.h"
-#include "SVGTextChunkLayoutInfo.h"
+#include "SVGTextLayoutEngine.h"
namespace WebCore {
@@ -55,20 +53,15 @@ public:
virtual FloatRect objectBoundingBox() const { return FloatRect(); }
virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
- // Used by SVGRenderTreeAsText
- const Vector<SVGTextChunk>& svgTextChunks() const { return m_svgTextChunks; }
+ InlineBox* closestLeafChildForPosition(const IntPoint&);
private:
- void propagateTextChunkPartInformation();
- void buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo&);
-
+ void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&);
+ void layoutChildBoxes(InlineFlowBox*);
void layoutRootBox();
- void layoutChildBoxes(InlineFlowBox* start);
private:
int m_logicalHeight;
- Vector<SVGChar> m_svgChars;
- Vector<SVGTextChunk> m_svgTextChunks;
};
} // namespace WebCore
diff --git a/WebCore/rendering/svg/SVGTextChunk.cpp b/WebCore/rendering/svg/SVGTextChunk.cpp
new file mode 100644
index 0000000..5dea6ad
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextChunk.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextChunk.h"
+
+#include "SVGInlineTextBox.h"
+#include "SVGTextFragment.h"
+
+namespace WebCore {
+
+SVGTextChunk::SVGTextChunk(bool isVerticalText, ETextAnchor textAnchor, SVGTextContentElement::SVGLengthAdjustType lengthAdjust, float desiredTextLength)
+ : m_isVerticalText(isVerticalText)
+ , m_textAnchor(textAnchor)
+ , m_lengthAdjust(lengthAdjust)
+ , m_desiredTextLength(desiredTextLength)
+{
+}
+
+void SVGTextChunk::calculateLength(float& length, unsigned& characters) const
+{
+ SVGTextFragment* lastFragment = 0;
+
+ unsigned boxCount = m_boxes.size();
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ SVGInlineTextBox* textBox = m_boxes.at(boxPosition);
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+
+ unsigned size = fragments.size();
+ if (!size)
+ continue;
+
+ for (unsigned i = 0; i < size; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+ characters += fragment.length;
+
+ if (m_isVerticalText)
+ length += fragment.height;
+ else
+ length += fragment.width;
+
+ if (!lastFragment) {
+ lastFragment = &fragment;
+ continue;
+ }
+
+ // Resepect gap between chunks.
+ if (m_isVerticalText)
+ length += fragment.y - (lastFragment->y + lastFragment->height);
+ else
+ length += fragment.x - (lastFragment->x + lastFragment->width);
+
+ lastFragment = &fragment;
+ }
+ }
+}
+
+float SVGTextChunk::calculateTextAnchorShift(float length) const
+{
+ switch (m_textAnchor) {
+ case TA_START:
+ return 0;
+ case TA_MIDDLE:
+ return -length / 2;
+ case TA_END:
+ return -length;
+ };
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextChunk.h b/WebCore/rendering/svg/SVGTextChunk.h
new file mode 100644
index 0000000..ebe6d81
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextChunk.h
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * 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 SVGTextChunk_h
+#define SVGTextChunk_h
+
+#if ENABLE(SVG)
+#include "SVGRenderStyleDefs.h"
+#include "SVGTextContentElement.h"
+
+namespace WebCore {
+
+class SVGInlineTextBox;
+
+// A SVGTextChunk describes a range of SVGTextFragments, see the SVG spec definition of a "text chunk".
+class SVGTextChunk {
+public:
+ SVGTextChunk(bool isVerticalText, ETextAnchor, SVGTextContentElement::SVGLengthAdjustType, float desiredTextLength);
+
+ void calculateLength(float& length, unsigned& characters) const;
+ float calculateTextAnchorShift(float length) const;
+
+ bool isVerticalText() const { return m_isVerticalText; }
+ ETextAnchor textAnchor() const { return m_textAnchor; }
+ SVGTextContentElement::SVGLengthAdjustType lengthAdjust() const { return m_lengthAdjust; }
+ float desiredTextLength() const { return m_desiredTextLength; }
+
+ Vector<SVGInlineTextBox*>& boxes() { return m_boxes; }
+ const Vector<SVGInlineTextBox*>& boxes() const { return m_boxes; }
+
+ bool hasDesiredTextLength() const { return m_lengthAdjust != SVGTextContentElement::LENGTHADJUST_UNKNOWN && m_desiredTextLength > 0; }
+ bool hasTextAnchor() const { return m_textAnchor != TA_START; }
+
+private:
+ // Contains all SVGInlineTextBoxes this chunk spans.
+ Vector<SVGInlineTextBox*> m_boxes;
+
+ // writing-mode specific property.
+ bool m_isVerticalText;
+
+ // text-anchor specific properties.
+ ETextAnchor m_textAnchor;
+
+ // textLength/lengthAdjust specific properties.
+ SVGTextContentElement::SVGLengthAdjustType m_lengthAdjust;
+ float m_desiredTextLength;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextChunkBuilder.cpp b/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
new file mode 100644
index 0000000..bbbae6c
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextChunkBuilder.h"
+
+#include "RenderSVGInlineText.h"
+#include "SVGElement.h"
+#include "SVGInlineTextBox.h"
+
+namespace WebCore {
+
+SVGTextChunkBuilder::SVGTextChunkBuilder()
+{
+}
+
+void SVGTextChunkBuilder::transformationForTextBox(SVGInlineTextBox* textBox, AffineTransform& transform) const
+{
+ DEFINE_STATIC_LOCAL(const AffineTransform, s_identityTransform, ());
+ if (!m_textBoxTransformations.contains(textBox)) {
+ transform = s_identityTransform;
+ return;
+ }
+
+ transform = m_textBoxTransformations.get(textBox);
+}
+
+void SVGTextChunkBuilder::buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes)
+{
+ if (lineLayoutBoxes.isEmpty())
+ return;
+
+ bool foundStart = false;
+ unsigned lastChunkStartPosition = 0;
+ unsigned boxPosition = 0;
+ unsigned boxCount = lineLayoutBoxes.size();
+ for (; boxPosition < boxCount; ++boxPosition) {
+ SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxPosition);
+ if (!textBox->startsNewTextChunk())
+ continue;
+
+ if (!foundStart) {
+ lastChunkStartPosition = boxPosition;
+ foundStart = true;
+ } else {
+ ASSERT(boxPosition > lastChunkStartPosition);
+ addTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition - lastChunkStartPosition);
+ lastChunkStartPosition = boxPosition;
+ }
+ }
+
+ if (!foundStart)
+ return;
+
+ if (boxPosition - lastChunkStartPosition > 0)
+ addTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition - lastChunkStartPosition);
+}
+
+void SVGTextChunkBuilder::layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes)
+{
+ buildTextChunks(lineLayoutBoxes);
+ if (m_textChunks.isEmpty())
+ return;
+
+ unsigned chunkCount = m_textChunks.size();
+ for (unsigned i = 0; i < chunkCount; ++i)
+ processTextChunk(m_textChunks.at(i));
+
+ m_textChunks.clear();
+}
+
+void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxStart, unsigned boxCount)
+{
+ SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxStart);
+ ASSERT(textBox);
+
+ RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer());
+ ASSERT(textRenderer);
+
+ const RenderStyle* style = textRenderer->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ SVGTextContentElement::SVGLengthAdjustType lengthAdjust = SVGTextContentElement::LENGTHADJUST_UNKNOWN;
+ float desiredTextLength = 0;
+
+ if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) {
+ lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
+ desiredTextLength = textContentElement->textLength().value(textContentElement);
+ }
+
+ SVGTextChunk chunk(svgStyle->isVerticalWritingMode(), svgStyle->textAnchor(), lengthAdjust, desiredTextLength);
+
+ Vector<SVGInlineTextBox*>& boxes = chunk.boxes();
+ for (unsigned i = boxStart; i < boxStart + boxCount; ++i)
+ boxes.append(lineLayoutBoxes.at(i));
+
+ m_textChunks.append(chunk);
+}
+
+void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
+{
+ bool processTextLength = chunk.hasDesiredTextLength();
+ bool processTextAnchor = chunk.hasTextAnchor();
+ if (!processTextAnchor && !processTextLength)
+ return;
+
+ const Vector<SVGInlineTextBox*>& boxes = chunk.boxes();
+ unsigned boxCount = boxes.size();
+ if (!boxCount)
+ return;
+
+ // Calculate absolute length of whole text chunk (starting from text box 'start', spanning 'length' text boxes).
+ float chunkLength = 0;
+ unsigned chunkCharacters = 0;
+ chunk.calculateLength(chunkLength, chunkCharacters);
+
+ bool isVerticalText = chunk.isVerticalText();
+ if (processTextLength) {
+ if (chunk.lengthAdjust() == SVGTextContentElement::LENGTHADJUST_SPACING) {
+ float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters;
+ unsigned atCharacter = 0;
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments();
+ if (fragments.isEmpty())
+ continue;
+ processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter);
+ }
+ } else {
+ ASSERT(chunk.lengthAdjust() == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS);
+ float scale = chunk.desiredTextLength() / chunkLength;
+ AffineTransform spacingAndGlyphsTransform;
+
+ bool foundFirstFragment = false;
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ SVGInlineTextBox* textBox = boxes.at(boxPosition);
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+ if (fragments.isEmpty())
+ continue;
+
+ if (!foundFirstFragment) {
+ foundFirstFragment = true;
+ buildSpacingAndGlyphsTransform(isVerticalText, scale, fragments.first(), spacingAndGlyphsTransform);
+ }
+
+ m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform);
+ }
+ }
+ }
+
+ if (!processTextAnchor)
+ return;
+
+ // If we previously applied a lengthAdjust="spacing" correction, we have to recalculate the chunk length, to be able to apply the text-anchor shift.
+ if (processTextLength && chunk.lengthAdjust() == SVGTextContentElement::LENGTHADJUST_SPACING) {
+ chunkLength = 0;
+ chunkCharacters = 0;
+ chunk.calculateLength(chunkLength, chunkCharacters);
+ }
+
+ float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength);
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments();
+ if (fragments.isEmpty())
+ continue;
+ processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments);
+ }
+}
+
+void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText, float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharacter)
+{
+ unsigned fragmentCount = fragments.size();
+ for (unsigned i = 0; i < fragmentCount; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+
+ if (isVerticalText)
+ fragment.y += textLengthShift * atCharacter;
+ else
+ fragment.x += textLengthShift * atCharacter;
+
+ atCharacter += fragment.length;
+ }
+}
+
+void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float textAnchorShift, Vector<SVGTextFragment>& fragments)
+{
+ unsigned fragmentCount = fragments.size();
+ for (unsigned i = 0; i < fragmentCount; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+
+ if (isVerticalText)
+ fragment.y += textAnchorShift;
+ else
+ fragment.x += textAnchorShift;
+ }
+}
+
+void SVGTextChunkBuilder::buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, const SVGTextFragment& fragment, AffineTransform& spacingAndGlyphsTransform)
+{
+ spacingAndGlyphsTransform.translate(fragment.x, fragment.y);
+
+ if (isVerticalText)
+ spacingAndGlyphsTransform.scaleNonUniform(1, scale);
+ else
+ spacingAndGlyphsTransform.scaleNonUniform(scale, 1);
+
+ spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextChunkBuilder.h b/WebCore/rendering/svg/SVGTextChunkBuilder.h
new file mode 100644
index 0000000..36342e7
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextChunkBuilder.h
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * 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 SVGTextChunkBuilder_h
+#define SVGTextChunkBuilder_h
+
+#if ENABLE(SVG)
+#include "SVGTextChunk.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SVGInlineTextBox;
+struct SVGTextFragment;
+
+// SVGTextChunkBuilder performs the third layout phase for SVG text.
+//
+// Phase one built the layout information from the SVG DOM stored in the RenderSVGInlineText objects (SVGTextLayoutAttributes).
+// Phase two performed the actual per-character layout, computing the final positions for each character, stored in the SVGInlineTextBox objects (SVGTextFragment).
+// Phase three performs all modifications that have to be applied to each individual text chunk (text-anchor & textLength).
+
+class SVGTextChunkBuilder : public Noncopyable {
+public:
+ SVGTextChunkBuilder();
+
+ const Vector<SVGTextChunk>& textChunks() const { return m_textChunks; }
+ void transformationForTextBox(SVGInlineTextBox*, AffineTransform&) const;
+
+ void buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes);
+ void layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes);
+
+private:
+ void addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxPosition, unsigned boxCount);
+ void processTextChunk(const SVGTextChunk&);
+
+ void processTextLengthSpacingCorrection(bool isVerticalText, float textLengthShift, Vector<SVGTextFragment>&, unsigned& atCharacter);
+ void processTextAnchorCorrection(bool isVerticalText, float textAnchorShift, Vector<SVGTextFragment>&);
+ void buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, const SVGTextFragment&, AffineTransform&);
+
+private:
+ Vector<SVGTextChunk> m_textChunks;
+ HashMap<SVGInlineTextBox*, AffineTransform> m_textBoxTransformations;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextFragment.h b/WebCore/rendering/svg/SVGTextFragment.h
new file mode 100644
index 0000000..2e520da
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextFragment.h
@@ -0,0 +1,57 @@
+/*
+ * 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
+ * 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 SVGTextFragment_h
+#define SVGTextFragment_h
+
+#if ENABLE(SVG)
+#include "AffineTransform.h"
+
+namespace WebCore {
+
+// A SVGTextFragment describes a text fragment of a RenderSVGInlineText which can be rendered at once.
+struct SVGTextFragment {
+ SVGTextFragment()
+ : positionListOffset(0)
+ , length(0)
+ , x(0)
+ , y(0)
+ , width(0)
+ , height(0)
+ {
+ }
+
+ // The first rendered character starts at RenderSVGInlineText::characters() + positionListOffset.
+ unsigned positionListOffset;
+ unsigned length;
+
+ float x;
+ float y;
+ float width;
+ float height;
+
+ // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, lengthAdjust="spacingAndGlyphs" (for textPath only),
+ // as well as orientation related shifts (see SVGTextLayoutEngine, which builds this transformation).
+ AffineTransform transform;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
index 3283b35..3037b77 100644
--- a/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
@@ -31,13 +31,13 @@ SVGTextLayoutAttributes::SVGTextLayoutAttributes()
{
}
-void SVGTextLayoutAttributes::fillWithEmptyValues(unsigned length)
+void SVGTextLayoutAttributes::reserveCapacity(unsigned length)
{
- m_xValues.fill(emptyValue(), length);
- m_yValues.fill(emptyValue(), length);
- m_dxValues.fill(emptyValue(), length);
- m_dyValues.fill(emptyValue(), length);
- m_rotateValues.fill(emptyValue(), length);
+ m_xValues.reserveCapacity(length);
+ m_yValues.reserveCapacity(length);
+ m_dxValues.reserveCapacity(length);
+ m_dyValues.reserveCapacity(length);
+ m_rotateValues.reserveCapacity(length);
}
float SVGTextLayoutAttributes::emptyValue()
@@ -46,7 +46,7 @@ float SVGTextLayoutAttributes::emptyValue()
return s_emptyValue;
}
-static inline void dumpLayoutVector(Vector<float>& values)
+static inline void dumpLayoutVector(const Vector<float>& values)
{
if (values.isEmpty()) {
fprintf(stderr, "empty");
@@ -63,7 +63,7 @@ static inline void dumpLayoutVector(Vector<float>& values)
}
}
-void SVGTextLayoutAttributes::dump()
+void SVGTextLayoutAttributes::dump() const
{
fprintf(stderr, "x values: ");
dumpLayoutVector(m_xValues);
@@ -86,11 +86,11 @@ void SVGTextLayoutAttributes::dump()
fprintf(stderr, "\n");
fprintf(stderr, "character data values:\n");
- Vector<CharacterData>::iterator end = m_characterDataValues.end();
- for (Vector<CharacterData>::iterator it = m_characterDataValues.begin(); it != end; ++it) {
- CharacterData& data = *it;
- fprintf(stderr, "| {spansCharacters=%i, glyphName='%s', unicodeString='%s', width=%lf, height=%lf}\n",
- data.spansCharacters, data.glyphName.utf8().data(), data.unicodeString.utf8().data(), data.width, data.height);
+ unsigned textMetricsSize = m_textMetricsValues.size();
+ for (unsigned i = 0; i < textMetricsSize; ++i) {
+ const SVGTextMetrics& metrics = m_textMetricsValues.at(i);
+ fprintf(stderr, "| {length=%i, glyphName='%s', unicodeString='%s', width=%lf, height=%lf}\n",
+ metrics.length(), metrics.glyph().name.utf8().data(), metrics.glyph().unicodeString.utf8().data(), metrics.width(), metrics.height());
}
fprintf(stderr, "\n");
}
diff --git a/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/WebCore/rendering/svg/SVGTextLayoutAttributes.h
index d88b356..d08d5b7 100644
--- a/WebCore/rendering/svg/SVGTextLayoutAttributes.h
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributes.h
@@ -21,6 +21,7 @@
#define SVGTextLayoutAttributes_h
#if ENABLE(SVG)
+#include "SVGTextMetrics.h"
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
@@ -30,8 +31,10 @@ class SVGTextLayoutAttributes {
public:
SVGTextLayoutAttributes();
- void fillWithEmptyValues(unsigned length);
- void dump();
+ void reserveCapacity(unsigned length);
+ void dump() const;
+
+ static float emptyValue();
Vector<float>& xValues() { return m_xValues; }
const Vector<float>& xValues() const { return m_xValues; }
@@ -48,31 +51,8 @@ public:
Vector<float>& rotateValues() { return m_rotateValues; }
const Vector<float>& rotateValues() const { return m_rotateValues; }
- static float emptyValue();
-
- struct CharacterData {
- CharacterData()
- : spansCharacters(0)
- , width(0)
- , height(0)
- {
- }
-
- // When multiple unicode characters map to a single glyph (eg. 'ffi' ligature)
- // 'spansCharacters' contains the number of characters this glyph spans.
- int spansCharacters;
-
- // The 'glyphName' / 'unicodeString' pair is needed for kerning calculations.
- String glyphName;
- String unicodeString;
-
- // 'width' and 'height' hold the size of this glyph/character.
- float width;
- float height;
- };
-
- Vector<CharacterData>& characterDataValues() { return m_characterDataValues; }
- const Vector<CharacterData>& characterDataValues() const { return m_characterDataValues; }
+ Vector<SVGTextMetrics>& textMetricsValues() { return m_textMetricsValues; }
+ const Vector<SVGTextMetrics>& textMetricsValues() const { return m_textMetricsValues; }
private:
Vector<float> m_xValues;
@@ -80,7 +60,7 @@ private:
Vector<float> m_dxValues;
Vector<float> m_dyValues;
Vector<float> m_rotateValues;
- Vector<CharacterData> m_characterDataValues;
+ Vector<SVGTextMetrics> m_textMetricsValues;
};
} // namespace WebCore
diff --git a/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
new file mode 100644
index 0000000..c3f4b6a
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutAttributesBuilder.h"
+
+#include "RenderSVGInlineText.h"
+#include "RenderSVGText.h"
+#include "SVGTextPositioningElement.h"
+
+// Set to a value > 0 to dump the text layout attributes
+#define DUMP_TEXT_LAYOUT_ATTRIBUTES 0
+
+namespace WebCore {
+
+SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder()
+{
+}
+
+void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot)
+{
+ ASSERT(textRoot);
+ m_scopes.clear();
+
+ // Build list of x/y/dx/dy/rotate values for each subtree element that may define these values (tspan/textPath etc).
+ unsigned atCharacter = 0;
+ UChar lastCharacter = '\0';
+ buildLayoutScopes(textRoot, atCharacter, lastCharacter);
+
+ if (!atCharacter)
+ return;
+
+ // Build list of x/y/dx/dy/rotate values for the outermost <text> element.
+ buildOutermostLayoutScope(textRoot, atCharacter);
+
+ // Propagate layout attributes to each RenderSVGInlineText object.
+ atCharacter = 0;
+ lastCharacter = '\0';
+ propagateLayoutAttributes(textRoot, atCharacter, lastCharacter);
+}
+
+static inline void extractFloatValuesFromSVGLengthList(SVGElement* lengthContext, SVGLengthList* list, Vector<float>& floatValues, unsigned textContentLength)
+{
+ ASSERT(lengthContext);
+ ASSERT(list);
+
+ unsigned length = list->numberOfItems();
+ if (length > textContentLength)
+ length = textContentLength;
+ floatValues.reserveCapacity(length);
+
+ ExceptionCode ec = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ SVGLength length = list->getItem(i, ec);
+ ASSERT(!ec);
+ floatValues.append(length.value(lengthContext));
+ }
+}
+
+static inline void extractFloatValuesFromSVGNumberList(SVGNumberList* list, Vector<float>& floatValues, unsigned textContentLength)
+{
+ ASSERT(list);
+
+ unsigned length = list->numberOfItems();
+ if (length > textContentLength)
+ length = textContentLength;
+ floatValues.reserveCapacity(length);
+
+ ExceptionCode ec = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ float length = list->getItem(i, ec);
+ ASSERT(!ec);
+ floatValues.append(length);
+ }
+}
+
+void SVGTextLayoutAttributesBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength) const
+{
+ ASSERT(renderer);
+ ASSERT(renderer->style());
+
+ scope.textContentStart = textContentStart;
+ scope.textContentLength = textContentLength;
+
+ SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(renderer);
+ if (!element)
+ return;
+
+ SVGTextLayoutAttributes& attributes = scope.attributes;
+ extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength);
+ extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength);
+
+ // The last rotation value spans the whole scope.
+ Vector<float>& rotateValues = attributes.rotateValues();
+ if (rotateValues.isEmpty())
+ return;
+
+ unsigned rotateValuesSize = rotateValues.size();
+ if (rotateValuesSize == textContentLength)
+ return;
+
+ float lastRotation = rotateValues.last();
+
+ rotateValues.resize(textContentLength);
+ for (unsigned i = rotateValuesSize; i < textContentLength; ++i)
+ rotateValues.at(i) = lastRotation;
+}
+
+static inline bool characterIsSpace(const UChar& character)
+{
+ return character == ' ';
+}
+
+static inline bool characterIsSpaceOrNull(const UChar& character)
+{
+ return character == ' ' || character == '\0';
+}
+
+static inline bool shouldPreserveAllWhiteSpace(RenderStyle* style)
+{
+ ASSERT(style);
+ return style->whiteSpace() == PRE;
+}
+
+void SVGTextLayoutAttributesBuilder::buildLayoutScopes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ if (child->isSVGInlineText()) {
+ RenderSVGInlineText* text = toRenderSVGInlineText(child);
+
+ if (!shouldPreserveAllWhiteSpace(text->style())) {
+ const UChar* characters = text->characters();
+ unsigned textLength = text->textLength();
+ for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) {
+ const UChar& currentCharacter = characters[textPosition];
+ if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter))
+ continue;
+
+ lastCharacter = currentCharacter;
+ ++atCharacter;
+ }
+ } else
+ atCharacter += text->textLength();
+
+ continue;
+ }
+
+ if (!child->isSVGInline())
+ continue;
+
+ unsigned textContentStart = atCharacter;
+ buildLayoutScopes(child, atCharacter, lastCharacter);
+
+ LayoutScope scope;
+ buildLayoutScope(scope, child, textContentStart, atCharacter - textContentStart);
+ m_scopes.append(scope);
+ }
+}
+
+void SVGTextLayoutAttributesBuilder::buildOutermostLayoutScope(RenderSVGText* textRoot, unsigned textLength)
+{
+ LayoutScope scope;
+ buildLayoutScope(scope, textRoot, 0, textLength);
+
+ // Handle <text> x/y default attributes.
+ Vector<float>& xValues = scope.attributes.xValues();
+ if (xValues.isEmpty())
+ xValues.append(0);
+
+ Vector<float>& yValues = scope.attributes.yValues();
+ if (yValues.isEmpty())
+ yValues.append(0);
+
+ m_scopes.prepend(scope);
+}
+
+void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) const
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ if (child->isSVGInlineText()) {
+ RenderSVGInlineText* text = toRenderSVGInlineText(child);
+ const UChar* characters = text->characters();
+ unsigned textLength = text->textLength();
+ bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());
+
+ SVGTextLayoutAttributes attributes;
+ attributes.reserveCapacity(textLength);
+
+ unsigned valueListPosition = atCharacter;
+ unsigned metricsLength = 1;
+ for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
+ const UChar& currentCharacter = characters[textPosition];
+
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
+ metricsLength = metrics.length();
+
+ if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
+ assignEmptyLayoutAttributesForCharacter(attributes);
+ attributes.textMetricsValues().append(SVGTextMetrics::emptyMetrics());
+ continue;
+ }
+
+ assignLayoutAttributesForCharacter(attributes, metrics, valueListPosition);
+
+ if (metricsLength > 1) {
+ for (unsigned i = 0; i < metricsLength - 1; ++i)
+ assignEmptyLayoutAttributesForCharacter(attributes);
+ }
+
+ lastCharacter = currentCharacter;
+ valueListPosition += metricsLength;
+ }
+
+#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
+ fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter);
+ attributes.dump();
+#endif
+
+ text->storeLayoutAttributes(attributes);
+ atCharacter = valueListPosition;
+ continue;
+ }
+
+ if (!child->isSVGInline())
+ continue;
+
+ propagateLayoutAttributes(child, atCharacter, lastCharacter);
+ }
+}
+
+float SVGTextLayoutAttributesBuilder::nextLayoutValue(LayoutValueType type, unsigned atCharacter) const
+{
+ for (int i = m_scopes.size() - 1; i >= 0; --i) {
+ const LayoutScope& scope = m_scopes.at(i);
+ if (scope.textContentStart > atCharacter || scope.textContentStart + scope.textContentLength < atCharacter)
+ continue;
+
+ const Vector<float>* valuesPointer = 0;
+ switch (type) {
+ case XValueAttribute:
+ valuesPointer = &scope.attributes.xValues();
+ break;
+ case YValueAttribute:
+ valuesPointer = &scope.attributes.yValues();
+ break;
+ case DxValueAttribute:
+ valuesPointer = &scope.attributes.dxValues();
+ break;
+ case DyValueAttribute:
+ valuesPointer = &scope.attributes.dyValues();
+ break;
+ case RotateValueAttribute:
+ valuesPointer = &scope.attributes.rotateValues();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ ASSERT(valuesPointer);
+ const Vector<float>& values = *valuesPointer;
+ if (values.isEmpty())
+ continue;
+
+ unsigned position = atCharacter - scope.textContentStart;
+ if (position >= values.size())
+ continue;
+
+ return values.at(position);
+ }
+
+ return SVGTextLayoutAttributes::emptyValue();
+}
+
+void SVGTextLayoutAttributesBuilder::assignLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes, SVGTextMetrics& metrics, unsigned valueListPosition) const
+{
+ attributes.xValues().append(nextLayoutValue(XValueAttribute, valueListPosition));
+ attributes.yValues().append(nextLayoutValue(YValueAttribute, valueListPosition));
+ attributes.dxValues().append(nextLayoutValue(DxValueAttribute, valueListPosition));
+ attributes.dyValues().append(nextLayoutValue(DyValueAttribute, valueListPosition));
+ attributes.rotateValues().append(nextLayoutValue(RotateValueAttribute, valueListPosition));
+ attributes.textMetricsValues().append(metrics);
+}
+
+void SVGTextLayoutAttributesBuilder::assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes) const
+{
+ attributes.xValues().append(SVGTextLayoutAttributes::emptyValue());
+ attributes.yValues().append(SVGTextLayoutAttributes::emptyValue());
+ attributes.dxValues().append(SVGTextLayoutAttributes::emptyValue());
+ attributes.dyValues().append(SVGTextLayoutAttributes::emptyValue());
+ attributes.rotateValues().append(SVGTextLayoutAttributes::emptyValue());
+ // This doesn't add an empty value to textMetricsValues() on purpose!
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutBuilder.h b/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
index 6df7fa1..f29ac64 100644
--- a/WebCore/rendering/svg/SVGTextLayoutBuilder.h
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
@@ -17,8 +17,8 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef SVGTextLayoutBuilder_h
-#define SVGTextLayoutBuilder_h
+#ifndef SVGTextLayoutAttributesBuilder_h
+#define SVGTextLayoutAttributesBuilder_h
#if ENABLE(SVG)
#include "SVGTextLayoutAttributes.h"
@@ -27,38 +27,54 @@
namespace WebCore {
class RenderObject;
-class RenderSVGInlineText;
class RenderSVGText;
-class SVGTextLayoutBuilder : public Noncopyable {
+// SVGTextLayoutAttributesBuilder performs the first layout phase for SVG text.
+//
+// It extracts the x/y/dx/dy/rotate values from the SVGTextPositioningElements in the DOM,
+// measures all characters in the RenderSVGText subtree and extracts kerning/ligature information.
+// These values are propagated to the corresponding RenderSVGInlineText renderers.
+// The first layout phase only extracts the relevant information needed in RenderBlockLineLayout
+// to create the InlineBox tree based on text chunk boundaries & BiDi information.
+// The second layout phase is carried out by SVGTextLayoutEngine.
+
+class SVGTextLayoutAttributesBuilder : public Noncopyable {
public:
- SVGTextLayoutBuilder();
+ SVGTextLayoutAttributesBuilder();
void buildLayoutAttributesForTextSubtree(RenderSVGText*);
private:
struct LayoutScope {
LayoutScope()
- : isVerticalWritingMode(false)
- , textContentStart(0)
+ : textContentStart(0)
, textContentLength(0)
{
}
- bool isVerticalWritingMode;
unsigned textContentStart;
unsigned textContentLength;
SVGTextLayoutAttributes attributes;
};
- void buildLayoutScopes(RenderObject*, unsigned& atCharacter);
- void buildLayoutScope(LayoutScope&, RenderObject*, unsigned textContentStart, unsigned textContentLength);
- void buildLayoutAttributesFromScopes();
- void propagateLayoutAttributes(RenderObject*, unsigned& atCharacter);
- void measureCharacters(RenderSVGInlineText*, SVGTextLayoutAttributes&);
+ void buildLayoutScope(LayoutScope&, RenderObject*, unsigned textContentStart, unsigned textContentLength) const;
+ void buildLayoutScopes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter);
+ void buildOutermostLayoutScope(RenderSVGText*, unsigned textLength);
+ void propagateLayoutAttributes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter) const;
+
+ enum LayoutValueType {
+ XValueAttribute,
+ YValueAttribute,
+ DxValueAttribute,
+ DyValueAttribute,
+ RotateValueAttribute
+ };
+
+ float nextLayoutValue(LayoutValueType, unsigned atCharacter) const;
+ void assignLayoutAttributesForCharacter(SVGTextLayoutAttributes&, SVGTextMetrics&, unsigned valueListPosition) const;
+ void assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes&) const;
private:
Vector<LayoutScope> m_scopes;
- SVGTextLayoutAttributes m_attributes;
};
} // namespace WebCore
diff --git a/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp b/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp
deleted file mode 100644
index 0b3a752..0000000
--- a/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-
-#if ENABLE(SVG)
-#include "SVGTextLayoutBuilder.h"
-
-#include "RenderSVGInlineText.h"
-#include "RenderSVGText.h"
-#include "SVGTextLayoutUtilities.h"
-#include "SVGTextPositioningElement.h"
-
-// Set to a value > 0 to dump the layout vectors
-#define DUMP_LAYOUT_VECTORS 0
-
-namespace WebCore {
-
-SVGTextLayoutBuilder::SVGTextLayoutBuilder()
-{
-}
-
-void SVGTextLayoutBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot)
-{
- ASSERT(textRoot);
- m_scopes.clear();
-
- // Build layout scopes.
- unsigned atCharacter = 0;
- buildLayoutScopes(textRoot, atCharacter);
-
- if (!atCharacter)
- return;
-
- // Add outermost scope, after text length is known.
- LayoutScope scope;
- buildLayoutScope(scope, textRoot, 0, atCharacter);
- m_scopes.prepend(scope);
-
- // Build layout information respecting scope of attribute values.
- buildLayoutAttributesFromScopes();
-
- atCharacter = 0;
- propagateLayoutAttributes(textRoot, atCharacter);
-}
-
-static inline void copyToDestinationVector(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned sourceStartOffset, unsigned length)
-{
- ASSERT(destinationStartOffset + length <= destination.size());
-
- Vector<float>::iterator sourceBegin = source.begin() + sourceStartOffset;
- std::copy(sourceBegin, sourceBegin + length, destination.begin() + destinationStartOffset);
-}
-
-static inline void copyToDestinationVectorIfSourceRangeIsNotEmpty(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned sourceStartOffset, unsigned length)
-{
- bool rangeEmpty = true;
-
- unsigned size = sourceStartOffset + length;
- for (unsigned i = sourceStartOffset; i < size; ++i) {
- if (source.at(i) == SVGTextLayoutAttributes::emptyValue())
- continue;
- rangeEmpty = false;
- break;
- }
-
- if (rangeEmpty)
- return;
-
- destination.resize(length);
- copyToDestinationVector(destination, destinationStartOffset, source, sourceStartOffset, length);
-}
-
-void SVGTextLayoutBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter)
-{
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
- if (!child->isSVGInlineText()) {
- if (child->isSVGInline())
- propagateLayoutAttributes(child, atCharacter);
- continue;
- }
-
- RenderSVGInlineText* text = static_cast<RenderSVGInlineText*>(child);
- unsigned textLength = text->textLength();
-
- // Build layout attributes for a single RenderSVGInlineText renderer.
- SVGTextLayoutAttributes attributes;
-
- // The x value list should always be as large as the text length.
- // Any values that are empty will be filled in by the actual text layout process later,
- // as we need to be able to query the x/y position for every character through SVG DOM.
- attributes.xValues().resize(textLength);
- copyToDestinationVector(attributes.xValues(), 0, m_attributes.xValues(), atCharacter, textLength);
-
- // Same for the y value list.
- attributes.yValues().resize(textLength);
- copyToDestinationVector(attributes.yValues(), 0, m_attributes.yValues(), atCharacter, textLength);
-
- // The dx/dy/rotate value lists may be empty.
- copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.dxValues(), 0, m_attributes.dxValues(), atCharacter, textLength);
- copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.dyValues(), 0, m_attributes.dyValues(), atCharacter, textLength);
- copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.rotateValues(), 0, m_attributes.rotateValues(), atCharacter, textLength);
-
- // Build CharacterData, which will be used to detect ligatures, holds kerning pairs (glyph name, unicode string) and character metrics.
- measureCharacters(text, attributes);
-
-#if DUMP_LAYOUT_VECTORS > 0
- fprintf(stderr, "Dumping layout vector for RenderSVGInlineText, renderer=%p, node=%p\n", text, text->node());
- attributes.dump();
-#endif
-
- text->storeLayoutAttributes(attributes);
- atCharacter += text->textLength();
- }
-}
-
-void SVGTextLayoutBuilder::buildLayoutScopes(RenderObject* start, unsigned& atCharacter)
-{
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
- if (child->isSVGInlineText()) {
- atCharacter += toRenderText(child)->textLength();
- continue;
- }
-
- if (!child->isSVGInline())
- continue;
-
- unsigned textContentStart = atCharacter;
- buildLayoutScopes(child, atCharacter);
-
- LayoutScope scope;
- buildLayoutScope(scope, child, textContentStart, atCharacter - textContentStart);
- m_scopes.append(scope);
- }
-}
-
-static inline void fillDestinationVectorWithLastSourceValue(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned length)
-{
- if (source.isEmpty())
- return;
-
- float lastValue = source.last();
-
- unsigned rotateValuesSize = source.size();
- for (unsigned i = rotateValuesSize; i < length; ++i) {
- ASSERT(i + destinationStartOffset < destination.size());
- destination.at(i + destinationStartOffset) = lastValue;
- }
-}
-
-void SVGTextLayoutBuilder::buildLayoutAttributesFromScopes()
-{
- ASSERT(!m_scopes.isEmpty());
-
- unsigned totalLength = m_scopes.first().textContentLength;
- if (!totalLength)
- return;
-
- m_attributes.fillWithEmptyValues(totalLength);
-
- // Build final list of x/y/dx/dy/rotate values for each character stores in the <text> subtree.
- for (unsigned atScope = 0; atScope < m_scopes.size(); ++atScope) {
- LayoutScope& scope = m_scopes.at(atScope);
- SVGTextLayoutAttributes& attributes = scope.attributes;
-
- copyToDestinationVector(m_attributes.xValues(), scope.textContentStart, attributes.xValues(), 0, attributes.xValues().size());
- copyToDestinationVector(m_attributes.yValues(), scope.textContentStart, attributes.yValues(), 0, attributes.yValues().size());
- copyToDestinationVector(m_attributes.dxValues(), scope.textContentStart, attributes.dxValues(), 0, attributes.dxValues().size());
- copyToDestinationVector(m_attributes.dyValues(), scope.textContentStart, attributes.dyValues(), 0, attributes.dyValues().size());
- copyToDestinationVector(m_attributes.rotateValues(), scope.textContentStart, attributes.rotateValues(), 0, attributes.rotateValues().size());
-
- // In horizontal (vertical) writing modes, the last y (x) value in the scope is the default y (x) value for all following characters, unless explicitely overriden.
- if (scope.isVerticalWritingMode)
- fillDestinationVectorWithLastSourceValue(m_attributes.xValues(), scope.textContentStart, attributes.xValues(), scope.textContentLength);
- else
- fillDestinationVectorWithLastSourceValue(m_attributes.yValues(), scope.textContentStart, attributes.yValues(), scope.textContentLength);
-
- // The last rotation value in the scope is the default rotation for all following character, unless explicitely overriden.
- fillDestinationVectorWithLastSourceValue(m_attributes.rotateValues(), scope.textContentStart, attributes.rotateValues(), scope.textContentLength);
- }
-}
-
-void SVGTextLayoutBuilder::measureCharacters(RenderSVGInlineText* text, SVGTextLayoutAttributes& attributes)
-{
- ASSERT(text);
- ASSERT(text->style());
- const Font& font = text->style()->font();
- const UChar* characters = text->characters();
- int length = text->textLength();
-
- TextRun run(0, 0);
- run.disableSpacing();
- run.disableRoundingHacks();
-
- int charsConsumed = 0;
- for (int position = 0; position < length; position += charsConsumed) {
- run.setText(characters + position, 1);
- int extraCharsAvailable = length - position - 1;
-
- SVGTextLayoutAttributes::CharacterData characterData;
- characterData.width = font.floatWidth(run, extraCharsAvailable, characterData.spansCharacters, characterData.glyphName);
- characterData.height = font.height();
- characterData.unicodeString = String(characters + position, characterData.spansCharacters);
- attributes.characterDataValues().append(characterData);
-
- charsConsumed = characterData.spansCharacters;
- }
-}
-
-static inline void extractFloatValuesFromSVGLengthList(SVGElement* lengthContext, SVGLengthList* list, Vector<float>& floatValues, int textContentLength)
-{
- ASSERT(lengthContext);
- ASSERT(list);
- ASSERT(textContentLength >= 0);
-
- ExceptionCode ec = 0;
- int length = list->numberOfItems();
- if (length > textContentLength)
- length = textContentLength;
-
- for (int i = 0; i < length; ++i) {
- SVGLength length(list->getItem(i, ec));
- ASSERT(!ec);
- floatValues.append(length.value(lengthContext));
- }
-}
-
-static inline void extractFloatValuesFromSVGNumberList(SVGNumberList* list, Vector<float>& floatValues, int textContentLength)
-{
- ASSERT(list);
- ASSERT(textContentLength >= 0);
-
- ExceptionCode ec = 0;
- int length = list->numberOfItems();
- if (length > textContentLength)
- length = textContentLength;
-
- for (int i = 0; i < length; ++i) {
- float length(list->getItem(i, ec));
- ASSERT(!ec);
- floatValues.append(length);
- }
-}
-
-static inline SVGTextPositioningElement* svgTextPositioningElementForInlineRenderer(RenderObject* renderer)
-{
- ASSERT(renderer);
- ASSERT(renderer->isSVGText() || renderer->isSVGInline());
-
- Node* node = renderer->node();
- ASSERT(node);
- ASSERT(node->isSVGElement());
-
- if (!node->hasTagName(SVGNames::textTag)
- && !node->hasTagName(SVGNames::tspanTag)
-#if ENABLE(SVG_FONTS)
- && !node->hasTagName(SVGNames::altGlyphTag)
-#endif
- && !node->hasTagName(SVGNames::trefTag))
- return 0;
-
- return static_cast<SVGTextPositioningElement*>(node);
-}
-
-void SVGTextLayoutBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength)
-{
- ASSERT(renderer);
- ASSERT(renderer->style());
-
- scope.isVerticalWritingMode = isVerticalWritingMode(renderer->style()->svgStyle());
- scope.textContentStart = textContentStart;
- scope.textContentLength = textContentLength;
-
- SVGTextPositioningElement* element = svgTextPositioningElementForInlineRenderer(renderer);
- if (!element)
- return;
-
- SVGTextLayoutAttributes& attributes = scope.attributes;
- extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength);
- extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength);
-}
-
-}
-
-#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
new file mode 100644
index 0000000..7eefad6
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
@@ -0,0 +1,579 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutEngine.h"
+
+#include "RenderSVGInlineText.h"
+#include "RenderSVGTextPath.h"
+#include "SVGElement.h"
+#include "SVGInlineTextBox.h"
+#include "SVGTextLayoutEngineBaseline.h"
+#include "SVGTextLayoutEngineSpacing.h"
+
+// Set to a value > 0 to dump the text fragments
+#define DUMP_TEXT_FRAGMENTS 0
+
+namespace WebCore {
+
+SVGTextLayoutEngine::SVGTextLayoutEngine()
+ : m_x(0)
+ , m_y(0)
+ , m_dx(0)
+ , m_dy(0)
+ , m_isVerticalText(false)
+ , m_inPathLayout(false)
+ , m_textPathLength(0)
+ , m_textPathCurrentOffset(0)
+ , m_textPathSpacing(0)
+ , m_textPathScaling(1)
+{
+}
+
+void SVGTextLayoutEngine::updateCharacerPositionIfNeeded(float& x, float& y)
+{
+ if (m_inPathLayout)
+ return;
+
+ // Replace characters x/y position, with the current text position plus any
+ // relative adjustments, if it doesn't specify an absolute position itself.
+ if (x == SVGTextLayoutAttributes::emptyValue())
+ x = m_x + m_dx;
+
+ if (y == SVGTextLayoutAttributes::emptyValue())
+ y = m_y + m_dy;
+
+ m_dx = 0;
+ m_dy = 0;
+}
+
+void SVGTextLayoutEngine::updateCurrentTextPosition(float x, float y, float glyphAdvance)
+{
+ // Update current text position after processing the character.
+ if (m_isVerticalText) {
+ m_x = x;
+ m_y = y + glyphAdvance;
+ } else {
+ m_x = x + glyphAdvance;
+ m_y = y;
+ }
+}
+
+void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues, unsigned positionListOffset)
+{
+ // Update relative positioning information.
+ if (dxValues.isEmpty() && dyValues.isEmpty())
+ return;
+
+ float dx = 0;
+ if (!dxValues.isEmpty()) {
+ float& dxCurrent = dxValues.at(positionListOffset);
+ if (dxCurrent != SVGTextLayoutAttributes::emptyValue())
+ dx = dxCurrent;
+ }
+
+ float dy = 0;
+ if (!dyValues.isEmpty()) {
+ float& dyCurrent = dyValues.at(positionListOffset);
+ if (dyCurrent != SVGTextLayoutAttributes::emptyValue())
+ dy = dyCurrent;
+ }
+
+ if (m_inPathLayout) {
+ if (m_isVerticalText) {
+ m_dx += dx;
+ m_dy = dy;
+ } else {
+ m_dx = dx;
+ m_dy += dy;
+ }
+
+ return;
+ }
+
+ m_dx = dx;
+ m_dy = dy;
+}
+
+void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, RenderSVGInlineText* text, unsigned positionListOffset, const SVGTextMetrics& lastCharacterMetrics)
+{
+ ASSERT(!m_currentTextFragment.length);
+
+ // Figure out length of fragment.
+ m_currentTextFragment.length = positionListOffset - m_currentTextFragment.positionListOffset;
+
+ // Figure out fragment metrics.
+ if (m_currentTextFragment.length == 1) {
+ // Fast path, can rely on already computed per-character metrics.
+ m_currentTextFragment.width = lastCharacterMetrics.width();
+ m_currentTextFragment.height = lastCharacterMetrics.height();
+ } else {
+ // Need to measure the whole range (range metrics != sum of character metrics)
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, m_currentTextFragment.positionListOffset, m_currentTextFragment.length);
+ m_currentTextFragment.width = metrics.width();
+ m_currentTextFragment.height = metrics.height();
+ }
+
+ textBox->textFragments().append(m_currentTextFragment);
+ m_currentTextFragment = SVGTextFragment();
+}
+
+bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const
+{
+ RenderObject* currentParent = parent;
+ while (currentParent) {
+ SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent);
+ if (textContentElement) {
+ SVGTextContentElement::SVGLengthAdjustType lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->textLength().value(textContentElement) > 0)
+ return true;
+ }
+
+ if (currentParent->isSVGText())
+ return false;
+
+ currentParent = currentParent->parent();
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayoutEngine& lineLayout)
+{
+ ASSERT(object);
+
+ m_inPathLayout = true;
+ RenderSVGTextPath* textPath = toRenderSVGTextPath(object);
+
+ m_textPath = textPath->layoutPath();
+ m_textPathStartOffset = textPath->startOffset();
+ m_textPathLength = m_textPath.length();
+ if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1)
+ m_textPathStartOffset *= m_textPathLength;
+
+ float totalLength = 0;
+ unsigned totalCharacters = 0;
+
+ lineLayout.m_chunkLayoutBuilder.buildTextChunks(lineLayout.m_lineLayoutBoxes);
+ const Vector<SVGTextChunk>& textChunks = lineLayout.m_chunkLayoutBuilder.textChunks();
+
+ unsigned size = textChunks.size();
+ for (unsigned i = 0; i < size; ++i) {
+ const SVGTextChunk& chunk = textChunks.at(i);
+
+ float length = 0;
+ unsigned characters = 0;
+ chunk.calculateLength(length, characters);
+
+ // Handle text-anchor as additional start offset for text paths.
+ m_textPathStartOffset += chunk.calculateTextAnchorShift(length);
+
+ totalLength += length;
+ totalCharacters += characters;
+ }
+
+ m_textPathCurrentOffset = m_textPathStartOffset;
+
+ // Eventually handle textLength adjustments.
+ SVGTextContentElement::SVGLengthAdjustType lengthAdjust = SVGTextContentElement::LENGTHADJUST_UNKNOWN;
+ float desiredTextLength = 0;
+
+ if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) {
+ lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
+ desiredTextLength = textContentElement->textLength().value(textContentElement);
+ }
+
+ if (!desiredTextLength)
+ return;
+
+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING)
+ m_textPathSpacing = (desiredTextLength - totalLength) / totalCharacters;
+ else
+ m_textPathScaling = desiredTextLength / totalLength;
+}
+
+void SVGTextLayoutEngine::endTextPathLayout()
+{
+ m_inPathLayout = false;
+ m_textPath = Path();
+ m_textPathLength = 0;
+ m_textPathStartOffset = 0;
+ m_textPathCurrentOffset = 0;
+ m_textPathSpacing = 0;
+ m_textPathScaling = 1;
+}
+
+void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox)
+{
+ ASSERT(textBox);
+
+ RenderSVGInlineText* text = toRenderSVGInlineText(textBox->textRenderer());
+ ASSERT(text);
+ ASSERT(text->parent());
+ ASSERT(text->parent()->node());
+ ASSERT(text->parent()->node()->isSVGElement());
+
+ const RenderStyle* style = text->style();
+ ASSERT(style);
+
+ textBox->clearTextFragments();
+ m_isVerticalText = style->svgStyle()->isVerticalWritingMode();
+ layoutTextOnLineOrPath(textBox, text, style);
+
+ if (m_inPathLayout) {
+ m_pathLayoutBoxes.append(textBox);
+ return;
+ }
+
+ m_lineLayoutBoxes.append(textBox);
+}
+
+void SVGTextLayoutEngine::finishLayout()
+{
+ // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks.
+ // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done.
+ m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes);
+
+ // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized.
+ if (!m_lineLayoutBoxes.isEmpty()) {
+#if DUMP_TEXT_FRAGMENTS > 0
+ fprintf(stderr, "Line layout: ");
+#endif
+
+ finalizeTransformMatrices(m_lineLayoutBoxes);
+ }
+
+ if (!m_pathLayoutBoxes.isEmpty()) {
+#if DUMP_TEXT_FRAGMENTS > 0
+ fprintf(stderr, "Path layout: ");
+#endif
+ finalizeTransformMatrices(m_pathLayoutBoxes);
+ }
+}
+
+void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes)
+{
+ unsigned boxCount = boxes.size();
+
+#if DUMP_TEXT_FRAGMENTS > 0
+ fprintf(stderr, "Dumping all text fragments in text sub tree, %i boxes\n", boxCount);
+
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ SVGInlineTextBox* textBox = boxes.at(boxPosition);
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+ fprintf(stderr, "-> Box %i: Dumping text fragments for SVGInlineTextBox, textBox=%p, textRenderer=%p\n", boxPosition, textBox, textBox->textRenderer());
+ fprintf(stderr, " textBox properties, start=%i, len=%i\n", textBox->start(), textBox->len());
+ fprintf(stderr, " textRenderer properties, textLength=%i\n", textBox->textRenderer()->textLength());
+
+ const UChar* characters = textBox->textRenderer()->characters();
+
+ unsigned fragmentCount = fragments.size();
+ for (unsigned i = 0; i < fragmentCount; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+ String fragmentString(characters + fragment.positionListOffset, fragment.length);
+ fprintf(stderr, " -> Fragment %i, x=%lf, y=%lf, width=%lf, height=%lf, positionListOffset=%i, length=%i, characters='%s'\n"
+ , i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.positionListOffset, fragment.length, fragmentString.utf8().data());
+ }
+ }
+#endif
+
+
+ if (!boxCount)
+ return;
+
+ AffineTransform textBoxTransformation;
+ for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
+ SVGInlineTextBox* textBox = boxes.at(boxPosition);
+ Vector<SVGTextFragment>& fragments = textBox->textFragments();
+
+ unsigned fragmentCount = fragments.size();
+ for (unsigned i = 0; i < fragmentCount; ++i) {
+ SVGTextFragment& fragment = fragments.at(i);
+ AffineTransform& transform = fragment.transform;
+ if (!transform.isIdentity()) {
+ transform.translateRight(fragment.x, fragment.y);
+ transform.translate(-fragment.x, -fragment.y);
+ }
+
+ m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation);
+ if (textBoxTransformation.isIdentity())
+ continue;
+
+ if (transform.isIdentity())
+ transform = textBoxTransformation;
+ else
+ transform.multiply(textBoxTransformation);
+ }
+ }
+
+ boxes.clear();
+}
+
+void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style)
+{
+ SVGElement* lengthContext = static_cast<SVGElement*>(text->parent()->node());
+
+ RenderObject* textParent = text->parent();
+ bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false;
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ SVGTextLayoutAttributes& attributes = text->layoutAttributes();
+ Vector<float>& xValues = attributes.xValues();
+ Vector<float>& yValues = attributes.yValues();
+ Vector<float>& dxValues = attributes.dxValues();
+ Vector<float>& dyValues = attributes.dyValues();
+ Vector<float>& rotateValues = attributes.rotateValues();
+ Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
+
+ unsigned boxStart = textBox->start();
+ unsigned boxLength = textBox->len();
+ unsigned textMetricsSize = textMetricsValues.size();
+ ASSERT(textMetricsSize <= xValues.size());
+ ASSERT(textMetricsSize <= yValues.size());
+ ASSERT(xValues.size() == yValues.size());
+
+ if (boxLength > textMetricsSize)
+ textMetricsSize = boxLength;
+
+ unsigned positionListOffset = 0;
+ unsigned metricsListOffset = 0;
+ const UChar* characters = text->characters();
+
+ const Font& font = style->font();
+ SVGTextLayoutEngineSpacing spacingLayout(font);
+ SVGTextLayoutEngineBaseline baselineLayout(font);
+
+ bool didStartTextFragment = false;
+ bool applySpacingToNextCharacter = false;
+
+ float lastAngle = 0;
+ float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext);
+ baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, text);
+
+ // Main layout algorithm.
+ unsigned positionListSize = xValues.size();
+ for (; metricsListOffset < textMetricsSize && positionListOffset < positionListSize; ++metricsListOffset) {
+ SVGTextMetrics& metrics = textMetricsValues.at(metricsListOffset);
+ // Advance to text box start location.
+ if (positionListOffset < boxStart) {
+ positionListOffset += metrics.length();
+ continue;
+ }
+
+ // Stop if we've finished processing this text box.
+ if (positionListOffset >= boxStart + boxLength)
+ break;
+
+ float x = xValues.at(positionListOffset);
+ float y = yValues.at(positionListOffset);
+
+ // When we've advanced to the box start offset, determine using the original x/y values,
+ // wheter this character starts a new text chunk, before doing any further processing.
+ if (positionListOffset == boxStart)
+ textBox->setStartsNewTextChunk(text->characterStartsNewTextChunk(boxStart));
+
+ if (metrics == SVGTextMetrics::emptyMetrics()) {
+ positionListOffset += metrics.length();
+ continue;
+ }
+
+ const UChar* currentCharacter = characters + positionListOffset;
+ float angle = 0;
+ if (!rotateValues.isEmpty()) {
+ float newAngle = rotateValues.at(positionListOffset);
+ if (newAngle != SVGTextLayoutAttributes::emptyValue())
+ angle = newAngle;
+ }
+
+ // Calculate glyph orientation angle.
+ float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter);
+
+ // Calculate glyph advance & x/y orientation shifts.
+ float xOrientationShift = 0;
+ float yOrientationShift = 0;
+ float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, metrics, orientationAngle, xOrientationShift, yOrientationShift);
+
+ // Assign current text position to x/y values, if needed.
+ updateCharacerPositionIfNeeded(x, y);
+
+ // Apply dx/dy value adjustments to current text position, if needed.
+ updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues, positionListOffset);
+
+ // Calculate SVG Fonts kerning, if needed.
+ float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, metrics.glyph());
+
+ // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed.
+ float spacing = spacingLayout.calculateCSSKerningAndSpacing(svgStyle, lengthContext, currentCharacter);
+
+ float textPathOffset = 0;
+ if (m_inPathLayout) {
+ float scaledGlyphAdvance = glyphAdvance * m_textPathScaling;
+ if (m_isVerticalText) {
+ // If there's an absolute y position available, it marks the beginning of a new position along the path.
+ if (y != SVGTextLayoutAttributes::emptyValue())
+ m_textPathCurrentOffset = y + m_textPathStartOffset;
+
+ m_textPathCurrentOffset += m_dy - kerning;
+ m_dy = 0;
+
+ // Apply dx/dy correction and setup translations that move to the glyph midpoint.
+ xOrientationShift += m_dx + baselineShift;
+ yOrientationShift -= scaledGlyphAdvance / 2;
+ } else {
+ // If there's an absolute x position available, it marks the beginning of a new position along the path.
+ if (x != SVGTextLayoutAttributes::emptyValue())
+ m_textPathCurrentOffset = x + m_textPathStartOffset;
+
+ m_textPathCurrentOffset += m_dx - kerning;
+ m_dx = 0;
+
+ // Apply dx/dy correction and setup translations that move to the glyph midpoint.
+ xOrientationShift -= scaledGlyphAdvance / 2;
+ yOrientationShift += m_dy - baselineShift;
+ }
+
+ // Calculate current offset along path.
+ textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2;
+
+ // Move to next character.
+ m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing + spacing * m_textPathScaling;
+
+ // Skip character, if we're before the path.
+ if (textPathOffset < 0) {
+ positionListOffset += metrics.length();
+ continue;
+ }
+
+ // Stop processing, if the next character lies behind the path.
+ if (textPathOffset > m_textPathLength)
+ break;
+
+ bool ok = false;
+ FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok);
+ ASSERT(ok);
+
+ x = point.x();
+ y = point.y();
+ angle = m_textPath.normalAngleAtLength(textPathOffset, ok);
+ ASSERT(ok);
+
+ // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle!
+ if (m_isVerticalText)
+ angle -= 90;
+ } else {
+ // Apply all previously calculated shift values.
+ if (m_isVerticalText) {
+ x += baselineShift;
+ y -= kerning;
+ } else {
+ x -= kerning;
+ y -= baselineShift;
+ }
+
+ x += m_dx;
+ y += m_dy;
+ }
+
+ // Determine wheter we have to start a new fragment.
+ bool shouldStartNewFragment = false;
+
+ if (m_dx || m_dy)
+ shouldStartNewFragment = true;
+
+ if (!shouldStartNewFragment && (m_isVerticalText || m_inPathLayout))
+ shouldStartNewFragment = true;
+
+ if (!shouldStartNewFragment && (angle || angle != lastAngle || orientationAngle))
+ shouldStartNewFragment = true;
+
+ if (!shouldStartNewFragment && (kerning || applySpacingToNextCharacter || definesTextLength))
+ shouldStartNewFragment = true;
+
+ // If we already started a fragment, close it now.
+ if (didStartTextFragment && shouldStartNewFragment) {
+ applySpacingToNextCharacter = false;
+ recordTextFragment(textBox, text, positionListOffset, textMetricsValues.at(metricsListOffset - 1));
+ }
+
+ // Eventually start a new fragment, if not yet done.
+ if (!didStartTextFragment || shouldStartNewFragment) {
+ ASSERT(!m_currentTextFragment.positionListOffset);
+ ASSERT(!m_currentTextFragment.length);
+
+ didStartTextFragment = true;
+ m_currentTextFragment.positionListOffset = positionListOffset;
+ m_currentTextFragment.x = x;
+ m_currentTextFragment.y = y;
+
+ // Build fragment transformation.
+ if (angle)
+ m_currentTextFragment.transform.rotate(angle);
+
+ if (xOrientationShift || yOrientationShift)
+ m_currentTextFragment.transform.translate(xOrientationShift, yOrientationShift);
+
+ if (orientationAngle)
+ m_currentTextFragment.transform.rotate(orientationAngle);
+
+ if (m_inPathLayout && m_textPathScaling != 1) {
+ if (m_isVerticalText)
+ m_currentTextFragment.transform.scaleNonUniform(1, m_textPathScaling);
+ else
+ m_currentTextFragment.transform.scaleNonUniform(m_textPathScaling, 1);
+ }
+ }
+
+ // Update current text position, after processing of the current character finished.
+ if (m_inPathLayout)
+ updateCurrentTextPosition(x, y, glyphAdvance);
+ else {
+ // Apply CSS 'kerning', 'letter-spacing' and 'word-spacing' to next character, if needed.
+ if (spacing)
+ applySpacingToNextCharacter = true;
+
+ float xNew = x - m_dx;
+ float yNew = y - m_dy;
+
+ if (m_isVerticalText)
+ xNew -= baselineShift;
+ else
+ yNew += baselineShift;
+
+ updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing);
+ }
+
+ positionListOffset += metrics.length();
+ lastAngle = angle;
+ }
+
+ if (!didStartTextFragment)
+ return;
+
+ // Close last open fragment, if needed.
+ recordTextFragment(textBox, text, positionListOffset, textMetricsValues.at(metricsListOffset - 1));
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutEngine.h b/WebCore/rendering/svg/SVGTextLayoutEngine.h
new file mode 100644
index 0000000..ad058d8
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutEngine.h
@@ -0,0 +1,94 @@
+/*
+ * 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
+ * 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 SVGTextLayoutEngine_h
+#define SVGTextLayoutEngine_h
+
+#if ENABLE(SVG)
+#include "Path.h"
+#include "SVGTextChunkBuilder.h"
+#include "SVGTextFragment.h"
+#include "SVGTextMetrics.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderStyle;
+class RenderSVGInlineText;
+class SVGElement;
+class SVGInlineTextBox;
+class SVGRenderStyle;
+
+// SVGTextLayoutEngine performs the second layout phase for SVG text.
+//
+// The InlineBox tree was created, containing the text chunk information, necessary to apply
+// certain SVG specific text layout properties (text-length adjustments and text-anchor).
+// The second layout phase uses the SVGTextLayoutAttributes stored in the individual
+// RenderSVGInlineText renderers to compute the final positions for each character
+// which are stored in the SVGInlineTextBox objects.
+
+class SVGTextLayoutEngine : public Noncopyable {
+public:
+ SVGTextLayoutEngine();
+ SVGTextChunkBuilder& chunkLayoutBuilder() { return m_chunkLayoutBuilder; }
+
+ void beginTextPathLayout(RenderObject*, SVGTextLayoutEngine& lineLayout);
+ void endTextPathLayout();
+
+ void layoutInlineTextBox(SVGInlineTextBox*);
+ void finishLayout();
+
+private:
+ void updateCharacerPositionIfNeeded(float& x, float& y);
+ void updateCurrentTextPosition(float x, float y, float glyphAdvance);
+ void updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues, unsigned valueListPosition);
+
+ void recordTextFragment(SVGInlineTextBox*, RenderSVGInlineText*, unsigned positionListOffset, const SVGTextMetrics& lastCharacterMetrics);
+ bool parentDefinesTextLength(RenderObject*) const;
+
+ void layoutTextOnLineOrPath(SVGInlineTextBox*, RenderSVGInlineText*, const RenderStyle*);
+ void finalizeTransformMatrices(Vector<SVGInlineTextBox*>&);
+
+private:
+ Vector<SVGInlineTextBox*> m_lineLayoutBoxes;
+ Vector<SVGInlineTextBox*> m_pathLayoutBoxes;
+ SVGTextChunkBuilder m_chunkLayoutBuilder;
+
+ SVGTextFragment m_currentTextFragment;
+ float m_x;
+ float m_y;
+ float m_dx;
+ float m_dy;
+ bool m_isVerticalText;
+ bool m_inPathLayout;
+
+ // Text on path layout
+ Path m_textPath;
+ float m_textPathLength;
+ float m_textPathStartOffset;
+ float m_textPathCurrentOffset;
+ float m_textPathSpacing;
+ float m_textPathScaling;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp
new file mode 100644
index 0000000..7060ac6
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutEngineBaseline.h"
+
+#include "Font.h"
+#include "RenderObject.h"
+#include "SVGRenderStyle.h"
+#include "SVGTextMetrics.h"
+#include "UnicodeRange.h"
+
+namespace WebCore {
+
+SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font)
+ : m_font(font)
+{
+}
+
+float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* lengthContext) const
+{
+ if (style->baselineShift() == BS_LENGTH) {
+ SVGLength baselineShiftValueLength = style->baselineShiftValue();
+ if (baselineShiftValueLength.unitType() == LengthTypePercentage)
+ return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize();
+
+ return baselineShiftValueLength.value(lengthContext);
+ }
+
+ switch (style->baselineShift()) {
+ case BS_BASELINE:
+ return 0;
+ case BS_SUB:
+ return -m_font.height() / 2;
+ case BS_SUPER:
+ return m_font.height() / 2;
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+EAlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const
+{
+ ASSERT(textRenderer);
+ ASSERT(textRenderer->style());
+ ASSERT(textRenderer->parent());
+ ASSERT(textRenderer->parent()->style());
+
+ const SVGRenderStyle* style = textRenderer->style()->svgStyle();
+ ASSERT(style);
+
+ EDominantBaseline baseline = style->dominantBaseline();
+ if (baseline == DB_AUTO) {
+ if (isVerticalText)
+ baseline = DB_CENTRAL;
+ else
+ baseline = DB_ALPHABETIC;
+ }
+
+ switch (baseline) {
+ case DB_USE_SCRIPT:
+ // FIXME: The dominant-baseline and the baseline-table components are set by determining the predominant script of the character data content.
+ return AB_ALPHABETIC;
+ case DB_NO_CHANGE:
+ return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
+ case DB_RESET_SIZE:
+ return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
+ case DB_IDEOGRAPHIC:
+ return AB_IDEOGRAPHIC;
+ case DB_ALPHABETIC:
+ return AB_ALPHABETIC;
+ case DB_HANGING:
+ return AB_HANGING;
+ case DB_MATHEMATICAL:
+ return AB_MATHEMATICAL;
+ case DB_CENTRAL:
+ return AB_CENTRAL;
+ case DB_MIDDLE:
+ return AB_MIDDLE;
+ case DB_TEXT_AFTER_EDGE:
+ return AB_TEXT_AFTER_EDGE;
+ case DB_TEXT_BEFORE_EDGE:
+ return AB_TEXT_BEFORE_EDGE;
+ default:
+ ASSERT_NOT_REACHED();
+ return AB_AUTO;
+ }
+}
+
+float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const
+{
+ ASSERT(textRenderer);
+ ASSERT(textRenderer->style());
+ ASSERT(textRenderer->style()->svgStyle());
+ ASSERT(textRenderer->parent());
+
+ const RenderObject* textRendererParent = textRenderer->parent();
+ ASSERT(textRendererParent);
+
+ EAlignmentBaseline baseline = textRenderer->style()->svgStyle()->alignmentBaseline();
+ if (baseline == AB_AUTO) {
+ baseline = dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
+ ASSERT(baseline != AB_AUTO);
+ }
+
+ // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
+ switch (baseline) {
+ case AB_BASELINE:
+ return dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
+ case AB_BEFORE_EDGE:
+ case AB_TEXT_BEFORE_EDGE:
+ return m_font.ascent();
+ case AB_MIDDLE:
+ return m_font.xHeight() / 2;
+ case AB_CENTRAL:
+ return (m_font.ascent() - m_font.descent()) / 2;
+ case AB_AFTER_EDGE:
+ case AB_TEXT_AFTER_EDGE:
+ case AB_IDEOGRAPHIC:
+ return m_font.descent();
+ case AB_ALPHABETIC:
+ return 0;
+ case AB_HANGING:
+ return m_font.ascent() * 8 / 10.f;
+ case AB_MATHEMATICAL:
+ return m_font.ascent() / 2;
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle* style, const UChar& character) const
+{
+ ASSERT(style);
+
+ switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) {
+ case GO_AUTO:
+ {
+ // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees.
+ // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees.
+ unsigned int unicodeRange = findCharUnicodeRange(character);
+ if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic)
+ return 90;
+
+ return 0;
+ }
+ case GO_90DEG:
+ return 90;
+ case GO_180DEG:
+ return 180;
+ case GO_270DEG:
+ return 270;
+ case GO_0DEG:
+ default:
+ return 0;
+ }
+}
+
+static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
+{
+ return !fabsf(fmodf(orientationAngle, 180));
+}
+
+float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics& metrics, float angle, float& xOrientationShift, float& yOrientationShift) const
+{
+ bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(angle);
+
+ // The function is based on spec requirements:
+ //
+ // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of
+ // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph.
+ //
+ // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of
+ // 180 degrees, then the current text position is incremented according to the horizontal metrics of the glyph.
+
+ // Vertical orientation handling.
+ if (isVerticalText) {
+ float ascentMinusDescent = m_font.ascent() - m_font.descent();
+ if (!angle) {
+ xOrientationShift = (ascentMinusDescent - metrics.width()) / 2;
+ yOrientationShift = m_font.ascent();
+ } else if (angle == 180)
+ xOrientationShift = (ascentMinusDescent + metrics.width()) / 2;
+ else if (angle == 270) {
+ yOrientationShift = metrics.width();
+ xOrientationShift = ascentMinusDescent;
+ }
+
+ // Vertical advance calculation.
+ if (angle && !orientationIsMultiplyOf180Degrees)
+ return metrics.width();
+
+ return metrics.height();
+ }
+
+ // Horizontal orientation handling.
+ if (angle == 90)
+ yOrientationShift = -metrics.width();
+ else if (angle == 180) {
+ xOrientationShift = metrics.width();
+ yOrientationShift = -m_font.ascent();
+ } else if (angle == 270)
+ xOrientationShift = metrics.width();
+
+ // Horizontal advance calculation.
+ if (angle && !orientationIsMultiplyOf180Degrees)
+ return metrics.height();
+
+ return metrics.width();
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h b/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h
new file mode 100644
index 0000000..d753b39
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h
@@ -0,0 +1,54 @@
+/*
+ * 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
+ * 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 SVGTextLayoutEngineBaseline_h
+#define SVGTextLayoutEngineBaseline_h
+
+#if ENABLE(SVG)
+#include "SVGRenderStyleDefs.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class Font;
+class RenderObject;
+class SVGElement;
+class SVGRenderStyle;
+class SVGTextMetrics;
+
+// Helper class used by SVGTextLayoutEngine to handle 'alignment-baseline' / 'dominant-baseline' and 'baseline-shift'.
+class SVGTextLayoutEngineBaseline : public Noncopyable {
+public:
+ SVGTextLayoutEngineBaseline(const Font&);
+
+ float calculateBaselineShift(const SVGRenderStyle*, SVGElement* lengthContext) const;
+ float calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const;
+ float calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle*, const UChar& character) const;
+ float calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics&, float angle, float& xOrientationShift, float& yOrientationShift) const;
+
+private:
+ EAlignmentBaseline dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const;
+
+ const Font& m_font;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp
new file mode 100644
index 0000000..6c54b67
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutEngineSpacing.h"
+
+#include "Font.h"
+#include "SVGRenderStyle.h"
+
+#if ENABLE(SVG_FONTS)
+#include "SVGFontElement.h"
+#endif
+
+namespace WebCore {
+
+SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font)
+ : m_font(font)
+ , m_lastCharacter(0)
+{
+}
+
+float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph)
+{
+#if ENABLE(SVG_FONTS)
+ if (!m_font.isSVGFont()) {
+ m_lastGlyph.isValid = false;
+ return 0;
+ }
+
+ SVGFontElement* svgFont = m_font.svgFont();
+ ASSERT(svgFont);
+
+ float kerning = 0;
+ if (m_lastGlyph.isValid) {
+ if (isVerticalText)
+ kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name);
+ else
+ kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name);
+ }
+
+ m_lastGlyph = currentGlyph;
+ m_lastGlyph.isValid = true;
+ kerning *= m_font.size() / m_font.primaryFont()->unitsPerEm();
+ return kerning;
+#else
+ UNUSED_PARAM(isVerticalText);
+ UNUSED_PARAM(currentGlyph);
+ return false;
+#endif
+}
+
+float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderStyle* style, SVGElement* lengthContext, const UChar* currentCharacter)
+{
+ float kerning = 0;
+ SVGLength kerningLength = style->kerning();
+ if (kerningLength.unitType() == LengthTypePercentage)
+ kerning = kerningLength.valueAsPercentage() * m_font.pixelSize();
+ else
+ kerning = kerningLength.value(lengthContext);
+
+ const UChar* lastCharacter = m_lastCharacter;
+ m_lastCharacter = currentCharacter;
+
+ if (!kerning && !m_font.letterSpacing() && !m_font.wordSpacing())
+ return 0;
+
+ float spacing = m_font.letterSpacing() + kerning;
+ if (currentCharacter && lastCharacter && m_font.wordSpacing()) {
+ if (Font::treatAsSpace(*currentCharacter) && !Font::treatAsSpace(*lastCharacter))
+ spacing += m_font.wordSpacing();
+ }
+
+ return spacing;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGCharacterData.cpp b/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h
index 394a303..0a6d736 100644
--- a/WebCore/rendering/SVGCharacterData.cpp
+++ b/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h
@@ -1,5 +1,4 @@
/*
- * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -16,40 +15,38 @@
* 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 "SVGCharacterData.h"
+#ifndef SVGTextLayoutEngineSpacing_h
+#define SVGTextLayoutEngineSpacing_h
#if ENABLE(SVG)
-#include "AffineTransform.h"
+#include "SVGTextMetrics.h"
namespace WebCore {
-bool SVGChar::isHidden() const
-{
- return pathData && pathData->hidden;
-}
+class Font;
+class SVGRenderStyle;
+class SVGElement;
-AffineTransform SVGChar::characterTransform() const
-{
- AffineTransform ctm;
+// Helper class used by SVGTextLayoutEngine to handle 'kerning' / 'letter-spacing' and 'word-spacing'.
+class SVGTextLayoutEngineSpacing : public Noncopyable {
+public:
+ SVGTextLayoutEngineSpacing(const Font&);
- // Rotate character around angle, and possibly scale.
- ctm.translate(x, y);
- ctm.rotate(angle);
+ float calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph);
+ float calculateCSSKerningAndSpacing(const SVGRenderStyle*, SVGElement* lengthContext, const UChar* currentCharacter);
- if (pathData) {
- ctm.scaleNonUniform(pathData->xScale, pathData->yScale);
- ctm.translate(pathData->xShift, pathData->yShift);
- ctm.rotate(pathData->orientationAngle);
- }
+private:
+ const Font& m_font;
+ const UChar* m_lastCharacter;
- ctm.translate(orientationShiftX - x, orientationShiftY - y);
- return ctm;
-}
+#if ENABLE(SVG_FONTS)
+ SVGTextMetrics::Glyph m_lastGlyph;
+#endif
+};
} // namespace WebCore
#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextMetrics.cpp b/WebCore/rendering/svg/SVGTextMetrics.cpp
new file mode 100644
index 0000000..58d0ad9
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextMetrics.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGTextMetrics.h"
+
+#include "RenderSVGInlineText.h"
+
+namespace WebCore {
+
+SVGTextMetrics::SVGTextMetrics()
+ : m_width(0)
+ , m_height(0)
+ , m_length(0)
+{
+}
+
+SVGTextMetrics::SVGTextMetrics(const Font& font, const TextRun& run, unsigned position, unsigned textLength)
+ : m_width(0)
+ , m_height(0)
+ , m_length(0)
+{
+ int extraCharsAvailable = textLength - (position + run.length());
+ int length = 0;
+
+ m_width = font.floatWidth(run, extraCharsAvailable, length, m_glyph.name);
+ m_height = font.height();
+ m_glyph.unicodeString = String(run.characters(), length);
+ m_glyph.isValid = true;
+
+ ASSERT(length >= 0);
+ m_length = static_cast<unsigned>(length);
+}
+
+bool SVGTextMetrics::operator==(const SVGTextMetrics& other)
+{
+ return m_width == other.m_width
+ && m_height == other.m_height
+ && m_length == other.m_length
+ && m_glyph == other.m_glyph;
+}
+
+SVGTextMetrics SVGTextMetrics::emptyMetrics()
+{
+ DEFINE_STATIC_LOCAL(SVGTextMetrics, s_emptyMetrics, ());
+ s_emptyMetrics.m_length = 1;
+ return s_emptyMetrics;
+}
+
+static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characters, unsigned position, unsigned length)
+{
+ TextRun run(characters + position, length);
+
+#if ENABLE(SVG_FONTS)
+ ASSERT(text->parent());
+ run.setReferencingRenderObject(text->parent());
+#endif
+
+ // Disable any word/character rounding.
+ run.disableRoundingHacks();
+
+ // We handle letter & word spacing ourselves.
+ run.disableSpacing();
+ return run;
+}
+
+SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length)
+{
+ ASSERT(text);
+ ASSERT(text->style());
+
+ TextRun run(constructTextRun(text, text->characters(), position, length));
+ return SVGTextMetrics(text->style()->font(), run, position, text->textLength());
+}
+
+void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, Vector<SVGTextMetrics>& allMetrics)
+{
+ ASSERT(text);
+ ASSERT(text->style());
+
+ const Font& font = text->style()->font();
+ const UChar* characters = text->characters();
+ unsigned length = text->textLength();
+
+ TextRun run(constructTextRun(text, 0, 0, 0));
+ for (unsigned position = 0; position < length; ) {
+ run.setText(characters + position, 1);
+
+ SVGTextMetrics metrics(font, run, position, text->textLength());
+ allMetrics.append(metrics);
+ position += metrics.length();
+ }
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextMetrics.h b/WebCore/rendering/svg/SVGTextMetrics.h
new file mode 100644
index 0000000..ba18589
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextMetrics.h
@@ -0,0 +1,78 @@
+/*
+ * 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
+ * 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 SVGTextMetrics_h
+#define SVGTextMetrics_h
+
+#if ENABLE(SVG)
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Font;
+class RenderSVGInlineText;
+class TextRun;
+
+class SVGTextMetrics {
+public:
+ static SVGTextMetrics emptyMetrics();
+ static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length);
+ static void measureAllCharactersIndividually(RenderSVGInlineText*, Vector<SVGTextMetrics>&);
+
+ bool operator==(const SVGTextMetrics&);
+
+ float width() const { return m_width; }
+ float height() const { return m_height; }
+ unsigned length() const { return m_length; }
+
+ struct Glyph {
+ Glyph()
+ : isValid(false)
+ {
+ }
+
+ bool operator==(const Glyph& other)
+ {
+ return isValid == other.isValid
+ && name == other.name
+ && unicodeString == other.unicodeString;
+ }
+
+ bool isValid;
+ String name;
+ String unicodeString;
+ };
+
+ // Only useful when measuring individual characters, to lookup ligatures.
+ const Glyph& glyph() const { return m_glyph; }
+
+private:
+ SVGTextMetrics();
+ SVGTextMetrics(const Font&, const TextRun&, unsigned position, unsigned textLength);
+
+ float m_width;
+ float m_height;
+ unsigned m_length;
+ Glyph m_glyph;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextQuery.cpp b/WebCore/rendering/svg/SVGTextQuery.cpp
new file mode 100644
index 0000000..fcc7924
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextQuery.cpp
@@ -0,0 +1,562 @@
+/*
+ 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
+ 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 "SVGTextQuery.h"
+
+#if ENABLE(SVG)
+#include "FloatConversion.h"
+#include "InlineFlowBox.h"
+#include "RenderBlock.h"
+#include "RenderInline.h"
+#include "RenderSVGInlineText.h"
+#include "SVGInlineTextBox.h"
+#include "SVGTextMetrics.h"
+#include "VisiblePosition.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+// Base structure for callback user data
+struct SVGTextQuery::Data {
+ Data()
+ : isVerticalText(false)
+ , processedCharacters(0)
+ , textRenderer(0)
+ , textBox(0)
+ {
+ }
+
+ bool isVerticalText;
+ unsigned processedCharacters;
+ RenderSVGInlineText* textRenderer;
+ const SVGInlineTextBox* textBox;
+};
+
+static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer)
+{
+ if (!renderer)
+ return 0;
+
+ if (renderer->isRenderBlock()) {
+ // If we're given a block element, it has to be a RenderSVGText.
+ ASSERT(renderer->isSVGText());
+ RenderBlock* renderBlock = toRenderBlock(renderer);
+
+ // RenderSVGText only ever contains a single line box.
+ InlineFlowBox* flowBox = renderBlock->firstLineBox();
+ ASSERT(flowBox == renderBlock->lastLineBox());
+ return flowBox;
+ }
+
+ if (renderer->isRenderInline()) {
+ // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath)
+ RenderInline* renderInline = toRenderInline(renderer);
+
+ // RenderSVGInline only ever contains a single line box.
+ InlineFlowBox* flowBox = renderInline->firstLineBox();
+ ASSERT(flowBox == renderInline->lastLineBox());
+ return flowBox;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static inline float mapLengthThroughFragmentTransformation(const SVGTextFragment& fragment, bool isVerticalText, float length)
+{
+ if (fragment.transform.isIdentity())
+ return length;
+
+ if (isVerticalText)
+ return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.yScale());
+
+ return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.xScale());
+}
+
+SVGTextQuery::SVGTextQuery(RenderObject* renderer)
+{
+ collectTextBoxesInFlowBox(flowBoxForRenderer(renderer));
+}
+
+void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox)
+{
+ if (!flowBox)
+ return;
+
+ for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) {
+ if (child->isInlineFlowBox()) {
+ // Skip generated content.
+ if (!child->renderer()->node())
+ continue;
+
+ collectTextBoxesInFlowBox(static_cast<InlineFlowBox*>(child));
+ continue;
+ }
+
+ ASSERT(child->isSVGInlineTextBox());
+ m_textBoxes.append(static_cast<SVGInlineTextBox*>(child));
+ }
+}
+
+bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fragmentCallback) const
+{
+ ASSERT(!m_textBoxes.isEmpty());
+
+ unsigned processedCharacters = 0;
+ unsigned textBoxCount = m_textBoxes.size();
+
+ // Loop over all text boxes
+ for (unsigned textBoxPosition = 0; textBoxPosition < textBoxCount; ++textBoxPosition) {
+ queryData->textBox = m_textBoxes.at(textBoxPosition);
+ queryData->textRenderer = toRenderSVGInlineText(queryData->textBox->textRenderer());
+ ASSERT(queryData->textRenderer);
+ ASSERT(queryData->textRenderer->style());
+ ASSERT(queryData->textRenderer->style()->svgStyle());
+
+ queryData->isVerticalText = queryData->textRenderer->style()->svgStyle()->isVerticalWritingMode();
+ const Vector<SVGTextFragment>& fragments = queryData->textBox->textFragments();
+
+ // Loop over all text fragments in this text box, firing a callback for each.
+ unsigned fragmentCount = fragments.size();
+ for (unsigned i = 0; i < fragmentCount; ++i) {
+ const SVGTextFragment& fragment = fragments.at(i);
+ if ((this->*fragmentCallback)(queryData, fragment))
+ return true;
+
+ processedCharacters += fragment.length;
+ }
+
+ queryData->processedCharacters = processedCharacters;
+ }
+
+ return false;
+}
+
+bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const
+{
+ // Reuse the same logic used for text selection & painting, to map our query start/length into start/endPositions of the current text fragment.
+ startPosition -= queryData->processedCharacters;
+ endPosition -= queryData->processedCharacters;
+
+ if (startPosition >= endPosition || startPosition < 0 || endPosition < 0)
+ return false;
+
+ modifyStartEndPositionsRespectingLigatures(queryData, startPosition, endPosition);
+ if (!queryData->textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, startPosition, endPosition))
+ return false;
+
+ ASSERT(startPosition < endPosition);
+ return true;
+}
+
+void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& endPosition) const
+{
+ const SVGTextLayoutAttributes& layoutAttributes = queryData->textRenderer->layoutAttributes();
+ const Vector<float>& xValues = layoutAttributes.xValues();
+ const Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes.textMetricsValues();
+
+ unsigned boxStart = queryData->textBox->start();
+ unsigned boxLength = queryData->textBox->len();
+
+ unsigned textMetricsOffset = 0;
+ unsigned textMetricsSize = textMetricsValues.size();
+
+ unsigned positionOffset = 0;
+ unsigned positionSize = xValues.size();
+
+ bool alterStartPosition = true;
+ bool alterEndPosition = true;
+
+ int lastPositionOffset = -1;
+ for (; textMetricsOffset < textMetricsSize && positionOffset < positionSize; ++textMetricsOffset) {
+ const SVGTextMetrics& metrics = textMetricsValues.at(textMetricsOffset);
+
+ // Advance to text box start location.
+ if (positionOffset < boxStart) {
+ positionOffset += metrics.length();
+ continue;
+ }
+
+ // Stop if we've finished processing this text box.
+ if (positionOffset >= boxStart + boxLength)
+ break;
+
+ // If the start position maps to a character in the metrics list, we don't need to modify it.
+ if (startPosition == static_cast<int>(positionOffset))
+ alterStartPosition = false;
+
+ // If the start position maps to a character in the metrics list, we don't need to modify it.
+ if (endPosition == static_cast<int>(positionOffset))
+ alterEndPosition = false;
+
+ // Detect ligatures.
+ if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
+ if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
+ startPosition = lastPositionOffset;
+ alterStartPosition = false;
+ }
+
+ if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
+ endPosition = positionOffset;
+ alterEndPosition = false;
+ }
+ }
+
+ if (!alterStartPosition && !alterEndPosition)
+ break;
+
+ lastPositionOffset = positionOffset;
+ positionOffset += metrics.length();
+ }
+
+ if (!alterStartPosition && !alterEndPosition)
+ return;
+
+ if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
+ if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
+ startPosition = lastPositionOffset;
+ alterStartPosition = false;
+ }
+
+ if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
+ endPosition = positionOffset;
+ alterEndPosition = false;
+ }
+ }
+}
+
+// numberOfCharacters() implementation
+bool SVGTextQuery::numberOfCharactersCallback(Data*, const SVGTextFragment&) const
+{
+ // no-op
+ return false;
+}
+
+unsigned SVGTextQuery::numberOfCharacters() const
+{
+ if (m_textBoxes.isEmpty())
+ return 0;
+
+ Data data;
+ executeQuery(&data, &SVGTextQuery::numberOfCharactersCallback);
+ return data.processedCharacters;
+}
+
+// textLength() implementation
+struct TextLengthData : SVGTextQuery::Data {
+ TextLengthData()
+ : textLength(0)
+ {
+ }
+
+ float textLength;
+};
+
+bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ TextLengthData* data = static_cast<TextLengthData*>(queryData);
+
+ float fragmentLength = queryData->isVerticalText ? fragment.height : fragment.width;
+ data->textLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength);
+ return false;
+}
+
+float SVGTextQuery::textLength() const
+{
+ if (m_textBoxes.isEmpty())
+ return 0;
+
+ TextLengthData data;
+ executeQuery(&data, &SVGTextQuery::textLengthCallback);
+ return data.textLength;
+}
+
+// subStringLength() implementation
+struct SubStringLengthData : SVGTextQuery::Data {
+ SubStringLengthData(unsigned queryStartPosition, unsigned queryLength)
+ : startPosition(queryStartPosition)
+ , length(queryLength)
+ , subStringLength(0)
+ {
+ }
+
+ unsigned startPosition;
+ unsigned length;
+
+ float subStringLength;
+};
+
+bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData);
+
+ int startPosition = data->startPosition;
+ int endPosition = startPosition + data->length;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ return false;
+
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset + startPosition, endPosition - startPosition);
+ float fragmentLength = queryData->isVerticalText ? metrics.height() : metrics.width();
+
+ data->subStringLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength);
+ return false;
+}
+
+float SVGTextQuery::subStringLength(unsigned startPosition, unsigned length) const
+{
+ if (m_textBoxes.isEmpty())
+ return 0;
+
+ SubStringLengthData data(startPosition, length);
+ executeQuery(&data, &SVGTextQuery::subStringLengthCallback);
+ return data.subStringLength;
+}
+
+// startPositionOfCharacter() implementation
+struct StartPositionOfCharacterData : SVGTextQuery::Data {
+ StartPositionOfCharacterData(unsigned queryPosition)
+ : position(queryPosition)
+ {
+ }
+
+ unsigned position;
+ FloatPoint startPosition;
+};
+
+bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterData*>(queryData);
+
+ int startPosition = data->position;
+ int endPosition = startPosition + 1;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ return false;
+
+ data->startPosition = FloatPoint(fragment.x, fragment.y);
+
+ if (startPosition) {
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition);
+ if (queryData->isVerticalText)
+ data->startPosition.move(0, metrics.height());
+ else
+ data->startPosition.move(metrics.width(), 0);
+ }
+
+ if (fragment.transform.isIdentity())
+ return true;
+
+ data->startPosition = fragment.transform.mapPoint(data->startPosition);
+ return true;
+}
+
+FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const
+{
+ if (m_textBoxes.isEmpty())
+ return FloatPoint();
+
+ StartPositionOfCharacterData data(position);
+ executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback);
+ return data.startPosition;
+}
+
+// endPositionOfCharacter() implementation
+struct EndPositionOfCharacterData : SVGTextQuery::Data {
+ EndPositionOfCharacterData(unsigned queryPosition)
+ : position(queryPosition)
+ {
+ }
+
+ unsigned position;
+ FloatPoint endPosition;
+};
+
+bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData);
+
+ int startPosition = data->position;
+ int endPosition = startPosition + 1;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ return false;
+
+ data->endPosition = FloatPoint(fragment.x, fragment.y);
+
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition + 1);
+ if (queryData->isVerticalText)
+ data->endPosition.move(0, metrics.height());
+ else
+ data->endPosition.move(metrics.width(), 0);
+
+ if (fragment.transform.isIdentity())
+ return true;
+
+ data->endPosition = fragment.transform.mapPoint(data->endPosition);
+ return true;
+}
+
+FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const
+{
+ if (m_textBoxes.isEmpty())
+ return FloatPoint();
+
+ EndPositionOfCharacterData data(position);
+ executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback);
+ return data.endPosition;
+}
+
+// rotationOfCharacter() implementation
+struct RotationOfCharacterData : SVGTextQuery::Data {
+ RotationOfCharacterData(unsigned queryPosition)
+ : position(queryPosition)
+ , rotation(0)
+ {
+ }
+
+ unsigned position;
+ float rotation;
+};
+
+bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData);
+
+ int startPosition = data->position;
+ int endPosition = startPosition + 1;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ return false;
+
+ AffineTransform newTransform(fragment.transform);
+ newTransform.scale(1 / fragment.transform.xScale(), 1 / fragment.transform.yScale());
+ data->rotation = narrowPrecisionToFloat(rad2deg(atan2(newTransform.b(), newTransform.a())));
+ return true;
+}
+
+float SVGTextQuery::rotationOfCharacter(unsigned position) const
+{
+ if (m_textBoxes.isEmpty())
+ return 0;
+
+ RotationOfCharacterData data(position);
+ executeQuery(&data, &SVGTextQuery::rotationOfCharacterCallback);
+ return data.rotation;
+}
+
+// extentOfCharacter() implementation
+struct ExtentOfCharacterData : SVGTextQuery::Data {
+ ExtentOfCharacterData(unsigned queryPosition)
+ : position(queryPosition)
+ {
+ }
+
+ unsigned position;
+ FloatRect extent;
+};
+
+static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent)
+{
+ extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->style()->font().ascent()));
+
+ if (startPosition) {
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition);
+ if (queryData->isVerticalText)
+ extent.move(0, metrics.height());
+ else
+ extent.move(metrics.width(), 0);
+ }
+
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset + startPosition, 1);
+ extent.setSize(FloatSize(metrics.width(), metrics.height()));
+
+ if (fragment.transform.isIdentity())
+ return;
+
+ extent = fragment.transform.mapRect(extent);
+}
+
+bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData);
+
+ int startPosition = data->position;
+ int endPosition = startPosition + 1;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ return false;
+
+ calculateGlyphBoundaries(queryData, fragment, startPosition, data->extent);
+ return true;
+}
+
+FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const
+{
+ if (m_textBoxes.isEmpty())
+ return FloatRect();
+
+ ExtentOfCharacterData data(position);
+ executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback);
+ return data.extent;
+}
+
+// characterNumberAtPosition() implementation
+struct CharacterNumberAtPositionData : SVGTextQuery::Data {
+ CharacterNumberAtPositionData(const FloatPoint& queryPosition)
+ : position(queryPosition)
+ {
+ }
+
+ FloatPoint position;
+};
+
+bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGTextFragment& fragment) const
+{
+ CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionData*>(queryData);
+
+ FloatRect extent;
+ for (unsigned i = 0; i < fragment.length; ++i) {
+ int startPosition = data->processedCharacters + i;
+ int endPosition = startPosition + 1;
+ if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
+ continue;
+
+ calculateGlyphBoundaries(queryData, fragment, startPosition, extent);
+ if (extent.contains(data->position)) {
+ data->processedCharacters += i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const
+{
+ if (m_textBoxes.isEmpty())
+ return -1;
+
+ CharacterNumberAtPositionData data(position);
+ if (!executeQuery(&data, &SVGTextQuery::characterNumberAtPositionCallback))
+ return -1;
+
+ return data.processedCharacters;
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGTextQuery.h b/WebCore/rendering/svg/SVGTextQuery.h
index f19c72e..9a671f4 100644
--- a/WebCore/rendering/SVGTextQuery.h
+++ b/WebCore/rendering/svg/SVGTextQuery.h
@@ -22,15 +22,14 @@
#if ENABLE(SVG)
#include "FloatRect.h"
+#include "SVGTextFragment.h"
#include <wtf/Vector.h>
namespace WebCore {
class InlineFlowBox;
class RenderObject;
-class RenderStyle;
class SVGInlineTextBox;
-struct SVGTextChunkPart;
class SVGTextQuery {
public:
@@ -49,22 +48,22 @@ public:
struct Data;
private:
- typedef bool (SVGTextQuery::*ProcessTextChunkPartCallback)(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool executeQuery(Data*, ProcessTextChunkPartCallback) const;
+ typedef bool (SVGTextQuery::*ProcessTextFragmentCallback)(Data*, const SVGTextFragment&) const;
+ bool executeQuery(Data*, ProcessTextFragmentCallback) const;
void collectTextBoxesInFlowBox(InlineFlowBox*);
- float measureCharacterRange(const SVGInlineTextBox*, RenderStyle*, bool isVerticalText, int startPosition, int length) const;
- bool mapStartAndLengthIntoChunkPartCoordinates(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&, int& startPosition, int& endPosition) const;
+ bool mapStartEndPositionsIntoFragmentCoordinates(Data*, const SVGTextFragment&, int& startPosition, int& endPosition) const;
+ void modifyStartEndPositionsRespectingLigatures(Data*, int& startPosition, int& endPosition) const;
private:
- bool numberOfCharactersCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool textLengthCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool subStringLengthCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool startPositionOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool endPositionOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool rotationOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool extentOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
- bool characterNumberAtPositionCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const;
+ bool numberOfCharactersCallback(Data*, const SVGTextFragment&) const;
+ bool textLengthCallback(Data*, const SVGTextFragment&) const;
+ bool subStringLengthCallback(Data*, const SVGTextFragment&) const;
+ bool startPositionOfCharacterCallback(Data*, const SVGTextFragment&) const;
+ bool endPositionOfCharacterCallback(Data*, const SVGTextFragment&) const;
+ bool rotationOfCharacterCallback(Data*, const SVGTextFragment&) const;
+ bool extentOfCharacterCallback(Data*, const SVGTextFragment&) const;
+ bool characterNumberAtPositionCallback(Data*, const SVGTextFragment&) const;
private:
Vector<SVGInlineTextBox*> m_textBoxes;